diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index d73f27c3..6734ecb5 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -20,9 +20,11 @@ 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 raddbg_from_pdb msvc debug || exit /b 1 - call build raddbg_from_dwarf msvc debug || exit /b 1 - call build raddbg clang debug || exit /b 1 - call build raddbg_from_pdb clang debug || exit /b 1 - call build raddbg_from_dwarf clang debug || exit /b 1 + call build raddbg msvc debug || exit /b 1 + call build raddbgi_from_pdb msvc debug || exit /b 1 + call build raddbgi_from_dwarf msvc debug || exit /b 1 + call build raddbgi_dump msvc debug || exit /b 1 + call build raddbg clang debug || exit /b 1 + call build raddbgi_from_pdb clang debug || exit /b 1 + call build raddbgi_from_dwarf clang debug || exit /b 1 + call build raddbgi_dump clang debug || exit /b 1 diff --git a/README.md b/README.md index 1af8fc83..13d40cec 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # The RAD Debugger Project +_**Note:** This README does not document usage instructions and tips for the +debugger itself, and is intended as a technical overview of the project. The +debugger's README, which includes usage instructions and tips, can be found +packaged along with debugger releases, or within the `build` folder after a +local copy has been built._ + 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. In the future we'll expand to also @@ -15,22 +21,25 @@ You can download pre-built binaries for the debugger The RAD Debugger project aims to simplify the debugger by simplifying and unifying the underlying debug info format. In that pursuit we've built -the RADDBG debug info format, which is what the debugger parses and uses. To +the RADDBGI debug info format, which is what the debugger parses and uses. To work with existing toolchains, we convert PDB (and eventually PE/ELF files -with embedded DWARF) into the RADDBG format on-demand. This conversion process +with embedded DWARF) into the RADDBGI format on-demand. This conversion process is currently an unoptimized reference version. Nevertheless it's still quite fast for smaller PDB files (in many cases faster than many other programs simply deserialize the PDBs). It is much slower for much larger projects at the moment, but we expect this will vastly improve overtime. -The RADDBG format is currently specified in code, in the files within the -`src/raddbg_format` folder. The other relevant folders for working with the -format are: +The RADDBGI format is currently specified in code, in the files within the +`src/lib_raddbgi_format` folder. The other relevant folders for working with +the format are: -- `raddbg_cons`: The RADDBG construction layer, for constructing RADDBG files. -- `raddbg_convert`: Our implementation of PDB-to-RADDBG (and an in-progress -implementation of a DWARF-to-RADDBG) conversion. -- `raddbg_dump`: Code for textually dumping information from RADDBG files. +- `lib_raddbgi_make`: The "RAD Debug Info Make" library, for making RADDBGI + debug info. +- `raddbgi_from_pdb`: Our PDB-to-RADDBGI converter. Can be used as a helper + codebase layer, or built as an executable with a command line interface + frontend. +- `raddbgi_from_dwarf`: Our in-progress DWARF-to-RADDBGI converter. +- `raddbgi_dump`: Our RADDBGI textual dumping utility. ## Development Setup Instructions @@ -119,13 +128,13 @@ such that the debugging experience is rock solid. Additionally, the debug info conversion process is not fast (nor wide) enough to support extremely large projects. This is for two reasons: (a) the -PDB-to-RADDBG converter is an unoptimized reference implementation, and (b) the -debugger learns of new modules (and thus which PDBs to load) in a +PDB-to-RADDBGI converter is an unoptimized reference implementation, and (b) +the debugger learns of new modules (and thus which PDBs to load) in a serially-dependent way (this is necessarily the case for correct debugging results). We expect that the conversion process' performance can be massively improved, and also that some heuristics can be used to begin converting PDBs -to RADDBGs before the debugger knows those PDBs are needed, thus ensuring the -associated RADDBG files are ready instantaneously when the associated modules +to RADDBGIs before the debugger knows those PDBs are needed, thus ensuring the +associated RADDBGI files are ready instantaneously when the associated modules are finally loaded by the debugger. Improving this situation is a major part of this phase, as it will make the debugger much more usable for large projects. @@ -145,9 +154,9 @@ The major parts of this phase are: abstraction API. - Porting the `src/unwind` layer to support x64 ELF unwinding (currently, there is only an x64 PE unwinding implementation). -- Creating a DWARF-to-RADDBG converter (in the same way that we've built a PDB- -to-RADDBG converter). A partial implementation of this is in -`src/raddbg_convert/dwarf`. +- Creating a DWARF-to-RADDBGI converter (in the same way that we've built a +PDB-to-RADDBGI converter). A partial implementation of this is in +`src/raddbgi_from_dwarf`. - Porting the `src/render` layer to implement all of the rendering features the frontend needs on a Linux-compatible API (the backend used on Windows is D3D11). - Porting the `src/font_provider` layer to a Linux-compatible font @@ -206,10 +215,16 @@ Layers depend on other layers, but circular dependencies would break the separability and isolation utility of layers (in effect, forming one big layer), so in other words, layers are arranged into a directed acyclic graph. +A few layers are built to be used completely independently from the rest of the +codebase, as libraries in other codebases and projects. As such, these layers do +not depend on any other layers in the codebase. The folders which contain these +layers are prefixed with `lib_`, like `lib_raddbgi_format`. + A list of the layers in the codebase and their associated namespaces is below: - `base` (no namespace): Universal, codebase-wide constructs. Strings, math, memory allocators, helper macros, command-line parsing, and so on. Depends on no other codebase layers. +- `codeview` (`CV_`): Code for parsing and/or writing the CodeView format. - `coff` (`COFF_`): Code for parsing and/or writing the COFF (Common Object File Format) file format. - `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements @@ -221,10 +236,10 @@ A list of the layers in the codebase and their associated namespaces is below: disassembly for a particular virtual address range in a process, and threads implemented in this layer decode and cache the disassembly for that range. - `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug - info stored in the RADDBG format. Users ask for debug info for a particular + info stored in the RADDBGI format. Users ask for debug info for a particular executable, and on separate threads, this layer loads the associated debug info file. If necessary, it will launch a separate conversion process to - convert original debug info into the RADDBG format. + convert original debug info into the RADDBGI format. - `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process control. The abstraction is used to provide a common interface for process control on target platforms. Used to implement part of `ctrl`. @@ -256,6 +271,16 @@ A list of the layers in the codebase and their associated namespaces is below: for asynchronously preparing data for memory visualization in the debugger. - `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a 128-bit hash of the data. Used as a general data store by other layers. +- `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user + programs to work with various features in the `raddbg` debugger. Does not + depend on `base`, and can be independently relocated to other codebases. +- `lib_raddbgi_make` (`RDIM_`): Standalone library for constructing RADDBGI + debug info data. Does not depend on `base`, and can be independently relocated + to other codebases. +- `lib_raddbgi_format` (`RDI_`): Standalone library which defines the core + RADDBGI types and helper functions for reading and writing the RADDBGI debug + info file format. Does not depend on `base`, and can be independently + relocated to other codebases. - `metagen` (`MG_`): A metaprogram which is used to generate primarily code and data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and generates C code which is then included by hand-written C code. Currently, it @@ -270,6 +295,7 @@ A list of the layers in the codebase and their associated namespaces is below: duplicate version of `base` and `os` are included in this layer. They are updated manually, as needed. This is to ensure the stability of the metaprogram. +- `msf` (`MSF_`): Code for parsing and/or writing the MSF file format. - `mule` (no namespace): Test executables for battle testing debugger functionality. - `natvis` (no namespace): NatVis files for type visualization of the codebase's @@ -283,20 +309,17 @@ A list of the layers in the codebase and their associated namespaces is below: - `os/socket` (`OS_`): An abstraction layer, building on `os/core`, providing networking operating system features under an abstract API, which is implemented per-target-operating-system. +- `pdb` (`PDB_`): Code for parsing and/or writing the PDB file format. - `pe` (`PE_`): Code for parsing and/or writing the PE (Portable Executable) file format. - `raddbg` (no namespace): The layer which ties everything together for the main graphical debugger. Not much "meat", just drives `df`, implements command line options, and so on. -- `raddbg_cons` (`CONS_`): Implements an API for constructing files of the - RADDBG debug info file format. -- `raddbg_dump` (`DUMP_`): A dumper utility program for dumping textualizations - of RADDBG debug info files. -- `raddbg_format` (`RADDBG_`): Standalone types and helper functions for the - RADDBG debug info file format. Does not depend on `base`. -- `raddbg_markup` (`RADDBG_`): Standalone header file for marking up user - programs to work with various features in the `raddbg` debugger. Does not - depend on `base`. +- `raddbgi_from_pdb` (`P2R_`): Our implementation of PDB-to-RADDBGI conversion. +- `raddbgi_from_dwarf` (`D2R_`): Our in-progress implementation of + DWARF-to-RADDBGI conversion. +- `raddbgi_dump` (`RADDBGIDUMP_`): A dumper utility program for dumping + textualizations of RADDBGI debug info files. - `regs` (`REGS_`): Types, helper functions, and metadata for registers on supported architectures. Used in reading/writing registers in `demon`, or in looking up register metadata. @@ -315,7 +338,7 @@ A list of the layers in the codebase and their associated namespaces is below: Used by the debugger to visualize source code files. Users ask for text lines, tokens, and metadata, and it is prepared on background threads. - `type_graph` (`TG_`): Code for analyzing and navigating type structures from - RADDBG debug info files, with the additional capability of constructing + RADDBGI debug info files, with the additional capability of constructing synthetic types *not* found in debug info. Used in `eval` and for various visualization features. - `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a diff --git a/build.bat b/build.bat index 8f00468b..348d870e 100644 --- a/build.bat +++ b/build.bat @@ -15,7 +15,7 @@ cd /D "%~dp0" :: `build raddbg clang` :: `build raddbg release` :: `build raddbg asan telemetry` -:: `build raddbg_from_pdb` +:: `build raddbgi_from_pdb` :: :: For a full list of possible build targets and their build command lines, :: search for @build_targets in this file. @@ -43,18 +43,16 @@ if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=add :: --- Compile/Link Line Definitions ------------------------------------------ set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -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 -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -set cl_debug= call cl /Od %cl_common% %auto_compile_flags% -set cl_release= call cl /O2 /DNDEBUG %cl_common% %auto_compile_flags% -set clang_debug= call clang -g -O0 %clang_common% %auto_compile_flags% -set clang_release= call clang -g -O2 -DNDEBUG %clang_common% %auto_compile_flags% +set cl_debug= call cl /Od /DBUILD_DEBUG=1 %cl_common% %auto_compile_flags% +set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% +set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% +set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis" logo.res set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" logo.res set cl_out= /out: set clang_out= -o :: --- Per-Build Settings ----------------------------------------------------- -set gfx=-DOS_FEATURE_GRAPHICAL=1 -set net=-DOS_FEATURE_SOCKET=1 set link_dll=-DLL if "%msvc%"=="1" set only_compile=/c if "%clang%"=="1" set only_compile=-c @@ -85,7 +83,7 @@ pushd build popd :: --- Get Current Git Commit Id ---------------------------------------------- -for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DRADDBG_GIT=\"%%i\" +for /f %%i in ('call git describe --always --dirty') do set compile=%compile% -DBUILD_GIT_HASH=\"%%i\" :: --- Build & Run Metaprogram ------------------------------------------------ if "%no_meta%"=="1" echo [skipping metagen] @@ -98,16 +96,17 @@ if not "%no_meta%"=="1" ( :: --- Build Everything (@build_targets) -------------------------------------- pushd build -if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1 -if "%raddbg_from_pdb%"=="1" %compile% ..\src\raddbg_convert\pdb\raddbg_from_pdb_main.c %compile_link% %out%raddbg_from_pdb.exe || exit /b 1 -if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe || exit /b 1 -if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe || exit /b 1 -if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1 -if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1 -if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1 -if "%mule_main%"=="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% %out%mule_main.exe || exit /b 1 -if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 -if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 +if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1 +if "%raddbgi_from_pdb%"=="1" %compile% ..\src\raddbgi_from_pdb\raddbgi_from_pdb_main.c %compile_link% %out%raddbgi_from_pdb.exe || exit /b 1 +if "%raddbgi_from_dwarf%"=="1" %compile% ..\src\raddbgi_from_dwarf\raddbgi_from_dwarf.c %compile_link% %out%raddbgi_from_dwarf.exe || exit /b 1 +if "%raddbgi_dump%"=="1" %compile% ..\src\raddbgi_dump\raddbgi_dump_main.c %compile_link% %out%raddbgi_dump.exe || exit /b 1 +if "%raddbgi_breakpad_from_pdb%"=="1" %compile% ..\src\raddbgi_breakpad_from_pdb\raddbgi_breakpad_from_pdb_main.c %compile_link% %out%raddbgi_breakpad_from_pdb.exe || exit /b 1 +if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1 +if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1 +if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1 +if "%mule_main%"=="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% %out%mule_main.exe || exit /b 1 +if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 +if "%mule_hotload%"=="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 popd :: --- Unset ------------------------------------------------------------------ diff --git a/project.4coder b/project.4coder index 0c9adfff..0fb436c2 100644 --- a/project.4coder +++ b/project.4coder @@ -56,7 +56,7 @@ commands = }, .rjf_f2 = { - .win = "build raddbg_from_pdb", + .win = "build raddbgi_from_pdb telemetry release", .linux = "", .out = "*compilation*", .footer_panel = true, @@ -72,6 +72,24 @@ commands = .save_dirty_files = true, .cursor_at_end = false, }, + .rjf_f4 = + { + .win = "build raddbgi_from_pdb release telemetry && pushd build && raddbgi_from_pdb.exe --exe:UnrealEditorFortnite.exe --pdb:UnrealEditorFortnite.pdb --out:UnrealEditorFortnite.raddbgi --capture && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, + .rjf_f5 = + { + .win = "pushd build && raddbgi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.raddbg --capture && popd", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, .build_raddbg = { .win = "build raddbg", @@ -90,18 +108,18 @@ commands = .save_dirty_files = true, .cursor_at_end = false, }, - .build_raddbg_from_pdb = + .build_raddbgi_from_pdb = { - .win = "build raddbg_from_pdb", + .win = "build raddbgi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .build_raddbg_dump = + .build_raddbgi_dump = { - .win = "build raddbg_dump", + .win = "build raddbgi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, @@ -117,6 +135,15 @@ commands = .save_dirty_files = true, .cursor_at_end = false, }, + .build_ryan_scratch = + { + .win = "build ryan_scratch", + .linux = "", + .out = "*compilation*", + .footer_panel = true, + .save_dirty_files = true, + .cursor_at_end = false, + }, .run_raddbg = { .win = "pushd build && raddbg.exe && popd", @@ -141,5 +168,7 @@ fkey_command_override = .F1 = "rjf_f1", .F2 = "rjf_f2", .F3 = "rjf_f3", + .F4 = "rjf_f4", + .F5 = "rjf_f5", }, }; diff --git a/src/base/base_arena.c b/src/base/base_arena.c index 06f38de4..f75dd30f 100644 --- a/src/base/base_arena.c +++ b/src/base/base_arena.c @@ -55,9 +55,6 @@ arena_alloc__sized(U64 init_res, U64 init_cmt) arena->cmt = cmt; arena->res = res; arena->align = 8; -#if ENABLE_DEV - arena->dev = 0; -#endif arena->grow = 1; arena->large_pages = large_pages; } @@ -209,10 +206,6 @@ arena_pop_to(Arena *arena, U64 big_pos_unclamped) internal void arena_absorb(Arena *arena, Arena *sub) { -#if ENABLE_DEV - arena_annotate_absorb__dev(arena, sub); -#endif - // base adjustment Arena *current = arena->current; U64 base_adjust = current->base_pos + current->res; @@ -233,9 +226,6 @@ internal void * arena_push(Arena *arena, U64 size) { void *memory = arena_push__impl(arena, size); -#if ENABLE_DEV - arena_annotate_push__dev(arena, size, memory); -#endif return memory; } @@ -246,9 +236,6 @@ arena_push_contiguous(Arena *arena, U64 size) arena->grow = 0; void *memory = arena_push(arena, size); arena->grow = restore; -#if ENABLE_DEV - arena_annotate_push__dev(arena, size, memory); -#endif return memory; } diff --git a/src/base/base_arena.h b/src/base/base_arena.h index 0a9ca92f..dd8249ce 100644 --- a/src/base/base_arena.h +++ b/src/base/base_arena.h @@ -36,7 +36,6 @@ struct Arena U64 cmt; U64 res; U64 align; - struct ArenaDev *dev; B8 grow; B8 large_pages; }; @@ -82,13 +81,7 @@ internal B32 ensure_commit(void **cmt, void *pos, U64 cmt_block_size); //////////////////////////////// //~ NOTE(allen): Main API Macros -#if !ENABLE_DEV -# define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) -#else -# define push_array_no_zero(a,T,c) (tctx_write_this_srcloc(), (T*)arena_push((a), sizeof(T)*(c))) -#endif -#define push_array_no_zero__no_annotation(a,T,c) (T*)arena_push__impl((a), sizeof(T)*(c)) - +#define push_array_no_zero(a,T,c) (T*)arena_push((a), sizeof(T)*(c)) #define push_array(a,T,c) (T*)MemoryZero(push_array_no_zero(a,T,c), sizeof(T)*(c)) #endif // BASE_ARENA_H diff --git a/src/base/base_arena_dev.c b/src/base/base_arena_dev.c deleted file mode 100644 index 94c334bd..00000000 --- a/src/base/base_arena_dev.c +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -// NOTE(allen): Dev Arena - -#if ENABLE_DEV - -internal void -arena_annotate_push__dev(Arena *arena, U64 size, void *ptr){ - ArenaDev *dev = arena->dev; - if (dev != 0 && ptr != 0){ - //- read location - char *file_name = 0; - U64 line_number = 0; - tctx_read_srcloc(&file_name, &line_number); - tctx_write_srcloc(0, 0); - - //- profile - ArenaProf *prof = dev->prof; - if (prof != 0){ - // c string -> string - String8 file_name_str = str8_lit("(null)"); - if (file_name != 0){ - file_name_str = str8_cstring(file_name); - } - // record - arena_prof_inc_counters__dev(dev->arena, prof, file_name_str, line_number, size, 1); - } - } -} - -internal void -arena_annotate_absorb__dev(Arena *arena, Arena *sub){ - ArenaDev *dev = arena->dev; - ArenaDev *sub_dev = sub->dev; - if (dev != 0 && sub_dev != 0){ - //- merge profiles - ArenaProf *prof = dev->prof; - ArenaProf *sub_prof = sub_dev->prof; - if (prof != 0 && sub_prof != 0){ - for (ArenaProfNode *sub_node = sub_prof->first; - sub_node != 0; - sub_node = sub_node->next){ - arena_prof_inc_counters__dev(dev->arena, prof, sub_node->file_name, sub_node->line, - sub_node->size, sub_node->count); - } - } - } - //- release the sub dev memory - if (sub_dev != 0){ - arena_release(sub_dev->arena); - } -} - -internal ArenaDev* -arena_equip__dev(Arena *arena){ - ArenaDev *result = arena->dev; - if (result == 0){ - Arena *dev_arena = arena_alloc(); - ArenaDev *dev = (ArenaDev*)arena_push__impl(dev_arena, sizeof(ArenaDev)); - MemoryZeroStruct(dev); - dev->arena = dev_arena; - arena->dev = dev; - result = dev; - } - return(result); -} - -internal void -arena_equip_profile__dev(Arena *arena){ - ArenaDev *dev = arena_equip__dev(arena); - if (dev->prof == 0){ - dev->prof = (ArenaProf*)arena_push__impl(dev->arena, sizeof(ArenaProf)); - MemoryZeroStruct(dev->prof); - } -} - -internal void -arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out){ - Assert(arena != out_arena); - - //- get dev & disable - ArenaDev *dev = arena->dev; - arena->dev = 0; - - //- get prof - ArenaProf *prof = (dev != 0)?dev->prof:0; - - //- not equipped with prof - if (prof == 0){ - str8_list_push(out_arena, out, str8_lit("not equipped with a memory profile\n")); - } - - //- print prof - if (prof != 0){ - Temp scratch = temp_begin(dev->arena); - - //- make flat array - U64 note_count = prof->count; - ArenaProfNode **notes = push_array_no_zero__no_annotation(scratch.arena, ArenaProfNode*, note_count); - { - ArenaProfNode **note_ptr = notes; - for (ArenaProfNode *node = prof->first; - node != 0; - node = node->next, note_ptr += 1){ - *note_ptr = node; - } - } - - //- file name size - U64 max_file_name_size = 0; - { - ArenaProfNode **note_ptr = notes; - for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ - max_file_name_size = Max(max_file_name_size, (**note_ptr).file_name.size); - } - } - - //- sort (> size, < [address]) - for (U64 i = 0; i < note_count; i += 1){ - ArenaProfNode **i_note = notes + i; - ArenaProfNode **min_note = i_note; - for (U64 j = i + 1; j < note_count; j += 1){ - ArenaProfNode **j_note = notes + j; - if ((**j_note).size > (**min_note).size || - ((**j_note).size == (**min_note).size && *j_note < *min_note)){ - min_note = j_note; - } - } - if (min_note != i_note){ - ArenaProfNode *t = *i_note; - *i_note = *min_note; - *min_note = t; - } - } - - //- total size - U64 total_size = 0; - { - ArenaProfNode **note_ptr = notes; - for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ - ArenaProfNode *note = *note_ptr; - total_size += note->size; - } - } - - //- print - { - str8_list_pushf(out_arena, out, "memory total: %llu\n", total_size); - - ArenaProfNode **note_ptr = notes; - for (U64 i = 0; i < note_count; i += 1, note_ptr += 1){ - ArenaProfNode *note = *note_ptr; - String8 location = push_str8f(scratch.arena, "%S:%5llu:", - note->file_name, note->line); - F32 percent = 100.f*((F32)note->size)/total_size; - str8_list_pushf(out_arena, out, "%*.*s %12llu %5.2f%% [%5llu]\n", - max_file_name_size + 7, str8_varg(location), - note->size, percent, note->count); - } - } - - temp_end(scratch); - } - - //- restore dev - arena->dev = dev; -} - -internal void -arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, - U64 size, U64 count){ - // find existing profile node - ArenaProfNode *prof_node = 0; - for (ArenaProfNode *node = prof->first; - node != 0; - node = node->next){ - if (node->line == line && str8_match(file_name, node->file_name, 0)){ - prof_node = node; - break; - } - } - // make new histogram node if necessary - if (prof_node == 0){ - prof_node = (ArenaProfNode*)arena_push(dev_arena, sizeof(*prof_node)); - SLLQueuePush(prof->first, prof->last, prof_node); - prof->count += 1; - prof_node->file_name = file_name; - prof_node->line = line; - } - // record this allocation - prof_node->size += size; - prof_node->count += count; -} - -#endif diff --git a/src/base/base_arena_dev.h b/src/base/base_arena_dev.h deleted file mode 100644 index 14d16b1d..00000000 --- a/src/base/base_arena_dev.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef BASE_ARENA_DEV_H -#define BASE_ARENA_DEV_H - -//////////////////////////////// -//~ NOTE(allen): Dev Arena Types - -typedef struct ArenaDev ArenaDev; -struct ArenaDev -{ - Arena *arena; - struct ArenaProf *prof; -}; - -typedef struct ArenaProf ArenaProf; -struct ArenaProf -{ - struct ArenaProfNode *first; - struct ArenaProfNode *last; - U64 count; -}; - -typedef struct ArenaProfNode ArenaProfNode; -struct ArenaProfNode -{ - ArenaProfNode *next; - String8 file_name; - U64 line; - U64 size; - U64 count; -}; - -//////////////////////////////// -//~ NOTE(allen): Dev Arena Functions - -#if ENABLE_DEV -internal void arena_annotate_push__dev(Arena *arena, U64 size, void *ptr); -internal void arena_annotate_absorb__dev(Arena *arena, Arena *sub); -internal ArenaDev* arena_equip__dev(Arena *arena); -internal void arena_equip_profile__dev(Arena *arena); -internal void arena_print_profile__dev(Arena *arena, Arena *out_arena, String8List *out); -internal void arena_prof_inc_counters__dev(Arena *dev_arena, ArenaProf *prof, String8 file_name, U64 line, U64 size, U64 count); -#endif - -#endif // BASE_ARENA_DEV_H diff --git a/src/base/base_bits.c b/src/base/base_bits.c deleted file mode 100644 index 98ae781f..00000000 --- a/src/base/base_bits.c +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS) - -internal U64 -count_bits_set16(U16 val) -{ - return __popcnt16(val); -} - -internal U64 -count_bits_set32(U32 val) -{ - return __popcnt(val); -} - -internal U64 -count_bits_set64(U64 val) -{ - return __popcnt64(val); -} - -internal U64 -ctz32(U32 mask) -{ - unsigned long idx; - _BitScanForward(&idx, mask); - return idx; -} - -internal U64 -ctz64(U64 mask) -{ - unsigned long idx; - _BitScanForward64(&idx, mask); - return idx; -} - -internal U64 -clz32(U32 mask) -{ - unsigned long idx; - _BitScanReverse(&idx, mask); - return 31 - idx; -} - -internal U64 -clz64(U64 mask) -{ - unsigned long idx; - _BitScanReverse64(&idx, mask); - return 63 - idx; -} - -#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; -} - -internal U64 -count_bits_set64(U64 val) -{ - NotImplemented; - return 0; -} - -internal U64 -ctz32(U32 val) -{ - NotImplemented; - return 0; -} - -internal U64 -clz32(U32 val) -{ - NotImplemented; - return 0; -} - -internal U64 -clz64(U64 val) -{ - NotImplemented; - return 0; -} - -#else -# error "bits not defined for this target" -#endif - diff --git a/src/base/base_bits.h b/src/base/base_bits.h deleted file mode 100644 index ab9482d3..00000000 --- a/src/base/base_bits.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef BASE_BITS_H -#define BASE_BITS_H - -#define ExtractBit(word, idx) (((word) >> (idx)) & 1) - -internal U64 count_bits_set16(U16 val); -internal U64 count_bits_set32(U32 val); -internal U64 count_bits_set64(U64 val); - -internal U64 ctz32(U32 val); -internal U64 ctz64(U64 val); -internal U64 clz32(U32 val); -internal U64 clz64(U64 val); - -#endif // BASE_BITS_H diff --git a/src/base/base_command_line.c b/src/base/base_command_line.c index 2a40b5c8..1bf3312d 100644 --- a/src/base/base_command_line.c +++ b/src/base/base_command_line.c @@ -82,6 +82,7 @@ internal CmdLine cmd_line_from_string_list(Arena *arena, String8List command_line) { CmdLine parsed = {0}; + parsed.exe_name = command_line.first->string; // NOTE(rjf): Set up config option table. { diff --git a/src/base/base_command_line.h b/src/base/base_command_line.h index bfbc35ef..b18fc874 100644 --- a/src/base/base_command_line.h +++ b/src/base/base_command_line.h @@ -29,6 +29,7 @@ struct CmdLineOptList typedef struct CmdLine CmdLine; struct CmdLine { + String8 exe_name; CmdLineOptList options; String8List inputs; U64 option_table_size; diff --git a/src/base/base_context_cracking.h b/src/base/base_context_cracking.h index 65f49e7b..f9f1a782 100644 --- a/src/base/base_context_cracking.h +++ b/src/base/base_context_cracking.h @@ -4,6 +4,9 @@ #ifndef BASE_CONTEXT_CRACKING_H #define BASE_CONTEXT_CRACKING_H +//////////////////////////////// +//~ rjf: Clang OS/Arch Cracking + #if defined(__clang__) # define COMPILER_CLANG 1 @@ -15,7 +18,7 @@ # elif defined(__APPLE__) && defined(__MACH__) # define OS_MAC 1 # else -# error This compiler/platform combo is not supported yet +# error This compiler/OS combo is not supported. # endif # if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) @@ -27,17 +30,40 @@ # elif defined(__arm__) # define ARCH_ARM32 1 # else -# error architecture not supported yet +# error Architecture not supported. # endif +//////////////////////////////// +//~ rjf: MSVC OS/Arch Cracking + #elif defined(_MSC_VER) -# define COMPILER_CL 1 +# define COMPILER_MSVC 1 + +# if _MSC_VER >= 1920 +# define COMPILER_MSVC_YEAR 2019 +# elif _MSC_VER >= 1910 +# define COMPILER_MSVC_YEAR 2017 +# elif _MSC_VER >= 1900 +# define COMPILER_MSVC_YEAR 2015 +# elif _MSC_VER >= 1800 +# define COMPILER_MSVC_YEAR 2013 +# elif _MSC_VER >= 1700 +# define COMPILER_MSVC_YEAR 2012 +# elif _MSC_VER >= 1600 +# define COMPILER_MSVC_YEAR 2010 +# elif _MSC_VER >= 1500 +# define COMPILER_MSVC_YEAR 2008 +# elif _MSC_VER >= 1400 +# define COMPILER_MSVC_YEAR 2005 +# else +# define COMPILER_MSVC_YEAR 0 +# endif # if defined(_WIN32) # define OS_WINDOWS 1 # else -# error This compiler/platform combo is not supported yet +# error This compiler/OS combo is not supported. # endif # if defined(_M_AMD64) @@ -49,9 +75,12 @@ # elif defined(_M_ARM) # define ARCH_ARM32 1 # else -# error architecture not supported yet +# error Architecture not supported. # endif +//////////////////////////////// +//~ rjf: GCC OS/Arch Cracking + #elif defined(__GNUC__) || defined(__GNUG__) # define COMPILER_GCC 1 @@ -59,7 +88,7 @@ # if defined(__gnu_linux__) || defined(__linux__) # define OS_LINUX 1 # else -# error This compiler/platform combo is not supported yet +# error This compiler/OS combo is not supported. # endif # if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) @@ -71,26 +100,96 @@ # elif defined(__arm__) # define ARCH_ARM32 1 # else -# error architecture not supported yet +# error Architecture not supported. # endif #else -# error This compiler is not supported yet +# error Compiler not supported. #endif +//////////////////////////////// +//~ rjf: Arch Cracking + #if defined(ARCH_X64) # define ARCH_64BIT 1 #elif defined(ARCH_X86) # define ARCH_32BIT 1 #endif +#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86 +# define ARCH_LITTLE_ENDIAN 1 +#else +# error Endianness of this architecture not understood by context cracker. +#endif + +//////////////////////////////// +//~ rjf: Language Cracking + #if defined(__cplusplus) # define LANG_CPP 1 #else # define LANG_C 1 #endif -// zeroify +//////////////////////////////// +//~ rjf: Build Option Cracking + +#if !defined(BUILD_DEBUG) +# define BUILD_DEBUG 1 +#endif + +#if !defined(BUILD_SUPPLEMENTARY_UNIT) +# define BUILD_SUPPLEMENTARY_UNIT 0 +#endif + +#if !defined(BUILD_ENTRY_DEFINING_UNIT) +# define BUILD_ENTRY_DEFINING_UNIT 1 +#endif + +#if !defined(BUILD_CONSOLE_INTERFACE) +# define BUILD_CONSOLE_INTERFACE 0 +#endif + +#if !defined(BUILD_VERSION_MAJOR) +# define BUILD_VERSION_MAJOR 0 +#endif + +#if !defined(BUILD_VERSION_MINOR) +# define BUILD_VERSION_MINOR 0 +#endif + +#if !defined(BUILD_VERSION_PATCH) +# define BUILD_VERSION_PATCH 0 +#endif + +#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH) +#if BUILD_DEBUG +# define BUILD_MODE_STRING_LITERAL_APPEND " [Debug]" +#else +# define BUILD_MODE_STRING_LITERAL_APPEND "" +#endif +#if defined(BUILD_GIT_HASH) +# define BUILD_GIT_HASH_STRING_LITERAL_APPEND " [" BUILD_GIT_HASH "]" +#else +# define BUILD_GIT_HASH_STRING_LITERAL_APPEND "" +#endif + +#if !defined(BUILD_TITLE) +# define BUILD_TITLE "Untitled" +#endif + +#if !defined(BUILD_RELEASE_PHASE_STRING_LITERAL) +# define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +#endif + +#if !defined(BUILD_ISSUES_LINK_STRING_LITERAL) +# define BUILD_ISSUES_LINK_STRING_LITERAL "https://github.com/EpicGames/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 + +//////////////////////////////// +//~ rjf: Zero All Undefined Options #if !defined(ARCH_32BIT) # define ARCH_32BIT 0 @@ -110,8 +209,8 @@ #if !defined(ARCH_ARM32) # define ARCH_ARM32 0 #endif -#if !defined(COMPILER_CL) -# define COMPILER_CL 0 +#if !defined(COMPILER_MSVC) +# define COMPILER_MSVC 0 #endif #if !defined(COMPILER_GCC) # define COMPILER_GCC 0 @@ -135,10 +234,4 @@ # define LANG_C 0 #endif -#if ARCH_ARM32 || ARCH_ARM64 || ARCH_X64 || ARCH_X86 -# define ARCH_LITTLE_ENDIAN 1 -#else -# error Endianness of this architecture not understood by context cracker -#endif - #endif // BASE_CONTEXT_CRACKING_H diff --git a/src/base/base_types.c b/src/base/base_core.c similarity index 85% rename from src/base/base_types.c rename to src/base/base_core.c index 9627f478..2d40fe34 100644 --- a/src/base/base_types.c +++ b/src/base/base_core.c @@ -2,7 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ Safe Casts +//~ rjf: Safe Casts internal U16 safe_cast_u16(U32 x) @@ -141,6 +141,106 @@ bswap_u64(U64 x) return result; } +#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS) + +internal U64 +count_bits_set16(U16 val) +{ + return __popcnt16(val); +} + +internal U64 +count_bits_set32(U32 val) +{ + return __popcnt(val); +} + +internal U64 +count_bits_set64(U64 val) +{ + return __popcnt64(val); +} + +internal U64 +ctz32(U32 mask) +{ + unsigned long idx; + _BitScanForward(&idx, mask); + return idx; +} + +internal U64 +ctz64(U64 mask) +{ + unsigned long idx; + _BitScanForward64(&idx, mask); + return idx; +} + +internal U64 +clz32(U32 mask) +{ + unsigned long idx; + _BitScanReverse(&idx, mask); + return 31 - idx; +} + +internal U64 +clz64(U64 mask) +{ + unsigned long idx; + _BitScanReverse64(&idx, mask); + return 63 - idx; +} + +#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; +} + +internal U64 +count_bits_set64(U64 val) +{ + NotImplemented; + return 0; +} + +internal U64 +ctz32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +clz32(U32 val) +{ + NotImplemented; + return 0; +} + +internal U64 +clz64(U64 val) +{ + NotImplemented; + return 0; +} + +#else +# error "Bit intrinsic functions not defined for this compiler." +#endif + //////////////////////////////// //~ rjf: Enum -> Sign @@ -287,6 +387,14 @@ txt_rng_union(TxtRng a, TxtRng b) return result; } +internal B32 +txt_rng_contains(TxtRng r, TxtPt pt) +{ + B32 result = ((txt_pt_less_than(r.min, pt) || txt_pt_match(r.min, pt)) && + txt_pt_less_than(pt, r.max)); + return result; +} + //////////////////////////////// //~ rjf: Toolchain/Environment Enum Functions @@ -344,8 +452,8 @@ architecture_from_context(void){ internal Compiler compiler_from_context(void){ Compiler compiler = Compiler_Null; -#if COMPILER_CL - compiler = Compiler_cl; +#if COMPILER_MSVC + compiler = Compiler_msvc; #elif COMPILER_GCC compiler = Compiler_gcc; #elif COMPILER_CLANG diff --git a/src/base/base_types.h b/src/base/base_core.h similarity index 73% rename from src/base/base_types.h rename to src/base/base_core.h index 3abf3251..87add9df 100644 --- a/src/base/base_types.h +++ b/src/base/base_core.h @@ -13,17 +13,6 @@ #include #include -//////////////////////////////// -//~ rjf: Build Configuration - -#if !defined(ENABLE_DEV) -# define ENABLE_DEV 0 -#endif - -#if !defined(SUPPLEMENT_UNIT) -# define SUPPLEMENT_UNIT 0 -#endif - //////////////////////////////// //~ rjf: Codebase Keywords @@ -31,7 +20,7 @@ #define global static #define local_persist static -#if COMPILER_CL || (COMPILER_CLANG && OS_WINDOWS) +#if COMPILER_MSVC || (COMPILER_CLANG && OS_WINDOWS) # pragma section(".rdata$", read) # define read_only __declspec(allocate(".rdata$")) #elif (COMPILER_CLANG && OS_LINUX) @@ -45,6 +34,80 @@ # define read_only #endif +#if COMPILER_MSVC +# define thread_static __declspec(thread) +#elif COMPILER_CLANG || COMPILER_GCC +# define thread_static __thread +#endif + +//////////////////////////////// +//~ rjf: Linkage Keyword Macros + +#if OS_WINDOWS +# define shared_function C_LINKAGE __declspec(dllexport) +#else +# define shared_function C_LINKAGE +#endif + +#if LANG_CPP +# define C_LINKAGE_BEGIN extern "C"{ +# define C_LINKAGE_END } +# define C_LINKAGE extern "C" +#else +# define C_LINKAGE_BEGIN +# define C_LINKAGE_END +# define C_LINKAGE +#endif + +//////////////////////////////// +//~ rjf: Units + +#define KB(n) (((U64)(n)) << 10) +#define MB(n) (((U64)(n)) << 20) +#define GB(n) (((U64)(n)) << 30) +#define TB(n) (((U64)(n)) << 40) +#define Thousand(n) ((n)*1000) +#define Million(n) ((n)*1000000) +#define Billion(n) ((n)*1000000000) + +//////////////////////////////// +//~ rjf: Branch Predictor Hints + +#if defined(__clang__) +# define Expect(expr, val) __builtin_expect((expr), (val)) +#else +# define Expect(expr, val) (expr) +#endif + +#define Likely(expr) Expect(expr,1) +#define Unlikely(expr) Expect(expr,0) + +//////////////////////////////// +//~ rjf: Clamps, Mins, Maxes + +#define Min(A,B) (((A)<(B))?(A):(B)) +#define Max(A,B) (((A)>(B))?(A):(B)) +#define ClampTop(A,X) Min(A,X) +#define ClampBot(X,B) Max(X,B) +#define Clamp(A,X,B) (((X)<(A))?(A):((X)>(B))?(B):(X)) + +//////////////////////////////// +//~ rjf: Member Offsets + +#define Member(T,m) (((T*)0)->m) +#define OffsetOf(T,m) IntFromPtr(&Member(T,m)) +#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off))) +#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m)) + +//////////////////////////////// +//~ rjf: For-Loop Construct Macros + +#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) + //////////////////////////////// //~ rjf: Memory Operation Macros @@ -67,99 +130,178 @@ #define MemoryMatchArray(a,b) MemoryMatch((a),(b),sizeof(a)) #define MemoryRead(T,p,e) ( ((p)+sizeof(T)<=(e))?(*(T*)(p)):(0) ) -#define MemoryConsume(T,p,e) \ -( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) ) - -//////////////////////////////// -//~ rjf: Units - -#define KB(n) (((U64)(n)) << 10) -#define MB(n) (((U64)(n)) << 20) -#define GB(n) (((U64)(n)) << 30) -#define TB(n) (((U64)(n)) << 40) -#define Thousand(n) ((n)*1000) -#define Million(n) ((n)*1000000) -#define Billion(n) ((n)*1000000000) +#define MemoryConsume(T,p,e) ( ((p)+sizeof(T)<=(e))?((p)+=sizeof(T),*(T*)((p)-sizeof(T))):((p)=(e),0) ) //////////////////////////////// //~ rjf: Asserts -#if COMPILER_CL +#if COMPILER_MSVC # define Trap() __debugbreak() #elif COMPILER_CLANG || COMPILER_GCC # define Trap() __builtin_trap() -# else -# error "undefined trap" +#else +# error Unknown trap intrinsic for this compiler. #endif #define AssertAlways(x) do{if(!(x)) {Trap();}}while(0) -#if !defined(NDEBUG) +#if BUILD_DEBUG # define Assert(x) AssertAlways(x) #else # define Assert(x) (void)(x) #endif -#define AssertImplies(a,b) Assert(!(a) || b) -#define AssertIff(a,b) Assert(!!(a) == !!(b)) #define InvalidPath Assert(!"Invalid Path!") #define NotImplemented Assert(!"Not Implemented!") - -#define StaticAssert(C,ID) global U8 Glue(ID,__LINE__)[(C)?1:-1] +#define NoOp ((void)0) +#define StaticAssert(C, ID) global U8 Glue(ID, __LINE__)[(C)?1:-1] //////////////////////////////// -//~ rjf: Branch Predictor Hints +//~ rjf: Atomic Operations -#if defined(__clang__) -# define Expect(expr, val) __builtin_expect((expr), (val)) +#if OS_WINDOWS +# include +# include +# include +# 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_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_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)) +# 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. +# endif #else -# define Expect(expr, val) (expr) +# error Atomic intrinsics not defined for this operating system. #endif -#define Likely(expr) Expect(expr,1) -#define Unlikely(expr) Expect(expr,0) +//////////////////////////////// +//~ rjf: Linked List Building Macros + +//- rjf: linked list macro helpers +#define CheckNil(nil,p) ((p) == 0 || (p) == nil) +#define SetNil(nil,p) ((p) = nil) + +//- rjf: doubly-linked-lists +#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \ +((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\ +CheckNil(nil,p) ? \ +((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\ +((p)==(l)) ? \ +((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\ +(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p)))) +#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev) +#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next) +#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\ +((n) == (l) ? (l) = (l)->prev : (0)),\ +(CheckNil(nil,(n)->prev) ? (0) :\ +((n)->prev->next = (n)->next)),\ +(CheckNil(nil,(n)->next) ? (0) :\ +((n)->next->prev = (n)->prev))) + +//- rjf: singly-linked, doubly-headed lists (queues) +#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ +((f)=(l)=(n),SetNil(nil,(n)->next)):\ +((l)->next=(n),(l)=(n),SetNil(nil,(n)->next))) +#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ +((f)=(l)=(n),SetNil(nil,(n)->next)):\ +((n)->next=(f),(f)=(n))) +#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\ +(SetNil(nil,f),SetNil(nil,l)):\ +((f)=(f)->next)) + +//- rjf: singly-linked, singly-headed lists (stacks) +#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) +#define SLLStackPop_N(f,next) ((f)=(f)->next) + +//- rjf: doubly-linked-list helpers +#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev) +#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev) +#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev) +#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev) +#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev) +#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev) + +//- rjf: singly-linked, doubly-headed list helpers +#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next) +#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next) +#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next) +#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next) +#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next) +#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next) + +//- rjf: singly-linked, singly-headed list helpers +#define SLLStackPush(f,n) SLLStackPush_N(f,n,next) +#define SLLStackPop(f) SLLStackPop_N(f,next) + +//////////////////////////////// +//~ rjf: Address Sanitizer Markup + +#if COMPILER_MSVC +# if defined(__SANITIZE_ADDRESS__) +# define ASAN_ENABLED 1 +# define NO_ASAN __declspec(no_sanitize_address) +# else +# define NO_ASAN +# endif +#elif COMPILER_CLANG +# if defined(__has_feature) +# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +# define ASAN_ENABLED 1 +# endif +# endif +# define NO_ASAN __attribute__((no_sanitize("address"))) +#else +# error "NO_ASAN is not defined for this compiler." +#endif + +#if ASAN_ENABLED +#pragma comment(lib, "clang_rt.asan-x86_64.lib") +C_LINKAGE void __asan_poison_memory_region(void const volatile *addr, size_t size); +C_LINKAGE void __asan_unpoison_memory_region(void const volatile *addr, size_t size); +# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size)) +# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size)) +#else +# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) +# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) +#endif //////////////////////////////// //~ rjf: Misc. Helper Macros -#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) - -#define Stmnt(S) do{ S }while(0) - #define Stringify_(S) #S #define Stringify(S) Stringify_(S) #define Glue_(A,B) A##B #define Glue(A,B) Glue_(A,B) -#define Min(A,B) ( ((A)<(B))?(A):(B) ) -#define Max(A,B) ( ((A)>(B))?(A):(B) ) - -#define ClampTop(A,X) Min(A,X) -#define ClampBot(X,B) Max(X,B) -#define Clamp(A,X,B) ( ((X)<(A))?(A):((X)>(B))?(B):(X) ) - -#define PtrClampTop(A,X) ClampTop(A,X) -#define PtrClampBot(X,B) ClampBot(X,B) -#define PtrClamp(A,X,B) Clamp(A,X,B) +#define ArrayCount(a) (sizeof(a) / sizeof((a)[0])) #define CeilIntegerDiv(a,b) (((a) + (b) - 1)/(b)) -#define Swap(T,a,b) Stmnt( T t__ = a; a = b; b = t__; ) +#define Swap(T,a,b) do{T t__ = a; a = b; b = t__;}while(0) #if ARCH_64BIT # define IntFromPtr(ptr) ((U64)(ptr)) #elif ARCH_32BIT # define IntFromPtr(ptr) ((U32)(ptr)) #else -# error missing ptr cast for this architecture +# error Missing pointer-to-integer cast for this architecture. #endif - #define PtrFromInt(i) (void*)((U8*)0 + (i)) -#define Member(T,m) (((T*)0)->m) -#define OffsetOf(T,m) IntFromPtr(&Member(T,m)) -#define MemberFromOffset(T,ptr,off) (T)((((U8 *)ptr)+(off))) -#define CastFromMember(T,m,ptr) (T*)(((U8*)ptr) - OffsetOf(T,m)) - #define Compose64Bit(a,b) ((((U64)a) << 32) | ((U64)b)); #define AlignPow2(x,b) (((x) + (b) - 1)&(~((b) - 1))) #define AlignDownPow2(x,b) ((x)&(~((b) - 1))) @@ -167,8 +309,7 @@ #define IsPow2(x) ((x)!=0 && ((x)&((x)-1))==0) #define IsPow2OrZero(x) ((((x) - 1)&(x)) == 0) -#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 ExtractBit(word, idx) (((word) >> (idx)) & 1) #if LANG_CPP # define zero_struct {} @@ -182,66 +323,6 @@ # define this_function_name __func__ #endif -#if LANG_CPP -# define C_LINKAGE_BEGIN extern "C"{ -# define C_LINKAGE_END } -# define C_LINKAGE extern "C" -#else -# define C_LINKAGE_BEGIN -# define C_LINKAGE_END -# define C_LINKAGE -#endif - -#if COMPILER_CL -# define thread_static __declspec(thread) -#elif COMPILER_CLANG || COMPILER_GCC -# define thread_static __thread -#endif - -#if OS_WINDOWS -# define shared_function C_LINKAGE __declspec(dllexport) -#else -# define shared_function C_LINKAGE -#endif - -//////////////////////////////// -//~ ASAN - -#if COMPILER_CL -# if defined(__SANITIZE_ADDRESS__) -# define ASAN_ENABLED 1 -# define NO_ASAN __declspec(no_sanitize_address) -# else -# define NO_ASAN -# endif -#elif COMPILER_CLANG -# if defined(__has_feature) -# if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) -# define ASAN_ENABLED 1 -# endif -# endif -# define NO_ASAN __attribute__((no_sanitize("address"))) -#else -# error "NO_ASAN is not defined" -#endif - -#if ASAN_ENABLED - -#pragma comment(lib, "clang_rt.asan-x86_64.lib") - -C_LINKAGE_BEGIN -void __asan_poison_memory_region(void const volatile *addr, size_t size); -void __asan_unpoison_memory_region(void const volatile *addr, size_t size); -C_LINKAGE_END - -# define AsanPoisonMemoryRegion(addr, size) __asan_poison_memory_region((addr), (size)) -# define AsanUnpoisonMemoryRegion(addr, size) __asan_unpoison_memory_region((addr), (size)) -#else -# define AsanPoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) -# define AsanUnpoisonMemoryRegion(addr, size) ((void)(addr), (void)(size)) - -#endif - //////////////////////////////// //~ rjf: Base Types @@ -259,10 +340,7 @@ typedef S32 B32; typedef S64 B64; typedef float F32; typedef double F64; - -//////////////////////////////// -//~ rjf: Large Base Types - +typedef void VoidProc(void); typedef struct U128 U128; struct U128 { @@ -272,8 +350,6 @@ struct U128 //////////////////////////////// //~ rjf: Basic Types & Spaces -typedef void VoidProc(void); - typedef enum Dimension { Dimension_X, @@ -341,7 +417,7 @@ Architecture; typedef enum Compiler { Compiler_Null, - Compiler_cl, + Compiler_msvc, Compiler_gcc, Compiler_clang, Compiler_COUNT, @@ -569,11 +645,13 @@ struct DateTime U16 min; // [0,59] U16 hour; // [0,24] U16 day; // [0,30] - union{ + union + { WeekDay week_day; U32 wday; }; - union{ + union + { Month month; U32 mon; }; @@ -601,7 +679,7 @@ struct FileProperties }; //////////////////////////////// -//~ Safe Casts +//~ rjf: Safe Casts internal U16 safe_cast_u16(U32 x); internal U32 safe_cast_u32(U64 x); @@ -629,6 +707,15 @@ internal U16 bswap_u16(U16 x); internal U32 bswap_u32(U32 x); internal U64 bswap_u64(U64 x); +internal U64 count_bits_set16(U16 val); +internal U64 count_bits_set32(U32 val); +internal U64 count_bits_set64(U64 val); + +internal U64 ctz32(U32 val); +internal U64 ctz64(U64 val); +internal U64 clz32(U32 val); +internal U64 clz64(U64 val); + //////////////////////////////// //~ rjf: Enum -> Sign @@ -651,6 +738,7 @@ internal TxtPt txt_pt_max(TxtPt a, TxtPt b); internal TxtRng txt_rng(TxtPt min, TxtPt max); internal TxtRng txt_rng_intersect(TxtRng a, TxtRng b); internal TxtRng txt_rng_union(TxtRng a, TxtRng b); +internal B32 txt_rng_contains(TxtRng r, TxtPt pt); //////////////////////////////// //~ rjf: Toolchain/Environment Enum Functions @@ -677,4 +765,4 @@ internal U64 ring_read(U8 *ring_base, U64 ring_size, U64 ring_pos, void *dst_dat #define ring_write_struct(ring_base, ring_size, ring_pos, ptr) ring_write((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr))) #define ring_read_struct(ring_base, ring_size, ring_pos, ptr) ring_read((ring_base), (ring_size), (ring_pos), (ptr), sizeof(*(ptr))) -#endif // BASE_TYPES_H +#endif // BASE_CORE_H diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c new file mode 100644 index 00000000..d8f9edee --- /dev/null +++ b/src/base/base_entry_point.c @@ -0,0 +1,95 @@ +internal void +main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **arguments, U64 arguments_count) +{ +#if PROFILE_TELEMETRY + local_persist U8 tm_data[MB(64)]; + tmLoadLibrary(TM_RELEASE); + tmSetMaxThreadCount(256); + tmInitialize(sizeof(tm_data), (char *)tm_data); +#endif + TCTX tctx; + tctx_init_and_equip(&tctx); + 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); + CmdLine cmdline = cmd_line_from_string_list(scratch.arena, command_line_argument_strings); + B32 capture = cmd_line_has_flag(&cmdline, str8_lit("capture")); + if(capture) + { + ProfBeginCapture(arguments[0]); + } +#if defined(OS_CORE_H) + os_init(); +#endif +#if defined(TASK_SYSTEM_H) + ts_init(); +#endif +#if defined(HASH_STORE_H) + hs_init(); +#endif +#if defined(FILE_STREAM_H) + fs_init(); +#endif +#if defined(TEXT_CACHE_H) + txt_init(); +#endif +#if defined(DASM_CACHE_H) + dasm_init(); +#endif +#if defined(DBGI_H) + dbgi_init(); +#endif +#if defined(TXTI_H) + txti_init(); +#endif +#if defined(DEMON_CORE_H) + dmn_init(); +#endif +#if defined(CTRL_CORE_H) + ctrl_init(); +#endif +#if defined(DASM_H) + dasmi_init(); +#endif +#if defined(OS_GRAPHICAL_H) + os_graphical_init(); +#endif +#if defined(FONT_PROVIDER_H) + fp_init(); +#endif +#if defined(RENDER_CORE_H) + r_init(&cmdline); +#endif +#if defined(TEXTURE_CACHE_H) + tex_init(); +#endif +#if defined(GEO_CACHE_H) + geo_init(); +#endif +#if defined(FONT_CACHE_H) + f_init(); +#endif +#if defined(DF_CORE_H) + DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); + df_core_init(&cmdline, hist); +#endif +#if defined(DF_GFX_H) + df_gfx_init(update_and_render, df_state_delta_history()); +#endif + entry_point(&cmdline); + if(capture) + { + ProfEndCapture(); + } + scratch_end(scratch); + tctx_release(); +} + +internal void +supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params) +{ + TCTX tctx; + tctx_init_and_equip(&tctx); + entry_point(params); + tctx_release(); +} diff --git a/src/base/base_entry_point.h b/src/base/base_entry_point.h new file mode 100644 index 00000000..fd6c0d92 --- /dev/null +++ b/src/base/base_entry_point.h @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#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 supplement_thread_base_entry_point(void (*entry_point)(void *params), void *params); + +#endif // BASE_ENTRY_POINT_H diff --git a/src/base/base_inc.c b/src/base/base_inc.c index e9824297..684cb1f6 100644 --- a/src/base/base_inc.c +++ b/src/base/base_inc.c @@ -7,12 +7,12 @@ #undef RADDBG_LAYER_COLOR #define RADDBG_LAYER_COLOR 0.20f, 0.60f, 0.80f -#include "base_types.c" -#include "base_markup.c" +#include "base_core.c" +#include "base_profile.c" #include "base_arena.c" #include "base_math.c" -#include "base_string.c" +#include "base_strings.c" #include "base_thread_context.c" #include "base_command_line.c" -#include "base_arena_dev.c" -#include "base_bits.c" +#include "base_markup.c" +#include "base_entry_point.c" diff --git a/src/base/base_inc.h b/src/base/base_inc.h index 2af02635..5757b895 100644 --- a/src/base/base_inc.h +++ b/src/base/base_inc.h @@ -8,16 +8,15 @@ //~ rjf: Base Includes #include "base_context_cracking.h" -#include "base_types.h" -#include "base_markup.h" -#include "base_ins.h" -#include "base_linked_lists.h" + +#include "base_core.h" +#include "base_profile.h" #include "base_arena.h" #include "base_math.h" -#include "base_string.h" +#include "base_strings.h" #include "base_thread_context.h" #include "base_command_line.h" -#include "base_arena_dev.h" -#include "base_bits.h" +#include "base_markup.h" +#include "base_entry_point.h" #endif // BASE_INC_H diff --git a/src/base/base_ins.h b/src/base/base_ins.h deleted file mode 100644 index 9f8d3202..00000000 --- a/src/base/base_ins.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef BASE_INS_H -#define BASE_INS_H - -//////////////////////////////// -// NOTE(allen): Implementations of Intrinsics - -#if OS_WINDOWS - -# include -# include -# include -# include - -# if ARCH_X64 -# define ins_atomic_u64_eval(x) InterlockedAdd((volatile LONG *)(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) InterlockedAdd((volatile LONG *)(x), c) -# 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)) -# endif - -#elif OS_LINUX - -# if ARCH_X64 -# define ins_atomic_u64_inc_eval(x) __sync_fetch_and_add((volatile U64 *)(x), 1) -# endif - -#else -// TODO(allen): -#endif - -//////////////////////////////// -// NOTE(allen): Intrinsic Checks - -#if ARCH_X64 - -# if !defined(ins_atomic_u64_inc_eval) -# error missing: ins_atomic_u64_inc_eval -# endif - -#else -# error the intrinsic set for this arch is not developed -#endif - - -#endif //BASE_INS_H diff --git a/src/base/base_linked_lists.h b/src/base/base_linked_lists.h deleted file mode 100644 index 436cedc5..00000000 --- a/src/base/base_linked_lists.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef BASE_LINKED_LIST_H -#define BASE_LINKED_LIST_H - -//////////////////////////////// -//~ rjf: Helpers - -#define CheckNil(nil,p) ((p) == 0 || (p) == nil) -#define SetNil(nil,p) ((p) = nil) - -//////////////////////////////// -//~ rjf: Base Macros - -//- rjf: Base Doubly-Linked-List Macros -#define DLLInsert_NPZ(nil,f,l,p,n,next,prev) (CheckNil(nil,f) ? \ -((f) = (l) = (n), SetNil(nil,(n)->next), SetNil(nil,(n)->prev)) :\ -CheckNil(nil,p) ? \ -((n)->next = (f), (f)->prev = (n), (f) = (n), SetNil(nil,(n)->prev)) :\ -((p)==(l)) ? \ -((l)->next = (n), (n)->prev = (l), (l) = (n), SetNil(nil, (n)->next)) :\ -(((!CheckNil(nil,p) && CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p)))) -#define DLLPushBack_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,f,l,l,n,next,prev) -#define DLLPushFront_NPZ(nil,f,l,n,next,prev) DLLInsert_NPZ(nil,l,f,f,n,prev,next) -#define DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\ -((n) == (l) ? (l) = (l)->prev : (0)),\ -(CheckNil(nil,(n)->prev) ? (0) :\ -((n)->prev->next = (n)->next)),\ -(CheckNil(nil,(n)->next) ? (0) :\ -((n)->next->prev = (n)->prev))) - -//- rjf: Base Singly-Linked-List Queue Macros -#define SLLQueuePush_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ -((f)=(l)=(n),SetNil(nil,(n)->next)):\ -((l)->next=(n),(l)=(n),SetNil(nil,(n)->next))) -#define SLLQueuePushFront_NZ(nil,f,l,n,next) (CheckNil(nil,f)?\ -((f)=(l)=(n),SetNil(nil,(n)->next)):\ -((n)->next=(f),(f)=(n))) -#define SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\ -(SetNil(nil,f),SetNil(nil,l)):\ -((f)=(f)->next)) - -//- rjf: Base Singly-Linked-List Stack Macros -#define SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) -#define SLLStackPop_N(f,next) ((f)=(f)->next) - -//////////////////////////////// -//~ rjf: Convenience Wrappers - -//- rjf: Doubly-Linked-List Wrappers -#define DLLInsert_NP(f,l,p,n,next,prev) DLLInsert_NPZ(0,f,l,p,n,next,prev) -#define DLLPushBack_NP(f,l,n,next,prev) DLLPushBack_NPZ(0,f,l,n,next,prev) -#define DLLPushFront_NP(f,l,n,next,prev) DLLPushFront_NPZ(0,f,l,n,next,prev) -#define DLLRemove_NP(f,l,n,next,prev) DLLRemove_NPZ(0,f,l,n,next,prev) -#define DLLInsert(f,l,p,n) DLLInsert_NPZ(0,f,l,p,n,next,prev) -#define DLLPushBack(f,l,n) DLLPushBack_NPZ(0,f,l,n,next,prev) -#define DLLPushFront(f,l,n) DLLPushFront_NPZ(0,f,l,n,next,prev) -#define DLLRemove(f,l,n) DLLRemove_NPZ(0,f,l,n,next,prev) - -//- rjf: Singly-Linked-List Queue Wrappers -#define SLLQueuePush_N(f,l,n,next) SLLQueuePush_NZ(0,f,l,n,next) -#define SLLQueuePushFront_N(f,l,n,next) SLLQueuePushFront_NZ(0,f,l,n,next) -#define SLLQueuePop_N(f,l,next) SLLQueuePop_NZ(0,f,l,next) -#define SLLQueuePush(f,l,n) SLLQueuePush_NZ(0,f,l,n,next) -#define SLLQueuePushFront(f,l,n) SLLQueuePushFront_NZ(0,f,l,n,next) -#define SLLQueuePop(f,l) SLLQueuePop_NZ(0,f,l,next) - -//- rjf: Singly-Linked-List Stack Wrappers -#define SLLStackPush(f,n) SLLStackPush_N(f,n,next) -#define SLLStackPop(f) SLLStackPop_N(f,next) - -#endif //BASE_LINKED_LIST_H diff --git a/src/base/base_markup.c b/src/base/base_markup.c index 7ea8904c..e0ba1b2b 100644 --- a/src/base/base_markup.c +++ b/src/base/base_markup.c @@ -1,2 +1,21 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) + +internal void +thread_name(String8 string) +{ + ProfThreadName("%.*s", str8_varg(string)); + os_set_thread_name(string); +} + +internal void +thread_namef(char *fmt, ...) +{ + Temp scratch = scratch_begin(0, 0); + va_list args; + va_start(args, fmt); + String8 string = push_str8fv(scratch.arena, fmt, args); + thread_name(string); + va_end(args); + scratch_end(scratch); +} diff --git a/src/base/base_markup.h b/src/base/base_markup.h index 03c1adab..7ca2ab36 100644 --- a/src/base/base_markup.h +++ b/src/base/base_markup.h @@ -4,76 +4,9 @@ #ifndef BASE_MARKUP_H #define BASE_MARKUP_H -//////////////////////////////// -//~ rjf: Zero Settings - -#if !defined(PROFILE_TELEMETRY) -# 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 - -#if PROFILE_TELEMETRY -# include "rad_tm.h" -# if OS_WINDOWS -# pragma comment(lib, "rad_tm_win64.lib") -# endif -#endif - -//////////////////////////////// -//~ rjf: Telemetry Profile Defines - -#if PROFILE_TELEMETRY -# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__) -# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) -# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0) -# define ProfTick(...) tmTick(0) -# define ProfIsCapturing(...) tmRunning() -# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100) -# define ProfEndCapture(...) tmClose(0) -# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0) -# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) -# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__) -# define ProfEndLockWait(...) tmEndWaitForLock(0) -# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__) -# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) -# define ProfColor(color) tmZoneColorSticky(color) -#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) -#endif - -//////////////////////////////// -//~ rjf: Helper Wrappers - -#define ProfBeginFunction(...) ProfBegin(this_function_name) -#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd()) - -//////////////////////////////// -//~ rjf: General Markup - -#define ThreadName(...) (ProfThreadName(__VA_ARGS__)) +internal void thread_namef(char *fmt, ...); +internal void thread_name(String8 string); +#define ThreadNameF(...) (ProfThreadName(__VA_ARGS__), thread_namef(__VA_ARGS__)) +#define ThreadName(str) (ProfThreadName("%s", str8_varg(str)), thread_name(str)) #endif // BASE_MARKUP_H diff --git a/src/base/base_profile.c b/src/base/base_profile.c new file mode 100644 index 00000000..7ea8904c --- /dev/null +++ b/src/base/base_profile.c @@ -0,0 +1,2 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) diff --git a/src/base/base_profile.h b/src/base/base_profile.h new file mode 100644 index 00000000..0809f207 --- /dev/null +++ b/src/base/base_profile.h @@ -0,0 +1,74 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef BASE_PROFILE_H +#define BASE_PROFILE_H + +//////////////////////////////// +//~ rjf: Zero Settings + +#if !defined(PROFILE_TELEMETRY) +# 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 + +#if PROFILE_TELEMETRY +# include "rad_tm.h" +# if OS_WINDOWS +# pragma comment(lib, "rad_tm_win64.lib") +# endif +#endif + +//////////////////////////////// +//~ rjf: Telemetry Profile Defines + +#if PROFILE_TELEMETRY +# define ProfBegin(...) tmEnter(0, 0, __VA_ARGS__) +# define ProfBeginDynamic(...) (TM_API_PTR ? TM_API_PTR->_tmEnterZoneV_Core(0, 0, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) +# define ProfEnd(...) (TM_API_PTR ? TM_API_PTR->_tmLeaveZone(0) : (void)0) +# define ProfTick(...) tmTick(0) +# define ProfIsCapturing(...) tmRunning() +# define ProfBeginCapture(...) tmOpen(0, __VA_ARGS__, __DATE__, "localhost", TMCT_TCP, TELEMETRY_DEFAULT_PORT, TMOF_INIT_NETWORKING|TMOF_CAPTURE_CONTEXT_SWITCHES, 100) +# define ProfEndCapture(...) tmClose(0) +# define ProfThreadName(...) (TM_API_PTR ? TM_API_PTR->_tmThreadName(0, 0, __VA_ARGS__) : (void)0) +# define ProfMsg(...) (TM_API_PTR ? TM_API_PTR->_tmMessageV_Core(0, TMMF_ICON_NOTE, __FILE__, &g_telemetry_filename_id, __LINE__, __VA_ARGS__) : (void)0) +# define ProfBeginLockWait(...) tmStartWaitForLock(0, 0, __VA_ARGS__) +# define ProfEndLockWait(...) tmEndWaitForLock(0) +# define ProfLockTake(...) tmAcquiredLock(0, 0, __VA_ARGS__) +# define ProfLockDrop(...) tmReleasedLock(0, __VA_ARGS__) +# define ProfColor(color) tmZoneColorSticky(color) +#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) +#endif + +//////////////////////////////// +//~ rjf: Helper Wrappers + +#define ProfBeginFunction(...) ProfBegin(this_function_name) +#define ProfScope(...) DeferLoop(ProfBeginDynamic(__VA_ARGS__), ProfEnd()) + +#endif // BASE_PROFILE_H diff --git a/src/base/base_string.c b/src/base/base_strings.c similarity index 95% rename from src/base/base_string.c rename to src/base/base_strings.c index 41df6577..dffc8da4 100644 --- a/src/base/base_string.c +++ b/src/base/base_strings.c @@ -4,7 +4,7 @@ //////////////////////////////// //~ rjf: Third Party Includes -#if !SUPPLEMENT_UNIT +#if !BUILD_SUPPLEMENTARY_UNIT # define STB_SPRINTF_IMPLEMENTATION # define STB_SPRINTF_STATIC # include "third_party/stb/stb_sprintf.h" @@ -1306,7 +1306,7 @@ utf8_encode(U8 *str, U32 codepoint){ inc = 3; } else if (codepoint <= 0x10FFFF){ - str[0] = (bitmask4 << 3) | ((codepoint >> 18) & bitmask3); + str[0] = (bitmask4 << 4) | ((codepoint >> 18) & bitmask3); str[1] = bit8 | ((codepoint >> 12) & bitmask6); str[2] = bit8 | ((codepoint >> 6) & bitmask6); str[3] = bit8 | ( codepoint & bitmask6); @@ -1565,6 +1565,64 @@ string_from_elapsed_time(Arena *arena, DateTime dt){ return(result); } +//////////////////////////////// +//~ rjf: Textual String Wrapping + +internal String8List +wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent) +{ + String8List list = {0}; + Rng1U64 line_range = r1u64(0, 0); + U64 wrapped_indent_level = 0; + static char *spaces = " "; + for (U64 idx = 0; idx <= string.size; idx += 1){ + U8 chr = idx < string.size ? string.str[idx] : 0; + if (chr == '\n'){ + Rng1U64 candidate_line_range = line_range; + candidate_line_range.max = idx; + // NOTE(nick): when wrapping is interrupted with \n we emit a string without including \n + // because later tool_fprint_list inserts separator after each node + // except for last node, so don't strip last \n. + if (idx + 1 == string.size){ + candidate_line_range.max += 1; + } + String8 substr = str8_substr(string, candidate_line_range); + str8_list_push(arena, &list, substr); + line_range = r1u64(idx+1,idx+1); + } + else + if (char_is_space(chr) || chr == 0){ + Rng1U64 candidate_line_range = line_range; + candidate_line_range.max = idx; + String8 substr = str8_substr(string, candidate_line_range); + U64 width_this_line = max_width-wrapped_indent_level; + if (list.node_count == 0){ + width_this_line = first_line_max_width; + } + if (substr.size > width_this_line){ + String8 line = str8_substr(string, line_range); + if (wrapped_indent_level > 0){ + line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line); + } + str8_list_push(arena, &list, line); + line_range = r1u64(line_range.max+1, candidate_line_range.max); + wrapped_indent_level = ClampTop(64, wrap_indent); + } + else{ + line_range = candidate_line_range; + } + } + } + if (line_range.min < string.size && line_range.max > line_range.min){ + String8 line = str8_substr(string, line_range); + if (wrapped_indent_level > 0){ + line = push_str8f(arena, "%.*s%S", wrapped_indent_level, spaces, line); + } + str8_list_push(arena, &list, line); + } + return list; +} + //////////////////////////////// //~ rjf: String <-> Color diff --git a/src/base/base_string.h b/src/base/base_strings.h similarity index 97% rename from src/base/base_string.h rename to src/base/base_strings.h index 5090f1bb..e4261089 100644 --- a/src/base/base_string.h +++ b/src/base/base_strings.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef BASE_STRING_H -#define BASE_STRING_H +#ifndef BASE_STRINGS_H +#define BASE_STRINGS_H //////////////////////////////// //~ rjf: Third Party Includes @@ -326,6 +326,11 @@ 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); +//////////////////////////////// +//~ rjf: Textual String Wrapping + +internal String8List wrapped_lines_from_string(Arena *arena, String8 string, U64 first_line_max_width, U64 max_width, U64 wrap_indent); + //////////////////////////////// //~ rjf: String <-> Color @@ -368,4 +373,4 @@ internal U64 str8_deserial_read_block(String8 string, U64 off, U64 size, Stri #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))) -#endif // BASE_STRING_H +#endif // BASE_STRINGS_H diff --git a/src/base/base_thread_context.c b/src/base/base_thread_context.c index 1efd6e60..45ab7afe 100644 --- a/src/base/base_thread_context.c +++ b/src/base/base_thread_context.c @@ -5,7 +5,7 @@ // NOTE(allen): Thread Context Functions C_LINKAGE thread_static TCTX* tctx_thread_local; -#if !SUPPLEMENT_UNIT +#if !BUILD_SUPPLEMENTARY_UNIT C_LINKAGE thread_static TCTX* tctx_thread_local = 0; #endif @@ -19,6 +19,15 @@ tctx_init_and_equip(TCTX *tctx){ tctx_thread_local = tctx; } +internal void +tctx_release(void) +{ + for(U64 i = 0; i < ArrayCount(tctx_thread_local->arenas); i += 1) + { + arena_release(tctx_thread_local->arenas[i]); + } +} + internal TCTX* tctx_get_equipped(void){ return(tctx_thread_local); diff --git a/src/base/base_thread_context.h b/src/base/base_thread_context.h index ce05d47f..4f61d009 100644 --- a/src/base/base_thread_context.h +++ b/src/base/base_thread_context.h @@ -23,6 +23,7 @@ struct TCTX // NOTE(allen): Thread Context Functions 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); diff --git a/src/raddbg_convert/pdb/raddbg_codeview.c b/src/codeview/codeview.c similarity index 75% rename from src/raddbg_convert/pdb/raddbg_codeview.c rename to src/codeview/codeview.c index 099365e4..ad1b528e 100644 --- a/src/raddbg_convert/pdb/raddbg_codeview.c +++ b/src/codeview/codeview.c @@ -1,10 +1,15 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ Generated Code + +#include "generated/codeview.meta.c" + //////////////////////////////// //~ CodeView Common Functions -static CV_NumericParsed +internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl){ CV_NumericParsed result = {0}; if (first + 2 <= opl){ @@ -52,7 +57,7 @@ cv_numeric_from_data_range(U8 *first, U8 *opl){ return(result); } -static B32 +internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num){ B32 result = 0; switch (num->kind){ @@ -66,7 +71,7 @@ cv_numeric_fits_in_u64(CV_NumericParsed *num){ return(result); } -static B32 +internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num){ B32 result = 0; switch (num->kind){ @@ -81,7 +86,7 @@ cv_numeric_fits_in_s64(CV_NumericParsed *num){ return(result); } -static B32 +internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num){ B32 result = 0; switch (num->kind){ @@ -94,7 +99,7 @@ cv_numeric_fits_in_f64(CV_NumericParsed *num){ return(result); } -static U64 +internal U64 cv_u64_from_numeric(CV_NumericParsed *num){ U64 result = 0; switch (num->kind){ @@ -116,7 +121,7 @@ cv_u64_from_numeric(CV_NumericParsed *num){ return(result); } -static S64 +internal S64 cv_s64_from_numeric(CV_NumericParsed *num){ S64 result = 0; switch (num->kind){ @@ -143,7 +148,7 @@ cv_s64_from_numeric(CV_NumericParsed *num){ return(result); } -static F64 +internal F64 cv_f64_from_numeric(CV_NumericParsed *num){ F64 result = 0; switch (num->kind){ @@ -164,54 +169,9 @@ cv_f64_from_numeric(CV_NumericParsed *num){ //////////////////////////////// //~ CodeView Sym Parser Functions -static CV_SymParsed* -cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align){ - Assert(1 <= sym_align && IsPow2OrZero(sym_align)); - ProfBegin("cv_sym_from_data"); - - Temp scratch = scratch_begin(&arena, 1); - - // gather up symbols - CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, sym_data, sym_align); - - // convert to result - CV_SymParsed *result = push_array(arena, CV_SymParsed, 1); - result->data = sym_data; - result->sym_align = sym_align; - result->sym_ranges = cv_rec_range_array_from_stream(arena, stream); - cv_sym_top_level_info_from_syms(arena, sym_data, &result->sym_ranges, &result->info); - - scratch_end(scratch); - - ProfEnd(); - - return(result); -} +//- the first pass parser -static CV_LeafParsed* -cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId itype_first){ - ProfBegin("cv_leaf_from_data"); - - Temp scratch = scratch_begin(&arena, 1); - - // gather up symbols - CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, leaf_data, 1); - - // convert to result - CV_LeafParsed *result = push_array(arena, CV_LeafParsed, 1); - result->data = leaf_data; - result->itype_first = itype_first; - result->itype_opl = itype_first + stream->total_count; - result->leaf_ranges = cv_rec_range_array_from_stream(arena, stream); - - scratch_end(scratch); - - ProfEnd(); - - return(result); -} - -static CV_RecRangeStream* +internal CV_RecRangeStream* cv_rec_range_stream_from_data(Arena *arena, String8 sym_data, U64 sym_align){ Assert(1 <= sym_align && IsPow2OrZero(sym_align)); @@ -248,7 +208,33 @@ cv_rec_range_stream_from_data(Arena *arena, String8 sym_data, U64 sym_align){ return(result); } -static void +//- sym + +internal CV_SymParsed* +cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align){ + Assert(1 <= sym_align && IsPow2OrZero(sym_align)); + ProfBegin("cv_sym_from_data"); + + Temp scratch = scratch_begin(&arena, 1); + + // gather up symbols + CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, sym_data, sym_align); + + // convert to result + CV_SymParsed *result = push_array(arena, CV_SymParsed, 1); + result->data = sym_data; + result->sym_align = sym_align; + result->sym_ranges = cv_rec_range_array_from_stream(arena, stream); + cv_sym_top_level_info_from_syms(arena, sym_data, &result->sym_ranges, &result->info); + + scratch_end(scratch); + + ProfEnd(); + + return(result); +} + +internal void cv_sym_top_level_info_from_syms(Arena *arena, String8 sym_data, CV_RecRangeArray *ranges, CV_SymTopLevelInfo *info_out){ @@ -313,17 +299,41 @@ cv_sym_top_level_info_from_syms(Arena *arena, String8 sym_data, } } +//- leaf + +internal CV_LeafParsed* +cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId itype_first){ + ProfBegin("cv_leaf_from_data"); + + Temp scratch = scratch_begin(&arena, 1); + + // gather up symbols + CV_RecRangeStream *stream = cv_rec_range_stream_from_data(scratch.arena, leaf_data, 1); + + // convert to result + CV_LeafParsed *result = push_array(arena, CV_LeafParsed, 1); + result->data = leaf_data; + result->itype_first = itype_first; + result->itype_opl = itype_first + stream->total_count; + result->leaf_ranges = cv_rec_range_array_from_stream(arena, stream); + + scratch_end(scratch); + + ProfEnd(); + + return(result); +} //- range streams -static CV_RecRangeChunk* +internal CV_RecRangeChunk* cv_rec_range_stream_push_chunk(Arena *arena, CV_RecRangeStream *stream){ CV_RecRangeChunk *result = push_array_no_zero(arena, CV_RecRangeChunk, 1); SLLQueuePush(stream->first_chunk, stream->last_chunk, result); return(result); } -static CV_RecRangeArray +internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream){ U64 total_count = stream->total_count; CV_RecRange *ranges = push_array_no_zero(arena, CV_RecRange, total_count); @@ -345,9 +355,8 @@ cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream){ //////////////////////////////// //~ CodeView C13 Parser Functions -static CV_C13Parsed* -cv_c13_from_data(Arena *arena, String8 c13_data, - PDB_Strtbl *strtbl, PDB_CoffSectionArray *sections){ +internal CV_C13Parsed* +cv_c13_from_data(Arena *arena, String8 c13_data, PDB_Strtbl *strtbl, PDB_CoffSectionArray *sections){ ProfBegin("cv_c13_from_data"); // gather c13 data @@ -399,76 +408,86 @@ cv_c13_from_data(Arena *arena, String8 c13_data, { // read header if (sizeof(CV_C13_SubSecLinesHeader) <= cap){ - CV_C13_SubSecLinesHeader *hdr = (CV_C13_SubSecLinesHeader*)first; + U32 read_off = 0; + U64 read_off_opl = node->size; + CV_C13_SubSecLinesHeader *hdr = (CV_C13_SubSecLinesHeader*)(first + read_off); + read_off += sizeof(*hdr); - // read file - U32 file_info_off = sizeof(*hdr); - if (file_info_off + sizeof(CV_C13_File) <= cap){ - CV_C13_File *file = (CV_C13_File*)(first + file_info_off); + // extract top level info + U32 sec_idx = hdr->sec; + B32 has_cols = !!(hdr->flags & CV_C13_SubSecLinesFlag_HasColumns); + U64 secrel_off = hdr->sec_off; + U64 secrel_opl = secrel_off + hdr->len; + U64 sec_base_off = sections->sections[sec_idx - 1].voff; + + // rjf: bad section index -> skip + if(sec_idx < 1 || sections->count < sec_idx) + { + continue; + } + + // read files + for(;read_off+sizeof(CV_C13_File) <= read_off_opl;) + { + // rjf: grab next file header + CV_C13_File *file = (CV_C13_File*)(first + read_off); + U32 file_off = file->file_off; + U32 line_count_unclamped = file->num_lines; + U32 block_size = file->block_size; - // extract top level info - U32 sec_idx = hdr->sec; - if (1 <= sec_idx && sec_idx <= sections->count){ - B32 has_cols = !!(hdr->flags & CV_C13_SubSecLinesFlag_HasColumns); - U64 secrel_off = hdr->sec_off; - U64 secrel_opl = secrel_off + hdr->len; - - U64 sec_base_off = sections->sections[sec_idx - 1].voff; - - U32 file_off = file->file_off; - U32 line_count_unclamped = file->num_lines; - U32 block_size = file->block_size; - - // file_name from file_off - String8 file_name = {0}; - if (file_off + sizeof(CV_C13_Checksum) <= file_chksms->size){ - CV_C13_Checksum *checksum = (CV_C13_Checksum*)(c13_data.str + file_chksms->off + file_off); - U32 name_off = checksum->name_off; - file_name = pdb_strtbl_string_from_off(strtbl, name_off); - } - - // array layouts - U32 line_item_size = sizeof(CV_C13_Line); - if (has_cols){ - line_item_size += sizeof(CV_C13_Column); - } - - U32 line_array_off = file_info_off + sizeof(*file); - U32 line_count_max = (cap - line_array_off)/line_item_size; - U32 line_count = ClampTop(line_count_unclamped, line_count_max); - - U32 col_array_off = line_array_off + line_count*sizeof(CV_C13_Line); - - // parse lines - U64 *voffs = push_array_no_zero(arena, U64, line_count + 1); - U32 *line_nums = push_array_no_zero(arena, U32, line_count); - - { - CV_C13_Line *line_ptr = (CV_C13_Line*)(first + line_array_off); - CV_C13_Line *line_opl = line_ptr + line_count; - - // TODO(allen): check order correctness here - - U32 i = 0; - for (; line_ptr < line_opl; line_ptr += 1, i += 1){ - voffs[i] = line_ptr->off + secrel_off + sec_base_off; - line_nums[i] = CV_C13_LineFlags_ExtractLineNumber(line_ptr->flags); - } - voffs[i] = secrel_opl + sec_base_off; - } - - // emit parsed lines - CV_C13LinesParsed *lines_parsed = push_array(arena, CV_C13LinesParsed, 1); - lines_parsed->sec_idx = sec_idx; - lines_parsed->file_off = file_off; - lines_parsed->secrel_base_off = secrel_off; - lines_parsed->file_name = file_name; - lines_parsed->voffs = voffs; - lines_parsed->line_nums = line_nums; - lines_parsed->line_count = line_count; - - node->lines = lines_parsed; + // file_name from file_off + String8 file_name = {0}; + if (file_off + sizeof(CV_C13_Checksum) <= file_chksms->size){ + CV_C13_Checksum *checksum = (CV_C13_Checksum*)(c13_data.str + file_chksms->off + file_off); + U32 name_off = checksum->name_off; + file_name = pdb_strtbl_string_from_off(strtbl, name_off); } + + // array layouts + U32 line_item_size = sizeof(CV_C13_Line); + if (has_cols){ + line_item_size += sizeof(CV_C13_Column); + } + + U32 line_array_off = read_off + sizeof(*file); + U32 line_count_max = (read_off_opl - line_array_off) / line_item_size; + U32 line_count = ClampTop(line_count_unclamped, line_count_max); + + U32 col_array_off = line_array_off + line_count*sizeof(CV_C13_Line); + + // parse lines + U64 *voffs = push_array_no_zero(arena, U64, line_count + 1); + U32 *line_nums = push_array_no_zero(arena, U32, line_count); + + { + CV_C13_Line *line_ptr = (CV_C13_Line*)(first + line_array_off); + CV_C13_Line *line_opl = line_ptr + line_count; + + // TODO(allen): check order correctness here + + U32 i = 0; + for (; line_ptr < line_opl; line_ptr += 1, i += 1){ + voffs[i] = line_ptr->off + secrel_off + sec_base_off; + line_nums[i] = CV_C13_LineFlags_ExtractLineNumber(line_ptr->flags); + } + voffs[i] = secrel_opl + sec_base_off; + } + + // emit parsed lines + CV_C13LinesParsedNode *lines_parsed_node = push_array(arena, CV_C13LinesParsedNode, 1); + CV_C13LinesParsed *lines_parsed = &lines_parsed_node->v; + lines_parsed->sec_idx = sec_idx; + lines_parsed->file_off = file_off; + lines_parsed->secrel_base_off = secrel_off; + lines_parsed->file_name = file_name; + lines_parsed->voffs = voffs; + lines_parsed->line_nums = line_nums; + lines_parsed->line_count = line_count; + SLLQueuePush(node->lines_first, node->lines_last, lines_parsed_node); + + // rjf: advance + read_off += sizeof(*file); + read_off += line_item_size*line_count; } } }break; diff --git a/src/raddbg_convert/pdb/raddbg_codeview.h b/src/codeview/codeview.h similarity index 66% rename from src/raddbg_convert/pdb/raddbg_codeview.h rename to src/codeview/codeview.h index aeed9188..a037bee2 100644 --- a/src/raddbg_convert/pdb/raddbg_codeview.h +++ b/src/codeview/codeview.h @@ -1,161 +1,33 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_CODEVIEW_H -#define RADDBG_CODEVIEW_H +#ifndef CODEVIEW_H +#define CODEVIEW_H #pragma pack(push, 1) // https://github.com/microsoft/microsoft-pdb/blob/master/include/cvinfo.h //////////////////////////////// -//~ CodeView Format Shared Types +//~ rjf: CodeView Format Shared Types typedef U32 CV_TypeId; typedef U32 CV_ItemId; - -static CV_TypeId cv_type_id_variadic = 0xFFFFFFFF; - typedef U16 CV_ModIndex; typedef U16 CV_SectionIndex; - typedef U16 CV_Reg; -#define CV_NumericKindXList(X) \ -X(CHAR, 0x8000)\ -X(SHORT, 0x8001)\ -X(USHORT, 0x8002)\ -X(LONG, 0x8003)\ -X(ULONG, 0x8004)\ -X(FLOAT32, 0x8005)\ -X(FLOAT64, 0x8006)\ -X(FLOAT80, 0x8007)\ -X(FLOAT128, 0x8008)\ -X(QUADWORD, 0x8009)\ -X(UQUADWORD, 0x800a)\ -X(FLOAT48, 0x800b)\ -X(COMPLEX32, 0x800c)\ -X(COMPLEX64, 0x800d)\ -X(COMPLEX80, 0x800e)\ -X(COMPLEX128, 0x800f)\ -X(VARSTRING, 0x8010)\ -X(OCTWORD, 0x8017)\ -X(UOCTWORD, 0x8018)\ -X(DECIMAL, 0x8019)\ -X(DATE, 0x801a)\ -X(UTF8STRING, 0x801b)\ -X(FLOAT16, 0x801c) +read_only global CV_TypeId cv_type_id_variadic = 0xFFFFFFFF; -typedef U16 CV_NumericKind; -typedef enum{ -#define X(N,c) CV_NumericKind_##N = c, - CV_NumericKindXList(X) -#undef X -} CV_NumericKindEnum; +//////////////////////////////// +//~ rjf: Generated Code -#define CV_ArchXList(X) \ -X(8080, 0x00)\ -X(8086, 0x01)\ -X(80286, 0x02)\ -X(80386, 0x03)\ -X(80486, 0x04)\ -X(PENTIUM, 0x05)\ -X(PENTIUMII, 0x06)\ -X(PENTIUMIII, 0x07)\ -X(MIPS, 0x10)\ -X(MIPS16, 0x11)\ -X(MIPS32, 0x12)\ -X(MIPS64, 0x13)\ -X(MIPSI, 0x14)\ -X(MIPSII, 0x15)\ -X(MIPSIII, 0x16)\ -X(MIPSIV, 0x17)\ -X(MIPSV, 0x18)\ -X(M68000, 0x20)\ -X(M68010, 0x21)\ -X(M68020, 0x22)\ -X(M68030, 0x23)\ -X(M68040, 0x24)\ -X(ALPHA, 0x30)\ -X(ALPHA_21164, 0x31)\ -X(ALPHA_21164A, 0x32)\ -X(ALPHA_21264, 0x33)\ -X(ALPHA_21364, 0x34)\ -X(PPC601, 0x40)\ -X(PPC603, 0x41)\ -X(PPC604, 0x42)\ -X(PPC620, 0x43)\ -X(PPCFP, 0x44)\ -X(PPCBE, 0x45)\ -X(SH3, 0x50)\ -X(SH3E, 0x51)\ -X(SH3DSP, 0x52)\ -X(SH4, 0x53)\ -X(SHMEDIA, 0x54)\ -X(ARM3, 0x60)\ -X(ARM4, 0x61)\ -X(ARM4T, 0x62)\ -X(ARM5, 0x63)\ -X(ARM5T, 0x64)\ -X(ARM6, 0x65)\ -X(ARM_XMAC, 0x66)\ -X(ARM_WMMX, 0x67)\ -X(ARM7, 0x68)\ -X(OMNI, 0x70)\ -X(IA64_1, 0x80)\ -X(IA64_2, 0x81)\ -X(CEE, 0x90)\ -X(AM33, 0xA0)\ -X(M32R, 0xB0)\ -X(TRICORE, 0xC0)\ -X(X64, 0xD0)\ -X(EBC, 0xE0)\ -X(THUMB, 0xF0)\ -X(ARMNT, 0xF4)\ -X(ARM64, 0xF6)\ -X(D3D11_SHADER, 0x100) +#include "generated/codeview.meta.h" -#define CV_Arch_IA64 CV_Arch_IA64_1 +//////////////////////////////// +//~ rjf: Registers -typedef U16 CV_Arch; -typedef enum{ -#define X(N,c) CV_Arch_##N = c, - CV_ArchXList(X) -#undef X -} CV_ArchEnum; -#define CV_Arch_PENTIUMPRO CV_Arch_PENTIUMII -#define CV_Arch_MIPSR4000 CV_Arch_MIPS -#define CV_Arch_ALPHA_21064 CV_Arch_ALPHA -#define CV_Arch_AMD64 CV_Arch_X64 - - -typedef U16 CV_Reg; - - -#define CV_AllRegXList(X) \ -X(ERR, 30000)\ -X(TEB, 30001)\ -X(TIMER, 30002)\ -X(EFAD1, 30003)\ -X(EFAD2, 30004)\ -X(EFAD3, 30005)\ -X(VFRAME, 30006)\ -X(HANDLE, 30007)\ -X(PARAMS, 30008)\ -X(LOCALS, 30009)\ -X(TID, 30010)\ -X(ENV, 30011)\ -X(CMDLN, 30012) - -typedef U16 CV_AllReg; -typedef enum{ -#define X(N,c) CV_AllReg_##N = c, - CV_AllRegXList(X) -#undef X -} CV_AllRegEnum; - - -// X(NAME, CODE, (RADDBG_RegsiterCode_X86) NAME, BYTE_POS, BYTE_SIZE) +// X(NAME, CODE, (RDI_RegisterCode_X86) NAME, BYTE_POS, BYTE_SIZE) #define CV_Reg_X86_XList(X) \ X(NONE, 0, nil, 0, 0)\ X(AL, 1, eax, 0, 1)\ @@ -402,13 +274,15 @@ X(YMM7D2, 394, ymm7, 16, 8)\ X(YMM7D3, 395, ymm7, 24, 8) typedef U16 CV_Regx86; -typedef enum{ +typedef enum CV_Regx86Enum +{ #define X(CVN,C,RDN,BP,BZ) CV_Regx86_##CVN = C, CV_Reg_X86_XList(X) #undef X -} CV_Regx86Enum; +} +CV_Regx86Enum; -// X(NAME, CODE, (RADDBG_RegsiterCode_X64) NAME, BYTE_POS, BYTE_SIZE) +// X(NAME, CODE, (RDI_RegisterCode_X64) NAME, BYTE_POS, BYTE_SIZE) #define CV_Reg_X64_XList(X) \ X(NONE, 0, nil, 0, 0)\ X(AL, 1, rax, 0, 1)\ @@ -1029,11 +903,13 @@ X(YMM15D2, 686, ymm15, 16, 8)\ X(YMM15D3, 687, ymm15, 24, 8) typedef U16 CV_Regx64; -typedef enum{ +typedef enum CV_Regx64Enum +{ #define X(CVN,C,RDN,BP,BZ) CV_Regx64_##CVN = C, CV_Reg_X64_XList(X) #undef X -} CV_Regx64Enum; +} +CV_Regx64Enum; #define CV_SignatureXList(X) \ @@ -1044,11 +920,13 @@ X(C13, 4)\ X(RESERVED, 5) typedef U16 CV_Signature; -typedef enum{ +typedef enum CV_SignatureEnum +{ #define X(N,c) CV_Signature_##N = c, CV_SignatureXList(X) #undef X -} CV_SignatureEnum; +} +CV_SignatureEnum; #define CV_LanguageXList(X) \ @@ -1071,231 +949,33 @@ X(MSIL, 0x0F)\ X(HLSL, 0x10) typedef U16 CV_Language; -typedef enum{ +typedef enum CV_LanguageEnum +{ #define X(N,c) CV_Language_##N = c, CV_LanguageXList(X) #undef X -} CV_LanguageEnum; - - +} +CV_LanguageEnum; //////////////////////////////// -//~ CodeView Format "Sym" and "Leaf" Header Type +//~ rjf: CodeView Format "Sym" and "Leaf" Header Type -typedef struct CV_RecHeader{ +typedef struct CV_RecHeader CV_RecHeader; +struct CV_RecHeader +{ U16 size; U16 kind; -} CV_RecHeader; - +}; //////////////////////////////// -//~ CodeView Format "Sym" Types -// (per-compilation-unit info, variables, procedures, etc.) - -#define CV_SymKindXList(X) \ -X(COMPILE, 0x0001)\ -X(REGISTER_16t, 0x0002)\ -X(CONSTANT_16t, 0x0003)\ -X(UDT_16t, 0x0004)\ -X(SSEARCH, 0x0005)\ -X(END, 0x0006)\ -X(SKIP, 0x0007)\ -X(CVRESERVE, 0x0008)\ -X(OBJNAME_ST, 0x0009)\ -X(ENDARG, 0x000a)\ -X(COBOLUDT_16t, 0x000b)\ -X(MANYREG_16t, 0x000c)\ -X(RETURN, 0x000d)\ -X(ENTRYTHIS, 0x000e)\ -X(BPREL16, 0x0100)\ -X(LDATA16, 0x0101)\ -X(GDATA16, 0x0102)\ -X(PUB16, 0x0103)\ -X(LPROC16, 0x0104)\ -X(GPROC16, 0x0105)\ -X(THUNK16, 0x0106)\ -X(BLOCK16, 0x0107)\ -X(WITH16, 0x0108)\ -X(LABEL16, 0x0109)\ -X(CEXMODEL16, 0x010a)\ -X(VFTABLE16, 0x010b)\ -X(REGREL16, 0x010c)\ -X(BPREL32_16t, 0x0200)\ -X(LDATA32_16t, 0x0201)\ -X(GDATA32_16t, 0x0202)\ -X(PUB32_16t, 0x0203)\ -X(LPROC32_16t, 0x0204)\ -X(GPROC32_16t, 0x0205)\ -X(THUNK32_ST, 0x0206)\ -X(BLOCK32_ST, 0x0207)\ -X(WITH32_ST, 0x0208)\ -X(LABEL32_ST, 0x0209)\ -X(CEXMODEL32, 0x020a)\ -X(VFTABLE32_16t, 0x020b)\ -X(REGREL32_16t, 0x020c)\ -X(LTHREAD32_16t, 0x020d)\ -X(GTHREAD32_16t, 0x020e)\ -X(SLINK32, 0x020f)\ -X(LPROCMIPS_16t, 0x0300)\ -X(GPROCMIPS_16t, 0x0301)\ -X(PROCREF_ST, 0x0400)\ -X(DATAREF_ST, 0x0401)\ -X(ALIGN, 0x0402)\ -X(LPROCREF_ST, 0x0403)\ -X(OEM, 0x0404)\ -X(TI16_MAX, 0x1000)\ -X(CONSTANT_ST, 0x1002)\ -X(UDT_ST, 0x1003)\ -X(COBOLUDT_ST, 0x1004)\ -X(MANYREG_ST, 0x1005)\ -X(BPREL32_ST, 0x1006)\ -X(LDATA32_ST, 0x1007)\ -X(GDATA32_ST, 0x1008)\ -X(PUB32_ST, 0x1009)\ -X(LPROC32_ST, 0x100a)\ -X(GPROC32_ST, 0x100b)\ -X(VFTABLE32, 0x100c)\ -X(REGREL32_ST, 0x100d)\ -X(LTHREAD32_ST, 0x100e)\ -X(GTHREAD32_ST, 0x100f)\ -X(LPROCMIPS_ST, 0x1010)\ -X(GPROCMIPS_ST, 0x1011)\ -X(FRAMEPROC, 0x1012)\ -X(COMPILE2_ST, 0x1013)\ -X(MANYREG2_ST, 0x1014)\ -X(LPROCIA64_ST, 0x1015)\ -X(GPROCIA64_ST, 0x1016)\ -X(LOCALSLOT_ST, 0x1017)\ -X(PARAMSLOT_ST, 0x1018)\ -X(ANNOTATION, 0x1019)\ -X(GMANPROC_ST, 0x101a)\ -X(LMANPROC_ST, 0x101b)\ -X(RESERVED1, 0x101c)\ -X(RESERVED2, 0x101d)\ -X(RESERVED3, 0x101e)\ -X(RESERVED4, 0x101f)\ -X(LMANDATA_ST, 0x1020)\ -X(GMANDATA_ST, 0x1021)\ -X(MANFRAMEREL_ST, 0x1022)\ -X(MANREGISTER_ST, 0x1023)\ -X(MANSLOT_ST, 0x1024)\ -X(MANMANYREG_ST, 0x1025)\ -X(MANREGREL_ST, 0x1026)\ -X(MANMANYREG2_ST, 0x1027)\ -X(MANTYPREF, 0x1028)\ -X(UNAMESPACE_ST, 0x1029)\ -X(ST_MAX, 0x1100)\ -X(OBJNAME, 0x1101)\ -X(THUNK32, 0x1102)\ -X(BLOCK32, 0x1103)\ -X(WITH32, 0x1104)\ -X(LABEL32, 0x1105)\ -X(REGISTER, 0x1106)\ -X(CONSTANT, 0x1107)\ -X(UDT, 0x1108)\ -X(COBOLUDT, 0x1109)\ -X(MANYREG, 0x110a)\ -X(BPREL32, 0x110b)\ -X(LDATA32, 0x110c)\ -X(GDATA32, 0x110d)\ -X(PUB32, 0x110e)\ -X(LPROC32, 0x110f)\ -X(GPROC32, 0x1110)\ -X(REGREL32, 0x1111)\ -X(LTHREAD32, 0x1112)\ -X(GTHREAD32, 0x1113)\ -X(LPROCMIPS, 0x1114)\ -X(GPROCMIPS, 0x1115)\ -X(COMPILE2, 0x1116)\ -X(MANYREG2, 0x1117)\ -X(LPROCIA64, 0x1118)\ -X(GPROCIA64, 0x1119)\ -X(LOCALSLOT, 0x111a)\ -X(PARAMSLOT, 0x111b)\ -X(LMANDATA, 0x111c)\ -X(GMANDATA, 0x111d)\ -X(MANFRAMEREL, 0x111e)\ -X(MANREGISTER, 0x111f)\ -X(MANSLOT, 0x1120)\ -X(MANMANYREG, 0x1121)\ -X(MANREGREL, 0x1122)\ -X(MANMANYREG2, 0x1123)\ -X(UNAMESPACE, 0x1124)\ -X(PROCREF, 0x1125)\ -X(DATAREF, 0x1126)\ -X(LPROCREF, 0x1127)\ -X(ANNOTATIONREF, 0x1128)\ -X(TOKENREF, 0x1129)\ -X(GMANPROC, 0x112a)\ -X(LMANPROC, 0x112b)\ -X(TRAMPOLINE, 0x112c)\ -X(MANCONSTANT, 0x112d)\ -X(ATTR_FRAMEREL, 0x112e)\ -X(ATTR_REGISTER, 0x112f)\ -X(ATTR_REGREL, 0x1130)\ -X(ATTR_MANYREG, 0x1131)\ -X(SEPCODE, 0x1132)\ -X(DEFRANGE_2005, 0x1134)\ -X(DEFRANGE2_2005, 0x1135)\ -X(SECTION, 0x1136)\ -X(COFFGROUP, 0x1137)\ -X(EXPORT, 0x1138)\ -X(CALLSITEINFO, 0x1139)\ -X(FRAMECOOKIE, 0x113a)\ -X(DISCARDED, 0x113b)\ -X(COMPILE3, 0x113c)\ -X(ENVBLOCK, 0x113d)\ -X(LOCAL, 0x113e)\ -X(DEFRANGE, 0x113f)\ -X(DEFRANGE_SUBFIELD, 0x1140)\ -X(DEFRANGE_REGISTER, 0x1141)\ -X(DEFRANGE_FRAMEPOINTER_REL, 0x1142)\ -X(DEFRANGE_SUBFIELD_REGISTER, 0x1143)\ -X(DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE, 0x1144)\ -X(DEFRANGE_REGISTER_REL, 0x1145)\ -X(LPROC32_ID, 0x1146)\ -X(GPROC32_ID, 0x1147)\ -X(LPROCMIPS_ID, 0x1148)\ -X(GPROCMIPS_ID, 0x1149)\ -X(LPROCIA64_ID, 0x114a)\ -X(GPROCIA64_ID, 0x114b)\ -X(BUILDINFO, 0x114c)\ -X(INLINESITE, 0x114d)\ -X(INLINESITE_END, 0x114e)\ -X(PROC_ID_END, 0x114f)\ -X(DEFRANGE_HLSL, 0x1150)\ -X(GDATA_HLSL, 0x1151)\ -X(LDATA_HLSL, 0x1152)\ -X(FILESTATIC, 0x1153)\ -X(LPROC32_DPC, 0x1155)\ -X(LPROC32_DPC_ID, 0x1156)\ -X(DEFRANGE_DPC_PTR_TAG, 0x1157)\ -X(DPC_SYM_TAG_MAP, 0x1158)\ -X(ARMSWITCHTABLE, 0x1159)\ -X(CALLEES, 0x115a)\ -X(CALLERS, 0x115b)\ -X(POGODATA, 0x115c)\ -X(INLINESITE2, 0x115d)\ -X(HEAPALLOCSITE, 0x115e)\ -X(MOD_TYPEREF, 0x115f)\ -X(REF_MINIPDB, 0x1160)\ -X(PDBMAP, 0x1161)\ -X(GDATA_HLSL32, 0x1162)\ -X(LDATA_HLSL32, 0x1163)\ -X(GDATA_HLSL32_EX, 0x1164)\ -X(LDATA_HLSL32_EX, 0x1165)\ -X(FASTLINK, 0x1167)\ -X(INLINEES, 0x1168) - -typedef U16 CV_SymKind; -typedef enum{ -#define X(N,c) CV_SymKind_##N = c, - CV_SymKindXList(X) -#undef X -} CV_SymKindEnum; +//~ rjf: CodeView Format "Sym" Types +// +// (per-compilation-unit info, variables, procedures, etc.) +// typedef U8 CV_ProcFlags; -enum{ +enum +{ CV_ProcFlag_NoFPO = (1 << 0), CV_ProcFlag_IntReturn = (1 << 1), CV_ProcFlag_FarReturn = (1 << 2), @@ -1307,7 +987,8 @@ enum{ }; typedef U16 CV_LocalFlags; -enum{ +enum +{ CV_LocalFlag_Param = (1 << 0), CV_LocalFlag_AddrTaken = (1 << 1), CV_LocalFlag_Compgen = (1 << 2), @@ -1321,13 +1002,16 @@ enum{ CV_LocalFlag_Static = (1 << 10), }; -typedef struct CV_LocalVarAttr{ +typedef struct CV_LocalVarAttr CV_LocalVarAttr; +struct CV_LocalVarAttr +{ U32 off; U16 seg; CV_LocalFlags flags; -} CV_LocalVarAttr; +}; + +//- (SymKind: COMPILE) -// (SymKind: COMPILE) typedef U32 CV_CompileFlags; #define CV_CompileFlags_ExtractLanguage(f) (((f) )&0xFF) #define CV_CompileFlags_ExtractFloatPrec(f) (((f)>> 8)&0x03) @@ -1336,23 +1020,30 @@ typedef U32 CV_CompileFlags; #define CV_CompileFlags_ExtractAmbientCode(f) (((f)>>15)&0x07) #define CV_CompileFlags_ExtractMode(f) (((f)>>18)&0x01) -typedef struct CV_SymCompile{ +typedef struct CV_SymCompile CV_SymCompile; +struct CV_SymCompile +{ U8 machine; CV_CompileFlags flags; // U8[] ver_str (null terminated) -} CV_SymCompile; +}; -// (SymKind: SSEARCH) -typedef struct CV_SymStartSearch{ +//- (SymKind: SSEARCH) + +typedef struct CV_SymStartSearch CV_SymStartSearch; +struct CV_SymStartSearch +{ U32 start_symbol; U16 segment; -} CV_SymStartSearch; +}; -// (SymKind: END) (empty) +//- (SymKind: END) (empty) + +//- (SymKind: RETURN) -// (SymKind: RETURN) typedef U8 CV_GenericStyle; -typedef enum{ +typedef enum CV_GenericStyleEnum +{ CV_GenericStyle_VOID, CV_GenericStyle_REG, // "return data is in register" CV_GenericStyle_ICAN, // "indirect caller allocated near" @@ -1360,52 +1051,69 @@ typedef enum{ CV_GenericStyle_IRAN, // "indirect returnee allocated near" CV_GenericStyle_IRAF, // "indirect returnee allocated far" CV_GenericStyle_UNUSED, -} CV_GenericStyleEnum; +} +CV_GenericStyleEnum; typedef U16 CV_GenericFlags; -enum{ +enum +{ CV_GenericFlags_CSTYLE = (1 << 0), CV_GenericFlags_RSCLEAN = (1 << 1), // "returnee stack cleanup" }; -typedef struct CV_Return{ +typedef struct CV_SymReturn CV_SymReturn; +struct CV_SymReturn +{ CV_GenericFlags flags; CV_GenericStyle style; -} CV_Return; +}; -// (SymKind: SLINK32) -typedef struct CV_SymSLink32{ +//- (SymKind: SLINK32) + +typedef struct CV_SymSLink32 CV_SymSLink32; +struct CV_SymSLink32 +{ U32 frame_size; U32 offset; U16 reg; -} CV_SymSLink32; +}; -// (SymKind: OEM) -typedef struct CV_SymOEM{ +//- (SymKind: OEM) + +typedef struct CV_SymOEM CV_SymOEM; +struct CV_SymOEM +{ COFF_Guid id; CV_TypeId itype; // padding align(4) -} CV_SymOEM; +}; -// (SymKind: VFTABLE32) -typedef struct CV_SymVPath32{ +//- (SymKind: VFTABLE32) + +typedef struct CV_SymVPath32 CV_SymVPath32; +struct CV_SymVPath32 +{ CV_TypeId root; CV_TypeId path; U32 off; U16 seg; -} CV_SymVPath32; +}; + +//- (SymKind: FRAMEPROC) -// (SymKind: FRAMEPROC) typedef U8 CV_EncodedFramePtrReg; -typedef enum{ +typedef enum CV_EncodedFramePtrRegEnum +{ CV_EncodedFramePtrReg_None, CV_EncodedFramePtrReg_StackPtr, CV_EncodedFramePtrReg_FramePtr, CV_EncodedFramePtrReg_BasePtr, -} CV_EncodedFramePtrRegEnum; +} +CV_EncodedFramePtrRegEnum; typedef U32 CV_FrameprocFlags; -enum{ +enum +{ CV_FrameprocFlag_UsesAlloca = (1 << 0), CV_FrameprocFlag_UsesSetJmp = (1 << 1), CV_FrameprocFlag_UsesLongJmp = (1 << 2), @@ -1428,11 +1136,12 @@ enum{ CV_FrameprocFlag_HasCFG = (1 << 21), CV_FrameprocFlag_HasCFW = (1 << 22), }; - #define CV_FrameprocFlags_ExtractLocalBasePointer(f) (((f) >> 14)&3) #define CV_FrameprocFlags_ExtractParamBasePointer(f) (((f) >> 16)&3) -typedef struct CV_SymFrameproc{ +typedef struct CV_SymFrameproc CV_SymFrameproc; +struct CV_SymFrameproc +{ U32 frame_size; U32 pad_size; U32 pad_off; @@ -1440,25 +1149,32 @@ typedef struct CV_SymFrameproc{ U32 eh_off; CV_SectionIndex eh_sec; CV_FrameprocFlags flags; -} CV_SymFrameproc; +}; -// (SymKind: ANNOTATION) -typedef struct CV_SymAnnotation{ +//- (SymKind: ANNOTATION) +typedef struct CV_SymAnnotation CV_SymAnnotation; +struct CV_SymAnnotation +{ U32 off; U16 seg; U16 count; // U8[] annotation (null terminated) -} CV_SymAnnotation; +}; -// (SymKind: OBJNAME) -typedef struct CV_SymObjname{ +//- (SymKind: OBJNAME) + +typedef struct CV_SymObjname CV_SymObjname; +struct CV_SymObjname +{ U32 sig; // U8[] name (null terminated) -} CV_SymObjname; +}; + +//- (SymKind: THUNK32) -// (SymKind: THUNK32) typedef U8 CV_ThunkOrdinal; -typedef enum{ +typedef enum CV_ThunkOrdinalEnum +{ CV_ThunkOrdinal_NoType, CV_ThunkOrdinal_Adjustor, CV_ThunkOrdinal_VCall, @@ -1466,9 +1182,12 @@ typedef enum{ CV_ThunkOrdinal_Load, CV_ThunkOrdinal_TrampIncremental, CV_ThunkOrdinal_TrampBranchIsland, -} CV_ThunkOrdinalEnum; +} +CV_ThunkOrdinalEnum; -typedef struct CV_SymThunk32{ +typedef struct CV_SymThunk32 CV_SymThunk32; +struct CV_SymThunk32 +{ U32 parent; U32 end; U32 next; @@ -1478,86 +1197,117 @@ typedef struct CV_SymThunk32{ CV_ThunkOrdinal ord; // U8[] name (null terminated) // U8[] variant (null terminated) -} CV_SymThunk32; +}; -// (SymKind: BLOCK32) -typedef struct CV_SymBlock32{ +//- (SymKind: BLOCK32) + +typedef struct CV_SymBlock32 CV_SymBlock32; +struct CV_SymBlock32 +{ U32 parent; U32 end; U32 len; U32 off; U16 sec; // U8[] name (null terminated) -} CV_SymBlock32; +}; -// (SymKind: LABEL32) -typedef struct CV_SymLabel32{ +//- (SymKind: LABEL32) + +typedef struct CV_SymLabel32 CV_SymLabel32; +struct CV_SymLabel32 +{ U32 off; U16 sec; CV_ProcFlags flags; // U8[] name (null terminated) -} CV_SymLabel32; +}; -// (SymKind: REGISTER) -typedef struct CV_SymRegister{ +//- (SymKind: REGISTER) + +typedef struct CV_SymRegister CV_SymRegister; +struct CV_SymRegister +{ CV_TypeId itype; U16 reg; // U8[] name (null terminated) -} CV_SymRegister; +}; -// (SymKind: CONSTANT) -typedef struct CV_SymConstant{ +//- (SymKind: CONSTANT) + +typedef struct CV_SymConstant CV_SymConstant; +struct CV_SymConstant +{ CV_TypeId itype; // CV_Numeric num // U8[] name (null terminated) -} CV_SymConstant; +}; -// (SymKind: UDT) -typedef struct CV_SymUDT{ +//- (SymKind: UDT) + +typedef struct CV_SymUDT CV_SymUDT; +struct CV_SymUDT +{ CV_TypeId itype; // U8[] name (null terminated) -} CV_SymUDT; +}; -// (SymKind: MANYREG) -typedef struct CV_SymManyreg{ +//- (SymKind: MANYREG) + +typedef struct CV_SymManyreg CV_SymManyreg; +struct CV_SymManyreg +{ CV_TypeId itype; U8 count; // U8[count] regs; -} CV_SymManyreg; +}; -// (SymKind: BPREL32) -typedef struct CV_SymBPRel32{ +//- (SymKind: BPREL32) + +typedef struct CV_SymBPRel32 CV_SymBPRel32; +struct CV_SymBPRel32 +{ U32 off; CV_TypeId itype; // U8[] name (null terminated) -} CV_SymBPRel32; +}; -// (SymKind: LDATA32, GDATA32) -typedef struct CV_SymData32{ +//- (SymKind: LDATA32, GDATA32) + +typedef struct CV_SymData32 CV_SymData32; +struct CV_SymData32 +{ CV_TypeId itype; U32 off; CV_SectionIndex sec; // U8[] name (null terminated) -} CV_SymData32; - -// (SymKind: PUB32) -typedef U32 CV_PubFlags; -enum{ - CV_PubFlag_Code = (1 << 0), - CV_PubFlag_Function = (1 << 1), - CV_PubFlag_ManagedCode = (1 << 2), - CV_PubFlag_MSIL = (1 << 3), }; -typedef struct CV_SymPub32{ +//- (SymKind: PUB32) + +typedef U32 CV_PubFlags; +enum +{ + CV_PubFlag_Code = (1 << 0), + CV_PubFlag_Function = (1 << 1), + CV_PubFlag_ManagedCode = (1 << 2), + CV_PubFlag_MSIL = (1 << 3), +}; + +typedef struct CV_SymPub32 CV_SymPub32; +struct CV_SymPub32 +{ CV_PubFlags flags; U32 off; CV_SectionIndex sec; // U8[] name (null terminated) -} CV_SymPub32; +}; -// (SymKind: LPROC32, GPROC32) -typedef struct CV_SymProc32{ +//- (SymKind: LPROC32, GPROC32) + +typedef struct CV_SymProc32 CV_SymProc32; +struct CV_SymProc32 +{ U32 parent; U32 end; U32 next; @@ -1569,25 +1319,32 @@ typedef struct CV_SymProc32{ U16 sec; CV_ProcFlags flags; // U8[] name (null terminated) -} CV_SymProc32; +}; -// (SymKind: REGREL32) -typedef struct CV_SymRegrel32{ +//- (SymKind: REGREL32) + +typedef struct CV_SymRegrel32 CV_SymRegrel32; +struct CV_SymRegrel32 +{ U32 reg_off; CV_TypeId itype; CV_Reg reg; // U8[] name (null terminated) -} CV_SymRegrel32; +}; -// (SymKind: LTHREAD32, GTHREAD32) -typedef struct CV_SymThread32{ +//- (SymKind: LTHREAD32, GTHREAD32) + +typedef struct CV_SymThread32 CV_SymThread32; +struct CV_SymThread32 +{ CV_TypeId itype; U32 tls_off; U16 tls_seg; // U8[] name (null terminated) -} CV_SymThread32; +}; + +//- (SymKind: COMPILE2) -// (SymKind: COMPILE2) typedef U32 CV_Compile2Flags; #define CV_Compile2Flags_ExtractLanguage(f) (((f) )&0xFF) #define CV_Compile2Flags_ExtractEditAndContinue(f) (((f)>> 8)&0x01) @@ -1600,7 +1357,9 @@ typedef U32 CV_Compile2Flags; #define CV_Compile2Flags_ExtractCVTCIL(f) (((f)>>15)&0x01) #define CV_Compile2Flags_ExtractMSILModule(f) (((f)>>16)&0x01) -typedef struct CV_SymCompile2{ +typedef struct CV_SymCompile2 CV_SymCompile2; +struct CV_SymCompile2 +{ CV_Compile2Flags flags; CV_Arch machine; U16 ver_fe_major; @@ -1610,58 +1369,80 @@ typedef struct CV_SymCompile2{ U16 ver_minor; U16 ver_build; // U8[] ver_str (null terminated) -} CV_SymCompile2; +}; -// (SymKind: MANYREG2) -typedef struct CV_SymManyreg2{ +//- (SymKind: MANYREG2) + +typedef struct CV_SymManyreg2 CV_SymManyreg2; +struct CV_SymManyreg2 +{ CV_TypeId itype; U16 count; // U16[count] regs; -} CV_SymManyreg2; +}; -// (SymKind: LOCALSLOT) -typedef struct CV_SymSlot{ +//- (SymKind: LOCALSLOT) + +typedef struct CV_SymSlot CV_SymSlot; +struct CV_SymSlot +{ U32 slot_index; CV_TypeId itype; // U8[] name (null terminated) -} CV_SymSlot; +}; -// (SymKind: MANFRAMEREL, ATTR_FRAMEREL) -typedef struct CV_SymAttrFrameRel{ +//- (SymKind: MANFRAMEREL, ATTR_FRAMEREL) + +typedef struct CV_SymAttrFrameRel CV_SymAttrFrameRel; +struct CV_SymAttrFrameRel +{ U32 off; CV_TypeId itype; CV_LocalVarAttr attr; // U8[] name (null terminated) -} CV_SymAttrFrameRel; +}; -// (SymKind: MANREGISTER, ATTR_REGISTER) -typedef struct CV_SymAttrReg{ +//- (SymKind: MANREGISTER, ATTR_REGISTER) + +typedef struct CV_SymAttrReg CV_SymAttrReg; +struct CV_SymAttrReg +{ CV_TypeId itype; CV_LocalVarAttr attr; U16 reg; // U8[] name (null terminated) -} CV_SymAttrReg; +}; -// (SymKind: MANMANYREG, ATTR_MANYREG) -typedef struct CV_SymAttrManyReg{ +//- (SymKind: MANMANYREG, ATTR_MANYREG) + + +typedef struct CV_SymAttrManyReg CV_SymAttrManyReg; +struct CV_SymAttrManyReg +{ CV_TypeId itype; CV_LocalVarAttr attr; U8 count; // U8[count] regs // U8[] name (null terminated) -} CV_SymAttrManyReg; +}; -// (SymKind: MANREGREL, ATTR_REGREL) -typedef struct CV_SymAttrRegRel{ +//- (SymKind: MANREGREL, ATTR_REGREL) + +typedef struct CV_SymAttrRegRel CV_SymAttrRegRel; +struct CV_SymAttrRegRel +{ U32 off; CV_TypeId itype; U16 reg; CV_LocalVarAttr attr; // U8[] name (null terminated) -} CV_SymAttrRegRel; +}; -// (SymKind: UNAMESPACE) -typedef struct CV_SymUNamespace{ +//- (SymKind: UNAMESPACE) + +typedef struct CV_SymUNamespace CV_SymUNamespace; +struct CV_SymUNamespace +{ // *** "dummy" is the first character of name - it should not be skipped! // *** It is placed here so the C compiler will accept this struct. // *** The actual fixed size part of this record has a size of zero. @@ -1669,40 +1450,52 @@ typedef struct CV_SymUNamespace{ U8 dummy; // U8[] name (null terminated) -} CV_SymUNamespace; +}; -// (SymKind: PROCREF, DATAREF, LPROCREF) -typedef struct CV_SymRef2{ +//- (SymKind: PROCREF, DATAREF, LPROCREF) + +typedef struct CV_SymRef2 CV_SymRef2; +struct CV_SymRef2 +{ U32 suc_name; U32 sym_off; CV_ModIndex imod; // U8[] name (null terminated) -} CV_SymRef2; +}; + +//- (SymKind: TRAMPOLINE) -// (SymKind: TRAMPOLINE) typedef U16 CV_TrampolineKind; -typedef enum{ +typedef enum CV_TrampolineKindEnum +{ CV_TrampolineKind_Incremental, CV_TrampolineKind_BranchIsland, -} CV_TrampolineKindEnum; +} +CV_TrampolineKindEnum; -typedef struct CV_SymTrampoline{ +typedef struct CV_SymTrampoline CV_SymTrampoline; +struct CV_SymTrampoline +{ CV_TrampolineKind kind; U16 thunk_size; U32 thunk_sec_off; U32 target_sec_off; CV_SectionIndex thunk_sec; CV_SectionIndex target_sec; -} CV_SymTrampoline; +}; + +//- (SymKind: SEPCODE) -// (SymKind: SEPCODE) typedef U32 CV_SepcodeFlags; -enum{ +enum +{ CV_SepcodeFlag_IsLexicalScope = (1 << 0), CV_SepcodeFlag_ReturnsToParent = (1 << 1), }; -typedef struct CV_SymSepcode{ +typedef struct CV_SymSepcode CV_SymSepcode; +struct CV_SymSepcode +{ U32 parent; U32 end; U32 len; @@ -1711,10 +1504,13 @@ typedef struct CV_SymSepcode{ U32 sec_parent_off; U16 sec; U16 sec_parent; -} CV_SymSepcode; +}; -// (SymKind: SECTION) -typedef struct CV_SymSection{ +//- (SymKind: SECTION) + +typedef struct CV_SymSection CV_SymSection; +struct CV_SymSection +{ U16 sec_index; U8 align; U8 pad; @@ -1722,20 +1518,25 @@ typedef struct CV_SymSection{ U32 size; U32 characteristics; // U8[] name (null terminated) -} CV_SymSection; +}; -// (SymKind: COFFGROUP) -typedef struct CV_SymCoffGroup{ +//- (SymKind: COFFGROUP) + +typedef struct CV_SymCoffGroup CV_SymCoffGroup; +struct CV_SymCoffGroup +{ U32 size; U32 characteristics; U32 off; U16 sec; // U8[] name (null terminated) -} CV_SymCoffGroup; +}; + +//- (SymKind: EXPORT) -// (SymKind: EXPORT) typedef U16 CV_ExportFlags; -enum{ +enum +{ CV_ExportFlag_Constant = (1 << 0), CV_ExportFlag_Data = (1 << 1), CV_ExportFlag_Private = (1 << 2), @@ -1744,52 +1545,68 @@ enum{ CV_ExportFlag_Forwarder = (1 << 5), }; -typedef struct CV_SymExport{ +typedef struct CV_SymExport CV_SymExport; +struct CV_SymExport +{ U16 ordinal; CV_ExportFlags flags; // U8[] name (null terminated) -} CV_SymExport; +}; -// (SymKind: CALLSITEINFO) -typedef struct CV_SymCallSiteInfo{ +//- (SymKind: CALLSITEINFO) + +typedef struct CV_SymCallSiteInfo CV_SymCallSiteInfo; +struct CV_SymCallSiteInfo +{ U32 off; U16 sec; U16 pad; CV_TypeId itype; -} CV_SymCallSiteInfo; +}; + +//- (SymKind: FRAMECOOKIE) -// (SymKind: FRAMECOOKIE) typedef U8 CV_FrameCookieKind; -typedef enum{ +typedef enum CV_FrameCookieKindEnum +{ CV_FrameCookieKind_Copy, CV_FrameCookieKind_XorSP, CV_FrameCookieKind_XorBP, CV_FrameCookieKind_XorR13, -} CV_FrameCookieKindEnum; +} +CV_FrameCookieKindEnum; -typedef struct CV_SymFrameCookie{ +typedef struct CV_SymFrameCookie CV_SymFrameCookie; +struct CV_SymFrameCookie +{ U32 off; CV_Reg reg; CV_FrameCookieKind kind; U8 flags; -} CV_SymFrameCookie; +}; + +//- (SymKind: DISCARDED) -// (SymKind: DISCARDED) typedef U8 CV_DiscardedKind; -typedef enum{ +typedef enum CV_DiscardedKindEnum +{ CV_DiscardedKind_Unknown, CV_DiscardedKind_NotSelected, CV_DiscardedKind_NotReferenced, -} CV_DiscardedKindEnum; +} +CV_DiscardedKindEnum; -typedef struct CV_SymDiscarded{ +typedef struct CV_SymDiscarded CV_SymDiscarded; +struct CV_SymDiscarded +{ CV_DiscardedKind kind; U32 file_id; U32 file_ln; // U8[] data (rest of data) -} CV_SymDiscarded; +}; + +//- (SymKind: COMPILE3) -// (SymKind: COMPILE3) typedef U32 CV_Compile3Flags; #define CV_Compile3Flags_ExtractLanguage(f) (((f) )&0xFF) #define CV_Compile3Flags_ExtractEditAndContinue(f) (((f)>> 9)&0x01) @@ -1805,7 +1622,9 @@ typedef U32 CV_Compile3Flags; #define CV_Compile3Flags_ExtractPGO(f) (((f)>>19)&0x01) #define CV_Compile3Flags_ExtractEXP(f) (((f)>>20)&0x01) -typedef struct CV_SymCompile3{ +typedef struct CV_SymCompile3 CV_SymCompile3; +struct CV_SymCompile3 +{ CV_Compile3Flags flags; CV_Arch machine; U16 ver_fe_major; @@ -1817,117 +1636,158 @@ typedef struct CV_SymCompile3{ U16 ver_build; U16 ver_qfe; // U8[] ver_str (null terminated) -} CV_SymCompile3; +}; -// (SymKind: ENVBLOCK) -typedef struct CV_SymEnvBlock{ +//- (SymKind: ENVBLOCK) + +typedef struct CV_SymEnvBlock CV_SymEnvBlock; +struct CV_SymEnvBlock +{ U8 flags; // U8[][] rgsz (sequence null terminated strings) -} CV_SymEnvBlock; +}; -// (SymKind: LOCAL) -typedef struct CV_SymLocal{ +//- (SymKind: LOCAL) + +typedef struct CV_SymLocal CV_SymLocal; +struct CV_SymLocal +{ CV_TypeId itype; CV_LocalFlags flags; // U8[] name (null terminated) -} CV_SymLocal; +}; //- DEFRANGE -typedef struct CV_LvarAddrRange{ +typedef struct CV_LvarAddrRange CV_LvarAddrRange; +struct CV_LvarAddrRange +{ U32 off; U16 sec; U16 len; -} CV_LvarAddrRange; +}; -typedef struct CV_LvarAddrGap{ +typedef struct CV_LvarAddrGap CV_LvarAddrGap; +struct CV_LvarAddrGap +{ U16 off; U16 len; -} CV_LvarAddrGap; +}; typedef U16 CV_RangeAttribs; -enum{ +enum +{ CV_RangeAttrib_Maybe = (1 << 0), }; -// (SymKind: DEFRANGE_SUBFIELD) -typedef struct CV_SymDefrangeSubfield{ +//- (SymKind: DEFRANGE_SUBFIELD) + +typedef struct CV_SymDefrangeSubfield CV_SymDefrangeSubfield; +struct CV_SymDefrangeSubfield +{ U32 program; U32 off_in_parent; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) -} CV_SymDefrangeSubfield; +}; -// (SymKind: DEFRANGE_REGISTER) -typedef struct CV_SymDefrangeRegister{ +//- (SymKind: DEFRANGE_REGISTER) + +typedef struct CV_SymDefrangeRegister CV_SymDefrangeRegister; +struct CV_SymDefrangeRegister +{ CV_Reg reg; CV_RangeAttribs attribs; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) -} CV_SymDefrangeRegister; +}; -// (SymKind: DEFRANGE_FRAMEPOINTER_REL) -typedef struct CV_SymDefrangeFramepointerRel{ +//- (SymKind: DEFRANGE_FRAMEPOINTER_REL) + +typedef struct CV_SymDefrangeFramepointerRel CV_SymDefrangeFramepointerRel; +struct CV_SymDefrangeFramepointerRel +{ S32 off; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) -} CV_SymDefrangeFramepointerRel; +}; -// (SymKind: DEFRANGE_SUBFIELD_REGISTER) -typedef struct CV_SymDefrangeSubfieldRegister{ +//- (SymKind: DEFRANGE_SUBFIELD_REGISTER) + +typedef struct CV_SymDefrangeSubfieldRegister CV_SymDefrangeSubfieldRegister; +struct CV_SymDefrangeSubfieldRegister +{ CV_Reg reg; CV_RangeAttribs attribs; U32 field_offset; CV_LvarAddrRange range; // CV_LvarAddrGap[] gaps (rest of data) -} CV_SymDefrangeSubfieldRegister; +}; -// (SymKind: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE) -typedef struct CV_SymDefrangeFramepointerRelFullScope{ +//- (SymKind: DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE) + +typedef struct CV_SymDefrangeFramepointerRelFullScope CV_SymDefrangeFramepointerRelFullScope; +struct CV_SymDefrangeFramepointerRelFullScope +{ S32 off; -} CV_SymDefrangeFramepointerRelFullScope; +}; + +//- (SymKind: DEFRANGE_REGISTER_REL) -// (SymKind: DEFRANGE_REGISTER_REL) typedef U16 CV_DefrangeRegisterRelFlags; -enum{ +enum +{ CV_DefrangeRegisterRelFlag_SpilledOutUDTMember = (1 << 0), }; #define CV_DefrangeRegisterRelFlag_ExtractOffsetParent(f) (((f)>>4)&0xFFF) -typedef struct CV_SymDefrangeRegisterRel{ +typedef struct CV_SymDefrangeRegisterRel CV_SymDefrangeRegisterRel; +struct CV_SymDefrangeRegisterRel +{ CV_Reg reg; CV_DefrangeRegisterRelFlags flags; S32 reg_off; CV_LvarAddrRange range; // CV_LvarAddGap[] gaps (rest of data) -} CV_SymDefrangeRegisterRel; +}; -// (SymKind: BUILDINFO) -typedef struct CV_SymBuildInfo{ +//- (SymKind: BUILDINFO) + +typedef struct CV_SymBuildInfo CV_SymBuildInfo; +struct CV_SymBuildInfo +{ CV_ItemId id; -} CV_SymBuildInfo; +}; -// (SymKind: INLINESITE) -typedef struct CV_SymInlineSite{ +//- (SymKind: INLINESITE) + +typedef struct CV_SymInlineSite CV_SymInlineSite; +struct CV_SymInlineSite +{ U32 parent; U32 end; CV_ItemId inlinee; // CV_BinaryAnnotation annotations (rest of data) -} CV_SymInlineSite; +}; -// (SymKind: INLINESITE_END) (empty) +//- (SymKind: INLINESITE_END) (empty) -// (SymKind: FILESTATIC) -typedef struct CV_SymFileStatic{ +//- (SymKind: FILESTATIC) + +typedef struct CV_SymFileStatic CV_SymFileStatic; +struct CV_SymFileStatic +{ CV_TypeId itype; U32 mod_offset; CV_LocalFlags flags; // U8[] name (null terminated) -} CV_SymFileStatic; +}; + +//- (SymKind: ARMSWITCHTABLE) -// (SymKind: ARMSWITCHTABLE) typedef U16 CV_ArmSwitchKind; -typedef enum{ +typedef enum +{ CV_ArmSwitchKind_INT1, CV_ArmSwitchKind_UINT1, CV_ArmSwitchKind_INT2, @@ -1941,7 +1801,9 @@ typedef enum{ CV_ArmSwitchKind_INT2SSHL1, } CV_ArmSwitchKindEnum; -typedef struct CV_SymArmSwitchTable{ +typedef struct CV_SymArmSwitchTable CV_SymArmSwitchTable; +struct CV_SymArmSwitchTable +{ U32 off_base; U16 sec_base; CV_ArmSwitchKind kind; @@ -1950,43 +1812,57 @@ typedef struct CV_SymArmSwitchTable{ U16 sec_branch; U16 sec_table; U32 entry_count; -} CV_SymArmSwitchTable; +}; -// (SymKind: CALLEES, CALLERS) -typedef struct CV_SymFunctionList{ +//- (SymKind: CALLEES, CALLERS) + +typedef struct CV_SymFunctionList CV_SymFunctionList; +struct CV_SymFunctionList +{ U32 count; // CV_TypeId[count] funcs // U32[clamp(count, rest_of_data/4)] invocations -} CV_SymFunctionList; +}; -// (SymKind: POGODATA) -typedef struct CV_SymPogoInfo{ +//- (SymKind: POGODATA) + +typedef struct CV_SymPogoInfo CV_SymPogoInfo; +struct CV_SymPogoInfo +{ U32 invocations; U64 dynamic_inst_count; U32 static_inst_count; U32 post_inline_static_inst_count; -} CV_SymPogoInfo; +}; -// (SymKind: INLINESITE2) -typedef struct CV_SymInlineSite2{ +//- (SymKind: INLINESITE2) + +typedef struct CV_SymInlineSite2 CV_SymInlineSite2; +struct CV_SymInlineSite2 +{ U32 parent_off; U32 end_off; CV_ItemId inlinee; U32 invocations; // CV_BinaryAnnotation annotations (rest of data) -} CV_SymInlineSite2; +}; -// (SymKind: HEAPALLOCSITE) -typedef struct CV_SymHeapAllocSite{ +//- (SymKind: HEAPALLOCSITE) + +typedef struct CV_SymHeapAllocSite CV_SymHeapAllocSite; +struct CV_SymHeapAllocSite +{ U32 off; U16 sec; U16 call_inst_len; CV_TypeId itype; -} CV_SymHeapAllocSite; +}; + +//- (SymKind: MOD_TYPEREF) -// (SymKind: MOD_TYPEREF) typedef U32 CV_ModTypeRefFlags; -enum{ +enum +{ CV_ModTypeRefFlag_None = (1 << 0), CV_ModTypeRefFlag_RefTMPCT = (1 << 1), CV_ModTypeRefFlag_OwnTMPCT = (1 << 2), @@ -1995,16 +1871,20 @@ enum{ CV_ModTypeRefFlag_RefTM = (1 << 5), }; -typedef struct CV_SymModTypeRef{ +typedef struct CV_SymModTypeRef CV_SymModTypeRef; +struct CV_SymModTypeRef +{ CV_ModTypeRefFlags flags; // contain stream number or module index depending on flags (undocumented) U32 word0; U32 word1; -} CV_SymModTypeRef; +}; + +//- (SymKind: REF_MINIPDB) -// (SymKind: REF_MINIPDB) typedef U16 CV_RefMiniPdbFlags; -enum{ +enum +{ CV_RefMiniPdbFlag_Local = (1 << 0), CV_RefMiniPdbFlag_Data = (1 << 1), CV_RefMiniPdbFlag_UDT = (1 << 2), @@ -2012,16 +1892,20 @@ enum{ CV_RefMiniPdbFlag_Const = (1 << 4), }; -typedef struct CV_SymRefMiniPdb{ +typedef struct CV_SymRefMiniPdb CV_SymRefMiniPdb; +struct CV_SymRefMiniPdb +{ U32 data; CV_ModIndex imod; CV_RefMiniPdbFlags flags; // U8[] name (null terminated) -} CV_SymRefMiniPdb; +}; + +//- (SymKind: FASTLINK) -// (SymKind: FASTLINK) typedef U16 CV_FastLinkFlags; -enum{ +enum +{ CV_FastLinkFlag_IsGlobalData = (1 << 0), CV_FastLinkFlag_IsData = (1 << 1), CV_FastLinkFlag_IsUDT = (1 << 2), @@ -2031,158 +1915,28 @@ enum{ CV_FastLinkFlag_IsNamespace = (1 << 6), }; -typedef struct CV_SymFastLink{ +typedef struct CV_SymFastLink CV_SymFastLink; +struct CV_SymFastLink +{ CV_TypeId itype; CV_FastLinkFlags flags; // U8[] name (null terminated) -} CV_SymFastLink; +}; -// (SymKind: INLINEES) -typedef struct CV_SymInlinees{ +//- (SymKind: INLINEES) + +typedef struct CV_SymInlinees CV_SymInlinees; +struct CV_SymInlinees +{ U32 count; // U32[count] desc; -} CV_SymInlinees; - +}; //////////////////////////////// -//~ CodeView Format "Leaf" Types +//~ rjf: CodeView Format "Leaf" Types +// // (type info) - -#define CV_LeafKindXList(X) \ -X(MODIFIER_16t, 0x0001)\ -X(POINTER_16t, 0x0002)\ -X(ARRAY_16t, 0x0003)\ -X(CLASS_16t, 0x0004)\ -X(STRUCTURE_16t, 0x0005)\ -X(UNION_16t, 0x0006)\ -X(ENUM_16t, 0x0007)\ -X(PROCEDURE_16t, 0x0008)\ -X(MFUNCTION_16t, 0x0009)\ -X(VTSHAPE, 0x000a)\ -X(COBOL0_16t, 0x000b)\ -X(COBOL1, 0x000c)\ -X(BARRAY_16t, 0x000d)\ -X(LABEL, 0x000e)\ -X(NULL, 0x000f)\ -X(NOTTRAN, 0x0010)\ -X(DIMARRAY_16t, 0x0011)\ -X(VFTPATH_16t, 0x0012)\ -X(PRECOMP_16t, 0x0013)\ -X(ENDPRECOMP, 0x0014)\ -X(OEM_16t, 0x0015)\ -X(TYPESERVER_ST, 0x0016)\ -X(SKIP_16t, 0x0200)\ -X(ARGLIST_16t, 0x0201)\ -X(DEFARG_16t, 0x0202)\ -X(LIST, 0x0203)\ -X(FIELDLIST_16t, 0x0204)\ -X(DERIVED_16t, 0x0205)\ -X(BITFIELD_16t, 0x0206)\ -X(METHODLIST_16t, 0x0207)\ -X(DIMCONU_16t, 0x0208)\ -X(DIMCONLU_16t, 0x0209)\ -X(DIMVARU_16t, 0x020a)\ -X(DIMVARLU_16t, 0x020b)\ -X(REFSYM, 0x020c)\ -X(BCLASS_16t, 0x0400)\ -X(VBCLASS_16t, 0x0401)\ -X(IVBCLASS_16t, 0x0402)\ -X(ENUMERATE_ST, 0x0403)\ -X(FRIENDFCN_16t, 0x0404)\ -X(INDEX_16t, 0x0405)\ -X(MEMBER_16t, 0x0406)\ -X(STMEMBER_16t, 0x0407)\ -X(METHOD_16t, 0x0408)\ -X(NESTTYPE_16t, 0x0409)\ -X(VFUNCTAB_16t, 0x040a)\ -X(FRIENDCLS_16t, 0x040b)\ -X(ONEMETHOD_16t, 0x040c)\ -X(VFUNCOFF_16t, 0x040d)\ -X(TI16_MAX, 0x1000)\ -X(MODIFIER, 0x1001)\ -X(POINTER, 0x1002)\ -X(ARRAY_ST, 0x1003)\ -X(CLASS_ST, 0x1004)\ -X(STRUCTURE_ST, 0x1005)\ -X(UNION_ST, 0x1006)\ -X(ENUM_ST, 0x1007)\ -X(PROCEDURE, 0x1008)\ -X(MFUNCTION, 0x1009)\ -X(COBOL0, 0x100a)\ -X(BARRAY, 0x100b)\ -X(DIMARRAY_ST, 0x100c)\ -X(VFTPATH, 0x100d)\ -X(PRECOMP_ST, 0x100e)\ -X(OEM, 0x100f)\ -X(ALIAS_ST, 0x1010)\ -X(OEM2, 0x1011)\ -X(SKIP, 0x1200)\ -X(ARGLIST, 0x1201)\ -X(DEFARG_ST, 0x1202)\ -X(FIELDLIST, 0x1203)\ -X(DERIVED, 0x1204)\ -X(BITFIELD, 0x1205)\ -X(METHODLIST, 0x1206)\ -X(DIMCONU, 0x1207)\ -X(DIMCONLU, 0x1208)\ -X(DIMVARU, 0x1209)\ -X(DIMVARLU, 0x120a)\ -X(BCLASS, 0x1400)\ -X(VBCLASS, 0x1401)\ -X(IVBCLASS, 0x1402)\ -X(FRIENDFCN_ST, 0x1403)\ -X(INDEX, 0x1404)\ -X(MEMBER_ST, 0x1405)\ -X(STMEMBER_ST, 0x1406)\ -X(METHOD_ST, 0x1407)\ -X(NESTTYPE_ST, 0x1408)\ -X(VFUNCTAB, 0x1409)\ -X(FRIENDCLS, 0x140a)\ -X(ONEMETHOD_ST, 0x140b)\ -X(VFUNCOFF, 0x140c)\ -X(NESTTYPEEX_ST, 0x140d)\ -X(MEMBERMODIFY_ST, 0x140e)\ -X(MANAGED_ST, 0x140f)\ -X(ST_MAX, 0x1500)\ -X(TYPESERVER, 0x1501)\ -X(ENUMERATE, 0x1502)\ -X(ARRAY, 0x1503)\ -X(CLASS, 0x1504)\ -X(STRUCTURE, 0x1505)\ -X(UNION, 0x1506)\ -X(ENUM, 0x1507)\ -X(DIMARRAY, 0x1508)\ -X(PRECOMP, 0x1509)\ -X(ALIAS, 0x150a)\ -X(DEFARG, 0x150b)\ -X(FRIENDFCN, 0x150c)\ -X(MEMBER, 0x150d)\ -X(STMEMBER, 0x150e)\ -X(METHOD, 0x150f)\ -X(NESTTYPE, 0x1510)\ -X(ONEMETHOD, 0x1511)\ -X(NESTTYPEEX, 0x1512)\ -X(MEMBERMODIFY, 0x1513)\ -X(MANAGED, 0x1514)\ -X(TYPESERVER2, 0x1515)\ -X(STRIDED_ARRAY, 0x1516)\ -X(HLSL, 0x1517)\ -X(MODIFIER_EX, 0x1518)\ -X(INTERFACE, 0x1519)\ -X(BINTERFACE, 0x151a)\ -X(VECTOR, 0x151b)\ -X(MATRIX, 0x151c)\ -X(VFTABLE, 0x151d)\ -/* ONGOING REVERSE ENGINEERING */ \ -X(CLASS2, 0x1608)\ -X(STRUCT2, 0x1609) - -typedef U16 CV_LeafKind; -typedef enum{ -#define X(N,c) CV_LeafKind_##N = c, - CV_LeafKindXList(X) -#undef X -} CV_LeafKindEnum; +// #define CV_LeafIDKindXList(X) \ X(FUNC_ID, 0x1601)\ @@ -2194,73 +1948,13 @@ X(UDT_SRC_LINE, 0x1606)\ X(UDT_MOD_SRC_LINE, 0x1607) typedef U16 CV_LeafIDKind; -typedef enum{ +typedef enum CV_LeafIDKindEnum +{ #define X(N,c) CV_LeafIDKind_##N = c, CV_LeafIDKindXList(X) #undef X -} CV_LeafIDKindEnum; - -#define CV_BasicTypeXList(X) \ -X(NOTYPE, 0x00)\ -X(ABS, 0x01)\ -X(SEGMENT, 0x02)\ -X(VOID, 0x03)\ -X(CURRENCY, 0x04)\ -X(NBASICSTR, 0x05)\ -X(FBASICSTR, 0x06)\ -X(NOTTRANS, 0x07)\ -X(HRESULT, 0x08)\ -X(CHAR, 0x10)\ -X(SHORT, 0x11)\ -X(LONG, 0x12)\ -X(QUAD, 0x13)\ -X(OCT, 0x14)\ -X(UCHAR, 0x20)\ -X(USHORT, 0x21)\ -X(ULONG, 0x22)\ -X(UQUAD, 0x23)\ -X(UOCT, 0x24)\ -X(BOOL8, 0x30)\ -X(BOOL16, 0x31)\ -X(BOOL32, 0x32)\ -X(BOOL64, 0x33)\ -X(FLOAT32, 0x40)\ -X(FLOAT64, 0x41)\ -X(FLOAT80, 0x42)\ -X(FLOAT128, 0x43)\ -X(FLOAT48, 0x44)\ -X(FLOAT32PP, 0x45)\ -X(FLOAT16, 0x46)\ -X(COMPLEX32, 0x50)\ -X(COMPLEX64, 0x51)\ -X(COMPLEX80, 0x52)\ -X(COMPLEX128, 0x53)\ -X(BIT, 0x60)\ -X(PASCHAR, 0x61)\ -X(BOOL32FF, 0x62)\ -X(INT8, 0x68)\ -X(UINT8, 0x69)\ -X(RCHAR, 0x70)\ -X(WCHAR, 0x71)\ -X(INT16, 0x72)\ -X(UINT16, 0x73)\ -X(INT32, 0x74)\ -X(UINT32, 0x75)\ -X(INT64, 0x76)\ -X(UINT64, 0x77)\ -X(INT128, 0x78)\ -X(UINT128, 0x79)\ -X(CHAR16, 0x7a)\ -X(CHAR32, 0x7b)\ -X(CHAR8, 0x7c)\ -X(PTR, 0xf0) - -typedef U8 CV_BasicType; -typedef enum{ -#define X(N,c) CV_BasicType_##N = c, - CV_BasicTypeXList(X) -#undef X -} CV_BasicTypeEnum; +} +CV_LeafIDKindEnum; #define CV_TypeId_Variadic 0 @@ -2274,7 +1968,8 @@ X(16_32BIT, 0x5)\ X(64BIT, 0x6) typedef U8 CV_BasicPointerKind; -typedef enum{ +typedef enum +{ #define X(N,c) CV_BasicPointerKind_##N = c, CV_BasicPointerKindXList(X) #undef X @@ -2284,44 +1979,49 @@ typedef enum{ #define CV_BasicPointerKindFromTypeId(x) (((x)>>8)&0xFF) typedef U8 CV_HFAKind; -typedef enum{ +typedef enum CV_HFAKindEnum +{ CV_HFAKind_None, CV_HFAKind_Float, CV_HFAKind_Double, CV_HFAKind_Other -} CV_HFAKindEnum; +} +CV_HFAKindEnum; typedef U8 CV_MoComUDTKind; -typedef enum{ +typedef enum CV_MoComUDTKindEnum +{ CV_MoComUDTKind_None, CV_MoComUDTKind_Ref, CV_MoComUDTKind_Value, CV_MoComUDTKind_Interface -} CV_MoComUDTKindEnum; +} +CV_MoComUDTKindEnum; typedef U16 CV_TypeProps; -enum{ - CV_TypeProp_Packed = (1 << 0), - CV_TypeProp_HasConstructorsDestructors = (1 << 1), - CV_TypeProp_OverloadedOperators = (1 << 2), - CV_TypeProp_IsNested = (1 << 3), - CV_TypeProp_ContainsNested = (1 << 4), - CV_TypeProp_OverloadedAssignment = (1 << 5), - CV_TypeProp_OverloadedCasting = (1 << 6), - CV_TypeProp_FwdRef = (1 << 7), - CV_TypeProp_Scoped = (1 << 8), - CV_TypeProp_HasUniqueName = (1 << 9), - CV_TypeProp_Sealed = (1 << 10), +enum +{ + CV_TypeProp_Packed = (1<<0), + CV_TypeProp_HasConstructorsDestructors = (1<<1), + CV_TypeProp_OverloadedOperators = (1<<2), + CV_TypeProp_IsNested = (1<<3), + CV_TypeProp_ContainsNested = (1<<4), + CV_TypeProp_OverloadedAssignment = (1<<5), + CV_TypeProp_OverloadedCasting = (1<<6), + CV_TypeProp_FwdRef = (1<<7), + CV_TypeProp_Scoped = (1<<8), + CV_TypeProp_HasUniqueName = (1<<9), + CV_TypeProp_Sealed = (1<<10), // HFA: 11,12 - CV_TypeProp_Intrinsic = (1 << 13), + CV_TypeProp_Intrinsic = (1<<13), // MOCOM: 14,15 }; - #define CV_TypeProps_ExtractHFA(f) (((f)>>11)&0x3) #define CV_TypeProps_ExtractMOCOM(f) (((f)>>14)&0x3) typedef U8 CV_PointerKind; -typedef enum{ +typedef enum CV_PointerKindEnum +{ CV_PointerKind_Near, // 16 bit CV_PointerKind_Far, // 16:16 bit CV_PointerKind_Huge, // 16:16 bit @@ -2335,19 +2035,23 @@ typedef enum{ CV_PointerKind_Near32, // 32 bit CV_PointerKind_Far32, // 16:32 bit CV_PointerKind_64, // 64 bit -} CV_PointerKindEnum; +} +CV_PointerKindEnum; typedef U8 CV_PointerMode; -typedef enum{ +typedef enum CV_PointerModeEnum +{ CV_PointerMode_Ptr, CV_PointerMode_LRef, CV_PointerMode_PtrMem, CV_PointerMode_PtrMethod, CV_PointerMode_RRef, -} CV_PointerModeEnum; +} +CV_PointerModeEnum; typedef U16 CV_MemberPointerKind; -typedef enum{ +typedef enum CV_MemberPointerKindEnum +{ CV_MemberPointerKind_Undef, CV_MemberPointerKind_DataSingle, CV_MemberPointerKind_DataMultiple, @@ -2357,21 +2061,25 @@ typedef enum{ CV_MemberPointerKind_FuncMultiple, CV_MemberPointerKind_FuncVirtual, CV_MemberPointerKind_FuncGeneral, -} CV_MemberPointerKindEnum; +} +CV_MemberPointerKindEnum; typedef U32 CV_VirtualTableShape; -typedef enum{ - CV_VirtualTableShape_Near, // 16 bit ptr - CV_VirtualTableShape_Far, // 16:16 bit ptr - CV_VirtualTableShape_Thin, // ??? - CV_VirtualTableShape_Outer, // address point displacment to outermost class entry[-1] - CV_VirtualTableShape_Meta, // far pointer to metaclass descriptor entry[-2] +typedef enum CV_VirtualTableShapeEnum +{ + CV_VirtualTableShape_Near, // 16 bit ptr + CV_VirtualTableShape_Far, // 16:16 bit ptr + CV_VirtualTableShape_Thin, // ??? + CV_VirtualTableShape_Outer, // address point displacment to outermost class entry[-1] + CV_VirtualTableShape_Meta, // far pointer to metaclass descriptor entry[-2] CV_VirtualTableShape_Near32, // 32 bit ptr CV_VirtualTableShape_Far32, // ??? -} CV_VirtualTableShapeEnum; +} +CV_VirtualTableShapeEnum; typedef U8 CV_MethodProp; -enum{ +enum +{ CV_MethodProp_Vanilla, CV_MethodProp_Virtual, CV_MethodProp_Static, @@ -2382,41 +2090,48 @@ enum{ }; typedef U8 CV_MemberAccess; -typedef enum{ +typedef enum CV_MemberAccessEnum +{ CV_MemberAccess_Null, CV_MemberAccess_Private, CV_MemberAccess_Protected, CV_MemberAccess_Public -} CV_MemberAccessEnum; +} +CV_MemberAccessEnum; typedef U16 CV_FieldAttribs; -enum{ +enum +{ // Access: 0,1 // MethodProp: [2:4] - CV_FieldAttrib_Pseudo = (1 << 5), - CV_FieldAttrib_NoInherit = (1 << 6), - CV_FieldAttrib_NoConstruct = (1 << 7), - CV_FieldAttrib_CompilerGenated = (1 << 8), - CV_FieldAttrib_Sealed = (1 << 9), + CV_FieldAttrib_Pseudo = (1<<5), + CV_FieldAttrib_NoInherit = (1<<6), + CV_FieldAttrib_NoConstruct = (1<<7), + CV_FieldAttrib_CompilerGenated = (1<<8), + CV_FieldAttrib_Sealed = (1<<9), }; #define CV_FieldAttribs_ExtractAccess(f) ((f)&0x3) #define CV_FieldAttribs_ExtractMethodProp(f) (((f)>>2)&0x7) typedef U16 CV_LabelKind; -typedef enum{ +typedef enum CV_LabelKindEnum +{ CV_LabelKind_Near = 0, CV_LabelKind_Far = 4, -} CV_LabelKindEnum; +} +CV_LabelKindEnum; typedef U8 CV_FunctionAttribs; -enum{ - CV_FunctionAttrib_CxxReturnUDT = (1 << 0), - CV_FunctionAttrib_Constructor = (1 << 1), - CV_FunctionAttrib_ConstructorVBase = (1 << 2), +enum +{ + CV_FunctionAttrib_CxxReturnUDT = (1<<0), + CV_FunctionAttrib_Constructor = (1<<1), + CV_FunctionAttrib_ConstructorVBase = (1<<2), }; typedef U8 CV_CallKind; -typedef enum{ +typedef enum CV_CallKindEnum +{ CV_CallKind_NearC, CV_CallKind_FarC, CV_CallKind_NearPascal, @@ -2442,62 +2157,87 @@ typedef enum{ CV_CallKind_Clr, CV_CallKind_Inline, CV_CallKind_NearVector, -} CV_CallKindEnum; +} +CV_CallKindEnum; -// (LeafKind: PRECOMP) -typedef struct CV_LeafPreComp{ +//- (LeafKind: PRECOMP) + +typedef struct CV_LeafPreComp CV_LeafPreComp; +struct CV_LeafPreComp +{ U32 start_index; U32 count; U32 signature; // U8[] name (null terminated) -} CV_LeafPreComp; +}; -// (LeafKind: TYPESERVER) -typedef struct CV_LeafTypeServer{ +//- (LeafKind: TYPESERVER) + +typedef struct CV_LeafTypeServer CV_LeafTypeServer; +struct CV_LeafTypeServer +{ U32 sig; U32 age; // U8[] name (null terminated) -} CV_LeafTypeServer; +}; -// (LeafKind: TYPESERVER2) -typedef struct CV_LeafTypeServer2{ +//- (LeafKind: TYPESERVER2) + +typedef struct CV_LeafTypeServer2 CV_LeafTypeServer2; +struct CV_LeafTypeServer2 +{ COFF_Guid sig70; U32 age; // U8[] name (null terminated) -} CV_LeafTypeServer2; +}; -// (LeafKind: SKIP) -typedef struct CV_LeafSkip{ +//- (LeafKind: SKIP) + +typedef struct CV_LeafSkip CV_LeafSkip; +struct CV_LeafSkip +{ CV_TypeId itype; -} CV_LeafSkip; +}; -// (LeafKind: VTSHAPE) -typedef struct CV_LeafVTShape{ +//- (LeafKind: VTSHAPE) + +typedef struct CV_LeafVTShape CV_LeafVTShape; +struct CV_LeafVTShape +{ U16 count; // U4[count] shapes (CV_VirtualTableShape) -} CV_LeafVTShape; +}; -// (LeafKind: LABEL) -typedef struct CV_LeafLabel{ +//- (LeafKind: LABEL) + +typedef struct CV_LeafLabel CV_LeafLabel; +struct CV_LeafLabel +{ CV_LabelKind kind; -} CV_LeafLabel; +}; + +//- (LeafKind: MODIFIER) -// (LeafKind: MODIFIER) typedef U16 CV_ModifierFlags; -enum{ +enum +{ CV_ModifierFlag_Const = (1 << 0), CV_ModifierFlag_Volatile = (1 << 1), CV_ModifierFlag_Unaligned = (1 << 2), }; -typedef struct CV_LeafModifier{ +typedef struct CV_LeafModifier CV_LeafModifier; +struct CV_LeafModifier +{ CV_TypeId itype; CV_ModifierFlags flags; -} CV_LeafModifier; +}; + +//- (LeafKind: POINTER) -// (LeafKind: POINTER) typedef U32 CV_PointerAttribs; -enum{ +enum +{ // Kind: [0:4] // Mode: [5:7] CV_PointerAttrib_IsFlat = (1 << 8), @@ -2515,22 +2255,30 @@ enum{ #define CV_PointerAttribs_ExtractMode(a) (((a)>>5)&0x7) #define CV_PointerAttribs_ExtractSize(a) (((a)>>13)&0x3F) -typedef struct CV_LeafPointer{ +typedef struct CV_LeafPointer CV_LeafPointer; +struct CV_LeafPointer +{ CV_TypeId itype; CV_PointerAttribs attribs; -} CV_LeafPointer; +}; -// (LeafKind: PROCEDURE) -typedef struct CV_LeafProcedure{ +//- (LeafKind: PROCEDURE) + +typedef struct CV_LeafProcedure CV_LeafProcedure; +struct CV_LeafProcedure +{ CV_TypeId ret_itype; CV_CallKind call_kind; CV_FunctionAttribs attribs; U16 arg_count; CV_TypeId arg_itype; -} CV_LeafProcedure; +}; -// (LeafKind: MFUNCTION) -typedef struct CV_LeafMFunction{ +//- (LeafKind: MFUNCTION) + +typedef struct CV_LeafMFunction CV_LeafMFunction; +struct CV_LeafMFunction +{ CV_TypeId ret_itype; CV_TypeId class_itype; CV_TypeId this_itype; @@ -2539,45 +2287,63 @@ typedef struct CV_LeafMFunction{ U16 arg_count; CV_TypeId arg_itype; S32 this_adjust; -} CV_LeafMFunction; +}; -// (LeafKind: ARGLIST) -typedef struct CV_LeafArgList{ +//- (LeafKind: ARGLIST) + +typedef struct CV_LeafArgList CV_LeafArgList; +struct CV_LeafArgList +{ U32 count; // CV_TypeId[count] itypes; -} CV_LeafArgList; +}; -// (LeafKind: BITFIELD) -typedef struct CV_LeafBitField{ +//- (LeafKind: BITFIELD) + +typedef struct CV_LeafBitField CV_LeafBitField; +struct CV_LeafBitField +{ CV_TypeId itype; U8 len; U8 pos; -} CV_LeafBitField; +}; + +//- (LeafKind: METHODLIST) -// (LeafKind: METHODLIST) // ("jagged" array of these vvvvvvvv) -typedef struct CV_LeafMethodListMember{ +typedef struct CV_LeafMethodListMember CV_LeafMethodListMember; +struct CV_LeafMethodListMember +{ CV_FieldAttribs attribs; U16 pad; CV_TypeId itype; // U32 vbaseoff (when Intro or PureIntro) -} CV_LeafMethodListMember; +}; -// (LeafKind: INDEX) -typedef struct CV_LeafIndex{ +//- (LeafKind: INDEX) + +typedef struct CV_LeafIndex CV_LeafIndex; +struct CV_LeafIndex +{ U16 pad; CV_TypeId itype; -} CV_LeafIndex; +}; -// (LeafKind: ARRAY) -typedef struct CV_LeafArray{ +//- (LeafKind: ARRAY) + +typedef struct CV_LeafArray CV_LeafArray; +struct CV_LeafArray +{ CV_TypeId entry_itype; CV_TypeId index_itype; // CV_Numeric count -} CV_LeafArray; +}; -// (LeafKind: CLASS, STRUCTURE, INTERFACE) -typedef struct CV_LeafStruct{ +//- (LeafKind: CLASS, STRUCTURE, INTERFACE) + +typedef struct CV_LeafStruct CV_LeafStruct; +struct CV_LeafStruct +{ U16 count; CV_TypeProps props; CV_TypeId field_itype; @@ -2586,131 +2352,182 @@ typedef struct CV_LeafStruct{ // CV_Numeric size // U8[] name (null terminated) // U8[] unique_name (null terminated) -} CV_LeafStruct; +}; -// (LeafKind: UNION) -typedef struct CV_LeafUnion{ +//- (LeafKind: UNION) + +typedef struct CV_LeafUnion CV_LeafUnion; +struct CV_LeafUnion +{ U16 count; CV_TypeProps props; CV_TypeId field_itype; // CV_Numeric size // U8[] name (null terminated) // U8[] unique_name (null terminated) -} CV_LeafUnion; +}; -// (LeafKind: ENUM) -typedef struct CV_LeafEnum{ +//- (LeafKind: ENUM) + +typedef struct CV_LeafEnum CV_LeafEnum; +struct CV_LeafEnum +{ U16 count; CV_TypeProps props; CV_TypeId base_itype; CV_TypeId field_itype; // U8[] name (null terminated) // U8[] unique_name (null terminated) -} CV_LeafEnum; +}; -// (LeafKind: ALIAS) -typedef struct CV_LeafAlias{ +//- (LeafKind: ALIAS) + +typedef struct CV_LeafAlias CV_LeafAlias; +struct CV_LeafAlias +{ CV_TypeId itype; // U8[] name (null terminated) -} CV_LeafAlias; +}; -// (LeafKind: MEMBER) -typedef struct CV_LeafMember{ +//- (LeafKind: MEMBER) + +typedef struct CV_LeafMember CV_LeafMember; +struct CV_LeafMember +{ CV_FieldAttribs attribs; CV_TypeId itype; // CV_Numeric offset // U8[] name (null terminated) -} CV_LeafMember; +}; -// (LeafKind: STMEMBER) -typedef struct CV_LeafStMember{ +//- (LeafKind: STMEMBER) + +typedef struct CV_LeafStMember CV_LeafStMember; +struct CV_LeafStMember +{ CV_FieldAttribs attribs; CV_TypeId itype; // U8[] name (null terminated) -} CV_LeafStMember; +}; -// (LeafKind: METHOD) -typedef struct CV_LeafMethod{ +//- (LeafKind: METHOD) + +typedef struct CV_LeafMethod CV_LeafMethod; +struct CV_LeafMethod +{ U16 count; CV_TypeId list_itype; // U8[] name (null terminated) -} CV_LeafMethod; +}; -// (LeafKind: ONEMETHOD) -typedef struct CV_LeafOneMethod{ +//- (LeafKind: ONEMETHOD) + +typedef struct CV_LeafOneMethod CV_LeafOneMethod; +struct CV_LeafOneMethod +{ CV_FieldAttribs attribs; CV_TypeId itype; // U32 vbaseoff (when Intro or PureIntro) // U8[] name (null terminated) -} CV_LeafOneMethod; +}; -// (LeafKind: ENUMERATE) -typedef struct CV_LeafEnumerate{ +//- (LeafKind: ENUMERATE) + +typedef struct CV_LeafEnumerate CV_LeafEnumerate; +struct CV_LeafEnumerate +{ CV_FieldAttribs attribs; // CV_Numeric val // U8[] name (null terminated) -} CV_LeafEnumerate; +}; -// (LeafKind: NESTTYPE) -typedef struct CV_LeafNestType{ +//- (LeafKind: NESTTYPE) + +typedef struct CV_LeafNestType CV_LeafNestType; +struct CV_LeafNestType +{ U16 pad; CV_TypeId itype; // U8[] name (null terminated) -} CV_LeafNestType; +}; -// (LeafKind: NESTTYPEEX) -typedef struct CV_LeafNestTypeEx{ +//- (LeafKind: NESTTYPEEX) + +typedef struct CV_LeafNestTypeEx CV_LeafNestTypeEx; +struct CV_LeafNestTypeEx +{ CV_FieldAttribs attribs; CV_TypeId itype; // U8[] name (null terminated) -} CV_LeafNestTypeEx; +}; -// (LeafKind: BCLASS) -typedef struct CV_LeafBClass{ +//- (LeafKind: BCLASS) + +typedef struct CV_LeafBClass CV_LeafBClass; +struct CV_LeafBClass +{ CV_FieldAttribs attribs; CV_TypeId itype; // CV_Numeric offset -} CV_LeafBClass; +}; -// (LeafKind: VBCLASS, IVBCLASS) -typedef struct CV_LeafVBClass{ +//- (LeafKind: VBCLASS, IVBCLASS) + +typedef struct CV_LeafVBClass CV_LeafVBClass; +struct CV_LeafVBClass +{ CV_FieldAttribs attribs; CV_TypeId itype; CV_TypeId vbptr_itype; // CV_Numeric vbptr_off // CV_Numeric vtable_off -} CV_LeafVBClass; +}; -// (LeafKind: VFUNCTAB) -typedef struct CV_LeafVFuncTab{ +//- (LeafKind: VFUNCTAB) + +typedef struct CV_LeafVFuncTab CV_LeafVFuncTab; +struct CV_LeafVFuncTab +{ U16 pad; CV_TypeId itype; -} CV_LeafVFuncTab; +}; -// (LeafKind: VFUNCOFF) -typedef struct CV_LeafVFuncOff{ +//- (LeafKind: VFUNCOFF) + +typedef struct CV_LeafVFuncOff CV_LeafVFuncOff; +struct CV_LeafVFuncOff +{ U16 pad; CV_TypeId itype; U32 off; -} CV_LeafVFuncOff; +}; -// (LeafKind: VFTABLE) -typedef struct CV_LeafVFTable{ +//- (LeafKind: VFTABLE) + +typedef struct CV_LeafVFTable CV_LeafVFTable; +struct CV_LeafVFTable +{ CV_TypeId owner_itype; CV_TypeId base_table_itype; U32 offset_in_object_layout; U32 names_len; // U8[] names (multiple null terminated strings) -} CV_LeafVFTable; +}; -// (LeafKind: VFTPATH) -typedef struct CV_LeafVFPath{ +//- (LeafKind: VFTPATH) + +typedef struct CV_LeafVFPath CV_LeafVFPath; +struct CV_LeafVFPath +{ U32 count; // CV_TypeId[count] base; -} CV_LeafVFPath; +}; -// (LeafKind: CLASS2, STRUCT2) -typedef struct CV_LeafStruct2{ +//- (LeafKind: CLASS2, STRUCT2) + +typedef struct CV_LeafStruct2 CV_LeafStruct2; +struct CV_LeafStruct2 +{ // NOTE: still reverse engineering this - if you find docs please help! CV_TypeProps props; U16 unknown1; @@ -2721,63 +2538,85 @@ typedef struct CV_LeafStruct2{ // CV_Numeric size // U8[] name (null terminated) // U8[] unique_name (null terminated) -} CV_LeafStruct2; +}; -// (LeafIDKind: FUNC_ID) -typedef struct CV_LeafFuncId{ +//- (LeafIDKind: FUNC_ID) + +typedef struct CV_LeafFuncId CV_LeafFuncId; +struct CV_LeafFuncId +{ CV_ItemId scope_string_id; CV_TypeId itype; // U8[] name (null terminated) -} CV_LeafFuncId; +}; -// (LeafIDKind: MFUNC_ID) -typedef struct CV_LeafMFuncId{ +//- (LeafIDKind: MFUNC_ID) + +typedef struct CV_LeafMFuncId CV_LeafMFuncId; +struct CV_LeafMFuncId +{ CV_TypeId owner_itype; CV_TypeId itype; // U8[] name (null terminated) -} CV_LeafMFuncId; +}; -// (LeafIDKind: STRING_ID) -typedef struct CV_LeafStringId{ +//- (LeafIDKind: STRING_ID) + +typedef struct CV_LeafStringId CV_LeafStringId; +struct CV_LeafStringId +{ CV_ItemId substr_list_id; // U8[] string (null terminated) -} CV_LeafStringId; +}; -// (LeafIDKind: BUILDINFO) -typedef enum{ +//- (LeafIDKind: BUILDINFO) + +typedef enum CV_BuildInfoIndexEnum +{ CV_BuildInfoIndex_BuildDirectory = 0, CV_BuildInfoIndex_CompilerExecutable = 1, CV_BuildInfoIndex_TargetSourceFile = 2, CV_BuildInfoIndex_CombinedPdb = 3, CV_BuildInfoIndex_CompileArguments = 4, -} CV_BuildInfoIndexEnum; +} +CV_BuildInfoIndexEnum; -typedef struct CV_LeafBuildInfo{ +typedef struct CV_LeafBuildInfo CV_LeafBuildInfo; +struct CV_LeafBuildInfo +{ U16 count; // CV_ItemId[count] items -} CV_LeafBuildInfo; +}; -// (LeafIDKind: SUBSTR_LIST) -typedef struct CV_LeafSubstrList{ +//- (LeafIDKind: SUBSTR_LIST) + +typedef struct CV_LeafSubstrList CV_LeafSubstrList; +struct CV_LeafSubstrList +{ U32 count; // CV_ItemId[count] items -} CV_LeafSubstrList; +}; -// (LeafIDKind: UDT_SRC_LINE) -typedef struct CV_LeafUDTSrcLine{ +//- (LeafIDKind: UDT_SRC_LINE) + +typedef struct CV_LeafUDTSrcLine CV_LeafUDTSrcLine; +struct CV_LeafUDTSrcLine +{ CV_TypeId udt_itype; CV_ItemId src_string_id; U32 line; -} CV_LeafUDTSrcLine; +}; -// (LeafIDKind: UDT_MOD_SRC_LINE) -typedef struct CV_LeafUDTModSrcLine{ +//- (LeafIDKind: UDT_MOD_SRC_LINE) + +typedef struct CV_LeafUDTModSrcLine CV_LeafUDTModSrcLine; +struct CV_LeafUDTModSrcLine +{ CV_TypeId udt_itype; CV_ItemId src_string_id; U32 line; CV_ModIndex imod; -} CV_LeafUDTModSrcLine; - +}; //////////////////////////////// //~ CodeView Format C13 Line Info Types @@ -2800,80 +2639,98 @@ X(MergedAssemblyInput, 0xFC)\ X(CoffSymbolRVA, 0xFD) typedef U32 CV_C13_SubSectionKind; -typedef enum{ +typedef enum +{ #define X(N,c) CV_C13_SubSectionKind_##N = c, CV_C13_SubSectionKindXList(X) #undef X } CV_C13_SubSectionKindEnum; -typedef struct CV_C13_SubSectionHeader{ +typedef struct CV_C13_SubSectionHeader CV_C13_SubSectionHeader; +struct CV_C13_SubSectionHeader +{ CV_C13_SubSectionKind kind; U32 size; -} CV_C13_SubSectionHeader; +}; //- FileChksms sub-section typedef U8 CV_C13_ChecksumKind; -typedef enum{ +typedef enum +{ CV_C13_ChecksumKind_Null, CV_C13_ChecksumKind_MD5, CV_C13_ChecksumKind_SHA1, CV_C13_ChecksumKind_SHA256, } CV_C13_ChecksumKindEnum; -typedef struct CV_C13_Checksum{ +typedef struct CV_C13_Checksum CV_C13_Checksum; +struct CV_C13_Checksum +{ U32 name_off; U8 len; CV_C13_ChecksumKind kind; -} CV_C13_Checksum; +}; //- Lines sub-section typedef U16 CV_C13_SubSecLinesFlags; -enum{ +enum +{ CV_C13_SubSecLinesFlag_HasColumns = (1 << 0) }; -typedef struct CV_C13_SubSecLinesHeader{ +typedef struct CV_C13_SubSecLinesHeader CV_C13_SubSecLinesHeader; +struct CV_C13_SubSecLinesHeader +{ U32 sec_off; CV_SectionIndex sec; CV_C13_SubSecLinesFlags flags; U32 len; -} CV_C13_SubSecLinesHeader; +}; -typedef struct CV_C13_File{ +typedef struct CV_C13_File CV_C13_File; +struct CV_C13_File +{ U32 file_off; U32 num_lines; U32 block_size; // CV_C13_Line[num_lines] lines; // CV_C13_Column[num_lines] columns; (if HasColumns) -} CV_C13_File; +}; typedef U32 CV_C13_LineFlags; #define CV_C13_LineFlags_ExtractLineNumber(f) ((f)&0xFFFFFF) #define CV_C13_LineFlags_ExtractDeltaToEnd(f) (((f)>>24)&0x7F) #define CV_C13_LineFlags_ExtractStatement(f) (((f)>>31)&0x1) -typedef struct CV_C13_Line{ +typedef struct CV_C13_Line CV_C13_Line; +struct CV_C13_Line +{ U32 off; CV_C13_LineFlags flags; -} CV_C13_Line; +}; -typedef struct CV_C13_Column{ +typedef struct CV_C13_Column CV_C13_Column; +struct CV_C13_Column +{ U16 start; U16 end; -} CV_C13_Column; +}; //- FrameData sub-section typedef U32 CV_C13_FrameDataFlags; -enum{ +enum +{ CV_C13_FrameDataFlag_HasStructuredExceptionHandling = (1 << 0), CV_C13_FrameDataFlag_HasExceptionHandling = (1 << 1), CV_C13_FrameDataFlag_HasIsFuncStart = (1 << 2), }; -typedef struct CV_C13_FrameData{ +typedef struct CV_C13_FrameData CV_C13_FrameData; +struct CV_C13_FrameData +{ U32 start_voff; U32 code_size; U32 local_size; @@ -2883,7 +2740,7 @@ typedef struct CV_C13_FrameData{ U16 prolog_size; U16 saved_reg_size; CV_C13_FrameDataFlags flags; -} CV_C13_FrameData; +}; #pragma pack(pop) @@ -2896,45 +2753,59 @@ typedef struct CV_C13_FrameData{ // case (x < 0x8000): kind=U16 val=x // case (x >= 0x8000): kind=x val=buf -typedef struct CV_NumericParsed{ +typedef struct CV_NumericParsed CV_NumericParsed; +struct CV_NumericParsed +{ CV_NumericKind kind; U8 *val; U64 encoded_size; -} CV_NumericParsed; +}; -typedef struct CV_RecRange{ +typedef struct CV_RecRange CV_RecRange; +struct CV_RecRange +{ U32 off; CV_RecHeader hdr; -} CV_RecRange; +}; #define CV_REC_RANGE_CHUNK_SIZE 511 -typedef struct CV_RecRangeChunk{ +typedef struct CV_RecRangeChunk CV_RecRangeChunk; +struct CV_RecRangeChunk +{ struct CV_RecRangeChunk *next; CV_RecRange ranges[CV_REC_RANGE_CHUNK_SIZE]; -} CV_RecRangeChunk; +}; -typedef struct CV_RecRangeStream{ +typedef struct CV_RecRangeStream CV_RecRangeStream; +struct CV_RecRangeStream +{ CV_RecRangeChunk *first_chunk; CV_RecRangeChunk *last_chunk; U64 total_count; -} CV_RecRangeStream; +}; -typedef struct CV_RecRangeArray{ +typedef struct CV_RecRangeArray CV_RecRangeArray; +struct CV_RecRangeArray +{ CV_RecRange *ranges; U64 count; -} CV_RecRangeArray; +}; //////////////////////////////// //~ CodeView Sym Parser Types -typedef struct CV_SymTopLevelInfo{ +typedef struct CV_SymTopLevelInfo CV_SymTopLevelInfo; +struct CV_SymTopLevelInfo +{ CV_Arch arch; CV_Language language; String8 compiler_name; -} CV_SymTopLevelInfo; +}; -typedef struct CV_SymParsed{ +typedef struct CV_SymParsed CV_SymParsed; +struct CV_SymParsed +{ // source information String8 data; U64 sym_align; @@ -2944,13 +2815,15 @@ typedef struct CV_SymParsed{ // top-level info derived from the syms CV_SymTopLevelInfo info; -} CV_SymParsed; +}; //////////////////////////////// //~ CodeView Leaf Parser Types -typedef struct CV_LeafParsed{ +typedef struct CV_LeafParsed CV_LeafParsed; +struct CV_LeafParsed +{ // source information String8 data; CV_TypeId itype_first; @@ -2958,12 +2831,14 @@ typedef struct CV_LeafParsed{ // leaf index derived from source CV_RecRangeArray leaf_ranges; -} CV_LeafParsed; +}; //////////////////////////////// //~ CodeView C13 Info Parser Types -typedef struct CV_C13LinesParsed{ +typedef struct CV_C13LinesParsed CV_C13LinesParsed; +struct CV_C13LinesParsed +{ // raw info U32 sec_idx; U32 file_off; @@ -2975,80 +2850,89 @@ typedef struct CV_C13LinesParsed{ U32 *line_nums; // [line_count] U16 *col_nums; // [2*line_count] U32 line_count; -} CV_C13LinesParsed; +}; -typedef struct CV_C13SubSectionNode{ +typedef struct CV_C13LinesParsedNode CV_C13LinesParsedNode; +struct CV_C13LinesParsedNode +{ + CV_C13LinesParsedNode *next; + CV_C13LinesParsed v; +}; + +typedef struct CV_C13SubSectionNode CV_C13SubSectionNode; +struct CV_C13SubSectionNode +{ struct CV_C13SubSectionNode *next; CV_C13_SubSectionKind kind; U32 off; U32 size; - union{ - CV_C13LinesParsed *lines; - }; -} CV_C13SubSectionNode; + CV_C13LinesParsedNode *lines_first; + CV_C13LinesParsedNode *lines_last; +}; -typedef struct CV_C13Parsed{ +typedef struct CV_C13Parsed CV_C13Parsed; +struct CV_C13Parsed +{ CV_C13SubSectionNode *first_sub_section; CV_C13SubSectionNode *last_sub_section; U64 sub_section_count; // accelerator CV_C13SubSectionNode *file_chksms_sub_section; -} CV_C13Parsed; - +}; //////////////////////////////// //~ CodeView Compound Types -typedef struct CV_TypeIdArray{ +typedef struct CV_TypeIdArray CV_TypeIdArray; +struct CV_TypeIdArray +{ CV_TypeId *itypes; U64 count; -} CV_TypeIdArray; +}; //////////////////////////////// //~ CodeView Common Functions -static CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl); +internal CV_NumericParsed cv_numeric_from_data_range(U8 *first, U8 *opl); -static B32 cv_numeric_fits_in_u64(CV_NumericParsed *num); -static B32 cv_numeric_fits_in_s64(CV_NumericParsed *num); -static B32 cv_numeric_fits_in_f64(CV_NumericParsed *num); +internal B32 cv_numeric_fits_in_u64(CV_NumericParsed *num); +internal B32 cv_numeric_fits_in_s64(CV_NumericParsed *num); +internal B32 cv_numeric_fits_in_f64(CV_NumericParsed *num); -static U64 cv_u64_from_numeric(CV_NumericParsed *num); -static S64 cv_s64_from_numeric(CV_NumericParsed *num); -static F64 cv_f64_from_numeric(CV_NumericParsed *num); +internal U64 cv_u64_from_numeric(CV_NumericParsed *num); +internal S64 cv_s64_from_numeric(CV_NumericParsed *num); +internal F64 cv_f64_from_numeric(CV_NumericParsed *num); //////////////////////////////// //~ CodeView Sym/Leaf Parser Functions //- the first pass parser -static CV_RecRangeStream* cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align); +internal CV_RecRangeStream* cv_rec_range_stream_from_data(Arena *arena, String8 data, U64 align); //- sym -static CV_SymParsed* cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align); +internal CV_SymParsed* cv_sym_from_data(Arena *arena, String8 sym_data, U64 sym_align); -static void cv_sym_top_level_info_from_syms(Arena *arena, String8 sym_data, - CV_RecRangeArray *ranges, - CV_SymTopLevelInfo *info_out); +internal void cv_sym_top_level_info_from_syms(Arena *arena, String8 sym_data, + CV_RecRangeArray *ranges, + CV_SymTopLevelInfo *info_out); //- leaf -static CV_LeafParsed* cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first); +internal CV_LeafParsed* cv_leaf_from_data(Arena *arena, String8 leaf_data, CV_TypeId first); //- range streams -static CV_RecRangeChunk* cv_rec_range_stream_push_chunk(Arena *arena, - CV_RecRangeStream *stream); +internal CV_RecRangeChunk* cv_rec_range_stream_push_chunk(Arena *arena, + CV_RecRangeStream *stream); // TODO(allen): check why this isn't a pointer return - // leave a note if there's a good reason, otherwise switch to pointer return -static CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, - CV_RecRangeStream *stream); +internal CV_RecRangeArray cv_rec_range_array_from_stream(Arena *arena, CV_RecRangeStream *stream); //////////////////////////////// //~ CodeView C13 Parser Functions typedef struct PDB_Strtbl PDB_Strtbl; typedef struct PDB_CoffSectionArray PDB_CoffSectionArray; -static CV_C13Parsed* cv_c13_from_data(Arena *arena, String8 c13_data, - struct PDB_Strtbl *strtbl, struct PDB_CoffSectionArray *sections); +internal CV_C13Parsed* cv_c13_from_data(Arena *arena, String8 c13_data, struct PDB_Strtbl *strtbl, struct PDB_CoffSectionArray *sections); -#endif //RADDBG_CODEVIEW_H +#endif // CODEVIEW_H diff --git a/src/codeview/codeview.mdesk b/src/codeview/codeview.mdesk new file mode 100644 index 00000000..e004557c --- /dev/null +++ b/src/codeview/codeview.mdesk @@ -0,0 +1,622 @@ +//////////////////////////////// +//~ rjf: CV Numerics + +@table(name val) +CV_NumericKindTable: +{ + {CHAR 0x8000} + {SHORT 0x8001} + {USHORT 0x8002} + {LONG 0x8003} + {ULONG 0x8004} + {FLOAT32 0x8005} + {FLOAT64 0x8006} + {FLOAT80 0x8007} + {FLOAT128 0x8008} + {QUADWORD 0x8009} + {UQUADWORD 0x800a} + {FLOAT48 0x800b} + {COMPLEX32 0x800c} + {COMPLEX64 0x800d} + {COMPLEX80 0x800e} + {COMPLEX128 0x800f} + {VARSTRING 0x8010} + {OCTWORD 0x8017} + {UOCTWORD 0x8018} + {DECIMAL 0x8019} + {DATE 0x801a} + {UTF8STRING 0x801b} + {FLOAT16 0x801c} +} + +@enum(U16) CV_NumericKind: +{ + @expand(CV_NumericKindTable a) `$(a.name) = $(a.val)` +} + +@enum2string_switch(CV_NumericKind) +cv_string_from_numeric_kind: +{ + @expand(CV_NumericKindTable a) `case CV_NumericKind_$(a.name):{result = str8_lit("$(a.name)");}break`; +} + +//////////////////////////////// +//~ rjf: CV Architectures + +@table(name val) +CV_ArchTable: +{ + {8080 0x00} + {8086 0x01} + {80286 0x02} + {80386 0x03} + {80486 0x04} + {PENTIUM 0x05} + {PENTIUMII 0x06} + {PENTIUMIII 0x07} + {MIPS 0x10} + {MIPS16 0x11} + {MIPS32 0x12} + {MIPS64 0x13} + {MIPSI 0x14} + {MIPSII 0x15} + {MIPSIII 0x16} + {MIPSIV 0x17} + {MIPSV 0x18} + {M68000 0x20} + {M68010 0x21} + {M68020 0x22} + {M68030 0x23} + {M68040 0x24} + {ALPHA 0x30} + {ALPHA_21164 0x31} + {ALPHA_21164A 0x32} + {ALPHA_21264 0x33} + {ALPHA_21364 0x34} + {PPC601 0x40} + {PPC603 0x41} + {PPC604 0x42} + {PPC620 0x43} + {PPCFP 0x44} + {PPCBE 0x45} + {SH3 0x50} + {SH3E 0x51} + {SH3DSP 0x52} + {SH4 0x53} + {SHMEDIA 0x54} + {ARM3 0x60} + {ARM4 0x61} + {ARM4T 0x62} + {ARM5 0x63} + {ARM5T 0x64} + {ARM6 0x65} + {ARM_XMAC 0x66} + {ARM_WMMX 0x67} + {ARM7 0x68} + {OMNI 0x70} + {IA64_1 0x80} + {IA64_2 0x81} + {CEE 0x90} + {AM33 0xA0} + {M32R 0xB0} + {TRICORE 0xC0} + {X64 0xD0} + {EBC 0xE0} + {THUMB 0xF0} + {ARMNT 0xF4} + {ARM64 0xF6} + {D3D11_SHADER 0x100} +} + +@enum(U16) CV_Arch: +{ + @expand(CV_ArchTable a) `$(a.name) = $(a.val)`, + `IA64 = CV_Arch_IA64_1`, + `PENTIUMPRO = CV_Arch_PENTIUMII`, + `MIPSR4000 = CV_Arch_MIPS`, + `ALPHA_21064 = CV_Arch_ALPHA`, + `AMD64 = CV_Arch_X64`, +} + +@enum2string_switch(CV_Arch) +cv_string_from_arch: +{ + @expand(CV_ArchTable a) `case CV_Arch_$(a.name):{result = str8_lit("$(a.name)");}break`; +} + +//////////////////////////////// +//~ rjf: CV Registers + +@table(name val) CV_AllRegTable: +{ + {ERR 30000} + {TEB 30001} + {TIMER 30002} + {EFAD1 30003} + {EFAD2 30004} + {EFAD3 30005} + {VFRAME 30006} + {HANDLE 30007} + {PARAMS 30008} + {LOCALS 30009} + {TID 30010} + {ENV 30011} + {CMDLN 30012} +} + +@enum(U16) CV_AllReg: +{ + @expand(CV_AllRegTable a) `$(a.name) = $(a.val)` +} + +//////////////////////////////// +//~ rjf: CV Sym Kinds + +@table(name header_type_name val) CV_SymKindTable: +{ + {COMPILE Compile 0x0001} + {REGISTER_16t - 0x0002} + {CONSTANT_16t - 0x0003} + {UDT_16t - 0x0004} + {SSEARCH StartSearch 0x0005} + {END - 0x0006} + {SKIP - 0x0007} + {CVRESERVE - 0x0008} + {OBJNAME_ST - 0x0009} + {ENDARG - 0x000a} + {COBOLUDT_16t - 0x000b} + {MANYREG_16t - 0x000c} + {RETURN Return 0x000d} + {ENTRYTHIS - 0x000e} + {BPREL16 - 0x0100} + {LDATA16 - 0x0101} + {GDATA16 - 0x0102} + {PUB16 - 0x0103} + {LPROC16 - 0x0104} + {GPROC16 - 0x0105} + {THUNK16 - 0x0106} + {BLOCK16 - 0x0107} + {WITH16 - 0x0108} + {LABEL16 - 0x0109} + {CEXMODEL16 - 0x010a} + {VFTABLE16 - 0x010b} + {REGREL16 - 0x010c} + {BPREL32_16t - 0x0200} + {LDATA32_16t - 0x0201} + {GDATA32_16t - 0x0202} + {PUB32_16t - 0x0203} + {LPROC32_16t - 0x0204} + {GPROC32_16t - 0x0205} + {THUNK32_ST - 0x0206} + {BLOCK32_ST - 0x0207} + {WITH32_ST - 0x0208} + {LABEL32_ST - 0x0209} + {CEXMODEL32 - 0x020a} + {VFTABLE32_16t - 0x020b} + {REGREL32_16t - 0x020c} + {LTHREAD32_16t - 0x020d} + {GTHREAD32_16t - 0x020e} + {SLINK32 SLink32 0x020f} + {LPROCMIPS_16t - 0x0300} + {GPROCMIPS_16t - 0x0301} + {PROCREF_ST - 0x0400} + {DATAREF_ST - 0x0401} + {ALIGN - 0x0402} + {LPROCREF_ST - 0x0403} + {OEM OEM 0x0404} + {TI16_MAX - 0x1000} + {CONSTANT_ST - 0x1002} + {UDT_ST - 0x1003} + {COBOLUDT_ST - 0x1004} + {MANYREG_ST - 0x1005} + {BPREL32_ST - 0x1006} + {LDATA32_ST - 0x1007} + {GDATA32_ST - 0x1008} + {PUB32_ST - 0x1009} + {LPROC32_ST - 0x100a} + {GPROC32_ST - 0x100b} + {VFTABLE32 VPath32 0x100c} + {REGREL32_ST - 0x100d} + {LTHREAD32_ST - 0x100e} + {GTHREAD32_ST - 0x100f} + {LPROCMIPS_ST - 0x1010} + {GPROCMIPS_ST - 0x1011} + {FRAMEPROC Frameproc 0x1012} + {COMPILE2_ST - 0x1013} + {MANYREG2_ST - 0x1014} + {LPROCIA64_ST - 0x1015} + {GPROCIA64_ST - 0x1016} + {LOCALSLOT_ST - 0x1017} + {PARAMSLOT_ST - 0x1018} + {ANNOTATION Annotation 0x1019} + {GMANPROC_ST - 0x101a} + {LMANPROC_ST - 0x101b} + {RESERVED1 - 0x101c} + {RESERVED2 - 0x101d} + {RESERVED3 - 0x101e} + {RESERVED4 - 0x101f} + {LMANDATA_ST - 0x1020} + {GMANDATA_ST - 0x1021} + {MANFRAMEREL_ST - 0x1022} + {MANREGISTER_ST - 0x1023} + {MANSLOT_ST - 0x1024} + {MANMANYREG_ST - 0x1025} + {MANREGREL_ST - 0x1026} + {MANMANYREG2_ST - 0x1027} + {MANTYPREF - 0x1028} + {UNAMESPACE_ST - 0x1029} + {ST_MAX - 0x1100} + {OBJNAME Objname 0x1101} + {THUNK32 Thunk32 0x1102} + {BLOCK32 Block32 0x1103} + {WITH32 - 0x1104} + {LABEL32 Label32 0x1105} + {REGISTER Register 0x1106} + {CONSTANT Constant 0x1107} + {UDT UDT 0x1108} + {COBOLUDT - 0x1109} + {MANYREG Manyreg 0x110a} + {BPREL32 BPRel32 0x110b} + {LDATA32 Data32 0x110c} + {GDATA32 Data32 0x110d} + {PUB32 Pub32 0x110e} + {LPROC32 Proc32 0x110f} + {GPROC32 Proc32 0x1110} + {REGREL32 Regrel32 0x1111} + {LTHREAD32 Thread32 0x1112} + {GTHREAD32 Thread32 0x1113} + {LPROCMIPS - 0x1114} + {GPROCMIPS - 0x1115} + {COMPILE2 Compile2 0x1116} + {MANYREG2 Manyreg2 0x1117} + {LPROCIA64 - 0x1118} + {GPROCIA64 - 0x1119} + {LOCALSLOT Slot 0x111a} + {PARAMSLOT - 0x111b} + {LMANDATA - 0x111c} + {GMANDATA - 0x111d} + {MANFRAMEREL AttrFrameRel 0x111e} + {MANREGISTER AttrReg 0x111f} + {MANSLOT - 0x1120} + {MANMANYREG AttrManyReg 0x1121} + {MANREGREL AttrRegRel 0x1122} + {MANMANYREG2 - 0x1123} + {UNAMESPACE UNamespace 0x1124} + {PROCREF Ref2 0x1125} + {DATAREF Ref2 0x1126} + {LPROCREF Ref2 0x1127} + {ANNOTATIONREF - 0x1128} + {TOKENREF - 0x1129} + {GMANPROC - 0x112a} + {LMANPROC - 0x112b} + {TRAMPOLINE Trampoline 0x112c} + {MANCONSTANT - 0x112d} + {ATTR_FRAMEREL AttrFrameRel 0x112e} + {ATTR_REGISTER AttrReg 0x112f} + {ATTR_REGREL AttrRegRel 0x1130} + {ATTR_MANYREG AttrManyReg 0x1131} + {SEPCODE Sepcode 0x1132} + {DEFRANGE_2005 - 0x1134} + {DEFRANGE2_2005 - 0x1135} + {SECTION Section 0x1136} + {COFFGROUP CoffGroup 0x1137} + {EXPORT Export 0x1138} + {CALLSITEINFO CallSiteInfo 0x1139} + {FRAMECOOKIE FrameCookie 0x113a} + {DISCARDED Discarded 0x113b} + {COMPILE3 Compile3 0x113c} + {ENVBLOCK EnvBlock 0x113d} + {LOCAL Local 0x113e} + {DEFRANGE - 0x113f} + {DEFRANGE_SUBFIELD DefrangeSubfield 0x1140} + {DEFRANGE_REGISTER DefrangeRegister 0x1141} + {DEFRANGE_FRAMEPOINTER_REL DefrangeFramepointerRel 0x1142} + {DEFRANGE_SUBFIELD_REGISTER DefrangeSubfieldRegister 0x1143} + {DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE DefrangeFramepointerRelFullScope 0x1144} + {DEFRANGE_REGISTER_REL DefrangeRegisterRel 0x1145} + {LPROC32_ID - 0x1146} + {GPROC32_ID - 0x1147} + {LPROCMIPS_ID - 0x1148} + {GPROCMIPS_ID - 0x1149} + {LPROCIA64_ID - 0x114a} + {GPROCIA64_ID - 0x114b} + {BUILDINFO BuildInfo 0x114c} + {INLINESITE InlineSite 0x114d} + {INLINESITE_END - 0x114e} + {PROC_ID_END - 0x114f} + {DEFRANGE_HLSL - 0x1150} + {GDATA_HLSL - 0x1151} + {LDATA_HLSL - 0x1152} + {FILESTATIC FileStatic 0x1153} + {LPROC32_DPC - 0x1155} + {LPROC32_DPC_ID - 0x1156} + {DEFRANGE_DPC_PTR_TAG - 0x1157} + {DPC_SYM_TAG_MAP - 0x1158} + {ARMSWITCHTABLE - 0x1159} + {CALLEES FunctionList 0x115a} + {CALLERS FunctionList 0x115b} + {POGODATA PogoInfo 0x115c} + {INLINESITE2 InlineSite2 0x115d} + {HEAPALLOCSITE HeapAllocSite 0x115e} + {MOD_TYPEREF ModTypeRef 0x115f} + {REF_MINIPDB RefMiniPdb 0x1160} + {PDBMAP - 0x1161} + {GDATA_HLSL32 - 0x1162} + {LDATA_HLSL32 - 0x1163} + {GDATA_HLSL32_EX - 0x1164} + {LDATA_HLSL32_EX - 0x1165} + {FASTLINK FastLink 0x1167} + {INLINEES Inlinees 0x1168} +} + +@enum(U16) CV_SymKind: +{ + @expand(CV_SymKindTable a) `$(a.name) = $(a.val)` +} + +@enum2string_switch(CV_SymKind) +cv_string_from_sym_kind: +{ + @expand(CV_SymKindTable a) `case CV_SymKind_$(a.name):{result = str8_lit("$(a.name)");}break`; +} + +@gen(functions) +{ + `internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v);`; +} + +@gen(functions) @c_file +{ + `internal U64`; + `cv_header_struct_size_from_sym_kind(CV_SymKind v)`; + `{`; + `U64 result = 0;`; + `switch(v)`; + `{`; + `default:{}break;`; + @expand(CV_SymKindTable a) `$(a.header_type_name != "-" -> "case CV_SymKind_"..a.name..":{result = sizeof(CV_Sym"..a.header_type_name..");}break;")`; + `}`; + `return result;`; + `}`; +} + +//////////////////////////////// +//~ rjf: CV Basic Types + +@table(name val type_name) +CV_BasicTypeTable: +{ + {NOTYPE 0x00 "" } + {ABS 0x01 "" } + {SEGMENT 0x02 "" } + {VOID 0x03 "void" } + {CURRENCY 0x04 "" } + {NBASICSTR 0x05 "" } + {FBASICSTR 0x06 "" } + {NOTTRANS 0x07 "" } + {HRESULT 0x08 "HRESULT" } + {CHAR 0x10 "char" } + {SHORT 0x11 "S16" } + {LONG 0x12 "S32" } + {QUAD 0x13 "S64" } + {OCT 0x14 "S128" } + {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" } + {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" } + {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" } + {CHAR8 0x7c "char" } + {PTR 0xf0 "PTR" } +} + +@enum(U8) CV_BasicType: +{ + @expand(CV_BasicTypeTable a) `$(a.name) = $(a.val)` +} + +@enum2string_switch(CV_BasicType) cv_string_from_basic_type: +{ + @expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.name)");}break` +} + +@enum2string_switch(CV_BasicType) cv_type_name_from_basic_type: +{ + @expand(CV_BasicTypeTable a) `case CV_BasicType_$(a.name):{result = str8_lit("$(a.type_name)");}break` +} + +//////////////////////////////// +//~ rjf: CV Leaf Kinds + +@table(name header_type_name val) +CV_LeafKindTable: +{ + {MODIFIER_16t - 0x0001} + {POINTER_16t - 0x0002} + {ARRAY_16t - 0x0003} + {CLASS_16t - 0x0004} + {STRUCTURE_16t - 0x0005} + {UNION_16t - 0x0006} + {ENUM_16t - 0x0007} + {PROCEDURE_16t - 0x0008} + {MFUNCTION_16t - 0x0009} + {VTSHAPE VTShape 0x000a} + {COBOL0_16t - 0x000b} + {COBOL1 - 0x000c} + {BARRAY_16t - 0x000d} + {LABEL Label 0x000e} + {NULL - 0x000f} + {NOTTRAN - 0x0010} + {DIMARRAY_16t - 0x0011} + {VFTPATH_16t - 0x0012} + {PRECOMP_16t - 0x0013} + {ENDPRECOMP - 0x0014} + {OEM_16t - 0x0015} + {TYPESERVER_ST - 0x0016} + {SKIP_16t - 0x0200} + {ARGLIST_16t - 0x0201} + {DEFARG_16t - 0x0202} + {LIST - 0x0203} + {FIELDLIST_16t - 0x0204} + {DERIVED_16t - 0x0205} + {BITFIELD_16t - 0x0206} + {METHODLIST_16t - 0x0207} + {DIMCONU_16t - 0x0208} + {DIMCONLU_16t - 0x0209} + {DIMVARU_16t - 0x020a} + {DIMVARLU_16t - 0x020b} + {REFSYM - 0x020c} + {BCLASS_16t - 0x0400} + {VBCLASS_16t - 0x0401} + {IVBCLASS_16t - 0x0402} + {ENUMERATE_ST - 0x0403} + {FRIENDFCN_16t - 0x0404} + {INDEX_16t - 0x0405} + {MEMBER_16t - 0x0406} + {STMEMBER_16t - 0x0407} + {METHOD_16t - 0x0408} + {NESTTYPE_16t - 0x0409} + {VFUNCTAB_16t - 0x040a} + {FRIENDCLS_16t - 0x040b} + {ONEMETHOD_16t - 0x040c} + {VFUNCOFF_16t - 0x040d} + {TI16_MAX - 0x1000} + {MODIFIER Modifier 0x1001} + {POINTER Pointer 0x1002} + {ARRAY_ST - 0x1003} + {CLASS_ST - 0x1004} + {STRUCTURE_ST - 0x1005} + {UNION_ST - 0x1006} + {ENUM_ST - 0x1007} + {PROCEDURE Procedure 0x1008} + {MFUNCTION MFunction 0x1009} + {COBOL0 - 0x100a} + {BARRAY - 0x100b} + {DIMARRAY_ST - 0x100c} + {VFTPATH VFPath 0x100d} + {PRECOMP_ST - 0x100e} + {OEM - 0x100f} + {ALIAS_ST - 0x1010} + {OEM2 - 0x1011} + {SKIP Skip 0x1200} + {ARGLIST ArgList 0x1201} + {DEFARG_ST - 0x1202} + {FIELDLIST - 0x1203} + {DERIVED - 0x1204} + {BITFIELD BitField 0x1205} + {METHODLIST MethodListMember 0x1206} + {DIMCONU - 0x1207} + {DIMCONLU - 0x1208} + {DIMVARU - 0x1209} + {DIMVARLU - 0x120a} + {BCLASS BClass 0x1400} + {VBCLASS VBClass 0x1401} + {IVBCLASS - 0x1402} + {FRIENDFCN_ST - 0x1403} + {INDEX Index 0x1404} + {MEMBER_ST - 0x1405} + {STMEMBER_ST - 0x1406} + {METHOD_ST - 0x1407} + {NESTTYPE_ST - 0x1408} + {VFUNCTAB VFuncTab 0x1409} + {FRIENDCLS - 0x140a} + {ONEMETHOD_ST - 0x140b} + {VFUNCOFF VFuncOff 0x140c} + {NESTTYPEEX_ST - 0x140d} + {MEMBERMODIFY_ST - 0x140e} + {MANAGED_ST - 0x140f} + {ST_MAX - 0x1500} + {TYPESERVER TypeServer 0x1501} + {ENUMERATE Enumerate 0x1502} + {ARRAY Array 0x1503} + {CLASS Struct 0x1504} + {STRUCTURE Struct 0x1505} + {UNION Union 0x1506} + {ENUM Enum 0x1507} + {DIMARRAY - 0x1508} + {PRECOMP PreComp 0x1509} + {ALIAS Alias 0x150a} + {DEFARG - 0x150b} + {FRIENDFCN - 0x150c} + {MEMBER Member 0x150d} + {STMEMBER StMember 0x150e} + {METHOD Method 0x150f} + {NESTTYPE NestType 0x1510} + {ONEMETHOD OneMethod 0x1511} + {NESTTYPEEX NestTypeEx 0x1512} + {MEMBERMODIFY - 0x1513} + {MANAGED - 0x1514} + {TYPESERVER2 TypeServer2 0x1515} + {STRIDED_ARRAY - 0x1516} + {HLSL - 0x1517} + {MODIFIER_EX - 0x1518} + {INTERFACE Struct 0x1519} + {BINTERFACE - 0x151a} + {VECTOR - 0x151b} + {MATRIX - 0x151c} + {VFTABLE - 0x151d} + {CLASS2 Struct2 0x1608} + {STRUCT2 Struct2 0x1609} +} + +@enum(U16) CV_LeafKind: +{ + @expand(CV_LeafKindTable a) `$(a.name) = $(a.val)`; +} + +@enum2string_switch(CV_LeafKind) +cv_string_from_leaf_kind: +{ + @expand(CV_LeafKindTable a) `case CV_LeafKind_$(a.name):{result = str8_lit("$(a.name)");}break`; +} + +@gen(functions) +{ + `internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v);`; +} + +@gen(functions) @c_file +{ + `internal U64`; + `cv_header_struct_size_from_leaf_kind(CV_LeafKind v)`; + `{`; + `U64 result = 0;`; + `switch(v)`; + `{`; + `default:{}break;`; + @expand(CV_LeafKindTable a) `$(a.header_type_name != "-" -> "case CV_LeafKind_"..a.name..":{result = sizeof(CV_Leaf"..a.header_type_name..");}break;")`; + `}`; + `return result;`; + `}`; +} diff --git a/src/raddbg_convert/pdb/raddbg_codeview_stringize.c b/src/codeview/codeview_stringize.c similarity index 97% rename from src/raddbg_convert/pdb/raddbg_codeview_stringize.c rename to src/codeview/codeview_stringize.c index 10534908..9c1245ae 100644 --- a/src/raddbg_convert/pdb/raddbg_codeview_stringize.c +++ b/src/codeview/codeview_stringize.c @@ -4,7 +4,7 @@ //////////////////////////////// //~ CodeView Common Stringize Functions -static void +internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num){ String8 numeric_kind_str = cv_string_from_numeric_kind(num->kind); str8_list_pushf(arena, out, "(%.*s)", str8_varg(numeric_kind_str)); @@ -23,17 +23,17 @@ cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num){ } } -static void +internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out, CV_LvarAddrRange *range){ str8_list_pushf(arena, out, "{off=%x, sec=%u, len=%u}", range->off, range->sec, range->len); } -static void +internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap){ str8_list_pushf(arena, out, "{off=%x, len=%u}", gap->off, gap->len); } -static void +internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, void *first, void *opl){ U64 gap_count = ((U8*)first - (U8*)opl)/sizeof(CV_LvarAddrGap); if (gap_count > 0){ @@ -48,56 +48,7 @@ cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, void *first, voi } } -static String8 -cv_string_from_sym_kind(CV_SymKind kind){ - String8 result = str8_lit("UNRECOGNIZED_SYM_KIND"); - switch (kind){ -#define X(N,c) case CV_SymKind_##N: result = str8_lit(#N); break; - CV_SymKindXList(X) -#undef X - } - return(result); -} - -static String8 -cv_string_from_basic_type(CV_BasicType basic_type){ - String8 result = str8_lit("UNRECOGNIZED_BASIC_TYPE"); - switch (basic_type){ -#define X(N,c) case CV_BasicType_##N: result = str8_lit(#N); break; - CV_BasicTypeXList(X) -#undef X - } - return(result); -} - -static String8 -cv_string_from_leaf_kind(CV_LeafKind kind){ - String8 result = str8_lit("UNRECOGNIZED_LEAF_KIND"); - switch (kind){ -#define X(N,c) case CV_LeafKind_##N: result = str8_lit(#N); break; - CV_LeafKindXList(X) -#undef X - -#define X(N,c) case CV_LeafIDKind_##N: result = str8_lit(#N); break; - CV_LeafIDKindXList(X) -#undef X - } - return(result); -} - -static String8 -cv_string_from_numeric_kind(CV_NumericKind kind){ - String8 result = str8_lit("UNRECOGNIZED_NUMERIC_KIND"); - switch (kind){ - case 0: str8_lit("PARSE_ERROR"); break; -#define X(N,c) case CV_NumericKind_##N: result = str8_lit(#N); break; - CV_NumericKindXList(X) -#undef X - } - return(result); -} - -static String8 +internal String8 cv_string_from_c13_sub_section_kind(CV_C13_SubSectionKind kind){ String8 result = str8_lit("UNRECOGNIZED_C13_SUB_SECTION_KIND"); switch (kind){ @@ -109,18 +60,7 @@ cv_string_from_c13_sub_section_kind(CV_C13_SubSectionKind kind){ return(result); } -static String8 -cv_string_from_machine(CV_Arch arch){ - String8 result = {0}; - switch (arch){ -#define X(N,c) case CV_Arch_##N: result = str8_lit(#N); break; - CV_ArchXList(X) -#undef X - } - return(result); -} - -static String8 +internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg){ String8 result = {0}; switch (arch){ @@ -147,7 +87,7 @@ cv_string_from_reg(CV_Arch arch, CV_Reg reg){ return(result); } -static String8 +internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind){ String8 result = {0}; switch (ptr_kind){ @@ -169,7 +109,7 @@ cv_string_from_pointer_kind(CV_PointerKind ptr_kind){ return(result); } -static String8 +internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode){ String8 result = {0}; switch (ptr_mode){ @@ -183,7 +123,7 @@ cv_string_from_pointer_mode(CV_PointerMode ptr_mode){ return(result); } -static String8 +internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind){ String8 result = {0}; switch (hfa_kind){ @@ -196,7 +136,7 @@ cv_string_from_hfa_kind(CV_HFAKind hfa_kind){ return(result); } -static String8 +internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind){ String8 result = {0}; switch (mo_com_udt_kind){ @@ -212,11 +152,11 @@ cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind){ //////////////////////////////// //~ CodeView Flags Stringize Functions -static char cv_stringize_spaces[] = " "; +global char cv_stringize_spaces[] = " "; #define SPACES cv_stringize_spaces -static void +internal void cv_stringize_modifier_flags(Arena *arena, String8List *out, U32 indent, CV_ModifierFlags flags){ if (flags & CV_ModifierFlag_Const){ @@ -230,7 +170,7 @@ cv_stringize_modifier_flags(Arena *arena, String8List *out, } } -static void +internal void cv_stringize_type_props(Arena *arena, String8List *out, U32 indent, CV_TypeProps props){ if (props & CV_TypeProp_Packed){ @@ -285,7 +225,7 @@ cv_stringize_type_props(Arena *arena, String8List *out, } } -static void +internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out, U32 indent, CV_PointerAttribs attribs){ if (attribs & CV_PointerAttrib_IsFlat){ @@ -332,7 +272,7 @@ cv_stringize_pointer_attribs(Arena *arena, String8List *out, indent, SPACES, size); } -static void +internal void cv_stringize_local_flags(Arena *arena, String8List *out, U32 indent, CV_LocalFlags flags){ if (flags & CV_LocalFlag_Param){ @@ -376,7 +316,7 @@ cv_stringize_local_flags(Arena *arena, String8List *out, //////////////////////////////// //~ CodeView Sym Stringize Functions -static void +internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym){ CV_StringizeSymParams params = {0}; params.arch = sym->info.arch; @@ -384,7 +324,7 @@ cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym){ cv_stringize_sym_array(arena, out, &sym->sym_ranges, sym->data, ¶ms); } -static void +internal void cv_stringize_sym_range(Arena *arena, String8List *out, CV_RecRange *range, String8 data, CV_StringizeSymParams *p){ @@ -417,7 +357,7 @@ cv_stringize_sym_range(Arena *arena, String8List *out, CV_SymCompile *compile = (CV_SymCompile*)first; // machine - String8 machine = cv_string_from_machine(compile->machine); + String8 machine = cv_string_from_arch(compile->machine); str8_list_pushf(arena, out, " machine=%.*s\n", str8_varg(machine)); @@ -742,7 +682,7 @@ cv_stringize_sym_range(Arena *arena, String8List *out, str8_list_pushf(arena, out, " flags=%x\n", compile2->flags); // machine - String8 machine = cv_string_from_machine(compile2->machine); + String8 machine = cv_string_from_arch(compile2->machine); str8_list_pushf(arena, out, " machine=%.*s\n", str8_varg(machine)); @@ -906,7 +846,7 @@ cv_stringize_sym_range(Arena *arena, String8List *out, str8_list_pushf(arena, out, " flags=%x\n", compile3->flags); // machine - String8 machine = cv_string_from_machine(compile3->machine); + String8 machine = cv_string_from_arch(compile3->machine); str8_list_pushf(arena, out, " machine=%.*s\n", str8_varg(machine)); @@ -1381,7 +1321,7 @@ cv_stringize_sym_range(Arena *arena, String8List *out, } } -static void +internal void cv_stringize_sym_array(Arena *arena, String8List *out, CV_RecRangeArray *ranges, String8 data, CV_StringizeSymParams *p){ @@ -1396,7 +1336,7 @@ cv_stringize_sym_array(Arena *arena, String8List *out, //////////////////////////////// //~ CodeView Leaf Stringize Functions -static void +internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf){ CV_StringizeLeafParams params = {0}; @@ -1404,7 +1344,7 @@ cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf){ leaf->data, ¶ms); } -static void +internal void cv_stringize_leaf_range(Arena *arena, String8List *out, CV_RecRange *range, CV_TypeId itype, String8 data, CV_StringizeLeafParams *p){ @@ -2312,7 +2252,7 @@ cv_stringize_leaf_range(Arena *arena, String8List *out, } } -static void +internal void cv_stringize_leaf_array(Arena *arena, String8List *out, CV_RecRangeArray *ranges, CV_TypeId itype_first, String8 data, CV_StringizeLeafParams *p){ @@ -2328,23 +2268,28 @@ cv_stringize_leaf_array(Arena *arena, String8List *out, //////////////////////////////// //~ CodeView C13 Stringize Functions -static void +internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13){ - for (CV_C13SubSectionNode *node = c13->first_sub_section; - node != 0; - node = node->next){ + for(CV_C13SubSectionNode *node = c13->first_sub_section; + node != 0; + node = node->next) + { String8 kind_str = cv_string_from_c13_sub_section_kind(node->kind); str8_list_pushf(arena, out, "C13 Sub Section [%llx] (%.*s):\n", node->off, str8_varg(kind_str)); - switch (node->kind){ + switch(node->kind) + { case CV_C13_SubSectionKind_Lines: { - CV_C13LinesParsed *lines = node->lines; - if (lines == 0){ + if (node->lines_first == 0) + { str8_list_push(arena, out, str8_lit(" failed to extract info\n")); } - else{ + else for(CV_C13LinesParsedNode *n = node->lines_first; n != 0; n = n->next) + { + CV_C13LinesParsed *lines = &n->v; + str8_list_pushf(arena, out, " section: %u\n", lines->sec_idx); str8_list_pushf(arena, out, " file off: %u\n", lines->file_off); str8_list_pushf(arena, out, " file name: %.*s\n", str8_varg(lines->file_name)); diff --git a/src/codeview/codeview_stringize.h b/src/codeview/codeview_stringize.h new file mode 100644 index 00000000..b37cd904 --- /dev/null +++ b/src/codeview/codeview_stringize.h @@ -0,0 +1,82 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef CODEVIEW_STRINGIZE_H +#define CODEVIEW_STRINGIZE_H + +//////////////////////////////// +//~ CodeView Stringize Helper Types + +typedef struct CV_StringizeSymParams{ + CV_Arch arch; +} CV_StringizeSymParams; + +typedef struct CV_StringizeLeafParams{ + U32 dummy; +} CV_StringizeLeafParams; + +//////////////////////////////// +//~ CodeView Common Stringize Functions + +internal void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num); + +internal void cv_stringize_lvar_addr_range(Arena *arena, String8List *out, + CV_LvarAddrRange *range); +internal void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap); +internal void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, + void *first, void *opl); + +internal String8 cv_string_from_basic_type(CV_BasicType basic_type); +internal String8 cv_string_from_c13_sub_section_kind(CV_C13_SubSectionKind kind); +internal String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg); +internal String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind); +internal String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode); +internal String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind); +internal String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind); + +//////////////////////////////// +//~ CodeView Flags Stringize Functions + +internal void cv_stringize_modifier_flags(Arena *arena, String8List *out, + U32 indent, CV_ModifierFlags flags); + +internal void cv_stringize_type_props(Arena *arena, String8List *out, + U32 indent, CV_TypeProps props); + +internal void cv_stringize_pointer_attribs(Arena *arena, String8List *out, + U32 indent, CV_PointerAttribs attribs); + +internal void cv_stringize_local_flags(Arena *arena, String8List *out, + U32 indent, CV_LocalFlags flags); + +//////////////////////////////// +//~ CodeView Sym Stringize Functions + +internal void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym); + +internal void cv_stringize_sym_range(Arena *arena, String8List *out, + CV_RecRange *range, String8 data, + CV_StringizeSymParams *p); +internal void cv_stringize_sym_array(Arena *arena, String8List *out, + CV_RecRangeArray *ranges, String8 data, + CV_StringizeSymParams *p); + +//////////////////////////////// +//~ CodeView Leaf Stringize Functions + +internal void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf); + +internal void cv_stringize_leaf_range(Arena *arena, String8List *out, + CV_RecRange *range, CV_TypeId itype, String8 data, + CV_StringizeLeafParams *p); +internal void cv_stringize_leaf_array(Arena *arena, String8List *out, + CV_RecRangeArray *ranges, CV_TypeId itype_first, + String8 data, + CV_StringizeLeafParams *p); + +//////////////////////////////// +//~ CodeView C13 Stringize Functions + +internal void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13); + +#endif // CODEVIEW_STRINGIZE_H diff --git a/src/codeview/generated/codeview.meta.c b/src/codeview/generated/codeview.meta.c new file mode 100644 index 00000000..2aaef62e --- /dev/null +++ b/src/codeview/generated/codeview.meta.c @@ -0,0 +1,706 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +internal String8 +cv_string_from_numeric_kind(CV_NumericKind v) +{ +String8 result = str8_lit(""); +switch(v) +{ +default:{}break; +case CV_NumericKind_CHAR:{result = str8_lit("CHAR");}break; +case CV_NumericKind_SHORT:{result = str8_lit("SHORT");}break; +case CV_NumericKind_USHORT:{result = str8_lit("USHORT");}break; +case CV_NumericKind_LONG:{result = str8_lit("LONG");}break; +case CV_NumericKind_ULONG:{result = str8_lit("ULONG");}break; +case CV_NumericKind_FLOAT32:{result = str8_lit("FLOAT32");}break; +case CV_NumericKind_FLOAT64:{result = str8_lit("FLOAT64");}break; +case CV_NumericKind_FLOAT80:{result = str8_lit("FLOAT80");}break; +case CV_NumericKind_FLOAT128:{result = str8_lit("FLOAT128");}break; +case CV_NumericKind_QUADWORD:{result = str8_lit("QUADWORD");}break; +case CV_NumericKind_UQUADWORD:{result = str8_lit("UQUADWORD");}break; +case CV_NumericKind_FLOAT48:{result = str8_lit("FLOAT48");}break; +case CV_NumericKind_COMPLEX32:{result = str8_lit("COMPLEX32");}break; +case CV_NumericKind_COMPLEX64:{result = str8_lit("COMPLEX64");}break; +case CV_NumericKind_COMPLEX80:{result = str8_lit("COMPLEX80");}break; +case CV_NumericKind_COMPLEX128:{result = str8_lit("COMPLEX128");}break; +case CV_NumericKind_VARSTRING:{result = str8_lit("VARSTRING");}break; +case CV_NumericKind_OCTWORD:{result = str8_lit("OCTWORD");}break; +case CV_NumericKind_UOCTWORD:{result = str8_lit("UOCTWORD");}break; +case CV_NumericKind_DECIMAL:{result = str8_lit("DECIMAL");}break; +case CV_NumericKind_DATE:{result = str8_lit("DATE");}break; +case CV_NumericKind_UTF8STRING:{result = str8_lit("UTF8STRING");}break; +case CV_NumericKind_FLOAT16:{result = str8_lit("FLOAT16");}break; +} +return result; +} + +internal String8 +cv_string_from_arch(CV_Arch v) +{ +String8 result = str8_lit(""); +switch(v) +{ +default:{}break; +case CV_Arch_8080:{result = str8_lit("8080");}break; +case CV_Arch_8086:{result = str8_lit("8086");}break; +case CV_Arch_80286:{result = str8_lit("80286");}break; +case CV_Arch_80386:{result = str8_lit("80386");}break; +case CV_Arch_80486:{result = str8_lit("80486");}break; +case CV_Arch_PENTIUM:{result = str8_lit("PENTIUM");}break; +case CV_Arch_PENTIUMII:{result = str8_lit("PENTIUMII");}break; +case CV_Arch_PENTIUMIII:{result = str8_lit("PENTIUMIII");}break; +case CV_Arch_MIPS:{result = str8_lit("MIPS");}break; +case CV_Arch_MIPS16:{result = str8_lit("MIPS16");}break; +case CV_Arch_MIPS32:{result = str8_lit("MIPS32");}break; +case CV_Arch_MIPS64:{result = str8_lit("MIPS64");}break; +case CV_Arch_MIPSI:{result = str8_lit("MIPSI");}break; +case CV_Arch_MIPSII:{result = str8_lit("MIPSII");}break; +case CV_Arch_MIPSIII:{result = str8_lit("MIPSIII");}break; +case CV_Arch_MIPSIV:{result = str8_lit("MIPSIV");}break; +case CV_Arch_MIPSV:{result = str8_lit("MIPSV");}break; +case CV_Arch_M68000:{result = str8_lit("M68000");}break; +case CV_Arch_M68010:{result = str8_lit("M68010");}break; +case CV_Arch_M68020:{result = str8_lit("M68020");}break; +case CV_Arch_M68030:{result = str8_lit("M68030");}break; +case CV_Arch_M68040:{result = str8_lit("M68040");}break; +case CV_Arch_ALPHA:{result = str8_lit("ALPHA");}break; +case CV_Arch_ALPHA_21164:{result = str8_lit("ALPHA_21164");}break; +case CV_Arch_ALPHA_21164A:{result = str8_lit("ALPHA_21164A");}break; +case CV_Arch_ALPHA_21264:{result = str8_lit("ALPHA_21264");}break; +case CV_Arch_ALPHA_21364:{result = str8_lit("ALPHA_21364");}break; +case CV_Arch_PPC601:{result = str8_lit("PPC601");}break; +case CV_Arch_PPC603:{result = str8_lit("PPC603");}break; +case CV_Arch_PPC604:{result = str8_lit("PPC604");}break; +case CV_Arch_PPC620:{result = str8_lit("PPC620");}break; +case CV_Arch_PPCFP:{result = str8_lit("PPCFP");}break; +case CV_Arch_PPCBE:{result = str8_lit("PPCBE");}break; +case CV_Arch_SH3:{result = str8_lit("SH3");}break; +case CV_Arch_SH3E:{result = str8_lit("SH3E");}break; +case CV_Arch_SH3DSP:{result = str8_lit("SH3DSP");}break; +case CV_Arch_SH4:{result = str8_lit("SH4");}break; +case CV_Arch_SHMEDIA:{result = str8_lit("SHMEDIA");}break; +case CV_Arch_ARM3:{result = str8_lit("ARM3");}break; +case CV_Arch_ARM4:{result = str8_lit("ARM4");}break; +case CV_Arch_ARM4T:{result = str8_lit("ARM4T");}break; +case CV_Arch_ARM5:{result = str8_lit("ARM5");}break; +case CV_Arch_ARM5T:{result = str8_lit("ARM5T");}break; +case CV_Arch_ARM6:{result = str8_lit("ARM6");}break; +case CV_Arch_ARM_XMAC:{result = str8_lit("ARM_XMAC");}break; +case CV_Arch_ARM_WMMX:{result = str8_lit("ARM_WMMX");}break; +case CV_Arch_ARM7:{result = str8_lit("ARM7");}break; +case CV_Arch_OMNI:{result = str8_lit("OMNI");}break; +case CV_Arch_IA64_1:{result = str8_lit("IA64_1");}break; +case CV_Arch_IA64_2:{result = str8_lit("IA64_2");}break; +case CV_Arch_CEE:{result = str8_lit("CEE");}break; +case CV_Arch_AM33:{result = str8_lit("AM33");}break; +case CV_Arch_M32R:{result = str8_lit("M32R");}break; +case CV_Arch_TRICORE:{result = str8_lit("TRICORE");}break; +case CV_Arch_X64:{result = str8_lit("X64");}break; +case CV_Arch_EBC:{result = str8_lit("EBC");}break; +case CV_Arch_THUMB:{result = str8_lit("THUMB");}break; +case CV_Arch_ARMNT:{result = str8_lit("ARMNT");}break; +case CV_Arch_ARM64:{result = str8_lit("ARM64");}break; +case CV_Arch_D3D11_SHADER:{result = str8_lit("D3D11_SHADER");}break; +} +return result; +} + +internal String8 +cv_string_from_sym_kind(CV_SymKind v) +{ +String8 result = str8_lit(""); +switch(v) +{ +default:{}break; +case CV_SymKind_COMPILE:{result = str8_lit("COMPILE");}break; +case CV_SymKind_REGISTER_16t:{result = str8_lit("REGISTER_16t");}break; +case CV_SymKind_CONSTANT_16t:{result = str8_lit("CONSTANT_16t");}break; +case CV_SymKind_UDT_16t:{result = str8_lit("UDT_16t");}break; +case CV_SymKind_SSEARCH:{result = str8_lit("SSEARCH");}break; +case CV_SymKind_END:{result = str8_lit("END");}break; +case CV_SymKind_SKIP:{result = str8_lit("SKIP");}break; +case CV_SymKind_CVRESERVE:{result = str8_lit("CVRESERVE");}break; +case CV_SymKind_OBJNAME_ST:{result = str8_lit("OBJNAME_ST");}break; +case CV_SymKind_ENDARG:{result = str8_lit("ENDARG");}break; +case CV_SymKind_COBOLUDT_16t:{result = str8_lit("COBOLUDT_16t");}break; +case CV_SymKind_MANYREG_16t:{result = str8_lit("MANYREG_16t");}break; +case CV_SymKind_RETURN:{result = str8_lit("RETURN");}break; +case CV_SymKind_ENTRYTHIS:{result = str8_lit("ENTRYTHIS");}break; +case CV_SymKind_BPREL16:{result = str8_lit("BPREL16");}break; +case CV_SymKind_LDATA16:{result = str8_lit("LDATA16");}break; +case CV_SymKind_GDATA16:{result = str8_lit("GDATA16");}break; +case CV_SymKind_PUB16:{result = str8_lit("PUB16");}break; +case CV_SymKind_LPROC16:{result = str8_lit("LPROC16");}break; +case CV_SymKind_GPROC16:{result = str8_lit("GPROC16");}break; +case CV_SymKind_THUNK16:{result = str8_lit("THUNK16");}break; +case CV_SymKind_BLOCK16:{result = str8_lit("BLOCK16");}break; +case CV_SymKind_WITH16:{result = str8_lit("WITH16");}break; +case CV_SymKind_LABEL16:{result = str8_lit("LABEL16");}break; +case CV_SymKind_CEXMODEL16:{result = str8_lit("CEXMODEL16");}break; +case CV_SymKind_VFTABLE16:{result = str8_lit("VFTABLE16");}break; +case CV_SymKind_REGREL16:{result = str8_lit("REGREL16");}break; +case CV_SymKind_BPREL32_16t:{result = str8_lit("BPREL32_16t");}break; +case CV_SymKind_LDATA32_16t:{result = str8_lit("LDATA32_16t");}break; +case CV_SymKind_GDATA32_16t:{result = str8_lit("GDATA32_16t");}break; +case CV_SymKind_PUB32_16t:{result = str8_lit("PUB32_16t");}break; +case CV_SymKind_LPROC32_16t:{result = str8_lit("LPROC32_16t");}break; +case CV_SymKind_GPROC32_16t:{result = str8_lit("GPROC32_16t");}break; +case CV_SymKind_THUNK32_ST:{result = str8_lit("THUNK32_ST");}break; +case CV_SymKind_BLOCK32_ST:{result = str8_lit("BLOCK32_ST");}break; +case CV_SymKind_WITH32_ST:{result = str8_lit("WITH32_ST");}break; +case CV_SymKind_LABEL32_ST:{result = str8_lit("LABEL32_ST");}break; +case CV_SymKind_CEXMODEL32:{result = str8_lit("CEXMODEL32");}break; +case CV_SymKind_VFTABLE32_16t:{result = str8_lit("VFTABLE32_16t");}break; +case CV_SymKind_REGREL32_16t:{result = str8_lit("REGREL32_16t");}break; +case CV_SymKind_LTHREAD32_16t:{result = str8_lit("LTHREAD32_16t");}break; +case CV_SymKind_GTHREAD32_16t:{result = str8_lit("GTHREAD32_16t");}break; +case CV_SymKind_SLINK32:{result = str8_lit("SLINK32");}break; +case CV_SymKind_LPROCMIPS_16t:{result = str8_lit("LPROCMIPS_16t");}break; +case CV_SymKind_GPROCMIPS_16t:{result = str8_lit("GPROCMIPS_16t");}break; +case CV_SymKind_PROCREF_ST:{result = str8_lit("PROCREF_ST");}break; +case CV_SymKind_DATAREF_ST:{result = str8_lit("DATAREF_ST");}break; +case CV_SymKind_ALIGN:{result = str8_lit("ALIGN");}break; +case CV_SymKind_LPROCREF_ST:{result = str8_lit("LPROCREF_ST");}break; +case CV_SymKind_OEM:{result = str8_lit("OEM");}break; +case CV_SymKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break; +case CV_SymKind_CONSTANT_ST:{result = str8_lit("CONSTANT_ST");}break; +case CV_SymKind_UDT_ST:{result = str8_lit("UDT_ST");}break; +case CV_SymKind_COBOLUDT_ST:{result = str8_lit("COBOLUDT_ST");}break; +case CV_SymKind_MANYREG_ST:{result = str8_lit("MANYREG_ST");}break; +case CV_SymKind_BPREL32_ST:{result = str8_lit("BPREL32_ST");}break; +case CV_SymKind_LDATA32_ST:{result = str8_lit("LDATA32_ST");}break; +case CV_SymKind_GDATA32_ST:{result = str8_lit("GDATA32_ST");}break; +case CV_SymKind_PUB32_ST:{result = str8_lit("PUB32_ST");}break; +case CV_SymKind_LPROC32_ST:{result = str8_lit("LPROC32_ST");}break; +case CV_SymKind_GPROC32_ST:{result = str8_lit("GPROC32_ST");}break; +case CV_SymKind_VFTABLE32:{result = str8_lit("VFTABLE32");}break; +case CV_SymKind_REGREL32_ST:{result = str8_lit("REGREL32_ST");}break; +case CV_SymKind_LTHREAD32_ST:{result = str8_lit("LTHREAD32_ST");}break; +case CV_SymKind_GTHREAD32_ST:{result = str8_lit("GTHREAD32_ST");}break; +case CV_SymKind_LPROCMIPS_ST:{result = str8_lit("LPROCMIPS_ST");}break; +case CV_SymKind_GPROCMIPS_ST:{result = str8_lit("GPROCMIPS_ST");}break; +case CV_SymKind_FRAMEPROC:{result = str8_lit("FRAMEPROC");}break; +case CV_SymKind_COMPILE2_ST:{result = str8_lit("COMPILE2_ST");}break; +case CV_SymKind_MANYREG2_ST:{result = str8_lit("MANYREG2_ST");}break; +case CV_SymKind_LPROCIA64_ST:{result = str8_lit("LPROCIA64_ST");}break; +case CV_SymKind_GPROCIA64_ST:{result = str8_lit("GPROCIA64_ST");}break; +case CV_SymKind_LOCALSLOT_ST:{result = str8_lit("LOCALSLOT_ST");}break; +case CV_SymKind_PARAMSLOT_ST:{result = str8_lit("PARAMSLOT_ST");}break; +case CV_SymKind_ANNOTATION:{result = str8_lit("ANNOTATION");}break; +case CV_SymKind_GMANPROC_ST:{result = str8_lit("GMANPROC_ST");}break; +case CV_SymKind_LMANPROC_ST:{result = str8_lit("LMANPROC_ST");}break; +case CV_SymKind_RESERVED1:{result = str8_lit("RESERVED1");}break; +case CV_SymKind_RESERVED2:{result = str8_lit("RESERVED2");}break; +case CV_SymKind_RESERVED3:{result = str8_lit("RESERVED3");}break; +case CV_SymKind_RESERVED4:{result = str8_lit("RESERVED4");}break; +case CV_SymKind_LMANDATA_ST:{result = str8_lit("LMANDATA_ST");}break; +case CV_SymKind_GMANDATA_ST:{result = str8_lit("GMANDATA_ST");}break; +case CV_SymKind_MANFRAMEREL_ST:{result = str8_lit("MANFRAMEREL_ST");}break; +case CV_SymKind_MANREGISTER_ST:{result = str8_lit("MANREGISTER_ST");}break; +case CV_SymKind_MANSLOT_ST:{result = str8_lit("MANSLOT_ST");}break; +case CV_SymKind_MANMANYREG_ST:{result = str8_lit("MANMANYREG_ST");}break; +case CV_SymKind_MANREGREL_ST:{result = str8_lit("MANREGREL_ST");}break; +case CV_SymKind_MANMANYREG2_ST:{result = str8_lit("MANMANYREG2_ST");}break; +case CV_SymKind_MANTYPREF:{result = str8_lit("MANTYPREF");}break; +case CV_SymKind_UNAMESPACE_ST:{result = str8_lit("UNAMESPACE_ST");}break; +case CV_SymKind_ST_MAX:{result = str8_lit("ST_MAX");}break; +case CV_SymKind_OBJNAME:{result = str8_lit("OBJNAME");}break; +case CV_SymKind_THUNK32:{result = str8_lit("THUNK32");}break; +case CV_SymKind_BLOCK32:{result = str8_lit("BLOCK32");}break; +case CV_SymKind_WITH32:{result = str8_lit("WITH32");}break; +case CV_SymKind_LABEL32:{result = str8_lit("LABEL32");}break; +case CV_SymKind_REGISTER:{result = str8_lit("REGISTER");}break; +case CV_SymKind_CONSTANT:{result = str8_lit("CONSTANT");}break; +case CV_SymKind_UDT:{result = str8_lit("UDT");}break; +case CV_SymKind_COBOLUDT:{result = str8_lit("COBOLUDT");}break; +case CV_SymKind_MANYREG:{result = str8_lit("MANYREG");}break; +case CV_SymKind_BPREL32:{result = str8_lit("BPREL32");}break; +case CV_SymKind_LDATA32:{result = str8_lit("LDATA32");}break; +case CV_SymKind_GDATA32:{result = str8_lit("GDATA32");}break; +case CV_SymKind_PUB32:{result = str8_lit("PUB32");}break; +case CV_SymKind_LPROC32:{result = str8_lit("LPROC32");}break; +case CV_SymKind_GPROC32:{result = str8_lit("GPROC32");}break; +case CV_SymKind_REGREL32:{result = str8_lit("REGREL32");}break; +case CV_SymKind_LTHREAD32:{result = str8_lit("LTHREAD32");}break; +case CV_SymKind_GTHREAD32:{result = str8_lit("GTHREAD32");}break; +case CV_SymKind_LPROCMIPS:{result = str8_lit("LPROCMIPS");}break; +case CV_SymKind_GPROCMIPS:{result = str8_lit("GPROCMIPS");}break; +case CV_SymKind_COMPILE2:{result = str8_lit("COMPILE2");}break; +case CV_SymKind_MANYREG2:{result = str8_lit("MANYREG2");}break; +case CV_SymKind_LPROCIA64:{result = str8_lit("LPROCIA64");}break; +case CV_SymKind_GPROCIA64:{result = str8_lit("GPROCIA64");}break; +case CV_SymKind_LOCALSLOT:{result = str8_lit("LOCALSLOT");}break; +case CV_SymKind_PARAMSLOT:{result = str8_lit("PARAMSLOT");}break; +case CV_SymKind_LMANDATA:{result = str8_lit("LMANDATA");}break; +case CV_SymKind_GMANDATA:{result = str8_lit("GMANDATA");}break; +case CV_SymKind_MANFRAMEREL:{result = str8_lit("MANFRAMEREL");}break; +case CV_SymKind_MANREGISTER:{result = str8_lit("MANREGISTER");}break; +case CV_SymKind_MANSLOT:{result = str8_lit("MANSLOT");}break; +case CV_SymKind_MANMANYREG:{result = str8_lit("MANMANYREG");}break; +case CV_SymKind_MANREGREL:{result = str8_lit("MANREGREL");}break; +case CV_SymKind_MANMANYREG2:{result = str8_lit("MANMANYREG2");}break; +case CV_SymKind_UNAMESPACE:{result = str8_lit("UNAMESPACE");}break; +case CV_SymKind_PROCREF:{result = str8_lit("PROCREF");}break; +case CV_SymKind_DATAREF:{result = str8_lit("DATAREF");}break; +case CV_SymKind_LPROCREF:{result = str8_lit("LPROCREF");}break; +case CV_SymKind_ANNOTATIONREF:{result = str8_lit("ANNOTATIONREF");}break; +case CV_SymKind_TOKENREF:{result = str8_lit("TOKENREF");}break; +case CV_SymKind_GMANPROC:{result = str8_lit("GMANPROC");}break; +case CV_SymKind_LMANPROC:{result = str8_lit("LMANPROC");}break; +case CV_SymKind_TRAMPOLINE:{result = str8_lit("TRAMPOLINE");}break; +case CV_SymKind_MANCONSTANT:{result = str8_lit("MANCONSTANT");}break; +case CV_SymKind_ATTR_FRAMEREL:{result = str8_lit("ATTR_FRAMEREL");}break; +case CV_SymKind_ATTR_REGISTER:{result = str8_lit("ATTR_REGISTER");}break; +case CV_SymKind_ATTR_REGREL:{result = str8_lit("ATTR_REGREL");}break; +case CV_SymKind_ATTR_MANYREG:{result = str8_lit("ATTR_MANYREG");}break; +case CV_SymKind_SEPCODE:{result = str8_lit("SEPCODE");}break; +case CV_SymKind_DEFRANGE_2005:{result = str8_lit("DEFRANGE_2005");}break; +case CV_SymKind_DEFRANGE2_2005:{result = str8_lit("DEFRANGE2_2005");}break; +case CV_SymKind_SECTION:{result = str8_lit("SECTION");}break; +case CV_SymKind_COFFGROUP:{result = str8_lit("COFFGROUP");}break; +case CV_SymKind_EXPORT:{result = str8_lit("EXPORT");}break; +case CV_SymKind_CALLSITEINFO:{result = str8_lit("CALLSITEINFO");}break; +case CV_SymKind_FRAMECOOKIE:{result = str8_lit("FRAMECOOKIE");}break; +case CV_SymKind_DISCARDED:{result = str8_lit("DISCARDED");}break; +case CV_SymKind_COMPILE3:{result = str8_lit("COMPILE3");}break; +case CV_SymKind_ENVBLOCK:{result = str8_lit("ENVBLOCK");}break; +case CV_SymKind_LOCAL:{result = str8_lit("LOCAL");}break; +case CV_SymKind_DEFRANGE:{result = str8_lit("DEFRANGE");}break; +case CV_SymKind_DEFRANGE_SUBFIELD:{result = str8_lit("DEFRANGE_SUBFIELD");}break; +case CV_SymKind_DEFRANGE_REGISTER:{result = str8_lit("DEFRANGE_REGISTER");}break; +case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL");}break; +case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = str8_lit("DEFRANGE_SUBFIELD_REGISTER");}break; +case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = str8_lit("DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE");}break; +case CV_SymKind_DEFRANGE_REGISTER_REL:{result = str8_lit("DEFRANGE_REGISTER_REL");}break; +case CV_SymKind_LPROC32_ID:{result = str8_lit("LPROC32_ID");}break; +case CV_SymKind_GPROC32_ID:{result = str8_lit("GPROC32_ID");}break; +case CV_SymKind_LPROCMIPS_ID:{result = str8_lit("LPROCMIPS_ID");}break; +case CV_SymKind_GPROCMIPS_ID:{result = str8_lit("GPROCMIPS_ID");}break; +case CV_SymKind_LPROCIA64_ID:{result = str8_lit("LPROCIA64_ID");}break; +case CV_SymKind_GPROCIA64_ID:{result = str8_lit("GPROCIA64_ID");}break; +case CV_SymKind_BUILDINFO:{result = str8_lit("BUILDINFO");}break; +case CV_SymKind_INLINESITE:{result = str8_lit("INLINESITE");}break; +case CV_SymKind_INLINESITE_END:{result = str8_lit("INLINESITE_END");}break; +case CV_SymKind_PROC_ID_END:{result = str8_lit("PROC_ID_END");}break; +case CV_SymKind_DEFRANGE_HLSL:{result = str8_lit("DEFRANGE_HLSL");}break; +case CV_SymKind_GDATA_HLSL:{result = str8_lit("GDATA_HLSL");}break; +case CV_SymKind_LDATA_HLSL:{result = str8_lit("LDATA_HLSL");}break; +case CV_SymKind_FILESTATIC:{result = str8_lit("FILESTATIC");}break; +case CV_SymKind_LPROC32_DPC:{result = str8_lit("LPROC32_DPC");}break; +case CV_SymKind_LPROC32_DPC_ID:{result = str8_lit("LPROC32_DPC_ID");}break; +case CV_SymKind_DEFRANGE_DPC_PTR_TAG:{result = str8_lit("DEFRANGE_DPC_PTR_TAG");}break; +case CV_SymKind_DPC_SYM_TAG_MAP:{result = str8_lit("DPC_SYM_TAG_MAP");}break; +case CV_SymKind_ARMSWITCHTABLE:{result = str8_lit("ARMSWITCHTABLE");}break; +case CV_SymKind_CALLEES:{result = str8_lit("CALLEES");}break; +case CV_SymKind_CALLERS:{result = str8_lit("CALLERS");}break; +case CV_SymKind_POGODATA:{result = str8_lit("POGODATA");}break; +case CV_SymKind_INLINESITE2:{result = str8_lit("INLINESITE2");}break; +case CV_SymKind_HEAPALLOCSITE:{result = str8_lit("HEAPALLOCSITE");}break; +case CV_SymKind_MOD_TYPEREF:{result = str8_lit("MOD_TYPEREF");}break; +case CV_SymKind_REF_MINIPDB:{result = str8_lit("REF_MINIPDB");}break; +case CV_SymKind_PDBMAP:{result = str8_lit("PDBMAP");}break; +case CV_SymKind_GDATA_HLSL32:{result = str8_lit("GDATA_HLSL32");}break; +case CV_SymKind_LDATA_HLSL32:{result = str8_lit("LDATA_HLSL32");}break; +case CV_SymKind_GDATA_HLSL32_EX:{result = str8_lit("GDATA_HLSL32_EX");}break; +case CV_SymKind_LDATA_HLSL32_EX:{result = str8_lit("LDATA_HLSL32_EX");}break; +case CV_SymKind_FASTLINK:{result = str8_lit("FASTLINK");}break; +case CV_SymKind_INLINEES:{result = str8_lit("INLINEES");}break; +} +return result; +} + +internal String8 +cv_string_from_basic_type(CV_BasicType v) +{ +String8 result = str8_lit(""); +switch(v) +{ +default:{}break; +case CV_BasicType_NOTYPE:{result = str8_lit("NOTYPE");}break; +case CV_BasicType_ABS:{result = str8_lit("ABS");}break; +case CV_BasicType_SEGMENT:{result = str8_lit("SEGMENT");}break; +case CV_BasicType_VOID:{result = str8_lit("VOID");}break; +case CV_BasicType_CURRENCY:{result = str8_lit("CURRENCY");}break; +case CV_BasicType_NBASICSTR:{result = str8_lit("NBASICSTR");}break; +case CV_BasicType_FBASICSTR:{result = str8_lit("FBASICSTR");}break; +case CV_BasicType_NOTTRANS:{result = str8_lit("NOTTRANS");}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("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("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("COMPLEX32");}break; +case CV_BasicType_COMPLEX64:{result = str8_lit("COMPLEX64");}break; +case CV_BasicType_COMPLEX80:{result = str8_lit("COMPLEX80");}break; +case CV_BasicType_COMPLEX128:{result = str8_lit("COMPLEX128");}break; +case CV_BasicType_BIT:{result = str8_lit("BIT");}break; +case CV_BasicType_PASCHAR:{result = str8_lit("PASCHAR");}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("RCHAR");}break; +case CV_BasicType_WCHAR:{result = str8_lit("WCHAR");}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("CHAR8");}break; +case CV_BasicType_PTR:{result = str8_lit("PTR");}break; +} +return result; +} + +internal String8 +cv_type_name_from_basic_type(CV_BasicType v) +{ +String8 result = str8_lit(""); +switch(v) +{ +default:{}break; +case CV_BasicType_NOTYPE:{result = str8_lit("");}break; +case CV_BasicType_ABS:{result = str8_lit("");}break; +case CV_BasicType_SEGMENT:{result = str8_lit("");}break; +case CV_BasicType_VOID:{result = str8_lit("void");}break; +case CV_BasicType_CURRENCY:{result = str8_lit("");}break; +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_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_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_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_CHAR8:{result = str8_lit("char");}break; +case CV_BasicType_PTR:{result = str8_lit("PTR");}break; +} +return result; +} + +internal String8 +cv_string_from_leaf_kind(CV_LeafKind v) +{ +String8 result = str8_lit(""); +switch(v) +{ +default:{}break; +case CV_LeafKind_MODIFIER_16t:{result = str8_lit("MODIFIER_16t");}break; +case CV_LeafKind_POINTER_16t:{result = str8_lit("POINTER_16t");}break; +case CV_LeafKind_ARRAY_16t:{result = str8_lit("ARRAY_16t");}break; +case CV_LeafKind_CLASS_16t:{result = str8_lit("CLASS_16t");}break; +case CV_LeafKind_STRUCTURE_16t:{result = str8_lit("STRUCTURE_16t");}break; +case CV_LeafKind_UNION_16t:{result = str8_lit("UNION_16t");}break; +case CV_LeafKind_ENUM_16t:{result = str8_lit("ENUM_16t");}break; +case CV_LeafKind_PROCEDURE_16t:{result = str8_lit("PROCEDURE_16t");}break; +case CV_LeafKind_MFUNCTION_16t:{result = str8_lit("MFUNCTION_16t");}break; +case CV_LeafKind_VTSHAPE:{result = str8_lit("VTSHAPE");}break; +case CV_LeafKind_COBOL0_16t:{result = str8_lit("COBOL0_16t");}break; +case CV_LeafKind_COBOL1:{result = str8_lit("COBOL1");}break; +case CV_LeafKind_BARRAY_16t:{result = str8_lit("BARRAY_16t");}break; +case CV_LeafKind_LABEL:{result = str8_lit("LABEL");}break; +case CV_LeafKind_NULL:{result = str8_lit("NULL");}break; +case CV_LeafKind_NOTTRAN:{result = str8_lit("NOTTRAN");}break; +case CV_LeafKind_DIMARRAY_16t:{result = str8_lit("DIMARRAY_16t");}break; +case CV_LeafKind_VFTPATH_16t:{result = str8_lit("VFTPATH_16t");}break; +case CV_LeafKind_PRECOMP_16t:{result = str8_lit("PRECOMP_16t");}break; +case CV_LeafKind_ENDPRECOMP:{result = str8_lit("ENDPRECOMP");}break; +case CV_LeafKind_OEM_16t:{result = str8_lit("OEM_16t");}break; +case CV_LeafKind_TYPESERVER_ST:{result = str8_lit("TYPESERVER_ST");}break; +case CV_LeafKind_SKIP_16t:{result = str8_lit("SKIP_16t");}break; +case CV_LeafKind_ARGLIST_16t:{result = str8_lit("ARGLIST_16t");}break; +case CV_LeafKind_DEFARG_16t:{result = str8_lit("DEFARG_16t");}break; +case CV_LeafKind_LIST:{result = str8_lit("LIST");}break; +case CV_LeafKind_FIELDLIST_16t:{result = str8_lit("FIELDLIST_16t");}break; +case CV_LeafKind_DERIVED_16t:{result = str8_lit("DERIVED_16t");}break; +case CV_LeafKind_BITFIELD_16t:{result = str8_lit("BITFIELD_16t");}break; +case CV_LeafKind_METHODLIST_16t:{result = str8_lit("METHODLIST_16t");}break; +case CV_LeafKind_DIMCONU_16t:{result = str8_lit("DIMCONU_16t");}break; +case CV_LeafKind_DIMCONLU_16t:{result = str8_lit("DIMCONLU_16t");}break; +case CV_LeafKind_DIMVARU_16t:{result = str8_lit("DIMVARU_16t");}break; +case CV_LeafKind_DIMVARLU_16t:{result = str8_lit("DIMVARLU_16t");}break; +case CV_LeafKind_REFSYM:{result = str8_lit("REFSYM");}break; +case CV_LeafKind_BCLASS_16t:{result = str8_lit("BCLASS_16t");}break; +case CV_LeafKind_VBCLASS_16t:{result = str8_lit("VBCLASS_16t");}break; +case CV_LeafKind_IVBCLASS_16t:{result = str8_lit("IVBCLASS_16t");}break; +case CV_LeafKind_ENUMERATE_ST:{result = str8_lit("ENUMERATE_ST");}break; +case CV_LeafKind_FRIENDFCN_16t:{result = str8_lit("FRIENDFCN_16t");}break; +case CV_LeafKind_INDEX_16t:{result = str8_lit("INDEX_16t");}break; +case CV_LeafKind_MEMBER_16t:{result = str8_lit("MEMBER_16t");}break; +case CV_LeafKind_STMEMBER_16t:{result = str8_lit("STMEMBER_16t");}break; +case CV_LeafKind_METHOD_16t:{result = str8_lit("METHOD_16t");}break; +case CV_LeafKind_NESTTYPE_16t:{result = str8_lit("NESTTYPE_16t");}break; +case CV_LeafKind_VFUNCTAB_16t:{result = str8_lit("VFUNCTAB_16t");}break; +case CV_LeafKind_FRIENDCLS_16t:{result = str8_lit("FRIENDCLS_16t");}break; +case CV_LeafKind_ONEMETHOD_16t:{result = str8_lit("ONEMETHOD_16t");}break; +case CV_LeafKind_VFUNCOFF_16t:{result = str8_lit("VFUNCOFF_16t");}break; +case CV_LeafKind_TI16_MAX:{result = str8_lit("TI16_MAX");}break; +case CV_LeafKind_MODIFIER:{result = str8_lit("MODIFIER");}break; +case CV_LeafKind_POINTER:{result = str8_lit("POINTER");}break; +case CV_LeafKind_ARRAY_ST:{result = str8_lit("ARRAY_ST");}break; +case CV_LeafKind_CLASS_ST:{result = str8_lit("CLASS_ST");}break; +case CV_LeafKind_STRUCTURE_ST:{result = str8_lit("STRUCTURE_ST");}break; +case CV_LeafKind_UNION_ST:{result = str8_lit("UNION_ST");}break; +case CV_LeafKind_ENUM_ST:{result = str8_lit("ENUM_ST");}break; +case CV_LeafKind_PROCEDURE:{result = str8_lit("PROCEDURE");}break; +case CV_LeafKind_MFUNCTION:{result = str8_lit("MFUNCTION");}break; +case CV_LeafKind_COBOL0:{result = str8_lit("COBOL0");}break; +case CV_LeafKind_BARRAY:{result = str8_lit("BARRAY");}break; +case CV_LeafKind_DIMARRAY_ST:{result = str8_lit("DIMARRAY_ST");}break; +case CV_LeafKind_VFTPATH:{result = str8_lit("VFTPATH");}break; +case CV_LeafKind_PRECOMP_ST:{result = str8_lit("PRECOMP_ST");}break; +case CV_LeafKind_OEM:{result = str8_lit("OEM");}break; +case CV_LeafKind_ALIAS_ST:{result = str8_lit("ALIAS_ST");}break; +case CV_LeafKind_OEM2:{result = str8_lit("OEM2");}break; +case CV_LeafKind_SKIP:{result = str8_lit("SKIP");}break; +case CV_LeafKind_ARGLIST:{result = str8_lit("ARGLIST");}break; +case CV_LeafKind_DEFARG_ST:{result = str8_lit("DEFARG_ST");}break; +case CV_LeafKind_FIELDLIST:{result = str8_lit("FIELDLIST");}break; +case CV_LeafKind_DERIVED:{result = str8_lit("DERIVED");}break; +case CV_LeafKind_BITFIELD:{result = str8_lit("BITFIELD");}break; +case CV_LeafKind_METHODLIST:{result = str8_lit("METHODLIST");}break; +case CV_LeafKind_DIMCONU:{result = str8_lit("DIMCONU");}break; +case CV_LeafKind_DIMCONLU:{result = str8_lit("DIMCONLU");}break; +case CV_LeafKind_DIMVARU:{result = str8_lit("DIMVARU");}break; +case CV_LeafKind_DIMVARLU:{result = str8_lit("DIMVARLU");}break; +case CV_LeafKind_BCLASS:{result = str8_lit("BCLASS");}break; +case CV_LeafKind_VBCLASS:{result = str8_lit("VBCLASS");}break; +case CV_LeafKind_IVBCLASS:{result = str8_lit("IVBCLASS");}break; +case CV_LeafKind_FRIENDFCN_ST:{result = str8_lit("FRIENDFCN_ST");}break; +case CV_LeafKind_INDEX:{result = str8_lit("INDEX");}break; +case CV_LeafKind_MEMBER_ST:{result = str8_lit("MEMBER_ST");}break; +case CV_LeafKind_STMEMBER_ST:{result = str8_lit("STMEMBER_ST");}break; +case CV_LeafKind_METHOD_ST:{result = str8_lit("METHOD_ST");}break; +case CV_LeafKind_NESTTYPE_ST:{result = str8_lit("NESTTYPE_ST");}break; +case CV_LeafKind_VFUNCTAB:{result = str8_lit("VFUNCTAB");}break; +case CV_LeafKind_FRIENDCLS:{result = str8_lit("FRIENDCLS");}break; +case CV_LeafKind_ONEMETHOD_ST:{result = str8_lit("ONEMETHOD_ST");}break; +case CV_LeafKind_VFUNCOFF:{result = str8_lit("VFUNCOFF");}break; +case CV_LeafKind_NESTTYPEEX_ST:{result = str8_lit("NESTTYPEEX_ST");}break; +case CV_LeafKind_MEMBERMODIFY_ST:{result = str8_lit("MEMBERMODIFY_ST");}break; +case CV_LeafKind_MANAGED_ST:{result = str8_lit("MANAGED_ST");}break; +case CV_LeafKind_ST_MAX:{result = str8_lit("ST_MAX");}break; +case CV_LeafKind_TYPESERVER:{result = str8_lit("TYPESERVER");}break; +case CV_LeafKind_ENUMERATE:{result = str8_lit("ENUMERATE");}break; +case CV_LeafKind_ARRAY:{result = str8_lit("ARRAY");}break; +case CV_LeafKind_CLASS:{result = str8_lit("CLASS");}break; +case CV_LeafKind_STRUCTURE:{result = str8_lit("STRUCTURE");}break; +case CV_LeafKind_UNION:{result = str8_lit("UNION");}break; +case CV_LeafKind_ENUM:{result = str8_lit("ENUM");}break; +case CV_LeafKind_DIMARRAY:{result = str8_lit("DIMARRAY");}break; +case CV_LeafKind_PRECOMP:{result = str8_lit("PRECOMP");}break; +case CV_LeafKind_ALIAS:{result = str8_lit("ALIAS");}break; +case CV_LeafKind_DEFARG:{result = str8_lit("DEFARG");}break; +case CV_LeafKind_FRIENDFCN:{result = str8_lit("FRIENDFCN");}break; +case CV_LeafKind_MEMBER:{result = str8_lit("MEMBER");}break; +case CV_LeafKind_STMEMBER:{result = str8_lit("STMEMBER");}break; +case CV_LeafKind_METHOD:{result = str8_lit("METHOD");}break; +case CV_LeafKind_NESTTYPE:{result = str8_lit("NESTTYPE");}break; +case CV_LeafKind_ONEMETHOD:{result = str8_lit("ONEMETHOD");}break; +case CV_LeafKind_NESTTYPEEX:{result = str8_lit("NESTTYPEEX");}break; +case CV_LeafKind_MEMBERMODIFY:{result = str8_lit("MEMBERMODIFY");}break; +case CV_LeafKind_MANAGED:{result = str8_lit("MANAGED");}break; +case CV_LeafKind_TYPESERVER2:{result = str8_lit("TYPESERVER2");}break; +case CV_LeafKind_STRIDED_ARRAY:{result = str8_lit("STRIDED_ARRAY");}break; +case CV_LeafKind_HLSL:{result = str8_lit("HLSL");}break; +case CV_LeafKind_MODIFIER_EX:{result = str8_lit("MODIFIER_EX");}break; +case CV_LeafKind_INTERFACE:{result = str8_lit("INTERFACE");}break; +case CV_LeafKind_BINTERFACE:{result = str8_lit("BINTERFACE");}break; +case CV_LeafKind_VECTOR:{result = str8_lit("VECTOR");}break; +case CV_LeafKind_MATRIX:{result = str8_lit("MATRIX");}break; +case CV_LeafKind_VFTABLE:{result = str8_lit("VFTABLE");}break; +case CV_LeafKind_CLASS2:{result = str8_lit("CLASS2");}break; +case CV_LeafKind_STRUCT2:{result = str8_lit("STRUCT2");}break; +} +return result; +} + +internal U64 +cv_header_struct_size_from_sym_kind(CV_SymKind v) +{ +U64 result = 0; +switch(v) +{ +default:{}break; +case CV_SymKind_COMPILE:{result = sizeof(CV_SymCompile);}break; +case CV_SymKind_SSEARCH:{result = sizeof(CV_SymStartSearch);}break; +case CV_SymKind_RETURN:{result = sizeof(CV_SymReturn);}break; +case CV_SymKind_SLINK32:{result = sizeof(CV_SymSLink32);}break; +case CV_SymKind_OEM:{result = sizeof(CV_SymOEM);}break; +case CV_SymKind_VFTABLE32:{result = sizeof(CV_SymVPath32);}break; +case CV_SymKind_FRAMEPROC:{result = sizeof(CV_SymFrameproc);}break; +case CV_SymKind_ANNOTATION:{result = sizeof(CV_SymAnnotation);}break; +case CV_SymKind_OBJNAME:{result = sizeof(CV_SymObjname);}break; +case CV_SymKind_THUNK32:{result = sizeof(CV_SymThunk32);}break; +case CV_SymKind_BLOCK32:{result = sizeof(CV_SymBlock32);}break; +case CV_SymKind_LABEL32:{result = sizeof(CV_SymLabel32);}break; +case CV_SymKind_REGISTER:{result = sizeof(CV_SymRegister);}break; +case CV_SymKind_CONSTANT:{result = sizeof(CV_SymConstant);}break; +case CV_SymKind_UDT:{result = sizeof(CV_SymUDT);}break; +case CV_SymKind_MANYREG:{result = sizeof(CV_SymManyreg);}break; +case CV_SymKind_BPREL32:{result = sizeof(CV_SymBPRel32);}break; +case CV_SymKind_LDATA32:{result = sizeof(CV_SymData32);}break; +case CV_SymKind_GDATA32:{result = sizeof(CV_SymData32);}break; +case CV_SymKind_PUB32:{result = sizeof(CV_SymPub32);}break; +case CV_SymKind_LPROC32:{result = sizeof(CV_SymProc32);}break; +case CV_SymKind_GPROC32:{result = sizeof(CV_SymProc32);}break; +case CV_SymKind_REGREL32:{result = sizeof(CV_SymRegrel32);}break; +case CV_SymKind_LTHREAD32:{result = sizeof(CV_SymThread32);}break; +case CV_SymKind_GTHREAD32:{result = sizeof(CV_SymThread32);}break; +case CV_SymKind_COMPILE2:{result = sizeof(CV_SymCompile2);}break; +case CV_SymKind_MANYREG2:{result = sizeof(CV_SymManyreg2);}break; +case CV_SymKind_LOCALSLOT:{result = sizeof(CV_SymSlot);}break; +case CV_SymKind_MANFRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break; +case CV_SymKind_MANREGISTER:{result = sizeof(CV_SymAttrReg);}break; +case CV_SymKind_MANMANYREG:{result = sizeof(CV_SymAttrManyReg);}break; +case CV_SymKind_MANREGREL:{result = sizeof(CV_SymAttrRegRel);}break; +case CV_SymKind_UNAMESPACE:{result = sizeof(CV_SymUNamespace);}break; +case CV_SymKind_PROCREF:{result = sizeof(CV_SymRef2);}break; +case CV_SymKind_DATAREF:{result = sizeof(CV_SymRef2);}break; +case CV_SymKind_LPROCREF:{result = sizeof(CV_SymRef2);}break; +case CV_SymKind_TRAMPOLINE:{result = sizeof(CV_SymTrampoline);}break; +case CV_SymKind_ATTR_FRAMEREL:{result = sizeof(CV_SymAttrFrameRel);}break; +case CV_SymKind_ATTR_REGISTER:{result = sizeof(CV_SymAttrReg);}break; +case CV_SymKind_ATTR_REGREL:{result = sizeof(CV_SymAttrRegRel);}break; +case CV_SymKind_ATTR_MANYREG:{result = sizeof(CV_SymAttrManyReg);}break; +case CV_SymKind_SEPCODE:{result = sizeof(CV_SymSepcode);}break; +case CV_SymKind_SECTION:{result = sizeof(CV_SymSection);}break; +case CV_SymKind_COFFGROUP:{result = sizeof(CV_SymCoffGroup);}break; +case CV_SymKind_EXPORT:{result = sizeof(CV_SymExport);}break; +case CV_SymKind_CALLSITEINFO:{result = sizeof(CV_SymCallSiteInfo);}break; +case CV_SymKind_FRAMECOOKIE:{result = sizeof(CV_SymFrameCookie);}break; +case CV_SymKind_DISCARDED:{result = sizeof(CV_SymDiscarded);}break; +case CV_SymKind_COMPILE3:{result = sizeof(CV_SymCompile3);}break; +case CV_SymKind_ENVBLOCK:{result = sizeof(CV_SymEnvBlock);}break; +case CV_SymKind_LOCAL:{result = sizeof(CV_SymLocal);}break; +case CV_SymKind_DEFRANGE_SUBFIELD:{result = sizeof(CV_SymDefrangeSubfield);}break; +case CV_SymKind_DEFRANGE_REGISTER:{result = sizeof(CV_SymDefrangeRegister);}break; +case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL:{result = sizeof(CV_SymDefrangeFramepointerRel);}break; +case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER:{result = sizeof(CV_SymDefrangeSubfieldRegister);}break; +case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:{result = sizeof(CV_SymDefrangeFramepointerRelFullScope);}break; +case CV_SymKind_DEFRANGE_REGISTER_REL:{result = sizeof(CV_SymDefrangeRegisterRel);}break; +case CV_SymKind_BUILDINFO:{result = sizeof(CV_SymBuildInfo);}break; +case CV_SymKind_INLINESITE:{result = sizeof(CV_SymInlineSite);}break; +case CV_SymKind_FILESTATIC:{result = sizeof(CV_SymFileStatic);}break; +case CV_SymKind_CALLEES:{result = sizeof(CV_SymFunctionList);}break; +case CV_SymKind_CALLERS:{result = sizeof(CV_SymFunctionList);}break; +case CV_SymKind_POGODATA:{result = sizeof(CV_SymPogoInfo);}break; +case CV_SymKind_INLINESITE2:{result = sizeof(CV_SymInlineSite2);}break; +case CV_SymKind_HEAPALLOCSITE:{result = sizeof(CV_SymHeapAllocSite);}break; +case CV_SymKind_MOD_TYPEREF:{result = sizeof(CV_SymModTypeRef);}break; +case CV_SymKind_REF_MINIPDB:{result = sizeof(CV_SymRefMiniPdb);}break; +case CV_SymKind_FASTLINK:{result = sizeof(CV_SymFastLink);}break; +case CV_SymKind_INLINEES:{result = sizeof(CV_SymInlinees);}break; +} +return result; +} +internal U64 +cv_header_struct_size_from_leaf_kind(CV_LeafKind v) +{ +U64 result = 0; +switch(v) +{ +default:{}break; +case CV_LeafKind_VTSHAPE:{result = sizeof(CV_LeafVTShape);}break; +case CV_LeafKind_LABEL:{result = sizeof(CV_LeafLabel);}break; +case CV_LeafKind_MODIFIER:{result = sizeof(CV_LeafModifier);}break; +case CV_LeafKind_POINTER:{result = sizeof(CV_LeafPointer);}break; +case CV_LeafKind_PROCEDURE:{result = sizeof(CV_LeafProcedure);}break; +case CV_LeafKind_MFUNCTION:{result = sizeof(CV_LeafMFunction);}break; +case CV_LeafKind_VFTPATH:{result = sizeof(CV_LeafVFPath);}break; +case CV_LeafKind_SKIP:{result = sizeof(CV_LeafSkip);}break; +case CV_LeafKind_ARGLIST:{result = sizeof(CV_LeafArgList);}break; +case CV_LeafKind_BITFIELD:{result = sizeof(CV_LeafBitField);}break; +case CV_LeafKind_METHODLIST:{result = sizeof(CV_LeafMethodListMember);}break; +case CV_LeafKind_BCLASS:{result = sizeof(CV_LeafBClass);}break; +case CV_LeafKind_VBCLASS:{result = sizeof(CV_LeafVBClass);}break; +case CV_LeafKind_INDEX:{result = sizeof(CV_LeafIndex);}break; +case CV_LeafKind_VFUNCTAB:{result = sizeof(CV_LeafVFuncTab);}break; +case CV_LeafKind_VFUNCOFF:{result = sizeof(CV_LeafVFuncOff);}break; +case CV_LeafKind_TYPESERVER:{result = sizeof(CV_LeafTypeServer);}break; +case CV_LeafKind_ENUMERATE:{result = sizeof(CV_LeafEnumerate);}break; +case CV_LeafKind_ARRAY:{result = sizeof(CV_LeafArray);}break; +case CV_LeafKind_CLASS:{result = sizeof(CV_LeafStruct);}break; +case CV_LeafKind_STRUCTURE:{result = sizeof(CV_LeafStruct);}break; +case CV_LeafKind_UNION:{result = sizeof(CV_LeafUnion);}break; +case CV_LeafKind_ENUM:{result = sizeof(CV_LeafEnum);}break; +case CV_LeafKind_PRECOMP:{result = sizeof(CV_LeafPreComp);}break; +case CV_LeafKind_ALIAS:{result = sizeof(CV_LeafAlias);}break; +case CV_LeafKind_MEMBER:{result = sizeof(CV_LeafMember);}break; +case CV_LeafKind_STMEMBER:{result = sizeof(CV_LeafStMember);}break; +case CV_LeafKind_METHOD:{result = sizeof(CV_LeafMethod);}break; +case CV_LeafKind_NESTTYPE:{result = sizeof(CV_LeafNestType);}break; +case CV_LeafKind_ONEMETHOD:{result = sizeof(CV_LeafOneMethod);}break; +case CV_LeafKind_NESTTYPEEX:{result = sizeof(CV_LeafNestTypeEx);}break; +case CV_LeafKind_TYPESERVER2:{result = sizeof(CV_LeafTypeServer2);}break; +case CV_LeafKind_INTERFACE:{result = sizeof(CV_LeafStruct);}break; +case CV_LeafKind_CLASS2:{result = sizeof(CV_LeafStruct2);}break; +case CV_LeafKind_STRUCT2:{result = sizeof(CV_LeafStruct2);}break; +} +return result; +} +C_LINKAGE_BEGIN +C_LINKAGE_END + diff --git a/src/codeview/generated/codeview.meta.h b/src/codeview/generated/codeview.meta.h new file mode 100644 index 00000000..b30192a7 --- /dev/null +++ b/src/codeview/generated/codeview.meta.h @@ -0,0 +1,523 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef CODEVIEW_META_H +#define CODEVIEW_META_H + +typedef U16 CV_NumericKind; +typedef enum CV_NumericKindEnum +{ +CV_NumericKind_CHAR = 0x8000, +CV_NumericKind_SHORT = 0x8001, +CV_NumericKind_USHORT = 0x8002, +CV_NumericKind_LONG = 0x8003, +CV_NumericKind_ULONG = 0x8004, +CV_NumericKind_FLOAT32 = 0x8005, +CV_NumericKind_FLOAT64 = 0x8006, +CV_NumericKind_FLOAT80 = 0x8007, +CV_NumericKind_FLOAT128 = 0x8008, +CV_NumericKind_QUADWORD = 0x8009, +CV_NumericKind_UQUADWORD = 0x800a, +CV_NumericKind_FLOAT48 = 0x800b, +CV_NumericKind_COMPLEX32 = 0x800c, +CV_NumericKind_COMPLEX64 = 0x800d, +CV_NumericKind_COMPLEX80 = 0x800e, +CV_NumericKind_COMPLEX128 = 0x800f, +CV_NumericKind_VARSTRING = 0x8010, +CV_NumericKind_OCTWORD = 0x8017, +CV_NumericKind_UOCTWORD = 0x8018, +CV_NumericKind_DECIMAL = 0x8019, +CV_NumericKind_DATE = 0x801a, +CV_NumericKind_UTF8STRING = 0x801b, +CV_NumericKind_FLOAT16 = 0x801c, +} CV_NumericKindEnum; + +typedef U16 CV_Arch; +typedef enum CV_ArchEnum +{ +CV_Arch_8080 = 0x00, +CV_Arch_8086 = 0x01, +CV_Arch_80286 = 0x02, +CV_Arch_80386 = 0x03, +CV_Arch_80486 = 0x04, +CV_Arch_PENTIUM = 0x05, +CV_Arch_PENTIUMII = 0x06, +CV_Arch_PENTIUMIII = 0x07, +CV_Arch_MIPS = 0x10, +CV_Arch_MIPS16 = 0x11, +CV_Arch_MIPS32 = 0x12, +CV_Arch_MIPS64 = 0x13, +CV_Arch_MIPSI = 0x14, +CV_Arch_MIPSII = 0x15, +CV_Arch_MIPSIII = 0x16, +CV_Arch_MIPSIV = 0x17, +CV_Arch_MIPSV = 0x18, +CV_Arch_M68000 = 0x20, +CV_Arch_M68010 = 0x21, +CV_Arch_M68020 = 0x22, +CV_Arch_M68030 = 0x23, +CV_Arch_M68040 = 0x24, +CV_Arch_ALPHA = 0x30, +CV_Arch_ALPHA_21164 = 0x31, +CV_Arch_ALPHA_21164A = 0x32, +CV_Arch_ALPHA_21264 = 0x33, +CV_Arch_ALPHA_21364 = 0x34, +CV_Arch_PPC601 = 0x40, +CV_Arch_PPC603 = 0x41, +CV_Arch_PPC604 = 0x42, +CV_Arch_PPC620 = 0x43, +CV_Arch_PPCFP = 0x44, +CV_Arch_PPCBE = 0x45, +CV_Arch_SH3 = 0x50, +CV_Arch_SH3E = 0x51, +CV_Arch_SH3DSP = 0x52, +CV_Arch_SH4 = 0x53, +CV_Arch_SHMEDIA = 0x54, +CV_Arch_ARM3 = 0x60, +CV_Arch_ARM4 = 0x61, +CV_Arch_ARM4T = 0x62, +CV_Arch_ARM5 = 0x63, +CV_Arch_ARM5T = 0x64, +CV_Arch_ARM6 = 0x65, +CV_Arch_ARM_XMAC = 0x66, +CV_Arch_ARM_WMMX = 0x67, +CV_Arch_ARM7 = 0x68, +CV_Arch_OMNI = 0x70, +CV_Arch_IA64_1 = 0x80, +CV_Arch_IA64_2 = 0x81, +CV_Arch_CEE = 0x90, +CV_Arch_AM33 = 0xA0, +CV_Arch_M32R = 0xB0, +CV_Arch_TRICORE = 0xC0, +CV_Arch_X64 = 0xD0, +CV_Arch_EBC = 0xE0, +CV_Arch_THUMB = 0xF0, +CV_Arch_ARMNT = 0xF4, +CV_Arch_ARM64 = 0xF6, +CV_Arch_D3D11_SHADER = 0x100, +CV_Arch_IA64 = CV_Arch_IA64_1, +CV_Arch_PENTIUMPRO = CV_Arch_PENTIUMII, +CV_Arch_MIPSR4000 = CV_Arch_MIPS, +CV_Arch_ALPHA_21064 = CV_Arch_ALPHA, +CV_Arch_AMD64 = CV_Arch_X64, +} CV_ArchEnum; + +typedef U16 CV_AllReg; +typedef enum CV_AllRegEnum +{ +CV_AllReg_ERR = 30000, +CV_AllReg_TEB = 30001, +CV_AllReg_TIMER = 30002, +CV_AllReg_EFAD1 = 30003, +CV_AllReg_EFAD2 = 30004, +CV_AllReg_EFAD3 = 30005, +CV_AllReg_VFRAME = 30006, +CV_AllReg_HANDLE = 30007, +CV_AllReg_PARAMS = 30008, +CV_AllReg_LOCALS = 30009, +CV_AllReg_TID = 30010, +CV_AllReg_ENV = 30011, +CV_AllReg_CMDLN = 30012, +} CV_AllRegEnum; + +typedef U16 CV_SymKind; +typedef enum CV_SymKindEnum +{ +CV_SymKind_COMPILE = 0x0001, +CV_SymKind_REGISTER_16t = 0x0002, +CV_SymKind_CONSTANT_16t = 0x0003, +CV_SymKind_UDT_16t = 0x0004, +CV_SymKind_SSEARCH = 0x0005, +CV_SymKind_END = 0x0006, +CV_SymKind_SKIP = 0x0007, +CV_SymKind_CVRESERVE = 0x0008, +CV_SymKind_OBJNAME_ST = 0x0009, +CV_SymKind_ENDARG = 0x000a, +CV_SymKind_COBOLUDT_16t = 0x000b, +CV_SymKind_MANYREG_16t = 0x000c, +CV_SymKind_RETURN = 0x000d, +CV_SymKind_ENTRYTHIS = 0x000e, +CV_SymKind_BPREL16 = 0x0100, +CV_SymKind_LDATA16 = 0x0101, +CV_SymKind_GDATA16 = 0x0102, +CV_SymKind_PUB16 = 0x0103, +CV_SymKind_LPROC16 = 0x0104, +CV_SymKind_GPROC16 = 0x0105, +CV_SymKind_THUNK16 = 0x0106, +CV_SymKind_BLOCK16 = 0x0107, +CV_SymKind_WITH16 = 0x0108, +CV_SymKind_LABEL16 = 0x0109, +CV_SymKind_CEXMODEL16 = 0x010a, +CV_SymKind_VFTABLE16 = 0x010b, +CV_SymKind_REGREL16 = 0x010c, +CV_SymKind_BPREL32_16t = 0x0200, +CV_SymKind_LDATA32_16t = 0x0201, +CV_SymKind_GDATA32_16t = 0x0202, +CV_SymKind_PUB32_16t = 0x0203, +CV_SymKind_LPROC32_16t = 0x0204, +CV_SymKind_GPROC32_16t = 0x0205, +CV_SymKind_THUNK32_ST = 0x0206, +CV_SymKind_BLOCK32_ST = 0x0207, +CV_SymKind_WITH32_ST = 0x0208, +CV_SymKind_LABEL32_ST = 0x0209, +CV_SymKind_CEXMODEL32 = 0x020a, +CV_SymKind_VFTABLE32_16t = 0x020b, +CV_SymKind_REGREL32_16t = 0x020c, +CV_SymKind_LTHREAD32_16t = 0x020d, +CV_SymKind_GTHREAD32_16t = 0x020e, +CV_SymKind_SLINK32 = 0x020f, +CV_SymKind_LPROCMIPS_16t = 0x0300, +CV_SymKind_GPROCMIPS_16t = 0x0301, +CV_SymKind_PROCREF_ST = 0x0400, +CV_SymKind_DATAREF_ST = 0x0401, +CV_SymKind_ALIGN = 0x0402, +CV_SymKind_LPROCREF_ST = 0x0403, +CV_SymKind_OEM = 0x0404, +CV_SymKind_TI16_MAX = 0x1000, +CV_SymKind_CONSTANT_ST = 0x1002, +CV_SymKind_UDT_ST = 0x1003, +CV_SymKind_COBOLUDT_ST = 0x1004, +CV_SymKind_MANYREG_ST = 0x1005, +CV_SymKind_BPREL32_ST = 0x1006, +CV_SymKind_LDATA32_ST = 0x1007, +CV_SymKind_GDATA32_ST = 0x1008, +CV_SymKind_PUB32_ST = 0x1009, +CV_SymKind_LPROC32_ST = 0x100a, +CV_SymKind_GPROC32_ST = 0x100b, +CV_SymKind_VFTABLE32 = 0x100c, +CV_SymKind_REGREL32_ST = 0x100d, +CV_SymKind_LTHREAD32_ST = 0x100e, +CV_SymKind_GTHREAD32_ST = 0x100f, +CV_SymKind_LPROCMIPS_ST = 0x1010, +CV_SymKind_GPROCMIPS_ST = 0x1011, +CV_SymKind_FRAMEPROC = 0x1012, +CV_SymKind_COMPILE2_ST = 0x1013, +CV_SymKind_MANYREG2_ST = 0x1014, +CV_SymKind_LPROCIA64_ST = 0x1015, +CV_SymKind_GPROCIA64_ST = 0x1016, +CV_SymKind_LOCALSLOT_ST = 0x1017, +CV_SymKind_PARAMSLOT_ST = 0x1018, +CV_SymKind_ANNOTATION = 0x1019, +CV_SymKind_GMANPROC_ST = 0x101a, +CV_SymKind_LMANPROC_ST = 0x101b, +CV_SymKind_RESERVED1 = 0x101c, +CV_SymKind_RESERVED2 = 0x101d, +CV_SymKind_RESERVED3 = 0x101e, +CV_SymKind_RESERVED4 = 0x101f, +CV_SymKind_LMANDATA_ST = 0x1020, +CV_SymKind_GMANDATA_ST = 0x1021, +CV_SymKind_MANFRAMEREL_ST = 0x1022, +CV_SymKind_MANREGISTER_ST = 0x1023, +CV_SymKind_MANSLOT_ST = 0x1024, +CV_SymKind_MANMANYREG_ST = 0x1025, +CV_SymKind_MANREGREL_ST = 0x1026, +CV_SymKind_MANMANYREG2_ST = 0x1027, +CV_SymKind_MANTYPREF = 0x1028, +CV_SymKind_UNAMESPACE_ST = 0x1029, +CV_SymKind_ST_MAX = 0x1100, +CV_SymKind_OBJNAME = 0x1101, +CV_SymKind_THUNK32 = 0x1102, +CV_SymKind_BLOCK32 = 0x1103, +CV_SymKind_WITH32 = 0x1104, +CV_SymKind_LABEL32 = 0x1105, +CV_SymKind_REGISTER = 0x1106, +CV_SymKind_CONSTANT = 0x1107, +CV_SymKind_UDT = 0x1108, +CV_SymKind_COBOLUDT = 0x1109, +CV_SymKind_MANYREG = 0x110a, +CV_SymKind_BPREL32 = 0x110b, +CV_SymKind_LDATA32 = 0x110c, +CV_SymKind_GDATA32 = 0x110d, +CV_SymKind_PUB32 = 0x110e, +CV_SymKind_LPROC32 = 0x110f, +CV_SymKind_GPROC32 = 0x1110, +CV_SymKind_REGREL32 = 0x1111, +CV_SymKind_LTHREAD32 = 0x1112, +CV_SymKind_GTHREAD32 = 0x1113, +CV_SymKind_LPROCMIPS = 0x1114, +CV_SymKind_GPROCMIPS = 0x1115, +CV_SymKind_COMPILE2 = 0x1116, +CV_SymKind_MANYREG2 = 0x1117, +CV_SymKind_LPROCIA64 = 0x1118, +CV_SymKind_GPROCIA64 = 0x1119, +CV_SymKind_LOCALSLOT = 0x111a, +CV_SymKind_PARAMSLOT = 0x111b, +CV_SymKind_LMANDATA = 0x111c, +CV_SymKind_GMANDATA = 0x111d, +CV_SymKind_MANFRAMEREL = 0x111e, +CV_SymKind_MANREGISTER = 0x111f, +CV_SymKind_MANSLOT = 0x1120, +CV_SymKind_MANMANYREG = 0x1121, +CV_SymKind_MANREGREL = 0x1122, +CV_SymKind_MANMANYREG2 = 0x1123, +CV_SymKind_UNAMESPACE = 0x1124, +CV_SymKind_PROCREF = 0x1125, +CV_SymKind_DATAREF = 0x1126, +CV_SymKind_LPROCREF = 0x1127, +CV_SymKind_ANNOTATIONREF = 0x1128, +CV_SymKind_TOKENREF = 0x1129, +CV_SymKind_GMANPROC = 0x112a, +CV_SymKind_LMANPROC = 0x112b, +CV_SymKind_TRAMPOLINE = 0x112c, +CV_SymKind_MANCONSTANT = 0x112d, +CV_SymKind_ATTR_FRAMEREL = 0x112e, +CV_SymKind_ATTR_REGISTER = 0x112f, +CV_SymKind_ATTR_REGREL = 0x1130, +CV_SymKind_ATTR_MANYREG = 0x1131, +CV_SymKind_SEPCODE = 0x1132, +CV_SymKind_DEFRANGE_2005 = 0x1134, +CV_SymKind_DEFRANGE2_2005 = 0x1135, +CV_SymKind_SECTION = 0x1136, +CV_SymKind_COFFGROUP = 0x1137, +CV_SymKind_EXPORT = 0x1138, +CV_SymKind_CALLSITEINFO = 0x1139, +CV_SymKind_FRAMECOOKIE = 0x113a, +CV_SymKind_DISCARDED = 0x113b, +CV_SymKind_COMPILE3 = 0x113c, +CV_SymKind_ENVBLOCK = 0x113d, +CV_SymKind_LOCAL = 0x113e, +CV_SymKind_DEFRANGE = 0x113f, +CV_SymKind_DEFRANGE_SUBFIELD = 0x1140, +CV_SymKind_DEFRANGE_REGISTER = 0x1141, +CV_SymKind_DEFRANGE_FRAMEPOINTER_REL = 0x1142, +CV_SymKind_DEFRANGE_SUBFIELD_REGISTER = 0x1143, +CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE = 0x1144, +CV_SymKind_DEFRANGE_REGISTER_REL = 0x1145, +CV_SymKind_LPROC32_ID = 0x1146, +CV_SymKind_GPROC32_ID = 0x1147, +CV_SymKind_LPROCMIPS_ID = 0x1148, +CV_SymKind_GPROCMIPS_ID = 0x1149, +CV_SymKind_LPROCIA64_ID = 0x114a, +CV_SymKind_GPROCIA64_ID = 0x114b, +CV_SymKind_BUILDINFO = 0x114c, +CV_SymKind_INLINESITE = 0x114d, +CV_SymKind_INLINESITE_END = 0x114e, +CV_SymKind_PROC_ID_END = 0x114f, +CV_SymKind_DEFRANGE_HLSL = 0x1150, +CV_SymKind_GDATA_HLSL = 0x1151, +CV_SymKind_LDATA_HLSL = 0x1152, +CV_SymKind_FILESTATIC = 0x1153, +CV_SymKind_LPROC32_DPC = 0x1155, +CV_SymKind_LPROC32_DPC_ID = 0x1156, +CV_SymKind_DEFRANGE_DPC_PTR_TAG = 0x1157, +CV_SymKind_DPC_SYM_TAG_MAP = 0x1158, +CV_SymKind_ARMSWITCHTABLE = 0x1159, +CV_SymKind_CALLEES = 0x115a, +CV_SymKind_CALLERS = 0x115b, +CV_SymKind_POGODATA = 0x115c, +CV_SymKind_INLINESITE2 = 0x115d, +CV_SymKind_HEAPALLOCSITE = 0x115e, +CV_SymKind_MOD_TYPEREF = 0x115f, +CV_SymKind_REF_MINIPDB = 0x1160, +CV_SymKind_PDBMAP = 0x1161, +CV_SymKind_GDATA_HLSL32 = 0x1162, +CV_SymKind_LDATA_HLSL32 = 0x1163, +CV_SymKind_GDATA_HLSL32_EX = 0x1164, +CV_SymKind_LDATA_HLSL32_EX = 0x1165, +CV_SymKind_FASTLINK = 0x1167, +CV_SymKind_INLINEES = 0x1168, +} CV_SymKindEnum; + +typedef U8 CV_BasicType; +typedef enum CV_BasicTypeEnum +{ +CV_BasicType_NOTYPE = 0x00, +CV_BasicType_ABS = 0x01, +CV_BasicType_SEGMENT = 0x02, +CV_BasicType_VOID = 0x03, +CV_BasicType_CURRENCY = 0x04, +CV_BasicType_NBASICSTR = 0x05, +CV_BasicType_FBASICSTR = 0x06, +CV_BasicType_NOTTRANS = 0x07, +CV_BasicType_HRESULT = 0x08, +CV_BasicType_CHAR = 0x10, +CV_BasicType_SHORT = 0x11, +CV_BasicType_LONG = 0x12, +CV_BasicType_QUAD = 0x13, +CV_BasicType_OCT = 0x14, +CV_BasicType_UCHAR = 0x20, +CV_BasicType_USHORT = 0x21, +CV_BasicType_ULONG = 0x22, +CV_BasicType_UQUAD = 0x23, +CV_BasicType_UOCT = 0x24, +CV_BasicType_BOOL8 = 0x30, +CV_BasicType_BOOL16 = 0x31, +CV_BasicType_BOOL32 = 0x32, +CV_BasicType_BOOL64 = 0x33, +CV_BasicType_FLOAT32 = 0x40, +CV_BasicType_FLOAT64 = 0x41, +CV_BasicType_FLOAT80 = 0x42, +CV_BasicType_FLOAT128 = 0x43, +CV_BasicType_FLOAT48 = 0x44, +CV_BasicType_FLOAT32PP = 0x45, +CV_BasicType_FLOAT16 = 0x46, +CV_BasicType_COMPLEX32 = 0x50, +CV_BasicType_COMPLEX64 = 0x51, +CV_BasicType_COMPLEX80 = 0x52, +CV_BasicType_COMPLEX128 = 0x53, +CV_BasicType_BIT = 0x60, +CV_BasicType_PASCHAR = 0x61, +CV_BasicType_BOOL32FF = 0x62, +CV_BasicType_INT8 = 0x68, +CV_BasicType_UINT8 = 0x69, +CV_BasicType_RCHAR = 0x70, +CV_BasicType_WCHAR = 0x71, +CV_BasicType_INT16 = 0x72, +CV_BasicType_UINT16 = 0x73, +CV_BasicType_INT32 = 0x74, +CV_BasicType_UINT32 = 0x75, +CV_BasicType_INT64 = 0x76, +CV_BasicType_UINT64 = 0x77, +CV_BasicType_INT128 = 0x78, +CV_BasicType_UINT128 = 0x79, +CV_BasicType_CHAR16 = 0x7a, +CV_BasicType_CHAR32 = 0x7b, +CV_BasicType_CHAR8 = 0x7c, +CV_BasicType_PTR = 0xf0, +} CV_BasicTypeEnum; + +typedef U16 CV_LeafKind; +typedef enum CV_LeafKindEnum +{ +CV_LeafKind_MODIFIER_16t = 0x0001, +CV_LeafKind_POINTER_16t = 0x0002, +CV_LeafKind_ARRAY_16t = 0x0003, +CV_LeafKind_CLASS_16t = 0x0004, +CV_LeafKind_STRUCTURE_16t = 0x0005, +CV_LeafKind_UNION_16t = 0x0006, +CV_LeafKind_ENUM_16t = 0x0007, +CV_LeafKind_PROCEDURE_16t = 0x0008, +CV_LeafKind_MFUNCTION_16t = 0x0009, +CV_LeafKind_VTSHAPE = 0x000a, +CV_LeafKind_COBOL0_16t = 0x000b, +CV_LeafKind_COBOL1 = 0x000c, +CV_LeafKind_BARRAY_16t = 0x000d, +CV_LeafKind_LABEL = 0x000e, +CV_LeafKind_NULL = 0x000f, +CV_LeafKind_NOTTRAN = 0x0010, +CV_LeafKind_DIMARRAY_16t = 0x0011, +CV_LeafKind_VFTPATH_16t = 0x0012, +CV_LeafKind_PRECOMP_16t = 0x0013, +CV_LeafKind_ENDPRECOMP = 0x0014, +CV_LeafKind_OEM_16t = 0x0015, +CV_LeafKind_TYPESERVER_ST = 0x0016, +CV_LeafKind_SKIP_16t = 0x0200, +CV_LeafKind_ARGLIST_16t = 0x0201, +CV_LeafKind_DEFARG_16t = 0x0202, +CV_LeafKind_LIST = 0x0203, +CV_LeafKind_FIELDLIST_16t = 0x0204, +CV_LeafKind_DERIVED_16t = 0x0205, +CV_LeafKind_BITFIELD_16t = 0x0206, +CV_LeafKind_METHODLIST_16t = 0x0207, +CV_LeafKind_DIMCONU_16t = 0x0208, +CV_LeafKind_DIMCONLU_16t = 0x0209, +CV_LeafKind_DIMVARU_16t = 0x020a, +CV_LeafKind_DIMVARLU_16t = 0x020b, +CV_LeafKind_REFSYM = 0x020c, +CV_LeafKind_BCLASS_16t = 0x0400, +CV_LeafKind_VBCLASS_16t = 0x0401, +CV_LeafKind_IVBCLASS_16t = 0x0402, +CV_LeafKind_ENUMERATE_ST = 0x0403, +CV_LeafKind_FRIENDFCN_16t = 0x0404, +CV_LeafKind_INDEX_16t = 0x0405, +CV_LeafKind_MEMBER_16t = 0x0406, +CV_LeafKind_STMEMBER_16t = 0x0407, +CV_LeafKind_METHOD_16t = 0x0408, +CV_LeafKind_NESTTYPE_16t = 0x0409, +CV_LeafKind_VFUNCTAB_16t = 0x040a, +CV_LeafKind_FRIENDCLS_16t = 0x040b, +CV_LeafKind_ONEMETHOD_16t = 0x040c, +CV_LeafKind_VFUNCOFF_16t = 0x040d, +CV_LeafKind_TI16_MAX = 0x1000, +CV_LeafKind_MODIFIER = 0x1001, +CV_LeafKind_POINTER = 0x1002, +CV_LeafKind_ARRAY_ST = 0x1003, +CV_LeafKind_CLASS_ST = 0x1004, +CV_LeafKind_STRUCTURE_ST = 0x1005, +CV_LeafKind_UNION_ST = 0x1006, +CV_LeafKind_ENUM_ST = 0x1007, +CV_LeafKind_PROCEDURE = 0x1008, +CV_LeafKind_MFUNCTION = 0x1009, +CV_LeafKind_COBOL0 = 0x100a, +CV_LeafKind_BARRAY = 0x100b, +CV_LeafKind_DIMARRAY_ST = 0x100c, +CV_LeafKind_VFTPATH = 0x100d, +CV_LeafKind_PRECOMP_ST = 0x100e, +CV_LeafKind_OEM = 0x100f, +CV_LeafKind_ALIAS_ST = 0x1010, +CV_LeafKind_OEM2 = 0x1011, +CV_LeafKind_SKIP = 0x1200, +CV_LeafKind_ARGLIST = 0x1201, +CV_LeafKind_DEFARG_ST = 0x1202, +CV_LeafKind_FIELDLIST = 0x1203, +CV_LeafKind_DERIVED = 0x1204, +CV_LeafKind_BITFIELD = 0x1205, +CV_LeafKind_METHODLIST = 0x1206, +CV_LeafKind_DIMCONU = 0x1207, +CV_LeafKind_DIMCONLU = 0x1208, +CV_LeafKind_DIMVARU = 0x1209, +CV_LeafKind_DIMVARLU = 0x120a, +CV_LeafKind_BCLASS = 0x1400, +CV_LeafKind_VBCLASS = 0x1401, +CV_LeafKind_IVBCLASS = 0x1402, +CV_LeafKind_FRIENDFCN_ST = 0x1403, +CV_LeafKind_INDEX = 0x1404, +CV_LeafKind_MEMBER_ST = 0x1405, +CV_LeafKind_STMEMBER_ST = 0x1406, +CV_LeafKind_METHOD_ST = 0x1407, +CV_LeafKind_NESTTYPE_ST = 0x1408, +CV_LeafKind_VFUNCTAB = 0x1409, +CV_LeafKind_FRIENDCLS = 0x140a, +CV_LeafKind_ONEMETHOD_ST = 0x140b, +CV_LeafKind_VFUNCOFF = 0x140c, +CV_LeafKind_NESTTYPEEX_ST = 0x140d, +CV_LeafKind_MEMBERMODIFY_ST = 0x140e, +CV_LeafKind_MANAGED_ST = 0x140f, +CV_LeafKind_ST_MAX = 0x1500, +CV_LeafKind_TYPESERVER = 0x1501, +CV_LeafKind_ENUMERATE = 0x1502, +CV_LeafKind_ARRAY = 0x1503, +CV_LeafKind_CLASS = 0x1504, +CV_LeafKind_STRUCTURE = 0x1505, +CV_LeafKind_UNION = 0x1506, +CV_LeafKind_ENUM = 0x1507, +CV_LeafKind_DIMARRAY = 0x1508, +CV_LeafKind_PRECOMP = 0x1509, +CV_LeafKind_ALIAS = 0x150a, +CV_LeafKind_DEFARG = 0x150b, +CV_LeafKind_FRIENDFCN = 0x150c, +CV_LeafKind_MEMBER = 0x150d, +CV_LeafKind_STMEMBER = 0x150e, +CV_LeafKind_METHOD = 0x150f, +CV_LeafKind_NESTTYPE = 0x1510, +CV_LeafKind_ONEMETHOD = 0x1511, +CV_LeafKind_NESTTYPEEX = 0x1512, +CV_LeafKind_MEMBERMODIFY = 0x1513, +CV_LeafKind_MANAGED = 0x1514, +CV_LeafKind_TYPESERVER2 = 0x1515, +CV_LeafKind_STRIDED_ARRAY = 0x1516, +CV_LeafKind_HLSL = 0x1517, +CV_LeafKind_MODIFIER_EX = 0x1518, +CV_LeafKind_INTERFACE = 0x1519, +CV_LeafKind_BINTERFACE = 0x151a, +CV_LeafKind_VECTOR = 0x151b, +CV_LeafKind_MATRIX = 0x151c, +CV_LeafKind_VFTABLE = 0x151d, +CV_LeafKind_CLASS2 = 0x1608, +CV_LeafKind_STRUCT2 = 0x1609, +} CV_LeafKindEnum; + +internal String8 cv_string_from_numeric_kind(CV_NumericKind v); +internal String8 cv_string_from_arch(CV_Arch v); +internal String8 cv_string_from_sym_kind(CV_SymKind v); +internal String8 cv_string_from_basic_type(CV_BasicType v); +internal String8 cv_type_name_from_basic_type(CV_BasicType v); +internal String8 cv_string_from_leaf_kind(CV_LeafKind v); +internal U64 cv_header_struct_size_from_sym_kind(CV_SymKind v); +internal U64 cv_header_struct_size_from_leaf_kind(CV_LeafKind v); +C_LINKAGE_BEGIN +C_LINKAGE_END + +#endif // CODEVIEW_META_H diff --git a/src/coff/coff.h b/src/coff/coff.h index 6563a4b0..abe1efa2 100644 --- a/src/coff/coff.h +++ b/src/coff/coff.h @@ -11,6 +11,16 @@ typedef U32 COFF_TimeStamp; #pragma pack(push,1) +typedef struct COFF_Guid COFF_Guid; +struct COFF_Guid +{ + U32 data1; + U16 data2; + U16 data3; + U32 data4; + U32 data5; +}; + typedef U16 COFF_Flags; enum { diff --git a/src/ctrl/ctrl.mdesk b/src/ctrl/ctrl.mdesk index 26da9727..af133ebc 100644 --- a/src/ctrl/ctrl.mdesk +++ b/src/ctrl/ctrl.mdesk @@ -49,37 +49,33 @@ CTRL_ExceptionCodeKindTable: //////////////////////////////// //~ rjf: Generators -@table_gen_enum CTRL_ExceptionCodeKind: +@enum CTRL_ExceptionCodeKind: { - `CTRL_ExceptionCodeKind_Null,`; - @expand(CTRL_ExceptionCodeKindTable a) `CTRL_ExceptionCodeKind_$(a.name),`; - `CTRL_ExceptionCodeKind_COUNT`; + Null, + @expand(CTRL_ExceptionCodeKindTable a) `$(a.name)`, + COUNT, } -@table_gen_data(type:U32, fallback:0) -ctrl_exception_code_kind_code_table: +@data(U32) ctrl_exception_code_kind_code_table: { - `0,`; - @expand(CTRL_ExceptionCodeKindTable a) `$(a.code),`; + `0`; + @expand(CTRL_ExceptionCodeKindTable a) `$(a.code)`; } -@table_gen_data(type:String8, fallback:`{0}`) -ctrl_exception_code_kind_display_string_table: +@data(String8) ctrl_exception_code_kind_display_string_table: { - `{0},`; - @expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)"),`; + `{0}`; + @expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.display_string)")`; } -@table_gen_data(type:String8, fallback:`{0}`) -ctrl_exception_code_kind_lowercase_code_string_table: +@data(String8) ctrl_exception_code_kind_lowercase_code_string_table: { - `{0},`; - @expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)"),`; + `{0}`; + @expand(CTRL_ExceptionCodeKindTable a) `str8_lit_comp("$(a.lower_name)")`; } -@table_gen_data(type:B8, fallback:0) -ctrl_exception_code_kind_default_enable_table: +@data(B8) ctrl_exception_code_kind_default_enable_table: { - `0,`; - @expand(CTRL_ExceptionCodeKindTable a) `$(a.default),`; + `0`; + @expand(CTRL_ExceptionCodeKindTable a) `$(a.default)`; } diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index e97f1142..f96c8ed8 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -2,70 +2,9 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: Main Layer Initialization +//~ rjf: Generated Code -internal void -ctrl_init(CTRL_WakeupFunctionType *wakeup_hook) -{ - Arena *arena = arena_alloc(); - ctrl_state = push_array(arena, CTRL_State, 1); - ctrl_state->arena = arena; - ctrl_state->wakeup_hook = wakeup_hook; - for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) - { - String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); - U64 reg_count = regs_reg_code_count_from_architecture(arch); - String8 *alias_names = regs_alias_code_string_table_from_architecture(arch); - U64 alias_count = regs_alias_code_count_from_architecture(arch); - ctrl_state->arch_string2reg_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); - ctrl_state->arch_string2alias_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); - for(U64 idx = 1; idx < reg_count; idx += 1) - { - eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2reg_tables[arch], reg_names[idx], idx); - } - for(U64 idx = 1; idx < alias_count; idx += 1) - { - eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2alias_tables[arch], alias_names[idx], idx); - } - } - ctrl_state->process_memory_cache.slots_count = 256; - ctrl_state->process_memory_cache.slots = push_array(arena, CTRL_ProcessMemoryCacheSlot, ctrl_state->process_memory_cache.slots_count); - ctrl_state->process_memory_cache.stripes_count = 8; - ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); - for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) - { - ctrl_state->process_memory_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); - ctrl_state->process_memory_cache.stripes[idx].cv = os_condition_variable_alloc(); - } - ctrl_state->u2c_ring_size = KB(64); - ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); - ctrl_state->u2c_ring_mutex = os_mutex_alloc(); - ctrl_state->u2c_ring_cv = os_condition_variable_alloc(); - ctrl_state->c2u_ring_size = KB(64); - ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); - ctrl_state->c2u_ring_mutex = os_mutex_alloc(); - ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); - ctrl_state->demon_event_arena = arena_alloc(); - ctrl_state->user_entry_point_arena = arena_alloc(); - for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) - { - if(ctrl_exception_code_kind_default_enable_table[k]) - { - ctrl_state->exception_code_filters[k/64] |= 1ull<<(k%64); - } - } - ctrl_state->u2ms_ring_size = KB(64); - 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->ctrl_thread = os_launch_thread(ctrl_thread__entry_point, 0, 0); - ctrl_state->ms_thread_count = Clamp(1, os_logical_core_count()-1, 4); - ctrl_state->ms_threads = push_array(arena, OS_Handle, ctrl_state->ms_thread_count); - for(U64 idx = 0; idx < ctrl_state->ms_thread_count; idx += 1) - { - ctrl_state->ms_threads[idx] = os_launch_thread(ctrl_mem_stream_thread__entry_point, (void *)idx, 0); - } -} +#include "generated/ctrl.meta.c" //////////////////////////////// //~ rjf: Basic Type Functions @@ -81,44 +20,29 @@ ctrl_hash_from_string(String8 string) return result; } +internal U64 +ctrl_hash_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle) +{ + U64 buf[] = {machine_id, handle.u64[0]}; + U64 hash = ctrl_hash_from_string(str8((U8 *)buf, sizeof(buf))); + return hash; +} + internal CTRL_EventCause -ctrl_event_cause_from_demon_event_kind(DEMON_EventKind event_kind) +ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind) { CTRL_EventCause cause = CTRL_EventCause_Null; switch(event_kind) { default:{}break; - case DEMON_EventKind_Error: {cause = CTRL_EventCause_Error;}break; - case DEMON_EventKind_Exception:{cause = CTRL_EventCause_InterruptedByException;}break; - case DEMON_EventKind_Trap: {cause = CTRL_EventCause_InterruptedByTrap;}break; - case DEMON_EventKind_Halt: {cause = CTRL_EventCause_InterruptedByHalt;}break; + case DMN_EventKind_Error: {cause = CTRL_EventCause_Error;}break; + case DMN_EventKind_Exception:{cause = CTRL_EventCause_InterruptedByException;}break; + case DMN_EventKind_Trap: {cause = CTRL_EventCause_InterruptedByTrap;}break; + case DMN_EventKind_Halt: {cause = CTRL_EventCause_InterruptedByHalt;}break; } return cause; } -internal B32 -ctrl_handle_match(CTRL_Handle a, CTRL_Handle b) -{ - return MemoryMatchStruct(&a, &b); -} - -//////////////////////////////// -//~ rjf: Ctrl <-> Demon Handle Translation Functions - -internal DEMON_Handle -ctrl_demon_handle_from_ctrl(CTRL_Handle h) -{ - DEMON_Handle result = h.u64[0]; - return result; -} - -internal CTRL_Handle -ctrl_handle_from_demon(DEMON_Handle h) -{ - CTRL_Handle result = {h}; - return result; -} - //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions @@ -192,120 +116,6 @@ ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src) return dst; } -internal void -ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DEMON_Handle module, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out) -{ - Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); - String8 exe_path = demon_full_path_from_module(scratch.arena, module); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - U64 base_vaddr = demon_base_vaddr_from_module(module); - for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) - { - CTRL_UserBreakpoint *bp = &n->v; - switch(bp->kind) - { - default:{}break; - - //- rjf: file:line-based breakpoints - case CTRL_UserBreakpointKind_FileNameAndLineColNumber: - { - // rjf: unpack & normalize - TxtPt pt = bp->pt; - String8 filename = bp->string; - String8 filename_normalized = push_str8_copy(scratch.arena, filename); - for(U64 idx = 0; idx < filename_normalized.size; idx += 1) - { - filename_normalized.str[idx] = char_to_lower(filename_normalized.str[idx]); - filename_normalized.str[idx] = char_to_correct_slash(filename_normalized.str[idx]); - } - - // rjf: filename -> src_id - U32 src_id = 0; - { - RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_NormalSourcePaths); - if(mapptr != 0) - { - RADDBG_ParsedNameMap map = {0}; - raddbg_name_map_parse(rdbg, mapptr, &map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, filename_normalized.str, filename_normalized.size); - if(node != 0) - { - U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); - if(id_count > 0) - { - src_id = ids[0]; - } - } - } - } - - // rjf: src_id * pt -> push - { - RADDBG_SourceFile *src = raddbg_element_from_idx(rdbg, source_files, src_id); - RADDBG_ParsedLineMap line_map = {0}; - raddbg_line_map_from_source_file(rdbg, src, &line_map); - U32 voff_count = 0; - U64 *voffs = raddbg_line_voffs_from_num(&line_map, pt.line, &voff_count); - for(U32 i = 0; i < voff_count; i += 1) - { - U64 vaddr = voffs[i] + base_vaddr; - DEMON_Trap trap = {process, vaddr, (U64)bp}; - demon_trap_chunk_list_push(arena, traps_out, 256, &trap); - } - } - }break; - - //- rjf: symbol:voff-based breakpoints - case CTRL_UserBreakpointKind_SymbolNameAndOffset: - { - String8 symbol_name = bp->string; - U64 voff = bp->u64; - if(rdbg != 0 && rdbg->procedures != 0) - { - RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Procedures); - if(mapptr != 0) - { - RADDBG_ParsedNameMap map = {0}; - raddbg_name_map_parse(rdbg, mapptr, &map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, symbol_name.str, symbol_name.size); - if(node != 0) - { - U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); - for(U32 match_i = 0; match_i < id_count; match_i += 1) - { - U64 proc_voff = raddbg_first_voff_from_proc(rdbg, ids[match_i]); - U64 proc_vaddr = proc_voff + base_vaddr; - DEMON_Trap trap = {process, proc_vaddr + voff, (U64)bp}; - demon_trap_chunk_list_push(arena, traps_out, 256, &trap); - } - } - } - } - }break; - } - } - dbgi_scope_close(scope); - scratch_end(scratch); -} - -internal void -ctrl_append_resolved_process_user_bp_traps(Arena *arena, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_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) - { - DEMON_Trap trap = {process, bp->u64, (U64)bp}; - demon_trap_chunk_list_push(arena, traps_out, 256, &trap); - } - } -} - //////////////////////////////// //~ rjf: Message Type Functions @@ -316,7 +126,7 @@ ctrl_msg_deep_copy(Arena *arena, CTRL_Msg *dst, CTRL_Msg *src) { MemoryCopyStruct(dst, src); dst->path = push_str8_copy(arena, src->path); - dst->strings = str8_list_copy(arena, &src->strings); + dst->entry_points = str8_list_copy(arena, &src->entry_points); dst->cmd_line_string_list = str8_list_copy(arena, &src->cmd_line_string_list); dst->env_string_list = str8_list_copy(arena, &src->env_string_list); dst->traps = ctrl_trap_list_copy(arena, &src->traps); @@ -355,6 +165,7 @@ ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs) // rjf: write flat parts str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->kind); + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->run_flags); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->msg_id); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->machine_id); str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->entity); @@ -368,9 +179,9 @@ ctrl_serialized_string_from_msg_list(Arena *arena, CTRL_MsgList *msgs) str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->path.size); str8_serial_push_data(scratch.arena, &msgs_srlzed, msg->path.str, msg->path.size); - // rjf: write general string list - str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->strings.node_count); - for(String8Node *n = msg->strings.first; n != 0; n = n->next) + // rjf: write entry point string list + str8_serial_push_struct(scratch.arena, &msgs_srlzed, &msg->entry_points.node_count); + for(String8Node *n = msg->entry_points.first; n != 0; n = n->next) { str8_serial_push_struct(scratch.arena, &msgs_srlzed, &n->string.size); str8_serial_push_data(scratch.arena, &msgs_srlzed, n->string.str, n->string.size); @@ -453,6 +264,7 @@ ctrl_msg_list_from_serialized_string(Arena *arena, String8 string) // rjf: read flat data read_off += str8_deserial_read_struct(string, read_off, &msg->kind); + read_off += str8_deserial_read_struct(string, read_off, &msg->run_flags); read_off += str8_deserial_read_struct(string, read_off, &msg->msg_id); read_off += str8_deserial_read_struct(string, read_off, &msg->machine_id); read_off += str8_deserial_read_struct(string, read_off, &msg->entity); @@ -467,16 +279,16 @@ ctrl_msg_list_from_serialized_string(Arena *arena, String8 string) msg->path.str = push_array_no_zero(arena, U8, msg->path.size); read_off += str8_deserial_read(string, read_off, msg->path.str, msg->path.size, 1); - // rjf: read general string list - U64 string_list_string_count = 0; - read_off += str8_deserial_read_struct(string, read_off, &string_list_string_count); - for(U64 idx = 0; idx < string_list_string_count; idx += 1) + // rjf: read entry point string list + U64 entry_point_list_string_count = 0; + read_off += str8_deserial_read_struct(string, read_off, &entry_point_list_string_count); + for(U64 idx = 0; idx < entry_point_list_string_count; idx += 1) { String8 str = {0}; read_off += str8_deserial_read_struct(string, read_off, &str.size); str.str = push_array_no_zero(arena, U8, str.size); read_off += str8_deserial_read(string, read_off, str.str, str.size, 1); - str8_list_push(arena, &msg->strings, str); + str8_list_push(arena, &msg->entry_points, str); } // rjf: read command line string list @@ -645,196 +457,439 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) } //////////////////////////////// -//~ rjf: Shared Functions +//~ rjf: Entity Type Functions -//- rjf: run index +//- rjf: cache creation/destruction -internal U64 -ctrl_run_idx(void) +internal CTRL_EntityStore * +ctrl_entity_store_alloc(void) { - U64 result = ins_atomic_u64_eval(&ctrl_state->run_idx); - return result; + 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); + CTRL_Entity *root = store->root = ctrl_entity_alloc(store, &ctrl_entity_nil, CTRL_EntityKind_Root, Architecture_Null, 0, dmn_handle_zero(), 0); + CTRL_Entity *local_machine = ctrl_entity_alloc(store, root, CTRL_EntityKind_Machine, architecture_from_context(), CTRL_MachineID_Local, dmn_handle_zero(), 0); + (void)local_machine; + return store; } -internal U64 -ctrl_memgen_idx(void) -{ - U64 result = ins_atomic_u64_eval(&ctrl_state->memgen_idx); - return result; -} - -internal U64 -ctrl_reggen_idx(void) -{ - U64 result = ins_atomic_u64_eval(&ctrl_state->reggen_idx); - return result; -} - -//- rjf: halt everything - internal void -ctrl_halt(void) +ctrl_entity_store_release(CTRL_EntityStore *cache) { - demon_halt(0, 0); + arena_release(cache->arena); } -//- rjf: entity introspection - -internal U32 -ctrl_id_from_machine_entity(CTRL_MachineID id, DEMON_Handle handle) -{ - U32 result = 0; - return result; -} - -//- rjf: exe -> dbg path mapping - -internal String8 -ctrl_inferred_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 result = {0}; - { - // TODO(rjf): do preliminary header parse of EXE if possible, look for connected debug info path - } - scratch_end(scratch); - return result; -} - -internal String8 -ctrl_forced_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - String8 result = {0}; - // TODO(rjf) - return result; -} - -internal String8 -ctrl_natural_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - String8 exe_extension = str8_skip_last_dot(exe_path); - String8 dbg_extension = {0}; - if(str8_match(exe_extension, str8_lit("exe"), 0)) {dbg_extension = str8_lit("pdb");} - if(str8_match(exe_extension, str8_lit("elf"), 0)) {dbg_extension = str8_lit("debug");} - String8 result = {0}; - if(dbg_extension.size != 0) - { - result = push_str8f(arena, "%S.%S", str8_chop_last_dot(exe_path), dbg_extension); - } - return result; -} - -internal String8 -ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - Temp scratch = scratch_begin(&arena, 1); - String8 forced_og_dbg_path = ctrl_forced_og_dbg_path_from_exe_path(scratch.arena, exe_path); - String8 inferred_og_dbg_path = ctrl_inferred_og_dbg_path_from_exe_path(scratch.arena, exe_path); - String8 natural_og_dbg_path = ctrl_natural_og_dbg_path_from_exe_path(scratch.arena, exe_path); - String8 og_dbg_path = forced_og_dbg_path.size?forced_og_dbg_path : inferred_og_dbg_path.size?inferred_og_dbg_path : natural_og_dbg_path; - og_dbg_path = push_str8_copy(arena, og_dbg_path); - scratch_end(scratch); - return og_dbg_path; -} - -//- rjf: handle -> arch - -internal Architecture -ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle) -{ - return demon_arch_from_object(ctrl_demon_handle_from_ctrl(handle)); -} - -//- rjf: process memory reading/writing - internal U64 -ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst) +ctrl_name_bucket_idx_from_string_size(U64 size) { - U64 actual_bytes_read = demon_read_memory(ctrl_demon_handle_from_ctrl(process), dst, range.min, dim_1u64(range)); - return actual_bytes_read; + 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 B32 -ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *src) +internal String8 +ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string) { - ProfBeginFunction(); - U64 size = dim_1u64(range); - B32 result = demon_write_memory(ctrl_demon_handle_from_ctrl(process), range.min, src, size); + 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: success -> increment memgen - if(result) + // rjf: pull from bucket free list + if(node != 0) { - ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); + 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+1) + { + 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: success -> wait for cache updates, for small regions - prefer relatively seamless - // writes within calling frame's "view" of the memory, at the expense of a small amount of - // time. - if(result) + // 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; + } + + // 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 + +internal CTRL_Entity * +ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Architecture arch, CTRL_MachineID machine_id, DMN_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->machine_id = machine_id; + 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_machine_id_handle(machine_id, 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(n->entity->machine_id == machine_id && dmn_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; + } + } + } + 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); - U64 endt_us = os_now_microseconds()+5000; - - //- rjf: gather tasks for all affected cached regions typedef struct Task Task; struct Task { Task *next; - CTRL_MachineID machine_id; - CTRL_Handle process; - Rng1U64 range; + CTRL_Entity *e; }; - Task *first_task = 0; - Task *last_task = 0; - CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; - for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) + 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) { - U64 stripe_idx = slot_idx%cache->stripes_count; - CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; - CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + for(CTRL_Entity *child = t->e->first; child != &ctrl_entity_nil; child = child->next) { - for(CTRL_ProcessMemoryCacheNode *proc_n = slot->first; proc_n != 0; proc_n = proc_n->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_machine_id_handle(t->e->machine_id, 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) { - for(U64 range_hash_idx = 0; range_hash_idx < proc_n->range_hash_slots_count; range_hash_idx += 1) + if(n->entity->machine_id == t->e->machine_id && dmn_handle_match(n->entity->handle, t->e->handle)) { - CTRL_ProcessMemoryRangeHashSlot *range_slot = &proc_n->range_hash_slots[range_hash_idx]; - for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) - { - Rng1U64 intersection_w_range = intersect_1u64(range, n->vaddr_range); - if(dim_1u64(intersection_w_range) != 0 && dim_1u64(n->vaddr_range) <= KB(64)) - { - Task *task = push_array(scratch.arena, Task, 1); - task->machine_id = proc_n->machine_id; - task->process = proc_n->process; - task->range = n->vaddr_range; - SLLQueuePush(first_task, last_task, task); - } - } + DLLRemove(slot->first, slot->last, n); + SLLStackPush(store->hash_node_free, n); + break; } } } } - - //- rjf: for all tasks, wait for up-to-date results - 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->machine_id, task->process, task->range, endt_us); - temp_end(temp); - } - scratch_end(scratch); } - - ProfEnd(); - return result; } +//- 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_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle) +{ + CTRL_Entity *entity = &ctrl_entity_nil; + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, 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(n->entity->machine_id == machine_id && dmn_handle_match(n->entity->handle, handle)) + { + entity = n->entity; + break; + } + } + } + return entity; +} + +//- rjf: applying events to entity caches + +internal void +ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) +{ + //- rjf: scan events & construct entities + for(CTRL_EventNode *n = list->first; n != 0; n = n->next) + { + CTRL_Event *event = &n->v; + switch(event->kind) + { + //- rjf: processes + case CTRL_EventKind_NewProc: + { + CTRL_Entity *machine = ctrl_entity_from_machine_id_handle(store, event->machine_id, dmn_handle_zero()); + CTRL_Entity *process = ctrl_entity_alloc(store, machine, CTRL_EntityKind_Process, event->arch, event->machine_id, event->entity, (U64)event->entity_id); + }break; + case CTRL_EventKind_EndProc: + { + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_release(store, process); + for(CTRL_Entity *entry = store->root->first, *next = &ctrl_entity_nil; + entry != &ctrl_entity_nil; + entry = next) + { + next = entry->next; + if(entry->kind == CTRL_EntityKind_EntryPoint && entry->id == process->id) + { + ctrl_entity_release(store, entry); + } + } + }break; + + //- rjf: threads + case CTRL_EventKind_NewThread: + { + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); + CTRL_Entity *thread = ctrl_entity_alloc(store, process, CTRL_EntityKind_Thread, event->arch, event->machine_id, event->entity, (U64)event->entity_id); + }break; + case CTRL_EventKind_EndThread: + { + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_release(store, thread); + }break; + case CTRL_EventKind_ThreadName: + { + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_equip_string(store, thread, event->string); + }break; + + //- rjf: modules + case CTRL_EventKind_NewModule: + { + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); + CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->arch, event->machine_id, event->entity, event->vaddr_rng.min); + ctrl_entity_equip_string(store, module, event->string); + module->vaddr_range = event->vaddr_rng; + }break; + case CTRL_EventKind_EndModule: + { + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + ctrl_entity_release(store, module); + }break; + } + } +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +ctrl_init(void) +{ + Arena *arena = arena_alloc(); + ctrl_state = push_array(arena, CTRL_State, 1); + ctrl_state->arena = arena; + for(Architecture arch = (Architecture)0; arch < Architecture_COUNT; arch = (Architecture)(arch+1)) + { + String8 *reg_names = regs_reg_code_string_table_from_architecture(arch); + U64 reg_count = regs_reg_code_count_from_architecture(arch); + String8 *alias_names = regs_alias_code_string_table_from_architecture(arch); + U64 alias_count = regs_alias_code_count_from_architecture(arch); + ctrl_state->arch_string2reg_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); + ctrl_state->arch_string2alias_tables[arch] = eval_string2num_map_make(ctrl_state->arena, 256); + for(U64 idx = 1; idx < reg_count; idx += 1) + { + eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2reg_tables[arch], reg_names[idx], idx); + } + for(U64 idx = 1; idx < alias_count; idx += 1) + { + eval_string2num_map_insert(ctrl_state->arena, &ctrl_state->arch_string2alias_tables[arch], alias_names[idx], idx); + } + } + ctrl_state->process_memory_cache.slots_count = 256; + ctrl_state->process_memory_cache.slots = push_array(arena, CTRL_ProcessMemoryCacheSlot, ctrl_state->process_memory_cache.slots_count); + ctrl_state->process_memory_cache.stripes_count = os_logical_core_count(); + ctrl_state->process_memory_cache.stripes = push_array(arena, CTRL_ProcessMemoryCacheStripe, ctrl_state->process_memory_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->process_memory_cache.stripes_count; idx += 1) + { + ctrl_state->process_memory_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + ctrl_state->process_memory_cache.stripes[idx].cv = os_condition_variable_alloc(); + } + ctrl_state->thread_reg_cache.slots_count = 1024; + ctrl_state->thread_reg_cache.slots = push_array(arena, CTRL_ThreadRegCacheSlot, ctrl_state->thread_reg_cache.slots_count); + ctrl_state->thread_reg_cache.stripes_count = os_logical_core_count(); + ctrl_state->thread_reg_cache.stripes = push_array(arena, CTRL_ThreadRegCacheStripe, ctrl_state->thread_reg_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->thread_reg_cache.stripes_count; idx += 1) + { + 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->u2c_ring_size = KB(64); + ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); + ctrl_state->u2c_ring_mutex = os_mutex_alloc(); + ctrl_state->u2c_ring_cv = os_condition_variable_alloc(); + ctrl_state->c2u_ring_size = KB(64); + ctrl_state->c2u_ring_base = push_array_no_zero(arena, U8, ctrl_state->c2u_ring_size); + ctrl_state->c2u_ring_mutex = os_mutex_alloc(); + ctrl_state->c2u_ring_cv = os_condition_variable_alloc(); + ctrl_state->ctrl_thread_entity_store = ctrl_entity_store_alloc(); + ctrl_state->dmn_event_arena = arena_alloc(); + ctrl_state->user_entry_point_arena = arena_alloc(); + for(CTRL_ExceptionCodeKind k = (CTRL_ExceptionCodeKind)0; k < CTRL_ExceptionCodeKind_COUNT; k = (CTRL_ExceptionCodeKind)(k+1)) + { + if(ctrl_exception_code_kind_default_enable_table[k]) + { + ctrl_state->exception_code_filters[k/64] |= 1ull<<(k%64); + } + } + ctrl_state->u2ms_ring_size = KB(64); + 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->ctrl_thread = os_launch_thread(ctrl_thread__entry_point, 0, 0); + ctrl_state->ms_thread_count = Clamp(1, os_logical_core_count()-1, 4); + ctrl_state->ms_threads = push_array(arena, OS_Handle, ctrl_state->ms_thread_count); + for(U64 idx = 0; idx < ctrl_state->ms_thread_count; idx += 1) + { + ctrl_state->ms_threads[idx] = os_launch_thread(ctrl_mem_stream_thread__entry_point, (void *)idx, 0); + } +} + +//////////////////////////////// +//~ rjf: Wakeup Callback Registration + +internal void +ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook) +{ + ctrl_state->wakeup_hook = wakeup_hook; +} + +//////////////////////////////// +//~ rjf: Process Memory Functions + //- rjf: process memory cache interaction internal U128 -ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated) +ctrl_calc_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated) { U64 key_hash_data[] = { @@ -849,7 +904,7 @@ ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Han } internal U128 -ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us) +ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated, B32 *out_is_stale, U64 endt_us) { U128 result = {0}; U64 size = dim_1u64(range); @@ -868,31 +923,23 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle B32 is_stale = 0; OS_MutexScopeR(process_stripe->rw_mutex) { - for(;;) + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + U64 range_slot_idx = range_hash%n->range_hash_slots_count; + CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; + for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) { - U64 range_slot_idx = range_hash%n->range_hash_slots_count; - CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; - for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) + if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) { - if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) - { - result = range_n->hash; - is_good = 1; - is_stale = range_n->memgen_idx < ctrl_memgen_idx(); - goto read_cache__break_all; - } + result = range_n->hash; + is_good = 1; + is_stale = (range_n->mem_gen != dmn_mem_gen()); + goto read_cache__break_all; } } } - if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait_rw_r(process_stripe->cv, process_stripe->rw_mutex, endt_us); } read_cache__break_all:; } @@ -905,7 +952,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle B32 process_node_exists = 0; for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { process_node_exists = 1; break; @@ -926,13 +973,14 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle } //- 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(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; @@ -941,6 +989,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle { if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) { + last_time_requested_us = range_n->last_time_requested_us; range_node_exists = 1; break; } @@ -965,13 +1014,42 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle } //- rjf: not good, or is stale -> submit hash request - if(!is_good || is_stale) + if((!is_good || is_stale) && os_now_microseconds() >= last_time_requested_us+10000) { - ctrl_u2ms_enqueue_req(machine_id, process, range, zero_terminated, endt_us); + if(ctrl_u2ms_enqueue_req(machine_id, process, range, zero_terminated, endt_us)) OS_MutexScopeW(process_stripe->rw_mutex) + { + for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->process, 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) + { + if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) + { + range_n->last_time_requested_us = os_now_microseconds(); + break; + } + } + } + } + } } //- rjf: out of time? -> exit if(os_now_microseconds() >= endt_us) + { + if(is_good && is_stale && out_is_stale) + { + out_is_stale[0] = 1; + } + break; + } + + //- rjf: done? -> exit + if(is_good && !is_stale) { break; } @@ -979,10 +1057,20 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle return result; } +//- rjf: bundled key/stream helper + +internal U128 +ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated) +{ + U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(machine_id, process, range, zero_terminated); + ctrl_stored_hash_from_process_vaddr_range(machine_id, 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_MachineID machine_id, CTRL_Handle process, Rng1U64 range, U64 endt_us) +ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us) { CTRL_ProcessMemorySlice result = {0}; if(range.max > range.min && @@ -1005,9 +1093,11 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID mac 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_hash_store_key_from_process_vaddr_range(machine_id, process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0); - U128 page_hash = ctrl_stored_hash_from_process_vaddr_range(machine_id, process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us); + U128 page_key = ctrl_calc_hash_store_key_from_process_vaddr_range(machine_id, 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(machine_id, process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, &page_is_stale, endt_us); U128 page_last_hash = hs_hash_from_key(page_key, 1); + result.stale = (result.stale || page_is_stale); page_hashes[page_idx] = page_hash; page_last_hashes[page_idx] = page_last_hash; } @@ -1097,6 +1187,20 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID mac result.data.size = dim_1u64(range); result.byte_bad_flags = byte_bad_flags; result.byte_changed_flags = byte_changed_flags; + if(byte_bad_flags != 0) + { + for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) + { + result.any_byte_bad = result.any_byte_bad || !!result.byte_bad_flags[idx]; + } + } + if(byte_changed_flags != 0) + { + for(U64 idx = 0; idx < (dim_1u64(range)+63)/64; idx += 1) + { + result.any_byte_changed = result.any_byte_changed || !!result.byte_changed_flags[idx]; + } + } hs_scope_close(scope); scratch_end(scratch); @@ -1105,214 +1209,378 @@ ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID mac } internal CTRL_ProcessMemorySlice -ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit, U64 endt_us) +ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr, U64 limit, U64 element_size, U64 endt_us) { CTRL_ProcessMemorySlice result = ctrl_query_cached_data_from_process_vaddr_range(arena, machine_id, process, r1u64(vaddr, vaddr+limit), endt_us); - for(U64 idx = 0; idx < result.data.size; idx += 1) + U64 element_count = result.data.size/element_size; + for(U64 element_idx = 0; element_idx < element_count; element_idx += 1) { - if(result.data.str[idx] == 0) + B32 element_is_zero = 1; + for(U64 element_byte_idx = 0; element_byte_idx < element_size; element_byte_idx += 1) { - result.data.size = idx; + 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; } -//- rjf: register reading/writing - -internal void * -ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) -{ - void *regs = demon_read_regs(ctrl_demon_handle_from_ctrl(thread)); - return regs; -} +//- rjf: process memory writing internal B32 -ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block) +ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src) { - B32 good = demon_write_regs(ctrl_demon_handle_from_ctrl(thread), block); - ins_atomic_u64_inc_eval(&ctrl_state->reggen_idx); - return good; -} - -internal U64 -ctrl_rip_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) -{ - U64 result = 0; - void *regs = ctrl_reg_block_from_thread(machine_id, thread); - if(regs != 0) - { - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); - result = regs_rip_from_arch_block(arch, regs); - } - return result; -} - -internal B32 -ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip) -{ - B32 result = 0; - void *regs = ctrl_reg_block_from_thread(machine_id, thread); - if(regs != 0) - { - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); - regs_arch_block_write_rip(arch, regs, rip); - ctrl_thread_write_reg_block(machine_id, thread, regs); - result = 1; - } - return result; -} - -internal U64 -ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread) -{ - U64 result = 0; - DEMON_Handle demon_handle = ctrl_demon_handle_from_ctrl(thread); - result = demon_tls_root_vaddr_from_thread(demon_handle); - return result; -} - -//- rjf: process * vaddr -> module - -internal CTRL_Handle -ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr) -{ - CTRL_Handle handle = {0}; + ProfBeginFunction(); + B32 result = dmn_process_write(process, range, src); + + //- rjf: success -> wait for cache updates, for small regions - prefer relatively seamless + // writes within calling frame's "view" of the memory, at the expense of a small amount of + // time. + if(result) { Temp scratch = scratch_begin(0, 0); - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, ctrl_demon_handle_from_ctrl(process)); - for(U64 idx = 0; idx < modules.count; idx += 1) + U64 endt_us = os_now_microseconds()+5000; + + //- rjf: gather tasks for all affected cached regions + typedef struct Task Task; + struct Task { - DEMON_Handle m = modules.handles[idx]; - Rng1U64 m_vaddr_rng = demon_vaddr_range_from_module(m); - if(contains_1u64(m_vaddr_rng, vaddr)) + Task *next; + CTRL_MachineID machine_id; + DMN_Handle process; + Rng1U64 range; + }; + Task *first_task = 0; + Task *last_task = 0; + CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; + for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) + { + U64 stripe_idx = slot_idx%cache->stripes_count; + CTRL_ProcessMemoryCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_ProcessMemoryCacheStripe *stripe = &cache->stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) { - handle = ctrl_handle_from_demon(m); + for(CTRL_ProcessMemoryCacheNode *proc_n = slot->first; proc_n != 0; proc_n = proc_n->next) + { + for(U64 range_hash_idx = 0; range_hash_idx < proc_n->range_hash_slots_count; range_hash_idx += 1) + { + CTRL_ProcessMemoryRangeHashSlot *range_slot = &proc_n->range_hash_slots[range_hash_idx]; + for(CTRL_ProcessMemoryRangeHashNode *n = range_slot->first; n != 0; n = n->next) + { + Rng1U64 intersection_w_range = intersect_1u64(range, n->vaddr_range); + if(dim_1u64(intersection_w_range) != 0 && dim_1u64(n->vaddr_range) <= KB(64)) + { + Task *task = push_array(scratch.arena, Task, 1); + task->machine_id = proc_n->machine_id; + task->process = proc_n->process; + task->range = n->vaddr_range; + SLLQueuePush(first_task, last_task, task); + } + } + } + } + } + } + + //- rjf: for all tasks, wait for up-to-date results + 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->machine_id, task->process, task->range, endt_us); + temp_end(temp); + } + + scratch_end(scratch); + } + + ProfEnd(); + return result; +} + +//////////////////////////////// +//~ rjf: Thread Register Functions + +//- rjf: thread register cache reading + +internal void * +ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) +{ + CTRL_ThreadRegCache *cache = &ctrl_state->thread_reg_cache; + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); + Architecture arch = thread_entity->arch; + U64 reg_block_size = regs_block_size_from_architecture(arch); + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, thread); + U64 slot_idx = hash%cache->slots_count; + U64 stripe_idx = slot_idx%cache->stripes_count; + CTRL_ThreadRegCacheSlot *slot = &cache->slots[slot_idx]; + CTRL_ThreadRegCacheStripe *stripe = &cache->stripes[stripe_idx]; + void *result = push_array(arena, U8, reg_block_size); + OS_MutexScopeR(stripe->rw_mutex) + { + // rjf: find existing node + CTRL_ThreadRegCacheNode *node = 0; + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; break; } } - scratch_end(scratch); + + // rjf: allocate existing node + if(!node) + { + OS_MutexScopeRWPromote(stripe->rw_mutex) + { + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; + break; + } + } + if(!node) + { + node = push_array(stripe->arena, CTRL_ThreadRegCacheNode, 1); + DLLPushBack(slot->first, slot->last, node); + node->machine_id = machine_id; + node->thread = thread; + node->block_size = reg_block_size; + node->block = push_array(stripe->arena, U8, reg_block_size); + } + } + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; + break; + } + } + } + + // rjf: copy from node + if(node) + { + U64 current_reg_gen = dmn_reg_gen(); + B32 need_stale = 1; + if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) + { + need_stale = 0; + node->reg_gen = current_reg_gen; + MemoryCopy(node->block, result, reg_block_size); + } + if(need_stale) + { + MemoryCopy(result, node->block, reg_block_size); + } + } } - return handle; + return result; } -//- rjf: unwinding +internal U64 +ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) +{ + U64 result = dmn_tls_root_vaddr_from_thread(thread); + return result; +} + +internal U64 +ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread) +{ + Temp scratch = scratch_begin(0, 0); + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); + Architecture arch = thread_entity->arch; + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, machine_id, thread); + U64 result = regs_rip_from_arch_block(arch, block); + scratch_end(scratch); + return result; +} + +//- rjf: thread register writing + +internal B32 +ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block) +{ + B32 good = dmn_thread_write_reg_block(thread, block); + return good; +} + +//////////////////////////////// +//~ rjf: Unwinding Functions internal CTRL_Unwind -ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, CTRL_Handle thread) +ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); DBGI_Scope *scope = dbgi_scope_open(); - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(thread)); - U64 arch_reg_block_size = regs_block_size_from_architecture(arch); CTRL_Unwind unwind = {0}; unwind.error = 1; - switch(arch) + + //- rjf: unpack args + CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); + CTRL_Entity *process_entity = thread_entity->parent; + Architecture arch = thread_entity->arch; + U64 arch_reg_block_size = regs_block_size_from_architecture(arch); + + //- rjf: grab initial register block + void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); + B32 regs_block_good = dmn_thread_read_reg_block(thread, regs_block); + + //- rjf: grab initial memory view + B32 stack_memview_good = 0; + UNW_MemView stack_memview = {0}; { - default:{}break; - case Architecture_x64: + U64 stack_base_unrounded = dmn_stack_base_vaddr_from_thread(thread); + U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); + U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); + U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); + U64 stack_size = stack_base - stack_top; + if(stack_base >= stack_top) { - // rjf: grab initial register block - void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); - B32 regs_block_good = 0; + U8 *stack_memory_base = push_array(scratch.arena, U8, stack_size); + U64 actual_stack_bytes_read = dmn_process_read(process_entity->handle, r1u64(stack_top, stack_top+stack_size), stack_memory_base); + String8 stack_memory = str8(stack_memory_base, actual_stack_bytes_read); + if(stack_memory.size >= stack_size) { - void *regs_raw = ctrl_reg_block_from_thread(machine_id, thread); - if(regs_raw != 0) - { - MemoryCopy(regs_block, regs_raw, arch_reg_block_size); - regs_block_good = 1; - } + stack_memview_good = 1; + stack_memview.data = stack_memory.str; + stack_memview.addr_first = stack_top; + stack_memview.addr_opl = stack_base; } - - // rjf: grab initial memory view - B32 stack_memview_good = 0; - UNW_MemView stack_memview = {0}; - if(regs_block_good) - { - U64 stack_base_unrounded = demon_stack_base_vaddr_from_thread(ctrl_demon_handle_from_ctrl(thread)); - U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); - U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); - U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); - U64 stack_size = stack_base - stack_top; - if(stack_base >= stack_top) - { - String8 stack_memory = {0}; - stack_memory.str = push_array_no_zero(scratch.arena, U8, stack_size); - stack_memory.size = ctrl_process_read(machine_id, process, r1u64(stack_top, stack_top+stack_size), stack_memory.str); - if(stack_memory.size != 0) - { - stack_memview_good = 1; - stack_memview.data = stack_memory.str; - stack_memview.addr_first = stack_top; - stack_memview.addr_opl = stack_base; - } - } - } - - // rjf: loop & unwind - UNW_MemView memview = stack_memview; - if(stack_memview_good) for(;;) - { - unwind.error = 0; - - // rjf: regs -> rip*module*binary - U64 rip = regs_rip_from_arch_block(arch, regs_block); - CTRL_Handle module = ctrl_module_from_process_vaddr(machine_id, process, rip); - - // rjf: cancel on 0 rip - if(rip == 0) - { - break; - } - - // rjf: binary -> all the binary info - String8 binary_full_path = demon_full_path_from_module(scratch.arena, ctrl_demon_handle_from_ctrl(module)); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_full_path, 0); - String8 binary_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - - // rjf: cancel on bad data - if(binary_data.size == 0) - { - unwind.error = 1; - break; - } - - // rjf: valid step -> push frame - CTRL_UnwindFrame *frame = push_array(arena, CTRL_UnwindFrame, 1); - frame->rip = rip; - frame->regs = push_array_no_zero(arena, U8, arch_reg_block_size); - MemoryCopy(frame->regs, regs_block, arch_reg_block_size); - DLLPushBack(unwind.first, unwind.last, frame); - unwind.count += 1; - - // rjf: unwind one step - UNW_Result unwind_step = unw_pe_x64(binary_data, &dbgi->pe, demon_vaddr_range_from_module(ctrl_demon_handle_from_ctrl(module)).min, &memview, (UNW_X64_Regs *)regs_block); - - // rjf: cancel on bad step - if(unwind_step.dead != 0) - { - break; - } - if(unwind_step.missed_read != 0) - { - unwind.error = 1; - break; - } - if(unwind_step.stack_pointer == 0) - { - break; - } - } - }break; + } } + + //- rjf: loop & unwind + UNW_MemView memview = stack_memview; + if(regs_block_good && stack_memview_good) + { + unwind.error = 0; + for(;;) + { + // rjf: regs -> rip*module + U64 rip = regs_rip_from_arch_block(arch, regs_block); + DMN_Handle module = {0}; + String8 module_name = {0}; + Rng1U64 module_vaddr_range = {0}; + 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_name = m->string; + module_vaddr_range = m->vaddr_range; + break; + } + } + + // rjf: cancel on 0 rip + if(rip == 0) + { + break; + } + + // rjf: module -> all the binary info + String8 binary_full_path = module_name; + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_full_path, 0); + String8 binary_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); + + // rjf: cancel on bad data + if(binary_data.size == 0) + { + unwind.error = 1; + break; + } + + // rjf: valid step -> push frame + CTRL_UnwindFrame *frame = push_array(arena, CTRL_UnwindFrame, 1); + frame->rip = rip; + frame->regs = push_array_no_zero(arena, U8, arch_reg_block_size); + MemoryCopy(frame->regs, regs_block, arch_reg_block_size); + DLLPushBack(unwind.first, unwind.last, frame); + unwind.count += 1; + + // rjf: unwind one step + UNW_Step unwind_step = {0}; + switch(arch) + { + default:{unwind_step.dead = 1;}break; + case Architecture_x64: + { + unwind_step = unw_unwind_pe_x64(binary_data, &dbgi->pe, module_vaddr_range.min, &memview, (REGS_RegBlockX64 *)regs_block); + }break; + } + + // rjf: cancel on bad step + if(unwind_step.dead != 0) + { + break; + } + if(unwind_step.missed_read != 0) + { + unwind.error = 1; + break; + } + if(unwind_step.stack_pointer == 0) + { + break; + } + } + } + dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); return unwind; } +//////////////////////////////// +//~ rjf: Halting All Attached Processes + +internal void +ctrl_halt(void) +{ + dmn_halt(0, 0); +} + +//////////////////////////////// +//~ rjf: Shared Accessor Functions + +//- rjf: run generation counter + +internal U64 +ctrl_run_gen(void) +{ + U64 result = dmn_run_gen(); + return result; +} + +internal U64 +ctrl_mem_gen(void) +{ + U64 result = dmn_mem_gen(); + return result; +} + +internal U64 +ctrl_reg_gen(void) +{ + U64 result = dmn_reg_gen(); + return result; +} + //- rjf: name -> register/alias hash tables, for eval internal EVAL_String2NumMap * @@ -1328,7 +1596,9 @@ ctrl_string2alias_from_arch(Architecture arch) } //////////////////////////////// -//~ rjf: User -> Ctrl Communication +//~ rjf: Control-Thread Functions + +//- rjf: user -> control thread communication internal B32 ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us) @@ -1390,14 +1660,14 @@ ctrl_u2c_pop_msgs(Arena *arena) return msgs; } -//////////////////////////////// -//~ rjf: Ctrl -> User Communication +//- rjf: control -> user thread communication internal void 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); for(CTRL_EventNode *n = events->first; n != 0; n = n ->next) { Temp scratch = scratch_begin(0, 0); @@ -1459,65 +1729,16 @@ ctrl_c2u_pop_events(Arena *arena) return events; } -//////////////////////////////// -//~ rjf: User -> Memory Stream Communication - -internal B32 -ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, 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(machine_id)+sizeof(process)+sizeof(vaddr_range)) - { - 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, &machine_id); - 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); - break; - } - if(os_now_microseconds() >= endt_us) {break;} - os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); - } - os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); - return good; -} - -internal void -ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, 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_machine_id)+sizeof(*out_process)+sizeof(*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_machine_id); - 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); - break; - } - os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); - } - os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); -} - -//////////////////////////////// -//~ rjf: Control-Thread-Only Functions - //- rjf: entry point internal void ctrl_thread__entry_point(void *p) { - TCTX tctx_; - tctx_init_and_equip(&tctx_); - ThreadName("[ctrl] thread"); + ThreadNameF("[ctrl] thread"); ProfBeginFunction(); - demon_primary_thread_begin(); + DMN_CtrlCtx *ctrl_ctx = dmn_ctrl_begin(); + + //- rjf: loop Temp scratch = scratch_begin(0, 0); for(;;) { @@ -1527,8 +1748,8 @@ ctrl_thread__entry_point(void *p) CTRL_MsgList msgs = ctrl_u2c_pop_msgs(scratch.arena); //- rjf: process messages + DMN_CtrlExclusiveAccessScope { - demon_exclusive_mode_begin(); B32 done = 0; for(CTRL_MsgNode *msg_n = msgs.first; msg_n != 0 && done == 0; msg_n = msg_n->next) { @@ -1540,40 +1761,156 @@ ctrl_thread__entry_point(void *p) case CTRL_MsgKind_COUNT:{}break; //- rjf: target operations - case CTRL_MsgKind_LaunchAndHandshake:{ctrl_thread__launch_and_handshake(msg);}break; - case CTRL_MsgKind_LaunchAndInit: {ctrl_thread__launch_and_init (msg);}break; - case CTRL_MsgKind_Attach: {ctrl_thread__attach (msg);}break; - case CTRL_MsgKind_Kill: {ctrl_thread__kill (msg);}break; - case CTRL_MsgKind_Detach: {ctrl_thread__detach (msg);}break; - case CTRL_MsgKind_Run: {ctrl_thread__run (msg); done = 1;}break; - case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (msg); done = 1;}break; + case CTRL_MsgKind_Launch: {ctrl_thread__launch (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Attach: {ctrl_thread__attach (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Kill: {ctrl_thread__kill (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Detach: {ctrl_thread__detach (ctrl_ctx, msg);}break; + case CTRL_MsgKind_Run: {ctrl_thread__run (ctrl_ctx, msg); done = 1;}break; + case CTRL_MsgKind_SingleStep: {ctrl_thread__single_step (ctrl_ctx, msg); done = 1;}break; //- rjf: configuration case CTRL_MsgKind_SetUserEntryPoints: { arena_clear(ctrl_state->user_entry_point_arena); MemoryZeroStruct(&ctrl_state->user_entry_points); - for(String8Node *n = msg->strings.first; n != 0; n = n->next) + for(String8Node *n = msg->entry_points.first; n != 0; n = n->next) { str8_list_push(ctrl_state->user_entry_point_arena, &ctrl_state->user_entry_points, n->string); } }break; } } - demon_exclusive_mode_end(); } } + scratch_end(scratch); ProfEnd(); } +//- rjf: breakpoint resolution + +internal void +ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) +{ + Temp scratch = scratch_begin(&arena, 1); + DBGI_Scope *scope = dbgi_scope_open(); + CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); + String8 exe_path = module_entity->string; + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); + RDI_Parsed *rdi = &dbgi->rdi; + U64 base_vaddr = module_entity->vaddr_range.min; + for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) + { + CTRL_UserBreakpoint *bp = &n->v; + switch(bp->kind) + { + default:{}break; + + //- rjf: file:line-based breakpoints + case CTRL_UserBreakpointKind_FileNameAndLineColNumber: + { + // rjf: unpack & normalize + TxtPt pt = bp->pt; + String8 filename = bp->string; + String8 filename_normalized = push_str8_copy(scratch.arena, filename); + for(U64 idx = 0; idx < filename_normalized.size; idx += 1) + { + filename_normalized.str[idx] = char_to_lower(filename_normalized.str[idx]); + filename_normalized.str[idx] = char_to_correct_slash(filename_normalized.str[idx]); + } + + // rjf: filename -> src_id + U32 src_id = 0; + { + RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_NormalSourcePaths); + if(mapptr != 0) + { + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, filename_normalized.str, filename_normalized.size); + if(node != 0) + { + U32 id_count = 0; + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); + if(id_count > 0) + { + src_id = ids[0]; + } + } + } + } + + // rjf: src_id * pt -> push + { + RDI_SourceFile *src = rdi_element_from_idx(rdi, source_files, src_id); + RDI_ParsedLineMap line_map = {0}; + rdi_line_map_from_source_file(rdi, src, &line_map); + U32 voff_count = 0; + U64 *voffs = rdi_line_voffs_from_num(&line_map, pt.line, &voff_count); + for(U32 i = 0; i < voff_count; i += 1) + { + U64 vaddr = voffs[i] + base_vaddr; + DMN_Trap trap = {process, vaddr, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } + }break; + + //- rjf: symbol:voff-based breakpoints + case CTRL_UserBreakpointKind_SymbolNameAndOffset: + { + String8 symbol_name = bp->string; + U64 voff = bp->u64; + if(rdi != 0 && rdi->procedures != 0) + { + RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); + if(mapptr != 0) + { + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, symbol_name.str, symbol_name.size); + if(node != 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) + { + U64 proc_voff = rdi_first_voff_from_proc(rdi, ids[match_i]); + U64 proc_vaddr = proc_voff + base_vaddr; + DMN_Trap trap = {process, proc_vaddr + voff, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } + } + } + }break; + } + } + dbgi_scope_close(scope); + scratch_end(scratch); +} + +internal void +ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_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) + { + DMN_Trap trap = {process, bp->u64, (U64)bp}; + dmn_trap_chunk_list_push(arena, traps_out, 256, &trap); + } + } +} + //- rjf: attached process running/event gathering -internal DEMON_Event * -ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_ctrls, CTRL_Spoof *spoof) +internal DMN_Event * +ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof) { ProfBeginFunction(); - DEMON_Event *event = push_array(arena, DEMON_Event, 1); + DMN_Event *event = push_array(arena, DMN_Event, 1); Temp scratch = scratch_begin(&arena, 1); //- rjf: loop -> try to get event, run, repeat @@ -1584,17 +1921,17 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c ProfScope("get next event") { // rjf: grab first event - DEMON_EventNode *next_event_node = ctrl_state->first_demon_event_node; + DMN_EventNode *next_event_node = ctrl_state->first_dmn_event_node; // rjf: determine if we should filter B32 should_filter_event = 0; if(next_event_node != 0) { - DEMON_Event *ev = &next_event_node->v; + DMN_Event *ev = &next_event_node->v; switch(ev->kind) { default:{}break; - case DEMON_EventKind_Exception: + case DMN_EventKind_Exception: { // NOTE(rjf): first chance exceptions -> try ignoring should_filter_event = (ev->exception_repeated == 0 && (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)); @@ -1629,35 +1966,43 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { DBGI_Scope *scope = dbgi_scope_open(); - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, ev->process); - if(modules.count != 0) + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, ev->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; + } + } + if(module != &ctrl_entity_nil) { // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - CTRL_Handle module = ctrl_handle_from_demon(modules.handles[0]); - String8 module_path = demon_full_path_from_module(scratch.arena, ctrl_demon_handle_from_ctrl(module)); + String8 module_path = module->string; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, module_path, max_U64); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - RADDBG_NameMap *unparsed_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_GlobalVariables); - if(rdbg->global_variables != 0 && unparsed_map != 0) + RDI_Parsed *rdi = &dbgi->rdi; + RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_GlobalVariables); + if(rdi->global_variables != 0 && unparsed_map != 0) { - RADDBG_ParsedNameMap map = {0}; - raddbg_name_map_parse(rdbg, unparsed_map, &map); + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, unparsed_map, &map); String8 name = str8_lit("__asan_shadow_memory_dynamic_address"); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, name.str, name.size); if(node != 0) { U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); if(id_count > 0) { - RADDBG_GlobalVariable *global_var = raddbg_element_from_idx(rdbg, global_variables, ids[0]); + RDI_GlobalVariable *global_var = rdi_element_from_idx(rdi, global_variables, ids[0]); U64 global_var_voff = global_var->voff; - U64 global_var_vaddr = global_var->voff + demon_base_vaddr_from_module(ctrl_demon_handle_from_ctrl(module)); - Architecture arch = demon_arch_from_object(ev->thread); + U64 global_var_vaddr = global_var->voff + module->vaddr_range.min; + Architecture arch = process->arch; U64 addr_size = bit_size_from_arch(arch)/8; - ctrl_process_read(CTRL_MachineID_Client, ctrl_handle_from_demon(ev->process), r1u64(global_var_vaddr, global_var_vaddr+addr_size), &asan_shadow_base_vaddr); + dmn_process_read(ev->process, r1u64(global_var_vaddr, global_var_vaddr+addr_size), &asan_shadow_base_vaddr); asan_shadow_variable_exists_but_is_zero = (asan_shadow_base_vaddr == 0); } } @@ -1691,7 +2036,7 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c if(next_event_node != 0 && !should_filter_event) { got_event = 1; - SLLQueuePop(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node); + SLLQueuePop(ctrl_state->first_dmn_event_node, ctrl_state->last_dmn_event_node); MemoryCopyStruct(event, &next_event_node->v); event->string = push_str8_copy(arena, event->string); run_ctrls->ignore_previous_exception = 1; @@ -1700,62 +2045,56 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c // rjf: good event but filtered? pop from queue if(next_event_node != 0 && should_filter_event) { - SLLQueuePop(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node); + SLLQueuePop(ctrl_state->first_dmn_event_node, ctrl_state->last_dmn_event_node); run_ctrls->ignore_previous_exception = 0; } } - //- rjf: no event -> demon_run for a new one - if(got_event == 0) ProfScope("no event -> demon_run for a new one") + //- rjf: no event -> dmn_ctrl_run for a new one + if(got_event == 0) ProfScope("no event -> dmn_ctrl_run for a new one") { // rjf: prep spoof - B32 do_spoof = (spoof != 0 && run_ctrls->single_step_thread == 0); + B32 do_spoof = (spoof != 0 && dmn_handle_match(run_ctrls->single_step_thread, dmn_handle_zero())); U64 size_of_spoof = 0; if(do_spoof) ProfScope("prep spoof") { - Architecture arch = demon_arch_from_object(ctrl_demon_handle_from_ctrl(spoof->process)); - demon_read_memory(ctrl_demon_handle_from_ctrl(spoof->process), &spoof_old_ip_value, spoof->vaddr, sizeof(spoof_old_ip_value)); + CTRL_Entity *spoof_process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, spoof->process); + Architecture arch = spoof_process->arch; size_of_spoof = bit_size_from_arch(arch)/8; + dmn_process_read(spoof_process->handle, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); } // rjf: set spoof if(do_spoof) ProfScope("set spoof") { - demon_write_memory(ctrl_demon_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof->new_ip_value, size_of_spoof); + dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof->new_ip_value); } // rjf: run for new events ProfScope("run for new events") { - DEMON_EventList events = demon_run(scratch.arena, run_ctrls); - for(DEMON_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next) + DMN_EventList events = dmn_ctrl_run(scratch.arena, ctrl_ctx, run_ctrls); + for(DMN_EventNode *src_n = events.first; src_n != 0; src_n = src_n->next) { - DEMON_EventNode *dst_n = ctrl_state->free_demon_event_node; + DMN_EventNode *dst_n = ctrl_state->free_dmn_event_node; if(dst_n != 0) { - SLLStackPop(ctrl_state->free_demon_event_node); + SLLStackPop(ctrl_state->free_dmn_event_node); } else { - dst_n = push_array(ctrl_state->demon_event_arena, DEMON_EventNode, 1); + dst_n = push_array(ctrl_state->dmn_event_arena, DMN_EventNode, 1); } MemoryCopyStruct(&dst_n->v, &src_n->v); - dst_n->v.string = push_str8_copy(ctrl_state->demon_event_arena, dst_n->v.string); - SLLQueuePush(ctrl_state->first_demon_event_node, ctrl_state->last_demon_event_node, dst_n); + dst_n->v.string = push_str8_copy(ctrl_state->dmn_event_arena, dst_n->v.string); + SLLQueuePush(ctrl_state->first_dmn_event_node, ctrl_state->last_dmn_event_node, dst_n); } } // rjf: unset spoof if(do_spoof) ProfScope("unset spoof") { - demon_write_memory(ctrl_demon_handle_from_ctrl(spoof->process), spoof->vaddr, &spoof_old_ip_value, size_of_spoof); - } - - // rjf: inc generation counters - { - ins_atomic_u64_inc_eval(&ctrl_state->run_idx); - ins_atomic_u64_inc_eval(&ctrl_state->memgen_idx); - ins_atomic_u64_inc_eval(&ctrl_state->reggen_idx); + dmn_process_write(spoof->process, r1u64(spoof->vaddr, spoof->vaddr+size_of_spoof), &spoof_old_ip_value); } } } @@ -1765,10 +2104,15 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c // simply been sent other debug events first if(spoof != 0) { - U64 spoof_thread_rip = demon_read_ip(ctrl_demon_handle_from_ctrl(spoof->thread)); + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, spoof->thread); + Architecture arch = thread->arch; + void *regs_block = push_array(scratch.arena, U8, regs_block_size_from_architecture(arch)); + dmn_thread_read_reg_block(spoof->thread, regs_block); + U64 spoof_thread_rip = regs_rip_from_arch_block(arch, regs_block); if(spoof_thread_rip == spoof->new_ip_value) { - demon_write_ip(ctrl_demon_handle_from_ctrl(spoof->thread), spoof_old_ip_value); + regs_arch_block_write_rip(arch, regs_block, spoof_old_ip_value); + dmn_thread_write_reg_block(spoof->thread, regs_block); } } @@ -1777,95 +2121,95 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c ProfScope("push ctrl events associated with this demon event") switch(event->kind) { default:{}break; - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_NewProc; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->process); - out_evt->arch = demon_arch_from_object(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->process; + out_evt->arch = event->arch; out_evt->entity_id = event->code; ctrl_state->process_counter += 1; }break; - case DEMON_EventKind_CreateThread: + case DMN_EventKind_CreateThread: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_NewThread; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); - out_evt->parent = ctrl_handle_from_demon(event->process); - out_evt->arch = demon_arch_from_object(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; + out_evt->parent = event->process; + out_evt->arch = event->arch; out_evt->entity_id = event->code; - out_evt->stack_base = demon_stack_base_vaddr_from_thread(event->thread); - out_evt->tls_root = demon_tls_root_vaddr_from_thread(event->thread); + out_evt->stack_base = dmn_stack_base_vaddr_from_thread(event->thread); + out_evt->tls_root = dmn_tls_root_vaddr_from_thread(event->thread); out_evt->rip_vaddr = event->instruction_pointer; out_evt->string = event->string; }break; - case DEMON_EventKind_LoadModule: + case DMN_EventKind_LoadModule: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; dbgi_binary_open(module_path); out_evt->kind = CTRL_EventKind_NewModule; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->module); - out_evt->parent = ctrl_handle_from_demon(event->process); - out_evt->arch = demon_arch_from_object(event->module); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->module; + out_evt->parent = event->process; + out_evt->arch = event->arch; out_evt->entity_id = event->code; out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); - out_evt->rip_vaddr = demon_base_vaddr_from_module(event->module); + out_evt->rip_vaddr = event->address; out_evt->string = module_path; }break; - case DEMON_EventKind_ExitProcess: + case DMN_EventKind_ExitProcess: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_EndProc; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->process; out_evt->u64_code = event->code; ctrl_state->process_counter -= 1; }break; - case DEMON_EventKind_ExitThread: + case DMN_EventKind_ExitThread: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_EndThread; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; out_evt->entity_id = event->code; }break; - case DEMON_EventKind_UnloadModule: + case DMN_EventKind_UnloadModule: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; dbgi_binary_close(module_path); out_evt->kind = CTRL_EventKind_EndModule; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->module); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->module; }break; - case DEMON_EventKind_DebugString: + case DMN_EventKind_DebugString: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_DebugString; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); - out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; + out_evt->parent = event->process; out_evt->string = event->string; }break; - case DEMON_EventKind_SetThreadName: + case DMN_EventKind_SetThreadName: { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); out_evt->kind = CTRL_EventKind_ThreadName; out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Client; - out_evt->entity = ctrl_handle_from_demon(event->thread); - out_evt->parent = ctrl_handle_from_demon(event->process); + out_evt->machine_id = CTRL_MachineID_Local; + out_evt->entity = event->thread; + out_evt->parent = event->process; out_evt->string = event->string; out_evt->entity_id = event->code; }break; @@ -1873,7 +2217,7 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c ctrl_c2u_push_events(&evts); //- rjf: clear process memory cache, if we've just started a lone process - if(event->kind == DEMON_EventKind_CreateProcess && ctrl_state->process_counter == 1) + if(event->kind == DMN_EventKind_CreateProcess && ctrl_state->process_counter == 1) { CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; for(U64 slot_idx = 0; slot_idx < cache->slots_count; slot_idx += 1) @@ -1894,10 +2238,10 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c } //- rjf: out of queued up demon events -> clear event arena - if(ctrl_state->first_demon_event_node == 0) + if(ctrl_state->first_dmn_event_node == 0) { - ctrl_state->free_demon_event_node = 0; - arena_clear(ctrl_state->demon_event_arena); + ctrl_state->free_dmn_event_node = 0; + arena_clear(ctrl_state->dmn_event_arena); } scratch_end(scratch); @@ -1910,8 +2254,8 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size) { - DEMON_Handle process = (DEMON_Handle)u; - U64 read_size = demon_read_memory(process, out, addr, size); + DMN_Handle process = *(DMN_Handle *)u; + U64 read_size = dmn_process_read(process, r1u64(addr, addr+size), out); B32 result = (read_size == size); return result; } @@ -1919,12 +2263,8 @@ ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size) //- rjf: msg kind implementations internal void -ctrl_thread__launch_and_handshake(CTRL_Msg *msg) +ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); - //- rjf: launch OS_LaunchOptions opts = {0}; { @@ -1933,445 +2273,50 @@ ctrl_thread__launch_and_handshake(CTRL_Msg *msg) opts.env = msg->env_string_list; opts.inherit_env = msg->env_inherit; } - U32 id = demon_launch_process(&opts); + U32 id = dmn_ctrl_launch(ctrl_ctx, &opts); - //- rjf: record start + //- 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_EventList evts = {0}; - CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); - event->kind = CTRL_EventKind_Started; - ctrl_c2u_push_events(&evts); + 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, Architecture_Null, 0, dmn_handle_zero(), (U64)id); + ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, entry, string); } - - //- rjf: run to handshake - DEMON_Event *stop_event = 0; - if(id != 0) - { - // rjf: prep run controls - DEMON_Handle unfrozen_process = 0; - DEMON_RunCtrls run_ctrls = {0}; - { - run_ctrls.run_entities_are_unfrozen = 1; - run_ctrls.run_entities_are_processes = 1; - run_ctrls.run_entities = &unfrozen_process; - run_ctrls.run_entity_count = 0; - } - - // rjf: run until handshake-signifying events - for(B32 done = 0; done == 0;) - { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); - switch(event->kind) - { - default:{}break; - case DEMON_EventKind_CreateProcess: - { - unfrozen_process = event->process; - run_ctrls.run_entity_count = 1; - }break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Breakpoint: - case DEMON_EventKind_Exception: - case DEMON_EventKind_ExitProcess: - case DEMON_EventKind_HandshakeComplete: - { - done = 1; - stop_event = event; - }break; - } - } - } - - //- rjf: record bad stop - if(stop_event == 0 && id == 0) - { - CTRL_EventList evts = {0}; - CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); - event->kind = CTRL_EventKind_Error; - event->cause = CTRL_EventCause_Error; - ctrl_c2u_push_events(&evts); - } - - //- rjf: record stop - { - CTRL_EventList evts = {0}; - CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); - event->kind = CTRL_EventKind_Stopped; - if(stop_event != 0) - { - event->cause = ctrl_event_cause_from_demon_event_kind(stop_event->kind); - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); - event->exception_code = stop_event->code; - event->vaddr_rng = r1u64(stop_event->address, stop_event->address); - event->rip_vaddr = stop_event->instruction_pointer; - } - ctrl_c2u_push_events(&evts); - } - - //- rjf: push request resolution event - { - CTRL_EventList evts = {0}; - CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); - evt->kind = CTRL_EventKind_LaunchAndHandshakeDone; - evt->machine_id= CTRL_MachineID_Client; - evt->msg_id = msg->msg_id; - evt->entity_id = id; - ctrl_c2u_push_events(&evts); - } - - dbgi_scope_close(scope); - scratch_end(scratch); - ProfEnd(); } internal void -ctrl_thread__launch_and_init(CTRL_Msg *msg) -{ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - ////////////////////////////// - //- rjf: launch - // - OS_LaunchOptions opts = {0}; - { - opts.cmd_line = msg->cmd_line_string_list; - opts.path = msg->path; - opts.env = msg->env_string_list; - opts.inherit_env = msg->env_inherit; - } - U32 id = demon_launch_process(&opts); - - ////////////////////////////// - //- rjf: record start - // - { - CTRL_EventList evts = {0}; - CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); - event->kind = CTRL_EventKind_Started; - ctrl_c2u_push_events(&evts); - } - - ////////////////////////////// - //- rjf: run to initialization (entry point) - // - DEMON_Event *stop_event = 0; - if(id != 0) - { - DEMON_Handle unfrozen_process[8] = {0}; - DEMON_RunCtrls run_ctrls = {0}; - run_ctrls.run_entities_are_unfrozen = 1; - run_ctrls.run_entities_are_processes = 1; - for(B32 done = 0; done == 0;) - { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); - switch(event->kind) - { - default:{}break; - - //- rjf: new process -> freeze process - case DEMON_EventKind_CreateProcess: - if(run_ctrls.run_entity_count < ArrayCount(unfrozen_process)) - { - unfrozen_process[run_ctrls.run_entity_count] = event->process; - run_ctrls.run_entities = &unfrozen_process[0]; - run_ctrls.run_entity_count += 1; - }break; - - //- rjf: breakpoint -> if it's the entry point, we're done. otherwise, keep going - case DEMON_EventKind_Breakpoint: - { - for(DEMON_TrapChunkNode *n = run_ctrls.traps.first; n != 0; n = n->next) - { - for(U64 idx = 0; idx < n->count; idx += 1) - { - if(n->v[idx].address == event->instruction_pointer) - { - done = 1; - stop_event = event; - goto end_look_for_entry_match; - } - } - } - end_look_for_entry_match:; - }break; - - //- rjf: exception -> done - case DEMON_EventKind_Exception: - { - done = 1; - stop_event = event; - }break; - - //- rjf: process ended? -> remove from unfrozen processes. zero processes -> done. - case DEMON_EventKind_ExitProcess: - { - for(U64 idx = 0; idx < run_ctrls.run_entity_count; idx += 1) - { - if(run_ctrls.run_entities[idx] == event->process && - idx+1 < run_ctrls.run_entity_count) - { - MemoryCopy(run_ctrls.run_entities+idx, run_ctrls.run_entities+idx+1, sizeof(DEMON_Handle)*(run_ctrls.run_entity_count-(idx+1))); - break; - } - } - if(run_ctrls.run_entity_count > 0) - { - run_ctrls.run_entity_count -= 1; - } - if(run_ctrls.run_entity_count == 0) - { - done = 1; - stop_event = event; - } - }break; - - //- rjf: done with handshake -> ready to find entry point. search launched processes - case DEMON_EventKind_HandshakeComplete: - { - DBGI_Scope *scope = dbgi_scope_open(); - - //- rjf: add traps for all possible entry points - for(U64 process_idx = 0; process_idx < run_ctrls.run_entity_count; process_idx += 1) - { - //- rjf: unpack first module info - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, run_ctrls.run_entities[process_idx]); - if(modules.count == 0) { continue; } - DEMON_Handle module = modules.handles[0]; - U64 module_base_vaddr = demon_base_vaddr_from_module(module); - String8 exe_path = demon_full_path_from_module(scratch.arena, module); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - RADDBG_NameMap *unparsed_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Procedures); - RADDBG_ParsedNameMap map = {0}; - raddbg_name_map_parse(rdbg, unparsed_map, &map); - - //- rjf: add trap for user-specified entry point, if specified - B32 entries_found = 0; - if(!entries_found) - { - for(String8Node *n = msg->strings.first; n != 0; n = n->next) - { - U32 procedure_id = 0; - { - String8 name = n->string; - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); - U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); - if(id_count > 0) - { - procedure_id = ids[0]; - } - } - U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id); - if(voff != 0) - { - entries_found = 1; - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); - } - } - } - - //- rjf: add traps for all custom user entry points - if(!entries_found) - { - for(String8Node *n = ctrl_state->user_entry_points.first; n != 0; n = n->next) - { - U32 procedure_id = 0; - { - String8 name = n->string; - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); - U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); - if(id_count > 0) - { - procedure_id = ids[0]; - } - } - U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id); - if(voff != 0) - { - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); - break; - } - } - } - - //- rjf: add traps for all high-level entry points - if(!entries_found) - { - String8 hi_entry_points[] = - { - str8_lit("WinMain"), - str8_lit("wWinMain"), - str8_lit("main"), - str8_lit("wmain"), - }; - for(U64 idx = 0; idx < ArrayCount(hi_entry_points); idx += 1) - { - U32 procedure_id = 0; - { - String8 name = hi_entry_points[idx]; - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); - U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); - if(id_count > 0) - { - procedure_id = ids[0]; - } - } - U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id); - if(voff != 0) - { - entries_found = 1; - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); - } - } - } - - //- rjf: add trap for PE header entry - if(!entries_found) - { - U64 voff = dbgi->pe.entry_point; - if(voff != 0) - { - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); - } - } - - //- rjf: add traps for all low-level entry points - if(!entries_found) - { - String8 lo_entry_points[] = - { - str8_lit("WinMainCRTStartup"), - str8_lit("wWinMainCRTStartup"), - str8_lit("mainCRTStartup"), - str8_lit("wmainCRTStartup"), - }; - for(U64 idx = 0; idx < ArrayCount(lo_entry_points); idx += 1) - { - U32 procedure_id = 0; - { - String8 name = lo_entry_points[idx]; - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); - U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); - if(id_count > 0) - { - procedure_id = ids[0]; - } - } - U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id); - if(voff != 0) - { - entries_found = 1; - DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff}; - demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap); - } - } - } - - //- rjf: no entry point found -> done - if(run_ctrls.traps.trap_count == 0) - { - done = 1; - stop_event = event; - } - } - - dbgi_scope_close(scope); - }break; - } - } - } - - ////////////////////////////// - //- rjf: record bad stop - // - if(stop_event == 0 && id == 0) - { - CTRL_EventList evts = {0}; - CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); - event->kind = CTRL_EventKind_Error; - event->cause = CTRL_EventCause_Error; - ctrl_c2u_push_events(&evts); - } - - ////////////////////////////// - //- rjf: record stop - // - { - CTRL_EventList evts = {0}; - CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); - event->kind = CTRL_EventKind_Stopped; - event->msg_id = msg->msg_id; - if(stop_event != 0) - { - event->cause = ctrl_event_cause_from_demon_event_kind(stop_event->kind); - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); - event->exception_code = stop_event->code; - event->vaddr_rng = r1u64(stop_event->address, stop_event->address); - event->rip_vaddr = stop_event->instruction_pointer; - } - ctrl_c2u_push_events(&evts); - } - - ////////////////////////////// - //- rjf: push request resolution event - // - { - CTRL_EventList evts = {0}; - CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); - evt->kind = CTRL_EventKind_LaunchAndInitDone; - evt->machine_id= CTRL_MachineID_Client; - evt->msg_id = msg->msg_id; - evt->entity_id = id; - ctrl_c2u_push_events(&evts); - } - - scratch_end(scratch); - ProfEnd(); -} - -internal void -ctrl_thread__attach(CTRL_Msg *msg) +ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); //- rjf: attach - B32 attach_successful = demon_attach_process(msg->entity_id); + B32 attach_successful = dmn_ctrl_attach(ctrl_ctx, msg->entity_id); //- rjf: run to handshake if(attach_successful) { - DEMON_Handle unfrozen_process = 0; - DEMON_RunCtrls run_ctrls = {0}; + DMN_Handle unfrozen_process = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: { unfrozen_process = event->process; run_ctrls.run_entities = &unfrozen_process; run_ctrls.run_entity_count = 1; }break; - case DEMON_EventKind_HandshakeComplete: + case DMN_EventKind_Halt: + case DMN_EventKind_Exception: + case DMN_EventKind_Error: + case DMN_EventKind_HandshakeComplete: { done = 1; }break; @@ -2379,14 +2324,15 @@ ctrl_thread__attach(CTRL_Msg *msg) } } - //- rjf: push request resolution event + //- rjf: record stop { CTRL_EventList evts = {0}; - CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); - evt->kind = CTRL_EventKind_AttachDone; - evt->machine_id= CTRL_MachineID_Client; - evt->msg_id = msg->msg_id; - evt->entity_id = !!attach_successful * msg->entity_id; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Stopped; + event->cause = CTRL_EventCause_Finished; + event->machine_id = CTRL_MachineID_Local; + event->msg_id = msg->msg_id; + event->entity_id = !!attach_successful * msg->entity_id; ctrl_c2u_push_events(&evts); } @@ -2396,45 +2342,50 @@ ctrl_thread__attach(CTRL_Msg *msg) } internal void -ctrl_thread__kill(CTRL_Msg *msg) +ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - DEMON_Handle process = ctrl_demon_handle_from_ctrl(msg->entity); + DMN_Handle process = msg->entity; U32 exit_code = msg->exit_code; //- rjf: send kill - B32 kill_worked = demon_kill_process(process, exit_code); + B32 kill_worked = dmn_ctrl_kill(ctrl_ctx, process, exit_code); //- rjf: wait for process to be dead - if(demon_object_exists(process) && kill_worked) + if(kill_worked) { - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; run_ctrls.run_entities = &process; run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); - if(event->kind == DEMON_EventKind_ExitProcess && event->process == process) + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); + if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) + { + done = 1; + } + if(event->kind == DMN_EventKind_Halt) { done = 1; } } } - //- rjf: push request resolution event + //- rjf: record stop { CTRL_EventList evts = {0}; - CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); - evt->kind = CTRL_EventKind_KillDone; - evt->machine_id= CTRL_MachineID_Client; - evt->msg_id = msg->msg_id; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Stopped; + event->cause = CTRL_EventCause_Finished; + event->machine_id = CTRL_MachineID_Local; + event->msg_id = msg->msg_id; if(kill_worked) { - evt->entity = msg->entity; + event->entity = msg->entity; } ctrl_c2u_push_events(&evts); } @@ -2445,44 +2396,49 @@ ctrl_thread__kill(CTRL_Msg *msg) } internal void -ctrl_thread__detach(CTRL_Msg *msg) +ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - DEMON_Handle process = ctrl_demon_handle_from_ctrl(msg->entity); + DMN_Handle process = msg->entity; //- rjf: detach - B32 detach_worked = demon_detach_process(process); + B32 detach_worked = dmn_ctrl_detach(ctrl_ctx, process); //- rjf: wait for process to be dead - if(demon_object_exists(process) && detach_worked) + if(detach_worked) { - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.run_entities_are_unfrozen = 1; run_ctrls.run_entities_are_processes = 1; run_ctrls.run_entities = &process; run_ctrls.run_entity_count = 1; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); - if(event->kind == DEMON_EventKind_ExitProcess && event->process == process) + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); + if(event->kind == DMN_EventKind_ExitProcess && dmn_handle_match(event->process, process)) + { + done = 1; + } + if(event->kind == DMN_EventKind_Halt) { done = 1; } } } - //- rjf: push request resolution event + //- rjf: record stop { CTRL_EventList evts = {0}; - CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); - evt->kind = CTRL_EventKind_DetachDone; - evt->machine_id= CTRL_MachineID_Client; - evt->msg_id = msg->msg_id; + CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); + event->kind = CTRL_EventKind_Stopped; + event->cause = CTRL_EventCause_Finished; + event->machine_id = CTRL_MachineID_Local; + event->msg_id = msg->msg_id; if(detach_worked) { - evt->entity = msg->entity; + event->entity = msg->entity; } ctrl_c2u_push_events(&evts); } @@ -2493,46 +2449,51 @@ ctrl_thread__detach(CTRL_Msg *msg) } internal void -ctrl_thread__run(CTRL_Msg *msg) +ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - DEMON_Event *stop_event = 0; + DMN_Event *stop_event = 0; CTRL_EventCause stop_cause = CTRL_EventCause_Null; - DEMON_Handle target_thread = ctrl_demon_handle_from_ctrl(msg->entity); - DEMON_Handle target_process = ctrl_demon_handle_from_ctrl(msg->parent); + DMN_Handle target_thread = msg->entity; + DMN_Handle target_process = msg->parent; U64 spoof_ip_vaddr = 911; - ////////////////////////////// - //- rjf: gather processes - // - DEMON_HandleArray processes = demon_all_processes(scratch.arena); - ////////////////////////////// //- rjf: gather all initial breakpoints // - DEMON_TrapChunkList user_traps = {0}; + DMN_TrapChunkList user_traps = {0}; + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) { - // rjf: resolve module-dependent user bps - for(U64 process_idx = 0; process_idx < processes.count; process_idx += 1) + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) { - DEMON_Handle process = processes.handles[process_idx]; - DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, process); - for(U64 module_idx = 0; module_idx < modules.count; module_idx += 1) + 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) { - DEMON_Handle module = modules.handles[module_idx]; - ctrl_append_resolved_module_user_bp_traps(scratch.arena, process, module, &msg->user_bps, &user_traps); + if(module->kind != CTRL_EntityKind_Module) { continue; } + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, machine->machine_id, process->handle, module->handle, &msg->user_bps, &user_traps); } - } - - // rjf: push virtual-address user breakpoints per-process - for(U64 process_idx = 0; process_idx < processes.count; process_idx += 1) - { - ctrl_append_resolved_process_user_bp_traps(scratch.arena, processes.handles[process_idx], &msg->user_bps, &user_traps); + + // rjf: push virtual-address user breakpoints per-process + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, machine->machine_id, process->handle, &msg->user_bps, &user_traps); } } + ////////////////////////////// + //- rjf: read initial stack-pointer-check value + // + // This MUST happen before any threads move, including single-stepping stuck + // threads, because otherwise, their stack pointer may change, if single-stepping + // causes e.g. entrance into a function via a call instruction. + // + U64 sp_check_value = dmn_rsp_from_thread(target_thread); + ////////////////////////////// //- rjf: single step "stuck threads" // @@ -2549,58 +2510,62 @@ ctrl_thread__run(CTRL_Msg *msg) if(stop_event == 0) { // rjf: gather stuck threads - DEMON_HandleList stuck_threads = {0}; - for(U64 i = 0; i < processes.count; i += 1) + DMN_HandleList stuck_threads = {0}; + for(CTRL_Entity *machine = ctrl_state->ctrl_thread_entity_store->root->first; + machine != &ctrl_entity_nil; + machine = machine->next) { - DEMON_Handle process = processes.handles[i]; - DEMON_HandleArray threads = demon_threads_from_process(scratch.arena, process); - for(U64 j = 0; j < threads.count; j += 1) + if(machine->kind != CTRL_EntityKind_Machine) { continue; } + for(CTRL_Entity *process = machine->first; process != &ctrl_entity_nil; process = process->next) { - DEMON_Handle thread = threads.handles[j]; - U64 rip = demon_read_ip(thread); - - // rjf: determine if thread is frozen - B32 thread_is_frozen = !msg->freeze_state_is_frozen; - for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) + if(process->kind != CTRL_EntityKind_Process) { continue; } + for(CTRL_Entity *thread = process->first; thread != &ctrl_entity_nil; thread = thread->next) { - if(ctrl_demon_handle_from_ctrl(n->v.handle) == thread) + U64 rip = dmn_rip_from_thread(thread->handle); + + // rjf: determine if thread is frozen + B32 thread_is_frozen = !msg->freeze_state_is_frozen; + for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) { - thread_is_frozen ^= 1; - break; + if(dmn_handle_match(n->v.handle, thread->handle)) + { + thread_is_frozen ^= 1; + break; + } } - } - - // rjf: not frozen? -> check if stuck & gather if so - if(thread_is_frozen == 0) - { - for(DEMON_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + + // rjf: not frozen? -> check if stuck & gather if so + if(thread_is_frozen == 0) { - B32 is_on_user_bp = 0; - for(DEMON_Trap *trap_ptr = n->v; trap_ptr < n->v+n->count; trap_ptr += 1) + for(DMN_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) { - if(trap_ptr->process == process && trap_ptr->address == rip) + B32 is_on_user_bp = 0; + for(DMN_Trap *trap_ptr = n->v; trap_ptr < n->v+n->count; trap_ptr += 1) { - is_on_user_bp = 1; + if(dmn_handle_match(trap_ptr->process, process->handle) && trap_ptr->vaddr == rip) + { + is_on_user_bp = 1; + } } - } - - B32 is_on_net_trap = 0; - for(CTRL_TrapNode *n = msg->traps.first; n != 0; n = n->next) - { - if(n->v.vaddr == rip) + + B32 is_on_net_trap = 0; + for(CTRL_TrapNode *n = msg->traps.first; n != 0; n = n->next) { - is_on_net_trap = 1; + if(n->v.vaddr == rip) + { + is_on_net_trap = 1; + } + } + + if(is_on_user_bp && (!is_on_net_trap || !dmn_handle_match(thread->handle, target_thread))) + { + dmn_handle_list_push(scratch.arena, &stuck_threads, thread->handle); + } + + if(is_on_user_bp && is_on_net_trap && dmn_handle_match(thread->handle, target_thread)) + { + target_thread_is_on_user_bp_and_trap_net_trap = 1; } - } - - if(is_on_user_bp && (!is_on_net_trap || thread != target_thread)) - { - demon_handle_list_push(scratch.arena, &stuck_threads, thread); - } - - if(is_on_user_bp && is_on_net_trap && thread == target_thread) - { - target_thread_is_on_user_bp_and_trap_net_trap = 1; } } } @@ -2608,28 +2573,28 @@ ctrl_thread__run(CTRL_Msg *msg) } // rjf: actually step stuck threads - for(DEMON_HandleNode *node = stuck_threads.first; + for(DMN_HandleNode *node = stuck_threads.first; node != 0; node = node->next) { - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.single_step_thread = node->v; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop; - case DEMON_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop; - case DEMON_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop; - case DEMON_EventKind_Halt: stop_cause = CTRL_EventCause_InterruptedByHalt; goto stop; + case DMN_EventKind_Error: stop_cause = CTRL_EventCause_Error; goto stop; + case DMN_EventKind_Exception: stop_cause = CTRL_EventCause_InterruptedByException; goto stop; + case DMN_EventKind_Trap: stop_cause = CTRL_EventCause_InterruptedByTrap; goto stop; + case DMN_EventKind_Halt: stop_cause = CTRL_EventCause_InterruptedByHalt; goto stop; stop:; { stop_event = event; done = 1; }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { done = 1; }break; @@ -2641,22 +2606,22 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////////// //- rjf: resolve trap net // - DEMON_TrapChunkList trap_net_traps = {0}; + DMN_TrapChunkList trap_net_traps = {0}; for(CTRL_TrapNode *node = msg->traps.first; node != 0; node = node->next) { - DEMON_Trap trap = {target_process, node->v.vaddr}; - demon_trap_chunk_list_push(scratch.arena, &trap_net_traps, 256, &trap); + DMN_Trap trap = {target_process, node->v.vaddr}; + dmn_trap_chunk_list_push(scratch.arena, &trap_net_traps, 256, &trap); } ////////////////////////////// //- rjf: join user breakpoints and trap net traps // - DEMON_TrapChunkList joined_traps = {0}; + DMN_TrapChunkList joined_traps = {0}; { - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &user_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &trap_net_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &user_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &trap_net_traps); } ////////////////////////////// @@ -2675,15 +2640,15 @@ ctrl_thread__run(CTRL_Msg *msg) // if(stop_event == 0) { - U64 sp_check_value = demon_read_sp(target_thread); B32 spoof_mode = 0; CTRL_Spoof spoof = {0}; + DMN_TrapChunkList entry_traps = {0}; for(;;) { ////////////////////////// //- rjf: choose low level traps // - DEMON_TrapChunkList *trap_list = &joined_traps; + DMN_TrapChunkList *trap_list = &joined_traps; if(spoof_mode) { trap_list = &user_traps; @@ -2701,16 +2666,16 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: setup run controls // - DEMON_RunCtrls run_ctrls = {0}; + DMN_RunCtrls run_ctrls = {0}; run_ctrls.ignore_previous_exception = 1; run_ctrls.run_entity_count = msg->freeze_state_threads.count; - run_ctrls.run_entities = push_array(scratch.arena, DEMON_Handle, run_ctrls.run_entity_count); + run_ctrls.run_entities = push_array(scratch.arena, DMN_Handle, run_ctrls.run_entity_count); run_ctrls.run_entities_are_unfrozen = !msg->freeze_state_is_frozen; { U64 idx = 0; for(CTRL_MachineIDHandlePairNode *n = msg->freeze_state_threads.first; n != 0; n = n->next) { - run_ctrls.run_entities[idx] = ctrl_demon_handle_from_ctrl(n->v.handle); + run_ctrls.run_entities[idx] = n->v.handle; idx += 1; } } @@ -2719,70 +2684,262 @@ ctrl_thread__run(CTRL_Msg *msg) ////////////////////////// //- rjf: get next event // - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, run_spoof); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, run_spoof); ////////////////////////// //- rjf: determine event handling // + B32 launch_done_first_module = 0; B32 hard_stop = 0; - CTRL_EventCause hard_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + CTRL_EventCause hard_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); B32 use_stepping_logic = 0; switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Halt: - case DEMON_EventKind_SingleStep: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Halt: + case DMN_EventKind_SingleStep: + case DMN_EventKind_Trap: { hard_stop = 1; }break; - case DEMON_EventKind_Exception: - case DEMON_EventKind_Breakpoint: + case DMN_EventKind_Exception: + case DMN_EventKind_Breakpoint: { use_stepping_logic = 1; }break; - case DEMON_EventKind_CreateProcess: + case DMN_EventKind_CreateProcess: { - DEMON_TrapChunkList new_traps = {0}; - ctrl_append_resolved_process_user_bp_traps(scratch.arena, event->process, &msg->user_bps, &new_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); + DMN_TrapChunkList new_traps = {0}; + ctrl_thread__append_resolved_process_user_bp_traps(scratch.arena, CTRL_MachineID_Local, event->process, &msg->user_bps, &new_traps); + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); }break; - case DEMON_EventKind_LoadModule: + case DMN_EventKind_LoadModule: { - DEMON_TrapChunkList new_traps = {0}; - ctrl_append_resolved_module_user_bp_traps(scratch.arena, event->process, event->module, &msg->user_bps, &new_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &new_traps); - demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &user_traps, &new_traps); + DMN_TrapChunkList new_traps = {0}; + ctrl_thread__append_resolved_module_user_bp_traps(scratch.arena, CTRL_MachineID_Local, event->process, event->module, &msg->user_bps, &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; } + ////////////////////////// + //- rjf: on launches, detect entry points, place traps + // + if(msg->run_flags & CTRL_RunFlag_StopOnEntryPoint && !launch_done_first_module && event->kind == DMN_EventKind_HandshakeComplete) + { + launch_done_first_module = 1; + + //- rjf: unpack process/module info + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, 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; + } + } + U64 module_base_vaddr = module->vaddr_range.min; + String8 exe_path = module->string; + DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); + RDI_Parsed *rdi = &dbgi->rdi; + RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, unparsed_map, &map); + + //- rjf: add traps for user-specified entry points on this message, if specified + B32 entries_found = 0; + if(!entries_found) + { + for(String8Node *n = msg->entry_points.first; n != 0; n = n->next) + { + U32 procedure_id = 0; + { + String8 name = n->string; + 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]; + } + } + U64 voff = rdi_first_voff_from_proc(rdi, procedure_id); + if(voff != 0) + { + entries_found = 1; + DMN_Trap trap = {process->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) + { + if(e->id == process->id) + { + U32 procedure_id = 0; + { + String8 name = e->string; + 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]; + } + } + U64 voff = rdi_first_voff_from_proc(rdi, procedure_id); + if(voff != 0) + { + entries_found = 1; + DMN_Trap trap = {process->handle, module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &entry_traps, 256, &trap); + } + } + } + } + + //- rjf: add traps for all custom user entry points + if(!entries_found) + { + for(String8Node *n = ctrl_state->user_entry_points.first; n != 0; n = n->next) + { + U32 procedure_id = 0; + { + String8 name = n->string; + 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]; + } + } + U64 voff = rdi_first_voff_from_proc(rdi, procedure_id); + if(voff != 0) + { + DMN_Trap trap = {process->handle, module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &entry_traps, 256, &trap); + break; + } + } + } + + //- rjf: add traps for all high-level entry points + if(!entries_found) + { + String8 hi_entry_points[] = + { + str8_lit("WinMain"), + str8_lit("wWinMain"), + str8_lit("main"), + str8_lit("wmain"), + }; + for(U64 idx = 0; idx < ArrayCount(hi_entry_points); idx += 1) + { + U32 procedure_id = 0; + { + String8 name = hi_entry_points[idx]; + 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]; + } + } + U64 voff = rdi_first_voff_from_proc(rdi, procedure_id); + if(voff != 0) + { + entries_found = 1; + DMN_Trap trap = {process->handle, module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &entry_traps, 256, &trap); + } + } + } + + //- rjf: add trap for PE header entry + if(!entries_found) + { + U64 voff = dbgi->pe.entry_point; + if(voff != 0) + { + DMN_Trap trap = {process->handle, module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &entry_traps, 256, &trap); + } + } + + //- rjf: add traps for all low-level entry points + if(!entries_found) + { + String8 lo_entry_points[] = + { + str8_lit("WinMainCRTStartup"), + str8_lit("wWinMainCRTStartup"), + str8_lit("mainCRTStartup"), + str8_lit("wmainCRTStartup"), + }; + for(U64 idx = 0; idx < ArrayCount(lo_entry_points); idx += 1) + { + U32 procedure_id = 0; + { + String8 name = lo_entry_points[idx]; + 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]; + } + } + U64 voff = rdi_first_voff_from_proc(rdi, procedure_id); + if(voff != 0) + { + entries_found = 1; + DMN_Trap trap = {process->handle, module_base_vaddr + voff}; + dmn_trap_chunk_list_push(scratch.arena, &entry_traps, 256, &trap); + } + } + } + + //- rjf: no entry point found -> done + if(entry_traps.trap_count == 0) + { + hard_stop = 1; + } + + //- rjf: found entry points -> add to joined traps + dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &entry_traps); + } + ////////////////////////// //- rjf: unpack info about thread attached to event // - Architecture arch = demon_arch_from_object(event->thread); - U64 reg_size = regs_block_size_from_architecture(arch); - void *thread_regs_block = demon_read_regs(event->thread); - U64 thread_rip_vaddr = regs_rip_from_arch_block(arch, thread_regs_block); - DEMON_Handle module = 0; + CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); + Architecture arch = thread->arch; + U64 thread_rip_vaddr = dmn_rsp_from_thread(event->thread); + DMN_Handle module = {0}; + String8 module_name = {0}; + U64 module_base_vaddr = 0; U64 thread_rip_voff = 0; { - Temp temp = temp_begin(scratch.arena); - DEMON_HandleArray modules = demon_modules_from_process(temp.arena, event->process); - if(modules.count != 0) + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->process); + for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) { - for(U64 idx = 0; idx < modules.count; idx += 1) + if(module->kind == CTRL_EntityKind_Module && contains_1u64(module->vaddr_range, thread_rip_vaddr)) { - Rng1U64 vaddr_range = demon_vaddr_range_from_module(modules.handles[idx]); - if(contains_1u64(vaddr_range, thread_rip_vaddr)) - { - module = modules.handles[idx]; - thread_rip_voff = thread_rip_vaddr - vaddr_range.min; - break; - } + module_name = module->string; + module_base_vaddr = module->vaddr_range.min; + thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; + break; } } - temp_end(temp); } ////////////////////////// @@ -2795,14 +2952,14 @@ ctrl_thread__run(CTRL_Msg *msg) // B32 hit_spoof = 0; B32 exception_stop = 0; - if(use_stepping_logic) + if(!hard_stop && use_stepping_logic) { - if(event->kind == DEMON_EventKind_Exception) + if(event->kind == DMN_EventKind_Exception) { // rjf: spoof check if(spoof_mode && - target_process == event->process && - target_thread == event->thread && + dmn_handle_match(target_process, event->process) && + dmn_handle_match(target_thread, event->thread) && spoof.new_ip_value == event->instruction_pointer) { hit_spoof = 1; @@ -2829,27 +2986,42 @@ ctrl_thread__run(CTRL_Msg *msg) } //- rjf: for breakpoint events, gather bp info + B32 hit_entry = 0; B32 hit_user_bp = 0; B32 hit_trap_net_bp = 0; B32 hit_conditional_bp_but_filtered = 0; CTRL_TrapFlags hit_trap_flags = 0; - if(use_stepping_logic) + if(!hard_stop && use_stepping_logic) { - if(event->kind == DEMON_EventKind_Breakpoint) + if(event->kind == DMN_EventKind_Breakpoint) { Temp temp = temp_begin(scratch.arena); String8List conditions = {0}; - // rjf: user breakpoints - for(DEMON_TrapChunkNode *n = user_traps.first; n != 0; n = n->next) + // rjf: entry breakpoints + for(DMN_TrapChunkNode *n = entry_traps.first; n != 0; n = n->next) { - DEMON_Trap *trap = n->v; - DEMON_Trap *opl = n->v + n->count; + DMN_Trap *trap = n->v; + DMN_Trap *opl = n->v + n->count; for(;trap < opl; trap += 1) { - if(trap->process == event->process && - trap->address == event->instruction_pointer && - (event->thread != target_thread || !target_thread_is_on_user_bp_and_trap_net_trap)) + if(dmn_handle_match(trap->process, event->process) && trap->vaddr == event->instruction_pointer) + { + hit_entry = 1; + } + } + } + + // 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(dmn_handle_match(trap->process, event->process) && + trap->vaddr == event->instruction_pointer && + (!dmn_handle_match(event->thread, target_thread) || !target_thread_is_on_user_bp_and_trap_net_trap)) { CTRL_UserBreakpoint *user_bp = (CTRL_UserBreakpoint *)trap->id; hit_user_bp = 1; @@ -2864,9 +3036,9 @@ ctrl_thread__run(CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) { - String8 exe_path = demon_full_path_from_module(temp.arena, module); + String8 exe_path = module_name; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) { String8 string = condition_n->string; @@ -2874,12 +3046,12 @@ ctrl_thread__run(CTRL_Msg *msg) { parse_ctx.arch = arch; parse_ctx.ip_voff = thread_rip_voff; - parse_ctx.rdbg = rdbg; + parse_ctx.rdi = rdi; parse_ctx.type_graph = tg_graph_begin(bit_size_from_arch(arch)/8, 256); parse_ctx.regs_map = ctrl_string2reg_from_arch(arch); parse_ctx.reg_alias_map = ctrl_string2alias_from_arch(arch); - parse_ctx.locals_map = eval_push_locals_map_from_raddbg_voff(temp.arena, rdbg, thread_rip_voff); - parse_ctx.member_map = eval_push_member_map_from_raddbg_voff(temp.arena, rdbg, thread_rip_voff); + parse_ctx.locals_map = eval_push_locals_map_from_rdi_voff(temp.arena, rdi, thread_rip_voff); + parse_ctx.member_map = eval_push_member_map_from_rdi_voff(temp.arena, rdi, thread_rip_voff); } EVAL_TokenArray tokens = eval_token_array_from_text(temp.arena, string); EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(temp.arena, &parse_ctx, string, &tokens); @@ -2889,7 +3061,7 @@ ctrl_thread__run(CTRL_Msg *msg) EVAL_IRTreeAndType ir_tree_and_type = {&eval_irtree_nil}; if(parse_has_expr && errors.count == 0) { - ir_tree_and_type = eval_irtree_and_type_from_expr(temp.arena, parse_ctx.type_graph, rdbg, &eval_string2expr_map_nil, parse.expr, &errors); + ir_tree_and_type = eval_irtree_and_type_from_expr(temp.arena, parse_ctx.type_graph, rdi, &eval_string2expr_map_nil, parse.expr, &errors); } EVAL_OpList op_list = {0}; if(parse_has_expr && ir_tree_and_type.tree != &eval_irtree_nil) @@ -2904,19 +3076,20 @@ ctrl_thread__run(CTRL_Msg *msg) EVAL_Result eval = {0}; if(bytecode.size != 0) { - U64 module_base = demon_base_vaddr_from_module(module); - U64 tls_base = 0; // TODO(rjf) + U64 module_base = module_base_vaddr; + U64 tls_base = dmn_tls_root_vaddr_from_thread(event->thread); EVAL_Machine machine = {0}; - machine.u = (void *)event->process; + machine.u = &event->process; machine.arch = arch; machine.memory_read = ctrl_eval_memory_read; - machine.reg_data = thread_regs_block; - machine.reg_size = reg_size; + machine.reg_size = regs_block_size_from_architecture(arch); + machine.reg_data = push_array(scratch.arena, U8, machine.reg_size); machine.module_base = &module_base; machine.tls_base = &tls_base; + dmn_thread_read_reg_block(event->thread, machine.reg_data); eval = eval_interpret(&machine, bytecode); } - if(eval.bad_eval == 0 && eval.value.u64 == 0) + if(eval.code == EVAL_ResultCode_Good && eval.value.u64 == 0) { hit_user_bp = 0; hit_conditional_bp_but_filtered = 1; @@ -2931,7 +3104,7 @@ ctrl_thread__run(CTRL_Msg *msg) } // rjf: gather trap net hits - if(!hit_user_bp && event->process == target_process) + if(!hit_user_bp && dmn_handle_match(event->process, target_process)) { for(CTRL_TrapNode *node = msg->traps.first; node != 0; @@ -2954,36 +3127,44 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_EventCause cond_bp_single_step_stop_cause = CTRL_EventCause_Null; if(hit_conditional_bp_but_filtered) { - DEMON_RunCtrls single_step_ctrls = {0}; + DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Exception: - case DEMON_EventKind_Halt: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Exception: + case DMN_EventKind_Halt: + case DMN_EventKind_Trap: { cond_bp_single_step_stop = 1; single_step_done = 1; use_stepping_logic = 0; - cond_bp_single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + cond_bp_single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { single_step_done = 1; - cond_bp_single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + cond_bp_single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; } } } + //- rjf: hit entry points on *any thread* cause a stop, if this msg says as such + B32 entry_stop = 0; + if(msg->run_flags & CTRL_RunFlag_StopOnEntryPoint && hit_entry) + { + entry_stop = 1; + use_stepping_logic = 0; + } + //- rjf: user breakpoints on *any thread* cause a stop B32 user_bp_stop = 0; - if(use_stepping_logic && hit_user_bp) + if(!hard_stop && use_stepping_logic && hit_user_bp) { user_bp_stop = 1; use_stepping_logic = 0; @@ -2991,9 +3172,9 @@ ctrl_thread__run(CTRL_Msg *msg) //- rjf: trap net on off-target threads are ignored B32 step_past_trap_net = 0; - if(use_stepping_logic && hit_trap_net_bp) + if(!hard_stop && use_stepping_logic && hit_trap_net_bp) { - if(event->thread != target_thread) + if(!dmn_handle_match(event->thread, target_thread)) { step_past_trap_net = 1; use_stepping_logic = 0; @@ -3002,9 +3183,9 @@ ctrl_thread__run(CTRL_Msg *msg) //- rjf: trap net on on-target threads trigger trap net logic B32 use_trap_net_logic = 0; - if(use_stepping_logic && hit_trap_net_bp) + if(!hard_stop && use_stepping_logic && hit_trap_net_bp) { - if(event->thread == target_thread) + if(dmn_handle_match(event->thread, target_thread)) { use_trap_net_logic = 1; } @@ -3014,40 +3195,40 @@ ctrl_thread__run(CTRL_Msg *msg) B32 stack_pointer_matches = 0; if(use_trap_net_logic) { - U64 sp = demon_read_sp(target_thread); + U64 sp = dmn_rsp_from_thread(target_thread); stack_pointer_matches = (sp == sp_check_value); } //- rjf: trap net logic: single step after hit B32 single_step_stop = 0; CTRL_EventCause single_step_stop_cause = CTRL_EventCause_Null; - if(use_trap_net_logic) + if(!hard_stop && use_trap_net_logic) { if(hit_trap_flags & CTRL_TrapFlag_SingleStepAfterHit) { - DEMON_RunCtrls single_step_ctrls = {0}; + DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.single_step_thread = target_thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Exception: - case DEMON_EventKind_Halt: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Exception: + case DMN_EventKind_Halt: + case DMN_EventKind_Trap: { single_step_stop = 1; single_step_done = 1; use_stepping_logic = 0; use_trap_net_logic = 0; - single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { single_step_done = 1; - single_step_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + single_step_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; } } @@ -3056,16 +3237,16 @@ ctrl_thread__run(CTRL_Msg *msg) //- rjf: trap net logic: begin spoof mode B32 begin_spoof_mode = 0; - if(use_trap_net_logic) + if(!hard_stop && use_trap_net_logic) { if(hit_trap_flags & CTRL_TrapFlag_BeginSpoofMode) { // rjf: setup spoof mode begin_spoof_mode = 1; - U64 spoof_sp = demon_read_sp(target_thread); + U64 spoof_sp = dmn_rsp_from_thread(target_thread); spoof_mode = 1; - spoof.process = ctrl_handle_from_demon(target_process); - spoof.thread = ctrl_handle_from_demon(target_thread); + spoof.process = target_process; + spoof.thread = target_thread; spoof.vaddr = spoof_sp; spoof.new_ip_value = spoof_ip_vaddr; } @@ -3073,21 +3254,21 @@ ctrl_thread__run(CTRL_Msg *msg) //- rjf: trap net logic: save stack pointer B32 save_stack_pointer = 0; - if(use_trap_net_logic) + if(!hard_stop && use_trap_net_logic) { if(hit_trap_flags & CTRL_TrapFlag_SaveStackPointer) { if(stack_pointer_matches) { save_stack_pointer = 1; - sp_check_value = demon_read_sp(target_thread); + sp_check_value = dmn_rsp_from_thread(target_thread); } } } //- rjf: trap net logic: end stepping B32 trap_net_stop = 0; - if(use_trap_net_logic) + if(!hard_stop && use_trap_net_logic) { if(hit_trap_flags & CTRL_TrapFlag_EndStepping) { @@ -3110,27 +3291,27 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_EventCause step_past_trap_net_stop_cause = CTRL_EventCause_Null; if(step_past_trap_net) { - DEMON_RunCtrls single_step_ctrls = {0}; + DMN_RunCtrls single_step_ctrls = {0}; single_step_ctrls.single_step_thread = event->thread; for(B32 single_step_done = 0; single_step_done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &single_step_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &single_step_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: - case DEMON_EventKind_Exception: - case DEMON_EventKind_Halt: - case DEMON_EventKind_Trap: + case DMN_EventKind_Error: + case DMN_EventKind_Exception: + case DMN_EventKind_Halt: + case DMN_EventKind_Trap: { step_past_trap_net_stop = 1; single_step_done = 1; - step_past_trap_net_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + step_past_trap_net_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; - case DEMON_EventKind_SingleStep: + case DMN_EventKind_SingleStep: { single_step_done = 1; - step_past_trap_net_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); + step_past_trap_net_stop_cause = ctrl_event_cause_from_dmn_event_kind(event->kind); }break; } } @@ -3162,6 +3343,10 @@ ctrl_thread__run(CTRL_Msg *msg) { stage_stop_cause = CTRL_EventCause_UserBreakpoint; } + else if(entry_stop) + { + stage_stop_cause = CTRL_EventCause_EntryPoint; + } else if(trap_net_stop) { stage_stop_cause = CTRL_EventCause_Finished; @@ -3184,9 +3369,9 @@ ctrl_thread__run(CTRL_Msg *msg) CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); event->kind = CTRL_EventKind_Stopped; event->cause = stop_cause; - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); + event->machine_id = CTRL_MachineID_Local; + event->entity = stop_event->thread; + event->parent = stop_event->process; event->exception_code = stop_event->code; event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; @@ -3199,7 +3384,7 @@ ctrl_thread__run(CTRL_Msg *msg) } internal void -ctrl_thread__single_step(CTRL_Msg *msg) +ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -3214,23 +3399,23 @@ ctrl_thread__single_step(CTRL_Msg *msg) } //- rjf: single step - DEMON_Event *stop_event = 0; + DMN_Event *stop_event = 0; CTRL_EventCause stop_cause = CTRL_EventCause_Null; { - DEMON_RunCtrls run_ctrls = {0}; - run_ctrls.single_step_thread = ctrl_demon_handle_from_ctrl(msg->entity); + DMN_RunCtrls run_ctrls = {0}; + run_ctrls.single_step_thread = msg->entity; for(B32 done = 0; done == 0;) { - DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, 0); + DMN_Event *event = ctrl_thread__next_dmn_event(scratch.arena, ctrl_ctx, msg, &run_ctrls, 0); switch(event->kind) { default:{}break; - case DEMON_EventKind_Error: {stop_cause = CTRL_EventCause_Error;}goto end_single_step; - case DEMON_EventKind_Exception: {stop_cause = CTRL_EventCause_InterruptedByException;}goto end_single_step; - case DEMON_EventKind_Halt: {stop_cause = CTRL_EventCause_InterruptedByHalt;}goto end_single_step; - case DEMON_EventKind_Trap: {stop_cause = CTRL_EventCause_InterruptedByTrap;}goto end_single_step; - case DEMON_EventKind_SingleStep: {stop_cause = CTRL_EventCause_Finished;}goto end_single_step; - case DEMON_EventKind_Breakpoint: {stop_cause = CTRL_EventCause_UserBreakpoint;}goto end_single_step; + case DMN_EventKind_Error: {stop_cause = CTRL_EventCause_Error;}goto end_single_step; + case DMN_EventKind_Exception: {stop_cause = CTRL_EventCause_InterruptedByException;}goto end_single_step; + case DMN_EventKind_Halt: {stop_cause = CTRL_EventCause_InterruptedByHalt;}goto end_single_step; + case DMN_EventKind_Trap: {stop_cause = CTRL_EventCause_InterruptedByTrap;}goto end_single_step; + case DMN_EventKind_SingleStep: {stop_cause = CTRL_EventCause_Finished;}goto end_single_step; + case DMN_EventKind_Breakpoint: {stop_cause = CTRL_EventCause_UserBreakpoint;}goto end_single_step; end_single_step: { stop_event = event; @@ -3247,9 +3432,9 @@ ctrl_thread__single_step(CTRL_Msg *msg) CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts); event->kind = CTRL_EventKind_Stopped; event->cause = stop_cause; - event->machine_id = CTRL_MachineID_Client; - event->entity = ctrl_handle_from_demon(stop_event->thread); - event->parent = ctrl_handle_from_demon(stop_event->process); + event->machine_id = CTRL_MachineID_Local; + event->entity = stop_event->thread; + event->parent = stop_event->process; event->exception_code = stop_event->code; event->vaddr_rng = r1u64(stop_event->address, stop_event->address); event->rip_vaddr = stop_event->instruction_pointer; @@ -3264,23 +3449,66 @@ ctrl_thread__single_step(CTRL_Msg *msg) //////////////////////////////// //~ rjf: Memory-Stream-Thread-Only Functions +//- rjf: user -> memory stream communication + +internal B32 +ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, DMN_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(machine_id)+sizeof(process)+sizeof(vaddr_range)) + { + 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, &machine_id); + 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); + break; + } + if(os_now_microseconds() >= endt_us) {break;} + os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, endt_us); + } + os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); + return good; +} + +internal void +ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, DMN_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_machine_id)+sizeof(*out_process)+sizeof(*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_machine_id); + 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); + break; + } + os_condition_variable_wait(ctrl_state->u2ms_ring_cv, ctrl_state->u2ms_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ctrl_state->u2ms_ring_cv); +} + //- rjf: entry point internal void ctrl_mem_stream_thread__entry_point(void *p) { - TCTX tctx_ = {0}; - tctx_init_and_equip(&tctx_); CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; for(;;) { //- rjf: unpack next request CTRL_MachineID machine_id = 0; - CTRL_Handle process = {0}; + DMN_Handle process = {0}; Rng1U64 vaddr_range = {0}; B32 zero_terminated = 0; ctrl_u2ms_dequeue_req(&machine_id, &process, &vaddr_range, &zero_terminated); - U128 key = ctrl_hash_store_key_from_process_vaddr_range(machine_id, process, vaddr_range, zero_terminated); + U128 key = ctrl_calc_hash_store_key_from_process_vaddr_range(machine_id, process, vaddr_range, zero_terminated); //- rjf: unpack process memory cache key U64 process_hash = ctrl_hash_from_string(str8_struct(&process)); @@ -3294,14 +3522,14 @@ ctrl_mem_stream_thread__entry_point(void *p) //- rjf: take task B32 got_task = 0; - U64 preexisting_memgen_idx = 0; + U64 preexisting_mem_gen = 0; U128 preexisting_hash = {0}; Rng1U64 vaddr_range_clamped = {0}; OS_MutexScopeW(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; @@ -3310,7 +3538,7 @@ ctrl_mem_stream_thread__entry_point(void *p) 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_memgen_idx = range_n->memgen_idx; + 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; @@ -3326,11 +3554,11 @@ ctrl_mem_stream_thread__entry_point(void *p) Arena *range_arena = 0; void *range_base = 0; U64 zero_terminated_size = 0; - U64 memgen_idx = ctrl_memgen_idx(); - if(got_task && memgen_idx != preexisting_memgen_idx) + U64 mem_gen = dmn_mem_gen(); + if(got_task && mem_gen != preexisting_mem_gen) { range_size = dim_1u64(vaddr_range_clamped); - U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, KB(64)); + U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, os_page_size()); range_arena = arena_alloc__sized(range_size+ARENA_HEADER_SIZE, range_size+ARENA_HEADER_SIZE); if(range_arena == 0) { @@ -3339,7 +3567,20 @@ ctrl_mem_stream_thread__entry_point(void *p) else { range_base = push_array_no_zero(range_arena, U8, range_size); - U64 bytes_read = ctrl_process_read(machine_id, process, vaddr_range_clamped, range_base); + U64 bytes_read = 0; + U64 retry_count = 0; + for(Rng1U64 vaddr_range_clamped_retry = vaddr_range_clamped; retry_count < 64; retry_count += 1) + { + bytes_read = dmn_process_read(process, vaddr_range_clamped_retry, range_base); + if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) + { + vaddr_range_clamped_retry.max -= (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + } + else + { + break; + } + } if(bytes_read == 0) { arena_release(range_arena); @@ -3378,7 +3619,7 @@ ctrl_mem_stream_thread__entry_point(void *p) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) { - if(n->machine_id == machine_id && ctrl_handle_match(n->process, process)) + if(n->machine_id == machine_id && dmn_handle_match(n->process, process)) { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; @@ -3389,7 +3630,7 @@ ctrl_mem_stream_thread__entry_point(void *p) if(!u128_match(u128_zero(), hash)) { range_n->hash = hash; - range_n->memgen_idx = memgen_idx; + range_n->mem_gen = mem_gen; } ins_atomic_u32_eval_assign(&range_n->is_taken, 0); goto commit__break_all; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index bda8ec5a..879b404b 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -10,16 +10,7 @@ typedef U64 CTRL_MsgID; typedef U64 CTRL_MachineID; -#define CTRL_MachineID_Client (1) - -//////////////////////////////// -//~ rjf: Handle Type - -typedef struct CTRL_Handle CTRL_Handle; -struct CTRL_Handle -{ - U64 u64[1]; -}; +#define CTRL_MachineID_Local (1) //////////////////////////////// //~ rjf: Machine/Handle Pair Types @@ -28,7 +19,7 @@ typedef struct CTRL_MachineIDHandlePair CTRL_MachineIDHandlePair; struct CTRL_MachineIDHandlePair { CTRL_MachineID machine_id; - CTRL_Handle handle; + DMN_Handle handle; }; typedef struct CTRL_MachineIDHandlePairNode CTRL_MachineIDHandlePairNode; @@ -46,6 +37,73 @@ struct CTRL_MachineIDHandlePairList U64 count; }; +//////////////////////////////// +//~ rjf: Entity Types + +typedef enum CTRL_EntityKind +{ + CTRL_EntityKind_Null, + CTRL_EntityKind_Root, + CTRL_EntityKind_Machine, + CTRL_EntityKind_Process, + CTRL_EntityKind_Thread, + CTRL_EntityKind_Module, + CTRL_EntityKind_EntryPoint, + CTRL_EntityKind_COUNT +} +CTRL_EntityKind; + +typedef struct CTRL_Entity CTRL_Entity; +struct CTRL_Entity +{ + CTRL_Entity *first; + CTRL_Entity *last; + CTRL_Entity *next; + CTRL_Entity *prev; + CTRL_Entity *parent; + CTRL_EntityKind kind; + Architecture arch; + CTRL_MachineID machine_id; + DMN_Handle handle; + U64 id; + Rng1U64 vaddr_range; + String8 string; +}; + +typedef struct CTRL_EntityHashNode CTRL_EntityHashNode; +struct CTRL_EntityHashNode +{ + CTRL_EntityHashNode *next; + CTRL_EntityHashNode *prev; + CTRL_Entity *entity; +}; + +typedef struct CTRL_EntityHashSlot CTRL_EntityHashSlot; +struct CTRL_EntityHashSlot +{ + CTRL_EntityHashNode *first; + CTRL_EntityHashNode *last; +}; + +typedef struct CTRL_EntityStringChunkNode CTRL_EntityStringChunkNode; +struct CTRL_EntityStringChunkNode +{ + CTRL_EntityStringChunkNode *next; + U64 size; +}; + +typedef struct CTRL_EntityStore CTRL_EntityStore; +struct CTRL_EntityStore +{ + Arena *arena; + CTRL_Entity *root; + CTRL_Entity *free; + CTRL_EntityHashSlot *hash_slots; + CTRL_EntityHashNode *hash_node_free; + U64 hash_slots_count; + CTRL_EntityStringChunkNode *free_string_chunks[8]; +}; + //////////////////////////////// //~ rjf: Unwind Types @@ -105,8 +163,8 @@ struct CTRL_TrapList typedef struct CTRL_Spoof CTRL_Spoof; struct CTRL_Spoof { - CTRL_Handle process; - CTRL_Handle thread; + DMN_Handle process; + DMN_Handle thread; U64 vaddr; U64 new_ip_value; }; @@ -159,8 +217,7 @@ struct CTRL_UserBreakpointList typedef enum CTRL_MsgKind { CTRL_MsgKind_Null, - CTRL_MsgKind_LaunchAndHandshake, - CTRL_MsgKind_LaunchAndInit, + CTRL_MsgKind_Launch, CTRL_MsgKind_Attach, CTRL_MsgKind_Kill, CTRL_MsgKind_Detach, @@ -171,20 +228,27 @@ typedef enum CTRL_MsgKind } CTRL_MsgKind; +typedef U32 CTRL_RunFlags; +enum +{ + CTRL_RunFlag_StopOnEntryPoint = (1<<0), +}; + typedef struct CTRL_Msg CTRL_Msg; struct CTRL_Msg { CTRL_MsgKind kind; + CTRL_RunFlags run_flags; CTRL_MsgID msg_id; CTRL_MachineID machine_id; - CTRL_Handle entity; - CTRL_Handle parent; + DMN_Handle entity; + DMN_Handle parent; U32 entity_id; U32 exit_code; B32 env_inherit; U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; String8 path; - String8List strings; + String8List entry_points; String8List cmd_line_string_list; String8List env_string_list; CTRL_TrapList traps; @@ -238,13 +302,6 @@ typedef enum CTRL_EventKind CTRL_EventKind_MemDecommit, CTRL_EventKind_MemRelease, - //- rjf: ctrl requests - CTRL_EventKind_LaunchAndHandshakeDone, - CTRL_EventKind_LaunchAndInitDone, - CTRL_EventKind_AttachDone, - CTRL_EventKind_KillDone, - CTRL_EventKind_DetachDone, - CTRL_EventKind_COUNT } CTRL_EventKind; @@ -254,6 +311,7 @@ typedef enum CTRL_EventCause CTRL_EventCause_Null, CTRL_EventCause_Error, CTRL_EventCause_Finished, + CTRL_EventCause_EntryPoint, CTRL_EventCause_UserBreakpoint, CTRL_EventCause_InterruptedByTrap, CTRL_EventCause_InterruptedByException, @@ -281,8 +339,8 @@ struct CTRL_Event CTRL_ExceptionKind exception_kind; CTRL_MsgID msg_id; CTRL_MachineID machine_id; - CTRL_Handle entity; - CTRL_Handle parent; + DMN_Handle entity; + DMN_Handle parent; Architecture arch; U64 u64_code; U32 entity_id; @@ -320,7 +378,8 @@ struct CTRL_ProcessMemoryRangeHashNode B32 zero_terminated; Rng1U64 vaddr_range_clamped; U128 hash; - U64 memgen_idx; + U64 mem_gen; + U64 last_time_requested_us; B32 is_taken; }; @@ -338,7 +397,7 @@ struct CTRL_ProcessMemoryCacheNode CTRL_ProcessMemoryCacheNode *prev; Arena *arena; CTRL_MachineID machine_id; - CTRL_Handle process; + DMN_Handle process; U64 range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_hash_slots; }; @@ -372,6 +431,47 @@ struct CTRL_ProcessMemorySlice String8 data; U64 *byte_bad_flags; U64 *byte_changed_flags; + B32 stale; + B32 any_byte_bad; + B32 any_byte_changed; +}; + +//////////////////////////////// +//~ rjf: Thread Register Cache Types + +typedef struct CTRL_ThreadRegCacheNode CTRL_ThreadRegCacheNode; +struct CTRL_ThreadRegCacheNode +{ + CTRL_ThreadRegCacheNode *next; + CTRL_ThreadRegCacheNode *prev; + CTRL_MachineID machine_id; + DMN_Handle thread; + U64 block_size; + void *block; + U64 reg_gen; +}; + +typedef struct CTRL_ThreadRegCacheSlot CTRL_ThreadRegCacheSlot; +struct CTRL_ThreadRegCacheSlot +{ + CTRL_ThreadRegCacheNode *first; + CTRL_ThreadRegCacheNode *last; +}; + +typedef struct CTRL_ThreadRegCacheStripe CTRL_ThreadRegCacheStripe; +struct CTRL_ThreadRegCacheStripe +{ + Arena *arena; + OS_Handle rw_mutex; +}; + +typedef struct CTRL_ThreadRegCache CTRL_ThreadRegCache; +struct CTRL_ThreadRegCache +{ + U64 slots_count; + CTRL_ThreadRegCacheSlot *slots; + U64 stripes_count; + CTRL_ThreadRegCacheStripe *stripes; }; //////////////////////////////// @@ -388,16 +488,14 @@ struct CTRL_State { Arena *arena; CTRL_WakeupFunctionType *wakeup_hook; - U64 run_idx; - U64 memgen_idx; - U64 reggen_idx; // rjf: name -> register/alias hash tables for eval EVAL_String2NumMap arch_string2reg_tables[Architecture_COUNT]; EVAL_String2NumMap arch_string2alias_tables[Architecture_COUNT]; - // rjf: process memory cache + // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; + CTRL_ThreadRegCache thread_reg_cache; // rjf: user -> ctrl msg ring buffer U64 u2c_ring_size; @@ -417,10 +515,11 @@ struct CTRL_State // rjf: ctrl thread state OS_Handle ctrl_thread; - Arena *demon_event_arena; - DEMON_EventNode *first_demon_event_node; - DEMON_EventNode *last_demon_event_node; - DEMON_EventNode *free_demon_event_node; + CTRL_EntityStore *ctrl_thread_entity_store; + 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; U64 exception_code_filters[(CTRL_ExceptionCodeKind_COUNT+63)/64]; @@ -443,24 +542,21 @@ struct CTRL_State //~ rjf: Globals global CTRL_State *ctrl_state = 0; - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void ctrl_init(CTRL_WakeupFunctionType *wakeup_hook); +read_only global CTRL_Entity ctrl_entity_nil = +{ + &ctrl_entity_nil, + &ctrl_entity_nil, + &ctrl_entity_nil, + &ctrl_entity_nil, + &ctrl_entity_nil, +}; //////////////////////////////// //~ rjf: Basic Type Functions internal U64 ctrl_hash_from_string(String8 string); -internal CTRL_EventCause ctrl_event_cause_from_demon_event_kind(DEMON_EventKind event_kind); -internal B32 ctrl_handle_match(CTRL_Handle a, CTRL_Handle b); - -//////////////////////////////// -//~ rjf: Ctrl <-> Demon Handle Translation Functions - -internal DEMON_Handle ctrl_demon_handle_from_ctrl(CTRL_Handle h); -internal CTRL_Handle ctrl_handle_from_demon(DEMON_Handle h); +internal U64 ctrl_hash_from_machine_id_handle(CTRL_MachineID machine_id, DMN_Handle handle); +internal CTRL_EventCause ctrl_event_cause_from_dmn_event_kind(DMN_EventKind event_kind); //////////////////////////////// //~ rjf: Machine/Handle Pair Type Functions @@ -479,8 +575,6 @@ internal CTRL_TrapList ctrl_trap_list_copy(Arena *arena, CTRL_TrapList *src); internal void ctrl_user_breakpoint_list_push(Arena *arena, CTRL_UserBreakpointList *list, CTRL_UserBreakpoint *bp); internal CTRL_UserBreakpointList ctrl_user_breakpoint_list_copy(Arena *arena, CTRL_UserBreakpointList *src); -internal void ctrl_append_resolved_module_user_bp_traps(Arena *arena, DEMON_Handle process, DEMON_Handle module, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out); -internal void ctrl_append_resolved_process_user_bp_traps(Arena *arena, DEMON_Handle process, CTRL_UserBreakpointList *user_bps, DEMON_TrapChunkList *traps_out); //////////////////////////////// //~ rjf: Message Type Functions @@ -507,97 +601,129 @@ internal String8 ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *eve internal CTRL_Event ctrl_event_from_serialized_string(Arena *arena, String8 string); //////////////////////////////// -//~ rjf: Shared Functions +//~ rjf: Entity Type Functions -//- rjf: run index -internal U64 ctrl_run_idx(void); -internal U64 ctrl_memgen_idx(void); -internal U64 ctrl_reggen_idx(void); +//- rjf: cache creation/destruction +internal CTRL_EntityStore *ctrl_entity_store_alloc(void); +internal void ctrl_entity_store_release(CTRL_EntityStore *store); -//- rjf: halt everything -internal void ctrl_halt(void); +//- rjf: string allocation/deletion +internal String8 ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string); +internal void ctrl_entity_string_release(CTRL_EntityStore *store, String8 string); -//- rjf: exe -> dbg path mapping -internal String8 ctrl_inferred_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); -internal String8 ctrl_forced_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); -internal String8 ctrl_natural_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); -internal String8 ctrl_og_dbg_path_from_exe_path(Arena *arena, String8 exe_path); +//- rjf: entity construction/deletion +internal CTRL_Entity *ctrl_entity_alloc(CTRL_EntityStore *store, CTRL_Entity *parent, CTRL_EntityKind kind, Architecture arch, CTRL_MachineID machine_id, DMN_Handle handle, U64 id); +internal void ctrl_entity_release(CTRL_EntityStore *store, CTRL_Entity *entity); -//- rjf: handle -> arch -internal Architecture ctrl_arch_from_handle(CTRL_MachineID machine, CTRL_Handle handle); +//- rjf: entity equipment +internal void ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *entity, String8 string); -//- rjf: process memory reading/writing -internal U64 ctrl_process_read(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *dst); -internal B32 ctrl_process_write(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, void *src); +//- rjf: entity store lookups +internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle); + +//- rjf: applying events to entity caches +internal void ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void ctrl_init(void); + +//////////////////////////////// +//~ rjf: Wakeup Callback Registration + +internal void ctrl_set_wakeup_hook(CTRL_WakeupFunctionType *wakeup_hook); + +//////////////////////////////// +//~ rjf: Process Memory Functions //- rjf: process memory cache interaction -internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated); -internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, B32 zero_terminated, U64 endt_us); +internal U128 ctrl_calc_hash_store_key_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated); +internal U128 ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_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_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 zero_terminated); //- rjf: process memory cache reading helpers -internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 range, U64 endt_us); -internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr, U64 limit, U64 endt_us); +internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us); +internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr, U64 limit, U64 element_size, U64 endt_us); -//- rjf: register reading/writing -internal void *ctrl_reg_block_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); -internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, CTRL_Handle thread, void *block); -internal U64 ctrl_rip_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); -internal B32 ctrl_thread_write_rip(CTRL_MachineID machine_id, CTRL_Handle thread, U64 rip); -internal U64 ctrl_tls_root_vaddr_from_thread(CTRL_MachineID machine_id, CTRL_Handle thread); +//- rjf: process memory writing +internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src); -//- rjf: process * vaddr -> module -internal CTRL_Handle ctrl_module_from_process_vaddr(CTRL_MachineID machine_id, CTRL_Handle process, U64 vaddr); +//////////////////////////////// +//~ rjf: Thread Register Functions -//- rjf: unwinding -internal CTRL_Unwind ctrl_unwind_from_process_thread(Arena *arena, CTRL_MachineID machine_id, CTRL_Handle process, CTRL_Handle thread); +//- rjf: thread register cache reading +internal void *ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); +internal U64 ctrl_query_cached_tls_root_vaddr_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); +internal U64 ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread); + +//- rjf: thread register writing +internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block); + +//////////////////////////////// +//~ rjf: Unwinding Functions + +internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); + +//////////////////////////////// +//~ rjf: Halting All Attached Processes + +internal void ctrl_halt(void); + +//////////////////////////////// +//~ rjf: Shared Accessor Functions + +//- rjf: generation counters +internal U64 ctrl_run_gen(void); +internal U64 ctrl_mem_gen(void); +internal U64 ctrl_reg_gen(void); //- rjf: name -> register/alias hash tables, for eval internal EVAL_String2NumMap *ctrl_string2reg_from_arch(Architecture arch); internal EVAL_String2NumMap *ctrl_string2alias_from_arch(Architecture arch); //////////////////////////////// -//~ rjf: User -> Ctrl Communication +//~ rjf: Control-Thread Functions +//- rjf: user -> control thread communication internal B32 ctrl_u2c_push_msgs(CTRL_MsgList *msgs, U64 endt_us); internal CTRL_MsgList ctrl_u2c_pop_msgs(Arena *arena); -//////////////////////////////// -//~ rjf: Ctrl -> User Communication - +//- rjf: control -> user thread communication internal void ctrl_c2u_push_events(CTRL_EventList *events); internal CTRL_EventList ctrl_c2u_pop_events(Arena *arena); -//////////////////////////////// -//~ rjf: User -> Memory Stream Communication - -internal B32 ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); -internal void ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, CTRL_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); - -//////////////////////////////// -//~ rjf: Control-Thread-Only Functions - //- rjf: entry point internal void ctrl_thread__entry_point(void *p); +//- rjf: breakpoint resolution +internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); + //- rjf: attached process running/event gathering -internal DEMON_Event *ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_ctrls, CTRL_Spoof *spoof); +internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); //- rjf: eval helpers internal B32 ctrl_eval_memory_read(void *u, void *out, U64 addr, U64 size); //- rjf: msg kind implementations -internal void ctrl_thread__launch_and_handshake(CTRL_Msg *msg); -internal void ctrl_thread__launch_and_init(CTRL_Msg *msg); -internal void ctrl_thread__attach(CTRL_Msg *msg); -internal void ctrl_thread__kill(CTRL_Msg *msg); -internal void ctrl_thread__detach(CTRL_Msg *msg); -internal void ctrl_thread__run(CTRL_Msg *msg); -internal void ctrl_thread__single_step(CTRL_Msg *msg); +internal void ctrl_thread__launch(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); +internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg); //////////////////////////////// -//~ rjf: Memory-Stream-Thread-Only Functions +//~ rjf: Memory-Stream Thread Functions + +//- rjf: user -> memory stream communication +internal B32 ctrl_u2ms_enqueue_req(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us); +internal void ctrl_u2ms_dequeue_req(CTRL_MachineID *out_machine_id, DMN_Handle *out_process, Rng1U64 *out_vaddr_range, B32 *out_zero_terminated); //- rjf: entry point internal void ctrl_mem_stream_thread__entry_point(void *p); -#endif //CTRL_CORE_H +#endif // CTRL_CORE_H diff --git a/src/ctrl/ctrl_inc.h b/src/ctrl/ctrl_inc.h index e485f6d0..24b17db2 100644 --- a/src/ctrl/ctrl_inc.h +++ b/src/ctrl/ctrl_inc.h @@ -74,4 +74,4 @@ #include "ctrl_core.h" -#endif //CTRL_INC_H +#endif // CTRL_INC_H diff --git a/src/ctrl/generated/ctrl.meta.c b/src/ctrl/generated/ctrl.meta.c index b9d27fe6..e36c61bf 100644 --- a/src/ctrl/generated/ctrl.meta.c +++ b/src/ctrl/generated/ctrl.meta.c @@ -3,3 +3,174 @@ //- GENERATED CODE +C_LINKAGE_BEGIN +U32 ctrl_exception_code_kind_code_table[38] = +{ +0, +0x40010005, +0x40010008, +0x40080201, +0x40080202, +0x0000071a, +0x80000002, +0xc0000005, +0xc0000006, +0xc0000008, +0xc0000017, +0xc000001d, +0xc0000025, +0xc0000026, +0xc000008c, +0xc000008d, +0xc000008e, +0xc000008f, +0xc0000090, +0xc0000091, +0xc0000092, +0xc0000093, +0xc0000094, +0xc0000095, +0xc0000096, +0xc00000fd, +0xc0000135, +0xc0000138, +0xc0000139, +0xc0000142, +0xc00002b4, +0xc00002b5, +0xc0000420, +0xc06d007e, +0xc06d007f, +0xe073616e, +0xe0736171, +0x0000087a, +}; + +String8 ctrl_exception_code_kind_display_string_table[38] = +{ +{0}, +str8_lit_comp("(Win32) Control-C"), +str8_lit_comp("(Win32) Control-Break"), +str8_lit_comp("(Win32) WinRT Originate Error"), +str8_lit_comp("(Win32) WinRT Transform Error"), +str8_lit_comp("(Win32) RPC Call Cancelled"), +str8_lit_comp("(Win32) Data Type Misalignment"), +str8_lit_comp("(Win32) Access Violation"), +str8_lit_comp("(Win32) In Page Error"), +str8_lit_comp("(Win32) Invalid Handle Specified"), +str8_lit_comp("(Win32) Not Enough Quota"), +str8_lit_comp("(Win32) Illegal Instruction"), +str8_lit_comp("(Win32) Cannot Continue From Exception"), +str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"), +str8_lit_comp("(Win32) Array Bounds Exceeded"), +str8_lit_comp("(Win32) Floating-Point Denormal Operand"), +str8_lit_comp("(Win32) Floating-Point Division By Zero"), +str8_lit_comp("(Win32) Floating-Point Inexact Result"), +str8_lit_comp("(Win32) Floating-Point Invalid Operation"), +str8_lit_comp("(Win32) Floating-Point Overflow"), +str8_lit_comp("(Win32) Floating-Point Stack Check"), +str8_lit_comp("(Win32) Floating-Point Underflow"), +str8_lit_comp("(Win32) Integer Division By Zero"), +str8_lit_comp("(Win32) Integer Overflow"), +str8_lit_comp("(Win32) Privileged Instruction"), +str8_lit_comp("(Win32) Stack Overflow"), +str8_lit_comp("(Win32) Unable To Locate DLL"), +str8_lit_comp("(Win32) Ordinal Not Found"), +str8_lit_comp("(Win32) Entry Point Not Found"), +str8_lit_comp("(Win32) DLL Initialization Failed"), +str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"), +str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"), +str8_lit_comp("(Win32) Assertion Failed"), +str8_lit_comp("(Win32) Module Not Found"), +str8_lit_comp("(Win32) Procedure Not Found"), +str8_lit_comp("(Win32) Sanitizer Error Detected"), +str8_lit_comp("(Win32) Sanitizer Raw Access Violation"), +str8_lit_comp("(Win32) DirectX Debug Layer"), +}; + +String8 ctrl_exception_code_kind_lowercase_code_string_table[38] = +{ +{0}, +str8_lit_comp("win32_ctrl_c"), +str8_lit_comp("win32_ctrl_break"), +str8_lit_comp("win32_win_rt_originate_error"), +str8_lit_comp("win32_win_rt_transform_error"), +str8_lit_comp("win32_rpc_call_cancelled"), +str8_lit_comp("win32_datatype_misalignment"), +str8_lit_comp("win32_access_violation"), +str8_lit_comp("win32_in_page_error"), +str8_lit_comp("win32_invalid_handle"), +str8_lit_comp("win32_not_enough_quota"), +str8_lit_comp("win32_illegal_instruction"), +str8_lit_comp("win32_cannot_continue_exception"), +str8_lit_comp("win32_invalid_exception_disposition"), +str8_lit_comp("win32_array_bounds_exceeded"), +str8_lit_comp("win32_floating_point_denormal_operand"), +str8_lit_comp("win32_floating_point_division_by_zero"), +str8_lit_comp("win32_floating_point_inexact_result"), +str8_lit_comp("win32_floating_point_invalid_operation"), +str8_lit_comp("win32_floating_point_overflow"), +str8_lit_comp("win32_floating_point_stack_check"), +str8_lit_comp("win32_floating_point_underflow"), +str8_lit_comp("win32_integer_division_by_zero"), +str8_lit_comp("win32_integer_overflow"), +str8_lit_comp("win32_privileged_instruction"), +str8_lit_comp("win32_stack_overflow"), +str8_lit_comp("win32_unable_to_locate_dll"), +str8_lit_comp("win32_ordinal_not_found"), +str8_lit_comp("win32_entry_point_not_found"), +str8_lit_comp("win32_dll_initialization_failed"), +str8_lit_comp("win32_floating_point_sse_multiple_faults"), +str8_lit_comp("win32_floating_point_sse_multiple_traps"), +str8_lit_comp("win32_assertion_failed"), +str8_lit_comp("win32_module_not_found"), +str8_lit_comp("win32_procedure_not_found"), +str8_lit_comp("win32_sanitizer_error_detected"), +str8_lit_comp("win32_sanitizer_raw_access_violation"), +str8_lit_comp("win32_directx_debug_layer"), +}; + +B8 ctrl_exception_code_kind_default_enable_table[38] = +{ +0, +1, +1, +0, +0, +0, +0, +1, +0, +1, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +1, +0, +0, +1, +0, +1, +}; + +C_LINKAGE_END + diff --git a/src/ctrl/generated/ctrl.meta.h b/src/ctrl/generated/ctrl.meta.h index a9a2fb8a..2d2abf32 100644 --- a/src/ctrl/generated/ctrl.meta.h +++ b/src/ctrl/generated/ctrl.meta.h @@ -46,176 +46,14 @@ CTRL_ExceptionCodeKind_Win32ProcedureNotFound, CTRL_ExceptionCodeKind_Win32SanitizerErrorDetected, CTRL_ExceptionCodeKind_Win32SanitizerRawAccessViolation, CTRL_ExceptionCodeKind_Win32DirectXDebugLayer, -CTRL_ExceptionCodeKind_COUNT +CTRL_ExceptionCodeKind_COUNT, } CTRL_ExceptionCodeKind; -U32 ctrl_exception_code_kind_code_table[] = -{ -0, -0x40010005, -0x40010008, -0x40080201, -0x40080202, -0x0000071a, -0x80000002, -0xc0000005, -0xc0000006, -0xc0000008, -0xc0000017, -0xc000001d, -0xc0000025, -0xc0000026, -0xc000008c, -0xc000008d, -0xc000008e, -0xc000008f, -0xc0000090, -0xc0000091, -0xc0000092, -0xc0000093, -0xc0000094, -0xc0000095, -0xc0000096, -0xc00000fd, -0xc0000135, -0xc0000138, -0xc0000139, -0xc0000142, -0xc00002b4, -0xc00002b5, -0xc0000420, -0xc06d007e, -0xc06d007f, -0xe073616e, -0xe0736171, -0x0000087a, -}; - -String8 ctrl_exception_code_kind_display_string_table[] = -{ -{0}, -str8_lit_comp("(Win32) Control-C"), -str8_lit_comp("(Win32) Control-Break"), -str8_lit_comp("(Win32) WinRT Originate Error"), -str8_lit_comp("(Win32) WinRT Transform Error"), -str8_lit_comp("(Win32) RPC Call Cancelled"), -str8_lit_comp("(Win32) Data Type Misalignment"), -str8_lit_comp("(Win32) Access Violation"), -str8_lit_comp("(Win32) In Page Error"), -str8_lit_comp("(Win32) Invalid Handle Specified"), -str8_lit_comp("(Win32) Not Enough Quota"), -str8_lit_comp("(Win32) Illegal Instruction"), -str8_lit_comp("(Win32) Cannot Continue From Exception"), -str8_lit_comp("(Win32) Invalid Exception Disposition Returned By Handler"), -str8_lit_comp("(Win32) Array Bounds Exceeded"), -str8_lit_comp("(Win32) Floating-Point Denormal Operand"), -str8_lit_comp("(Win32) Floating-Point Division By Zero"), -str8_lit_comp("(Win32) Floating-Point Inexact Result"), -str8_lit_comp("(Win32) Floating-Point Invalid Operation"), -str8_lit_comp("(Win32) Floating-Point Overflow"), -str8_lit_comp("(Win32) Floating-Point Stack Check"), -str8_lit_comp("(Win32) Floating-Point Underflow"), -str8_lit_comp("(Win32) Integer Division By Zero"), -str8_lit_comp("(Win32) Integer Overflow"), -str8_lit_comp("(Win32) Privileged Instruction"), -str8_lit_comp("(Win32) Stack Overflow"), -str8_lit_comp("(Win32) Unable To Locate DLL"), -str8_lit_comp("(Win32) Ordinal Not Found"), -str8_lit_comp("(Win32) Entry Point Not Found"), -str8_lit_comp("(Win32) DLL Initialization Failed"), -str8_lit_comp("(Win32) Floating Point SSE Multiple Faults"), -str8_lit_comp("(Win32) Floating Point SSE Multiple Traps"), -str8_lit_comp("(Win32) Assertion Failed"), -str8_lit_comp("(Win32) Module Not Found"), -str8_lit_comp("(Win32) Procedure Not Found"), -str8_lit_comp("(Win32) Sanitizer Error Detected"), -str8_lit_comp("(Win32) Sanitizer Raw Access Violation"), -str8_lit_comp("(Win32) DirectX Debug Layer"), -}; - -String8 ctrl_exception_code_kind_lowercase_code_string_table[] = -{ -{0}, -str8_lit_comp("win32_ctrl_c"), -str8_lit_comp("win32_ctrl_break"), -str8_lit_comp("win32_win_rt_originate_error"), -str8_lit_comp("win32_win_rt_transform_error"), -str8_lit_comp("win32_rpc_call_cancelled"), -str8_lit_comp("win32_datatype_misalignment"), -str8_lit_comp("win32_access_violation"), -str8_lit_comp("win32_in_page_error"), -str8_lit_comp("win32_invalid_handle"), -str8_lit_comp("win32_not_enough_quota"), -str8_lit_comp("win32_illegal_instruction"), -str8_lit_comp("win32_cannot_continue_exception"), -str8_lit_comp("win32_invalid_exception_disposition"), -str8_lit_comp("win32_array_bounds_exceeded"), -str8_lit_comp("win32_floating_point_denormal_operand"), -str8_lit_comp("win32_floating_point_division_by_zero"), -str8_lit_comp("win32_floating_point_inexact_result"), -str8_lit_comp("win32_floating_point_invalid_operation"), -str8_lit_comp("win32_floating_point_overflow"), -str8_lit_comp("win32_floating_point_stack_check"), -str8_lit_comp("win32_floating_point_underflow"), -str8_lit_comp("win32_integer_division_by_zero"), -str8_lit_comp("win32_integer_overflow"), -str8_lit_comp("win32_privileged_instruction"), -str8_lit_comp("win32_stack_overflow"), -str8_lit_comp("win32_unable_to_locate_dll"), -str8_lit_comp("win32_ordinal_not_found"), -str8_lit_comp("win32_entry_point_not_found"), -str8_lit_comp("win32_dll_initialization_failed"), -str8_lit_comp("win32_floating_point_sse_multiple_faults"), -str8_lit_comp("win32_floating_point_sse_multiple_traps"), -str8_lit_comp("win32_assertion_failed"), -str8_lit_comp("win32_module_not_found"), -str8_lit_comp("win32_procedure_not_found"), -str8_lit_comp("win32_sanitizer_error_detected"), -str8_lit_comp("win32_sanitizer_raw_access_violation"), -str8_lit_comp("win32_directx_debug_layer"), -}; - -B8 ctrl_exception_code_kind_default_enable_table[] = -{ -0, -1, -1, -0, -0, -0, -0, -1, -0, -1, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -1, -0, -0, -1, -0, -1, -}; - +C_LINKAGE_BEGIN +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]; +extern B8 ctrl_exception_code_kind_default_enable_table[38]; +C_LINKAGE_END #endif // CTRL_META_H diff --git a/src/dasm/dasm.c b/src/dasm/dasm.c deleted file mode 100644 index 0561dfb4..00000000 --- a/src/dasm/dasm.c +++ /dev/null @@ -1,540 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -dasm_init(void) -{ - Arena *arena = arena_alloc(); - dasm_shared = push_array(arena, DASM_Shared, 1); - dasm_shared->arena = arena; - dasm_shared->entity_map.slots_count = 1024; - dasm_shared->entity_map.slots = push_array(arena, DASM_EntitySlot, dasm_shared->entity_map.slots_count); - dasm_shared->entity_map_stripes.count = 64; - dasm_shared->entity_map_stripes.v = push_array(arena, DASM_Stripe, dasm_shared->entity_map_stripes.count); - for(U64 idx = 0; idx < dasm_shared->entity_map_stripes.count; idx += 1) - { - dasm_shared->entity_map_stripes.v[idx].arena = arena_alloc(); - dasm_shared->entity_map_stripes.v[idx].rw_mutex = os_rw_mutex_alloc(); - dasm_shared->entity_map_stripes.v[idx].cv = os_condition_variable_alloc(); - } - dasm_shared->u2d_ring_mutex = os_mutex_alloc(); - dasm_shared->u2d_ring_cv = os_condition_variable_alloc(); - dasm_shared->u2d_ring_size = KB(64); - dasm_shared->u2d_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2d_ring_size); - dasm_shared->decode_thread_count = Max(1, os_logical_core_count()-1); - dasm_shared->decode_threads = push_array(arena, OS_Handle, dasm_shared->decode_thread_count); - for(U64 idx = 0; idx < dasm_shared->decode_thread_count; idx += 1) - { - dasm_shared->decode_threads[idx] = os_launch_thread(dasm_decode_thread_entry_point, (void *)idx, 0); - } -} - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 -dasm_hash_from_string(String8 string) -{ - U64 result = 5381; - for(U64 i = 0; i < string.size; i += 1) - { - result = ((result << 5) + result) + string.str[i]; - } - return result; -} - -//////////////////////////////// -//~ rjf: Instruction Type Functions - -internal void -dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst) -{ - DASM_InstChunkNode *node = list->last; - if(node == 0 || node->count >= node->cap) - { - node = push_array(arena, DASM_InstChunkNode, 1); - node->v = push_array_no_zero(arena, DASM_Inst, cap); - node->cap = cap; - SLLQueuePush(list->first, list->last, node); - list->node_count += 1; - } - MemoryCopyStruct(&node->v[node->count], inst); - node->count += 1; - list->inst_count += 1; -} - -internal DASM_InstArray -dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list) -{ - DASM_InstArray array = {0}; - array.count = list->inst_count; - array.v = push_array_no_zero(arena, DASM_Inst, array.count); - U64 idx = 0; - for(DASM_InstChunkNode *n = list->first; n != 0; n = n->next) - { - MemoryCopy(array.v+idx, n->v, sizeof(DASM_Inst)*n->count); - idx += n->count; - } - return array; -} - -internal U64 -dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off) -{ - U64 result = 0; - for(U64 idx = 0; idx < array->count; idx += 1) - { - if(array->v[idx].off == off) - { - result = idx; - break; - } - } - return result; -} - -internal U64 -dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx) -{ - U64 off = 0; - if(idx < array->count) - { - off = array->v[idx].off; - } - return off; -} - -//////////////////////////////// -//~ rjf: Disassembly Functions - -#include "third_party/udis86/config.h" -#include "third_party/udis86/udis86.h" -#include "third_party/udis86/libudis86/decode.c" -#include "third_party/udis86/libudis86/itab.c" -#include "third_party/udis86/libudis86/syn-att.c" -#include "third_party/udis86/libudis86/syn-intel.c" -#include "third_party/udis86/libudis86/syn.c" -#include "third_party/udis86/libudis86/udis86.c" - -internal DASM_InstChunkList -dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data) -{ - DASM_InstChunkList inst_list = {0}; - switch(arch) - { - default:{}break; - - //- rjf: x86/x64 decoding - case Architecture_x64: - case Architecture_x86: - { - // rjf: grab context - struct ud udc; - ud_init(&udc); - ud_set_mode(&udc, bit_size_from_arch(arch)); - ud_set_pc(&udc, addr); - ud_set_input_buffer(&udc, data.str, data.size); - ud_set_vendor(&udc, UD_VENDOR_ANY); - ud_set_syntax(&udc, UD_SYN_INTEL); - - // rjf: disassemble - U64 byte_process_start_off = 0; - for(U64 off = 0; off < data.size;) - { - // rjf: disassemble one instruction - U64 size = ud_disassemble(&udc); - if(size == 0) - { - break; - } - - // rjf: analyze - struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0); - U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0; - - // rjf: push - String8 string = push_str8f(arena, "%s", udc.asm_buf); - DASM_Inst inst = {string, off, rel_voff}; - dasm_inst_chunk_list_push(arena, &inst_list, 1024, &inst); - - // rjf: increment - off += size; - if(bytes_processed_counter != 0 && (off-byte_process_start_off >= 1000)) - { - ins_atomic_u64_add_eval(bytes_processed_counter, (off-byte_process_start_off)); - byte_process_start_off = off; - } - } - }break; - } - return inst_list; -} - -//////////////////////////////// -//~ rjf: Cache Lookups - -//- rjf: opening handles & correllation with module - -internal DASM_Handle -dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range) -{ - DASM_Handle result = {0}; - if(machine != 0 && process.u64[0] != 0) - { - U64 hash = dasm_hash_from_string(str8_struct(&process)); - U64 slot_idx = hash%dasm_shared->entity_map.slots_count; - U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; - DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) - { - DASM_Entity *entity = 0; - for(DASM_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->machine_id == machine && - ctrl_handle_match(e->process, process) && - MemoryMatchStruct(&e->vaddr_range, &vaddr_range)) - { - entity = e; - break; - } - } - if(entity == 0) - { - entity = push_array(stripe->arena, DASM_Entity, 1); - SLLQueuePush(slot->first, slot->last, entity); - entity->machine_id = machine; - entity->process = process; - entity->vaddr_range= vaddr_range; - entity->id = ins_atomic_u64_inc_eval(&dasm_shared->entity_id_gen); - entity->decode_inst_arena = arena_alloc__sized(MB(256), KB(64)); - entity->decode_string_arena = arena_alloc__sized(GB(1), KB(64)); - } - result.u64[0] = hash; - result.u64[1] = entity->id; - } - } - return result; -} - -//- rjf: asking for top-level info of a handle - -internal DASM_BinaryInfo -dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle) -{ - DASM_BinaryInfo info = {0}; - { - U64 hash = handle.u64[0]; - U64 id = handle.u64[1]; - U64 slot_idx = hash%dasm_shared->entity_map.slots_count; - U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; - DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) - { - DASM_Entity *entity = 0; - for(DASM_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - info.machine_id = entity->machine_id; - info.process = entity->process; - info.vaddr_range = entity->vaddr_range; - info.bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed); - info.bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); - } - } - } - return info; -} - -//- rjf: asking for decoded instructions - -internal DASM_InstArray -dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us) -{ - DASM_InstArray result = {0}; - if(handle.u64[0] != 0 || handle.u64[1] != 0) - { - U64 hash = handle.u64[0]; - U64 id = handle.u64[1]; - U64 slot_idx = hash%dasm_shared->entity_map.slots_count; - U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; - DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; - B32 sent = 0; - OS_MutexScopeR(stripe->rw_mutex) for(;;) - { - DASM_Entity *entity = 0; - for(DASM_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - U64 last_time_sent_us = 0; - if(entity != 0) - { - U64 bytes_processed = ins_atomic_u64_eval(&entity->bytes_processed); - U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); - last_time_sent_us = ins_atomic_u64_eval(&entity->last_time_sent_us); - if(bytes_processed == bytes_to_process && bytes_processed != 0) - { - result.count = entity->decode_inst_array.count; - result.v = push_array_no_zero(arena, DASM_Inst, result.count); - MemoryCopy(result.v, entity->decode_inst_array.v, sizeof(DASM_Inst)*result.count); - for(U64 idx = 0; idx < result.count; idx += 1) - { - result.v[idx].string = push_str8_copy(arena, result.v[idx].string); - } - break; - } - } - if(!sent && entity != 0 && last_time_sent_us+10000 <= os_now_microseconds()) - { - DASM_DecodeRequest req = {handle}; - sent = dasm_u2d_enqueue_request(&req, endt_us); - ins_atomic_u64_eval_assign(&entity->last_time_sent_us, os_now_microseconds()); - } - if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - } - return result; -} - -//////////////////////////////// -//~ rjf: Decode Threads - -internal B32 -dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us) -{ - B32 result = 0; - OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;) - { - U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos); - U64 available_size = (dasm_shared->u2d_ring_size-unconsumed_size); - if(available_size >= sizeof(*req)) - { - result = 1; - dasm_shared->u2d_ring_write_pos += ring_write_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_write_pos, req); - dasm_shared->u2d_ring_write_pos += 7; - dasm_shared->u2d_ring_write_pos -= dasm_shared->u2d_ring_write_pos%8; - break; - } - if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, endt_us); - } - if(result) - { - os_condition_variable_broadcast(dasm_shared->u2d_ring_cv); - } - return result; -} - -internal DASM_DecodeRequest -dasm_u2d_dequeue_request(void) -{ - DASM_DecodeRequest req = {0}; - OS_MutexScope(dasm_shared->u2d_ring_mutex) for(;;) - { - U64 unconsumed_size = (dasm_shared->u2d_ring_write_pos-dasm_shared->u2d_ring_read_pos); - if(unconsumed_size >= sizeof(DASM_DecodeRequest)) - { - dasm_shared->u2d_ring_read_pos += ring_read_struct(dasm_shared->u2d_ring_base, dasm_shared->u2d_ring_size, dasm_shared->u2d_ring_read_pos, &req); - dasm_shared->u2d_ring_read_pos += 7; - dasm_shared->u2d_ring_read_pos -= dasm_shared->u2d_ring_read_pos%8; - break; - } - os_condition_variable_wait(dasm_shared->u2d_ring_cv, dasm_shared->u2d_ring_mutex, max_U64); - } - os_condition_variable_broadcast(dasm_shared->u2d_ring_cv); - return req; -} - -internal void -dasm_decode_thread_entry_point(void *p) -{ - TCTX tctx_; - tctx_init_and_equip(&tctx_); - for(;;) - { - Temp scratch = scratch_begin(0, 0); - - //- rjf: get next request & unpack - DASM_DecodeRequest req = dasm_u2d_dequeue_request(); - DASM_Handle handle = req.handle; - U64 hash = handle.u64[0]; - U64 id = handle.u64[1]; - U64 slot_idx = hash%dasm_shared->entity_map.slots_count; - U64 stripe_idx = slot_idx%dasm_shared->entity_map_stripes.count; - DASM_EntitySlot *slot = &dasm_shared->entity_map.slots[slot_idx]; - DASM_Stripe *stripe = &dasm_shared->entity_map_stripes.v[stripe_idx]; - - //- rjf: request -> ctrl info - B32 is_first_to_task = 0; - CTRL_MachineID ctrl_machine_id = 0; - CTRL_Handle ctrl_process = {0}; - Rng1U64 vaddr_range = {0}; - Architecture arch = Architecture_Null; - U64 *bytes_processed_counter = 0; - OS_MutexScopeR(stripe->rw_mutex) - { - DASM_Entity *entity = 0; - for(DASM_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - U64 initial_working_count = ins_atomic_u32_eval_cond_assign(&entity->working_count, 1, 0); - if(initial_working_count == 0) - { - is_first_to_task = 1; - ctrl_machine_id = entity->machine_id; - ctrl_process = entity->process; - vaddr_range = entity->vaddr_range; - arch = ctrl_arch_from_handle(ctrl_machine_id, ctrl_process); - bytes_processed_counter = &entity->bytes_processed; - U64 bytes_to_process = dim_1u64(vaddr_range); - ins_atomic_u64_eval_assign(&entity->bytes_processed, 0); - ins_atomic_u64_eval_assign(&entity->bytes_to_process, bytes_to_process); - } - } - } - - //- rjf: bad handle or machine id -> bad task - B32 good_task = (is_first_to_task && ctrl_process.u64[0] != 0 && ctrl_machine_id != 0 && arch != Architecture_Null && bytes_processed_counter != 0); - - //- rjf: good task -> clear entity's info - if(good_task) - { - OS_MutexScopeW(stripe->rw_mutex) - { - DASM_Entity *entity = 0; - for(DASM_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - arena_clear(entity->decode_inst_arena); - arena_clear(entity->decode_string_arena); - MemoryZeroStruct(&entity->decode_inst_array); - } - } - } - - //- rjf: good task -> read process memory & decode instructions - stop each - // 4k and write into cache, so users can read incremental results - if(good_task) - { - U64 chunk_size = KB(4); - for(U64 off = 0; vaddr_range.min+off < vaddr_range.max; off += chunk_size) - { - Rng1U64 chunk_vaddr_range = r1u64(vaddr_range.min+off, vaddr_range.min+off+chunk_size); - chunk_vaddr_range.min = ClampTop(chunk_vaddr_range.min, vaddr_range.max); - chunk_vaddr_range.max = ClampTop(chunk_vaddr_range.max, vaddr_range.max); - - //- rjf: read next chunk & decode - String8 data = {0}; - DASM_InstChunkList inst_list = {0}; - if(good_task) - { - data.str = push_array_no_zero(scratch.arena, U8, dim_1u64(chunk_vaddr_range)); - data.size = ctrl_process_read(ctrl_machine_id, ctrl_process, chunk_vaddr_range, data.str); - if(data.size != 0) - { - inst_list = dasm_inst_chunk_list_from_arch_addr_data(scratch.arena, bytes_processed_counter, arch, chunk_vaddr_range.min, data); - } - } - - //- rjf: write into cache - { - OS_MutexScopeW(stripe->rw_mutex) - { - DASM_Entity *entity = 0; - for(DASM_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - DASM_Inst *new_chunk_base = push_array(entity->decode_inst_arena, DASM_Inst, inst_list.inst_count); - U64 off = 0; - for(DASM_InstChunkNode *node = inst_list.first; node != 0; node = node->next) - { - MemoryCopy(new_chunk_base+off, node->v, sizeof(DASM_Inst)*node->count); - off += node->count; - } - for(U64 idx = 0; idx < inst_list.inst_count; idx += 1) - { - new_chunk_base[idx].string = push_str8_copy(entity->decode_string_arena, new_chunk_base[idx].string); - } - entity->decode_inst_array.count += inst_list.inst_count; - if(entity->decode_inst_array.v == 0) - { - entity->decode_inst_array.v = new_chunk_base; - } - } - } - os_condition_variable_broadcast(stripe->cv); - } - } - } - - //- rjf: mark task as complete - if(good_task) - { - OS_MutexScopeR(stripe->rw_mutex) - { - DASM_Entity *entity = 0; - for(DASM_Entity *e = slot->first; e != 0; e = e->next) - { - if(e->id == id) - { - entity = e; - break; - } - } - if(entity != 0) - { - U64 bytes_to_process = ins_atomic_u64_eval(&entity->bytes_to_process); - ins_atomic_u64_eval_assign(&entity->bytes_processed, bytes_to_process); - ins_atomic_u64_eval_assign(&entity->working_count, 0); - } - } - } - - scratch_end(scratch); - } -} diff --git a/src/dasm/dasm.h b/src/dasm/dasm.h deleted file mode 100644 index a49412e0..00000000 --- a/src/dasm/dasm.h +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef DASM_H -#define DASM_H - -//////////////////////////////// -//~ rjf: Handle Type - -typedef struct DASM_Handle DASM_Handle; -struct DASM_Handle -{ - U64 u64[2]; -}; - -//////////////////////////////// -//~ rjf: Instruction Types - -typedef struct DASM_Inst DASM_Inst; -struct DASM_Inst -{ - String8 string; - U64 off; - U64 addr; -}; - -typedef struct DASM_InstChunkNode DASM_InstChunkNode; -struct DASM_InstChunkNode -{ - DASM_InstChunkNode *next; - DASM_Inst *v; - U64 cap; - U64 count; -}; - -typedef struct DASM_InstChunkList DASM_InstChunkList; -struct DASM_InstChunkList -{ - DASM_InstChunkNode *first; - DASM_InstChunkNode *last; - U64 node_count; - U64 inst_count; -}; - -typedef struct DASM_InstArray DASM_InstArray; -struct DASM_InstArray -{ - DASM_Inst *v; - U64 count; -}; - -//////////////////////////////// -//~ rjf: Striped Access Types - -typedef struct DASM_Stripe DASM_Stripe; -struct DASM_Stripe -{ - Arena *arena; - OS_Handle cv; - OS_Handle rw_mutex; -}; - -typedef struct DASM_StripeTable DASM_StripeTable; -struct DASM_StripeTable -{ - U64 count; - DASM_Stripe *v; -}; - -//////////////////////////////// -//~ rjf: Entity Cache Types - -typedef struct DASM_Entity DASM_Entity; -struct DASM_Entity -{ - DASM_Entity *next; - - // rjf: key info - CTRL_MachineID machine_id; - CTRL_Handle process; - Rng1U64 vaddr_range; - U64 id; - - // rjf: top-level info - U64 last_time_sent_us; - U64 working_count; - U64 bytes_processed; - U64 bytes_to_process; - - // rjf: decoded instruction data - Arena *decode_inst_arena; - Arena *decode_string_arena; - DASM_InstArray decode_inst_array; -}; - -typedef struct DASM_EntitySlot DASM_EntitySlot; -struct DASM_EntitySlot -{ - DASM_Entity *first; - DASM_Entity *last; -}; - -typedef struct DASM_EntityMap DASM_EntityMap; -struct DASM_EntityMap -{ - U64 slots_count; - DASM_EntitySlot *slots; -}; - -//////////////////////////////// -//~ rjf: Introspection Info Types - -typedef struct DASM_BinaryInfo DASM_BinaryInfo; -struct DASM_BinaryInfo -{ - CTRL_MachineID machine_id; - CTRL_Handle process; - Rng1U64 vaddr_range; - U64 bytes_processed; - U64 bytes_to_process; -}; - -//////////////////////////////// -//~ rjf: Decode Request Types - -typedef struct DASM_DecodeRequest DASM_DecodeRequest; -struct DASM_DecodeRequest -{ - DASM_Handle handle; -}; - -//////////////////////////////// -//~ rjf: Shared State - -typedef struct DASM_Shared DASM_Shared; -struct DASM_Shared -{ - Arena *arena; - - // rjf: entity table - DASM_EntityMap entity_map; - DASM_StripeTable entity_map_stripes; - U64 entity_id_gen; - - // rjf: user -> decode ring - OS_Handle u2d_ring_mutex; - OS_Handle u2d_ring_cv; - U64 u2d_ring_size; - U8 *u2d_ring_base; - U64 u2d_ring_write_pos; - U64 u2d_ring_read_pos; - - // rjf: decode threads - U64 decode_thread_count; - OS_Handle *decode_threads; -}; - -//////////////////////////////// -//~ rjf: Globals - -global DASM_Shared *dasm_shared = 0; - -//////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void dasm_init(void); - -//////////////////////////////// -//~ rjf: Basic Helpers - -internal U64 dasm_hash_from_string(String8 string); - -//////////////////////////////// -//~ rjf: Instruction Type Functions - -internal void dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst); -internal DASM_InstArray dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list); -internal U64 dasm_inst_array_idx_from_off__linear_scan(DASM_InstArray *array, U64 off); -internal U64 dasm_inst_array_off_from_idx(DASM_InstArray *array, U64 idx); - -//////////////////////////////// -//~ rjf: Disassembly Functions - -internal DASM_InstChunkList dasm_inst_chunk_list_from_arch_addr_data(Arena *arena, U64 *bytes_processed_counter, Architecture arch, U64 addr, String8 data); - -//////////////////////////////// -//~ rjf: Cache Lookups - -//- rjf: opening handles & correllation with module -internal DASM_Handle dasm_handle_from_ctrl_process_range(CTRL_MachineID machine, CTRL_Handle process, Rng1U64 vaddr_range); - -//- rjf: asking for top-level info of a handle -internal DASM_BinaryInfo dasm_binary_info_from_handle(Arena *arena, DASM_Handle handle); - -//- rjf: asking for decoded instructions -internal DASM_InstArray dasm_inst_array_from_handle(Arena *arena, DASM_Handle handle, U64 endt_us); - -//////////////////////////////// -//~ rjf: Decode Threads - -internal B32 dasm_u2d_enqueue_request(DASM_DecodeRequest *req, U64 endt_us); -internal DASM_DecodeRequest dasm_u2d_dequeue_request(void); - -internal void dasm_decode_thread_entry_point(void *p); - -#endif //DASM_H diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c new file mode 100644 index 00000000..7bc0ec02 --- /dev/null +++ b/src/dasm_cache/dasm_cache.c @@ -0,0 +1,599 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Third Party Includes + +#include "third_party/udis86/config.h" +#include "third_party/udis86/udis86.h" +#include "third_party/udis86/libudis86/decode.c" +#include "third_party/udis86/libudis86/itab.c" +#include "third_party/udis86/libudis86/syn-att.c" +#include "third_party/udis86/libudis86/syn-intel.c" +#include "third_party/udis86/libudis86/syn.c" +#include "third_party/udis86/libudis86/udis86.c" + +//////////////////////////////// +//~ rjf: Instruction Type Functions + +internal void +dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst) +{ + DASM_InstChunkNode *node = list->last; + if(node == 0 || node->count >= node->cap) + { + node = push_array(arena, DASM_InstChunkNode, 1); + node->v = push_array_no_zero(arena, DASM_Inst, cap); + node->cap = cap; + SLLQueuePush(list->first, list->last, node); + list->node_count += 1; + } + MemoryCopyStruct(&node->v[node->count], inst); + node->count += 1; + list->inst_count += 1; +} + +internal DASM_InstArray +dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list) +{ + DASM_InstArray array = {0}; + array.count = list->inst_count; + array.v = push_array_no_zero(arena, DASM_Inst, array.count); + U64 idx = 0; + for(DASM_InstChunkNode *n = list->first; n != 0; n = n->next) + { + MemoryCopy(array.v+idx, n->v, sizeof(DASM_Inst)*n->count); + idx += n->count; + } + return array; +} + +internal U64 +dasm_inst_array_idx_from_code_off__linear_scan(DASM_InstArray *array, U64 off) +{ + U64 result = 0; + for(U64 idx = 0; idx < array->count; idx += 1) + { + if(array->v[idx].code_off == off) + { + result = idx; + break; + } + } + return result; +} + +internal U64 +dasm_inst_array_code_off_from_idx(DASM_InstArray *array, U64 idx) +{ + U64 off = 0; + if(idx < array->count) + { + off = array->v[idx].code_off; + } + return off; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +dasm_init(void) +{ + Arena *arena = arena_alloc(); + dasm_shared = push_array(arena, DASM_Shared, 1); + dasm_shared->arena = arena; + dasm_shared->slots_count = 1024; + dasm_shared->stripes_count = Min(dasm_shared->slots_count, os_logical_core_count()); + dasm_shared->slots = push_array(arena, DASM_Slot, dasm_shared->slots_count); + dasm_shared->stripes = push_array(arena, DASM_Stripe, dasm_shared->stripes_count); + for(U64 idx = 0; idx < dasm_shared->stripes_count; idx += 1) + { + dasm_shared->stripes[idx].arena = arena_alloc(); + dasm_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + dasm_shared->stripes[idx].cv = os_condition_variable_alloc(); + } + dasm_shared->u2p_ring_size = KB(64); + dasm_shared->u2p_ring_base = push_array_no_zero(arena, U8, dasm_shared->u2p_ring_size); + dasm_shared->u2p_ring_cv = os_condition_variable_alloc(); + dasm_shared->u2p_ring_mutex = os_mutex_alloc(); + dasm_shared->parse_thread_count = 1; + dasm_shared->parse_threads = push_array(arena, OS_Handle, dasm_shared->parse_thread_count); + for(U64 idx = 0; idx < dasm_shared->parse_thread_count; idx += 1) + { + dasm_shared->parse_threads[idx] = os_launch_thread(dasm_parse_thread__entry_point, (void *)idx, 0); + } + dasm_shared->evictor_thread = os_launch_thread(dasm_evictor_thread__entry_point, 0, 0); +} + +//////////////////////////////// +//~ rjf: User Clock + +internal void +dasm_user_clock_tick(void) +{ + ins_atomic_u64_inc_eval(&dasm_shared->user_clock_idx); +} + +internal U64 +dasm_user_clock_idx(void) +{ + U64 idx = ins_atomic_u64_eval(&dasm_shared->user_clock_idx); + return idx; +} + +//////////////////////////////// +//~ rjf: Scoped Access + +internal DASM_Scope * +dasm_scope_open(void) +{ + if(dasm_tctx == 0) + { + Arena *arena = arena_alloc(); + dasm_tctx = push_array(arena, DASM_TCTX, 1); + dasm_tctx->arena = arena; + } + DASM_Scope *scope = dasm_tctx->free_scope; + if(scope != 0) + { + SLLStackPop(dasm_tctx->free_scope); + } + else + { + scope = push_array_no_zero(dasm_tctx->arena, DASM_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +dasm_scope_close(DASM_Scope *scope) +{ + for(DASM_Touch *t = scope->top_touch, *next = 0; t != 0; t = next) + { + next = t->next; + U64 slot_idx = t->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]; + OS_MutexScopeR(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(t->hash, n->hash) && + t->addr == n->addr && + t->arch == n->arch && + t->style_flags == n->style_flags && + t->syntax == n->syntax) + { + ins_atomic_u64_dec_eval(&n->scope_ref_count); + break; + } + } + } + SLLStackPush(dasm_tctx->free_touch, t); + } + SLLStackPush(dasm_tctx->free_scope, scope); +} + +internal void +dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node) +{ + DASM_Touch *touch = dasm_tctx->free_touch; + ins_atomic_u64_inc_eval(&node->scope_ref_count); + ins_atomic_u64_eval_assign(&node->last_time_touched_us, os_now_microseconds()); + ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx()); + if(touch != 0) + { + SLLStackPop(dasm_tctx->free_touch); + } + else + { + touch = push_array_no_zero(dasm_tctx->arena, DASM_Touch, 1); + } + MemoryZeroStruct(touch); + touch->hash = node->hash; + touch->addr = node->addr; + touch->arch = node->arch; + touch->style_flags = node->style_flags; + touch->syntax = node->syntax; + SLLStackPush(scope->top_touch, touch); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal DASM_Info +dasm_info_from_hash_addr_arch_style(DASM_Scope *scope, U128 hash, U64 addr, Architecture arch, DASM_StyleFlags style_flags, DASM_Syntax syntax) +{ + DASM_Info info = {0}; + if(!u128_match(hash, u128_zero())) + { + 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]; + B32 found = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && + addr == n->addr && + arch == n->arch && + style_flags == n->style_flags && + syntax == n->syntax) + { + MemoryCopyStruct(&info, &n->info); + found = 1; + dasm_scope_touch_node__stripe_r_guarded(scope, n); + break; + } + } + } + B32 node_is_new = 0; + if(!found) + { + OS_MutexScopeW(stripe->rw_mutex) + { + DASM_Node *node = 0; + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(hash, n->hash) && + addr == n->addr && + arch == n->arch && + style_flags == n->style_flags && + syntax == n->syntax) + { + node = n; + break; + } + } + if(node == 0) + { + node = stripe->free_node; + if(node) + { + SLLStackPop(stripe->free_node); + } + else + { + node = push_array_no_zero(stripe->arena, DASM_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + node->hash = hash; + node->addr = addr; + node->arch = arch; + node->style_flags = style_flags; + node->syntax = syntax; + node_is_new = 1; + } + } + } + if(node_is_new) + { + dasm_u2p_enqueue_req(hash, addr, arch, style_flags, syntax, max_U64); + } + } + return info; +} + +internal DASM_Info +dasm_info_from_key_addr_arch_style(DASM_Scope *scope, U128 key, U64 addr, Architecture arch, DASM_StyleFlags style_flags, DASM_Syntax syntax, U128 *hash_out) +{ + DASM_Info result = {0}; + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) + { + U128 hash = hs_hash_from_key(key, rewind_idx); + result = dasm_info_from_hash_addr_arch_style(scope, hash, addr, arch, style_flags, syntax); + if(result.insts.count != 0) + { + if(hash_out) + { + *hash_out = hash; + } + break; + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Parse Threads + +internal B32 +dasm_u2p_enqueue_req(U128 hash, U64 addr, Architecture arch, DASM_StyleFlags style_flags, DASM_Syntax syntax, 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(addr)+sizeof(arch)) + { + 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, &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, &addr); + 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, &arch); + 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, &style_flags); + 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, &syntax); + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, endt_us); + } + if(good) + { + os_condition_variable_broadcast(dasm_shared->u2p_ring_cv); + } + return good; +} + +internal void +dasm_u2p_dequeue_req(U128 *hash_out, U64 *addr_out, Architecture *arch_out, DASM_StyleFlags *style_flags_out, DASM_Syntax *syntax_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(*addr_out)+sizeof(*arch_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, addr_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, arch_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, style_flags_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, syntax_out); + break; + } + os_condition_variable_wait(dasm_shared->u2p_ring_cv, dasm_shared->u2p_ring_mutex, max_U64); + } + os_condition_variable_broadcast(dasm_shared->u2p_ring_mutex); +} + +internal void +dasm_parse_thread__entry_point(void *p) +{ + ThreadNameF("[dasm] parse thread #%I64u", (U64)p); + for(;;) + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: get next request + U128 hash = {0}; + U64 addr = 0; + Architecture arch = Architecture_Null; + DASM_StyleFlags style_flags = 0; + DASM_Syntax syntax = DASM_Syntax_Intel; + dasm_u2p_dequeue_req(&hash, &addr, &arch, &style_flags, &syntax); + HS_Scope *hs_scope = hs_scope_open(); + + //- rjf: unpack hash + U64 slot_idx = hash.u64[1]%dasm_shared->slots_count; + U64 stripe_idx = slot_idx%dasm_shared->stripes_count; + DASM_Slot *slot = &dasm_shared->slots[slot_idx]; + DASM_Stripe *stripe = &dasm_shared->stripes[stripe_idx]; + + //- rjf: take task + B32 got_task = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash) && + n->addr == addr && + n->arch == arch && + n->style_flags == style_flags && + n->syntax == syntax) + { + got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); + break; + } + } + } + + //- rjf: hash -> data + String8 data = {0}; + if(got_task) + { + data = hs_data_from_hash(hs_scope, hash); + } + + //- rjf: data * arch * addr -> decode artifacts + DASM_InstChunkList inst_list = {0}; + String8List inst_strings = {0}; + if(got_task) + { + switch(arch) + { + default:{}break; + + //- rjf: x86/x64 decoding + case Architecture_x64: + case Architecture_x86: + { + // rjf: grab context + struct ud udc; + ud_init(&udc); + ud_set_mode(&udc, bit_size_from_arch(arch)); + ud_set_pc(&udc, addr); + ud_set_input_buffer(&udc, data.str, data.size); + ud_set_vendor(&udc, UD_VENDOR_ANY); + ud_set_syntax(&udc, syntax == DASM_Syntax_Intel ? UD_SYN_INTEL : UD_SYN_ATT); + + // rjf: disassemble + U64 byte_process_start_off = 0; + for(U64 off = 0; off < data.size;) + { + // rjf: disassemble one instruction + U64 size = ud_disassemble(&udc); + if(size == 0) + { + break; + } + + // rjf: analyze + struct ud_operand *first_op = (struct ud_operand *)ud_insn_opr(&udc, 0); + U64 rel_voff = (first_op != 0 && first_op->type == UD_OP_JIMM) ? ud_syn_rel_target(&udc, first_op) : 0; + + // rjf: push + String8 addr_part = {0}; + if(style_flags & DASM_StyleFlag_Addresses) + { + addr_part = push_str8f(scratch.arena, "%016I64X ", addr+off); + } + String8 code_bytes_part = {0}; + if(style_flags & DASM_StyleFlag_CodeBytes) + { + String8List code_bytes_strings = {0}; + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit("{")); + for(U64 byte_idx = 0; byte_idx < size || byte_idx < 16; byte_idx += 1) + { + if(byte_idx < size) + { + str8_list_pushf(scratch.arena, &code_bytes_strings, "%02x%s ", (U32)data.str[off+byte_idx], byte_idx == size-1 ? "}" : ""); + } + else if(byte_idx < 8) + { + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); + } + } + str8_list_push(scratch.arena, &code_bytes_strings, str8_lit(" ")); + code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0); + } + String8 inst_string = push_str8f(scratch.arena, "%S%S%s", addr_part, code_bytes_part, udc.asm_buf); + DASM_Inst inst = {off, rel_voff, r1u64(inst_strings.total_size + inst_strings.node_count, + inst_strings.total_size + inst_strings.node_count + inst_string.size)}; + dasm_inst_chunk_list_push(scratch.arena, &inst_list, 1024, &inst); + str8_list_push(scratch.arena, &inst_strings, inst_string); + + // rjf: increment + off += size; + } + }break; + } + } + + //- rjf: artifacts -> value bundle + Arena *info_arena = 0; + DASM_Info info = {0}; + if(got_task) + { + //- rjf: produce joined text + Arena *text_arena = arena_alloc(); + StringJoin text_join = {0}; + text_join.sep = str8_lit("\n"); + String8 text = str8_list_join(text_arena, &inst_strings, &text_join); + + //- rjf: produce unique key for this disassembly's text + U128 text_key = {0}; + { + U64 hash_data[] = + { + hash.u64[0], + hash.u64[1], + addr, + (U64)arch, + (U64)style_flags, + (U64)syntax, + 0x4d534144, + }; + text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data))); + } + + //- rjf: submit text data to hash store + U128 text_hash = hs_submit_data(text_key, &text_arena, text); + + //- rjf: produce value bundle + info_arena = arena_alloc(); + info.text_key = text_key; + info.insts = dasm_inst_array_from_chunk_list(info_arena, &inst_list); + } + + //- rjf: commit results to cache + if(got_task) OS_MutexScopeW(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash) && + addr == n->addr && + arch == n->arch && + style_flags == n->style_flags && + syntax == n->syntax) + { + n->info_arena = info_arena; + MemoryCopyStruct(&n->info, &info); + ins_atomic_u32_eval_assign(&n->is_working, 0); + ins_atomic_u64_inc_eval(&n->load_count); + break; + } + } + } + + hs_scope_close(hs_scope); + scratch_end(scratch); + } +} + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void +dasm_evictor_thread__entry_point(void *p) +{ + ThreadNameF("[dasm] evictor thread"); + for(;;) + { + U64 check_time_us = os_now_microseconds(); + U64 check_time_user_clocks = dasm_user_clock_idx(); + U64 evict_threshold_us = 10*1000000; + U64 evict_threshold_user_clocks = 10; + for(U64 slot_idx = 0; slot_idx < dasm_shared->slots_count; slot_idx += 1) + { + 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]; + B32 slot_has_work = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first; n != 0; n = n->next) + { + 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) + { + slot_has_work = 1; + break; + } + } + } + if(slot_has_work) OS_MutexScopeW(stripe->rw_mutex) + { + for(DASM_Node *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + 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) + { + DLLRemove(slot->first, slot->last, n); + if(n->info_arena != 0) + { + arena_release(n->info_arena); + } + SLLStackPush(stripe->free_node, n); + } + } + } + os_sleep_milliseconds(5); + } + os_sleep_milliseconds(1000); + } +} diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h new file mode 100644 index 00000000..6daa60b1 --- /dev/null +++ b/src/dasm_cache/dasm_cache.h @@ -0,0 +1,231 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DASM_CACHE_H +#define DASM_CACHE_H + +//////////////////////////////// +//~ rjf: Stringification Types + +typedef U32 DASM_StyleFlags; +enum +{ + DASM_StyleFlag_Addresses = (1<<0), + DASM_StyleFlag_CodeBytes = (1<<1), +}; + +typedef enum DASM_Syntax +{ + DASM_Syntax_Intel, + DASM_Syntax_ATT, + DASM_Syntax_COUNT +} +DASM_Syntax; + +//////////////////////////////// +//~ rjf: Instruction Types + +typedef struct DASM_Inst DASM_Inst; +struct DASM_Inst +{ + U64 code_off; + U64 addr; + Rng1U64 text_range; +}; + +typedef struct DASM_InstChunkNode DASM_InstChunkNode; +struct DASM_InstChunkNode +{ + DASM_InstChunkNode *next; + DASM_Inst *v; + U64 cap; + U64 count; +}; + +typedef struct DASM_InstChunkList DASM_InstChunkList; +struct DASM_InstChunkList +{ + DASM_InstChunkNode *first; + DASM_InstChunkNode *last; + U64 node_count; + U64 inst_count; +}; + +typedef struct DASM_InstArray DASM_InstArray; +struct DASM_InstArray +{ + DASM_Inst *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Value Bundle Type + +typedef struct DASM_Info DASM_Info; +struct DASM_Info +{ + U128 text_key; + DASM_InstArray insts; +}; + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct DASM_Node DASM_Node; +struct DASM_Node +{ + // rjf: links + DASM_Node *next; + DASM_Node *prev; + + // rjf: key + U128 hash; + U64 addr; + Architecture arch; + DASM_StyleFlags style_flags; + DASM_Syntax syntax; + + // rjf: value + Arena *info_arena; + DASM_Info info; + + // rjf: metadata + B32 is_working; + U64 scope_ref_count; + U64 last_time_touched_us; + U64 last_user_clock_idx_touched; + U64 load_count; +}; + +typedef struct DASM_Slot DASM_Slot; +struct DASM_Slot +{ + DASM_Node *first; + DASM_Node *last; +}; + +typedef struct DASM_Stripe DASM_Stripe; +struct DASM_Stripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; + DASM_Node *free_node; +}; + +//////////////////////////////// +//~ rjf: Scoped Access Types + +typedef struct DASM_Touch DASM_Touch; +struct DASM_Touch +{ + DASM_Touch *next; + U128 hash; + U64 addr; + Architecture arch; + DASM_StyleFlags style_flags; + DASM_Syntax syntax; +}; + +typedef struct DASM_Scope DASM_Scope; +struct DASM_Scope +{ + DASM_Scope *next; + DASM_Touch *top_touch; +}; + +//////////////////////////////// +//~ rjf: Thread Context + +typedef struct DASM_TCTX DASM_TCTX; +struct DASM_TCTX +{ + Arena *arena; + DASM_Scope *free_scope; + DASM_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State + +typedef struct DASM_Shared DASM_Shared; +struct DASM_Shared +{ + Arena *arena; + + // rjf: user clock + U64 user_clock_idx; + + // rjf: cache + U64 slots_count; + U64 stripes_count; + DASM_Slot *slots; + DASM_Stripe *stripes; + + // rjf: user -> parse thread + U64 u2p_ring_size; + U8 *u2p_ring_base; + U64 u2p_ring_write_pos; + U64 u2p_ring_read_pos; + OS_Handle u2p_ring_cv; + OS_Handle u2p_ring_mutex; + + // rjf: parse threads + U64 parse_thread_count; + OS_Handle *parse_threads; + + // rjf: evictor thread + OS_Handle evictor_thread; +}; + +//////////////////////////////// +//~ rjf: Globals + +thread_static DASM_TCTX *dasm_tctx = 0; +global DASM_Shared *dasm_shared = 0; + +//////////////////////////////// +//~ rjf: Instruction Type Functions + +internal void dasm_inst_chunk_list_push(Arena *arena, DASM_InstChunkList *list, U64 cap, DASM_Inst *inst); +internal DASM_InstArray dasm_inst_array_from_chunk_list(Arena *arena, DASM_InstChunkList *list); +internal U64 dasm_inst_array_idx_from_code_off__linear_scan(DASM_InstArray *array, U64 off); +internal U64 dasm_inst_array_code_off_from_idx(DASM_InstArray *array, U64 idx); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void dasm_init(void); + +//////////////////////////////// +//~ rjf: User Clock + +internal void dasm_user_clock_tick(void); +internal U64 dasm_user_clock_idx(void); + +//////////////////////////////// +//~ rjf: Scoped Access + +internal DASM_Scope *dasm_scope_open(void); +internal void dasm_scope_close(DASM_Scope *scope); +internal void dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal DASM_Info dasm_info_from_hash_addr_arch_style(DASM_Scope *scope, U128 hash, U64 addr, Architecture arch, DASM_StyleFlags style_flags, DASM_Syntax syntax); +internal DASM_Info dasm_info_from_key_addr_arch_style(DASM_Scope *scope, U128 key, U64 addr, Architecture arch, DASM_StyleFlags style_flags, DASM_Syntax syntax, U128 *hash_out); + +//////////////////////////////// +//~ rjf: Parse Threads + +internal B32 dasm_u2p_enqueue_req(U128 hash, U64 addr, Architecture arch, DASM_StyleFlags style_flags, DASM_Syntax syntax, U64 endt_us); +internal void dasm_u2p_dequeue_req(U128 *hash_out, U64 *addr_out, Architecture *arch_out, DASM_StyleFlags *style_flags_out, DASM_Syntax *syntax_out); +internal void dasm_parse_thread__entry_point(void *p); + +//////////////////////////////// +//~ rjf: Evictor Threads + +internal void dasm_evictor_thread__entry_point(void *p); + +#endif // DASM_CACHE_H diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 0198fe16..de5d7143 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -11,7 +11,7 @@ dbgi_init(void) dbgi_shared = push_array(arena, DBGI_Shared, 1); dbgi_shared->arena = arena; dbgi_shared->force_slots_count = 1024; - dbgi_shared->force_stripes_count = 64; + dbgi_shared->force_stripes_count = Min(dbgi_shared->force_slots_count, os_logical_core_count()); dbgi_shared->force_slots = push_array(arena, DBGI_ForceSlot, dbgi_shared->force_slots_count); dbgi_shared->force_stripes = push_array(arena, DBGI_ForceStripe, dbgi_shared->force_stripes_count); for(U64 idx = 0; idx < dbgi_shared->force_stripes_count; idx += 1) @@ -21,7 +21,7 @@ dbgi_init(void) dbgi_shared->force_stripes[idx].cv = os_condition_variable_alloc(); } dbgi_shared->binary_slots_count = 1024; - dbgi_shared->binary_stripes_count = 64; + dbgi_shared->binary_stripes_count = Min(dbgi_shared->binary_slots_count, os_logical_core_count()); dbgi_shared->binary_slots = push_array(arena, DBGI_BinarySlot, dbgi_shared->binary_slots_count); dbgi_shared->binary_stripes = push_array(arena, DBGI_BinaryStripe, dbgi_shared->binary_stripes_count); for(U64 idx = 0; idx < dbgi_shared->binary_stripes_count; idx += 1) @@ -31,7 +31,7 @@ dbgi_init(void) dbgi_shared->binary_stripes[idx].cv = os_condition_variable_alloc(); } dbgi_shared->fuzzy_search_slots_count = 64; - dbgi_shared->fuzzy_search_stripes_count = 8; + dbgi_shared->fuzzy_search_stripes_count = Min(dbgi_shared->fuzzy_search_slots_count, os_logical_core_count()); dbgi_shared->fuzzy_search_slots = push_array(arena, DBGI_FuzzySearchSlot, dbgi_shared->fuzzy_search_slots_count); dbgi_shared->fuzzy_search_stripes = push_array(arena, DBGI_FuzzySearchStripe, dbgi_shared->fuzzy_search_stripes_count); for(U64 idx = 0; idx < dbgi_shared->fuzzy_search_stripes_count; idx += 1) @@ -85,12 +85,12 @@ dbgi_ensure_tctx_inited(void) //~ rjf: Helpers internal U64 -dbgi_hash_from_string(String8 string) +dbgi_hash_from_string(String8 string, StringMatchFlags match_flags) { U64 result = 5381; for(U64 i = 0; i < string.size; i += 1) { - result = ((result << 5) + result) + string.str[i]; + result = ((result << 5) + result) + ((match_flags & StringMatchFlag_CaseInsensitive) ? char_to_lower(string.str[i]) : string.str[i]); } return result; } @@ -111,7 +111,7 @@ dbgi_fuzzy_item_num_from_array_element_idx__linear_search(DBGI_FuzzySearchItemAr } internal String8 -dbgi_fuzzy_item_string_from_rdbg_target_element_idx(RADDBG_Parsed *rdbg, DBGI_FuzzySearchTarget target, U64 element_idx) +dbgi_fuzzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, DBGI_FuzzySearchTarget target, U64 element_idx) { String8 result = {0}; switch(target) @@ -119,31 +119,31 @@ dbgi_fuzzy_item_string_from_rdbg_target_element_idx(RADDBG_Parsed *rdbg, DBGI_Fu // NOTE(rjf): no default - warn if we miss a case case DBGI_FuzzySearchTarget_Procedures: { - RADDBG_Procedure *proc = raddbg_element_from_idx(rdbg, procedures, element_idx); + RDI_Procedure *proc = rdi_element_from_idx(rdi, procedures, element_idx); U64 name_size = 0; - U8 *name_base = raddbg_string_from_idx(rdbg, proc->name_string_idx, &name_size); + U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size); result = str8(name_base, name_size); }break; case DBGI_FuzzySearchTarget_GlobalVariables: { - RADDBG_GlobalVariable *gvar = raddbg_element_from_idx(rdbg, global_variables, element_idx); + RDI_GlobalVariable *gvar = rdi_element_from_idx(rdi, global_variables, element_idx); U64 name_size = 0; - U8 *name_base = raddbg_string_from_idx(rdbg, gvar->name_string_idx, &name_size); + U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size); result = str8(name_base, name_size); }break; case DBGI_FuzzySearchTarget_ThreadVariables: { - RADDBG_ThreadVariable *tvar = raddbg_element_from_idx(rdbg, thread_variables, element_idx); + RDI_ThreadVariable *tvar = rdi_element_from_idx(rdi, thread_variables, element_idx); U64 name_size = 0; - U8 *name_base = raddbg_string_from_idx(rdbg, tvar->name_string_idx, &name_size); + U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size); result = str8(name_base, name_size); }break; case DBGI_FuzzySearchTarget_UDTs: { - RADDBG_UDT *udt = raddbg_element_from_idx(rdbg, udts, element_idx); - RADDBG_TypeNode *type_node = raddbg_element_from_idx(rdbg, type_nodes, udt->self_type_idx); + RDI_UDT *udt = rdi_element_from_idx(rdi, udts, element_idx); + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); U64 name_size = 0; - U8 *name_base = raddbg_string_from_idx(rdbg, type_node->user_defined.name_string_idx, &name_size); + U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size); result = str8(name_base, name_size); }break; case DBGI_FuzzySearchTarget_COUNT:{}break; @@ -157,7 +157,8 @@ dbgi_fuzzy_item_string_from_rdbg_target_element_idx(RADDBG_Parsed *rdbg, DBGI_Fu internal void dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path) { - U64 hash = dbgi_hash_from_string(exe_path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = dbgi_hash_from_string(exe_path, match_flags); U64 slot_idx = hash%dbgi_shared->force_slots_count; U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; @@ -167,7 +168,7 @@ dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path) DBGI_ForceNode *node = 0; for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) { - if(str8_match(n->exe_path, exe_path, 0)) + if(str8_match(n->exe_path, exe_path, match_flags)) { node = n; break; @@ -192,7 +193,8 @@ internal String8 dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path) { String8 result = {0}; - U64 hash = dbgi_hash_from_string(exe_path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = dbgi_hash_from_string(exe_path, match_flags); U64 slot_idx = hash%dbgi_shared->force_slots_count; U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; @@ -202,7 +204,7 @@ dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path) DBGI_ForceNode *node = 0; for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) { - if(str8_match(exe_path, n->exe_path, 0)) + if(str8_match(exe_path, n->exe_path, match_flags)) { node = n; break; @@ -297,7 +299,8 @@ dbgi_binary_open(String8 exe_path) { Temp scratch = scratch_begin(0, 0); exe_path = path_normalized_from_string(scratch.arena, exe_path); - U64 hash = dbgi_hash_from_string(exe_path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = dbgi_hash_from_string(exe_path, match_flags); U64 slot_idx = hash%dbgi_shared->binary_slots_count; U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; @@ -308,7 +311,7 @@ dbgi_binary_open(String8 exe_path) DBGI_Binary *binary = 0; for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0)) + if(str8_match(bin->exe_path, exe_path, match_flags)) { binary = bin; break; @@ -336,7 +339,8 @@ dbgi_binary_close(String8 exe_path) { Temp scratch = scratch_begin(0, 0); exe_path = path_normalized_from_string(scratch.arena, exe_path); - U64 hash = dbgi_hash_from_string(exe_path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = dbgi_hash_from_string(exe_path, match_flags); U64 slot_idx = hash%dbgi_shared->binary_slots_count; U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; @@ -346,7 +350,7 @@ dbgi_binary_close(String8 exe_path) DBGI_Binary *binary = 0; for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0)) + if(str8_match(bin->exe_path, exe_path, match_flags)) { binary = bin; break; @@ -361,8 +365,7 @@ dbgi_binary_close(String8 exe_path) if(need_deletion) for(;;) { os_rw_mutex_drop_w(stripe->rw_mutex); - for(U64 start_t = os_now_microseconds(); - os_now_microseconds() <= start_t + 250;); + for(U64 start_t = os_now_microseconds(); os_now_microseconds() <= start_t + 250;); os_rw_mutex_take_w(stripe->rw_mutex); if(binary->refcount == 0 && ins_atomic_u64_eval(&binary->scope_touch_count) == 0) { @@ -393,7 +396,8 @@ dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us) DBGI_Parse *parse = &dbgi_parse_nil; if(exe_path.size != 0) { - U64 hash = dbgi_hash_from_string(exe_path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 hash = dbgi_hash_from_string(exe_path, match_flags); U64 slot_idx = hash%dbgi_shared->binary_slots_count; U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; @@ -404,7 +408,7 @@ dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us) DBGI_Binary *binary = 0; for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0)) + if(str8_match(bin->exe_path, exe_path, match_flags)) { binary = bin; break; @@ -446,6 +450,7 @@ dbgi_fuzzy_search_items_from_key_exe_query(DBGI_Scope *scope, U128 key, String8 Temp scratch = scratch_begin(0, 0); DBGI_FuzzySearchItemArray items = {0}; exe_path = path_normalized_from_string(scratch.arena, exe_path); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); { //- rjf: unpack key U64 slot_idx = key.u64[1]%dbgi_shared->fuzzy_search_slots_count; @@ -481,7 +486,7 @@ dbgi_fuzzy_search_items_from_key_exe_query(DBGI_Scope *scope, U128 key, String8 // rjf: try to grab last valid results for this key/query; determine if stale B32 stale = 1; - if(str8_match(exe_path, node->buckets[node->gen%ArrayCount(node->buckets)].exe_path, 0) && + if(str8_match(exe_path, node->buckets[node->gen%ArrayCount(node->buckets)].exe_path, match_flags) && target == node->buckets[node->gen%ArrayCount(node->buckets)].target && node->gen != 0) { @@ -632,17 +637,16 @@ dbgi_p2u_pop_events(Arena *arena, U64 endt_us) internal void dbgi_parse_thread_entry_point(void *p) { - TCTX tctx_; - tctx_init_and_equip(&tctx_); - ProfThreadName("[dbgi] parse #%I64U", (U64)p); + ThreadNameF("[dbgi] parse #%I64U", (U64)p); for(;;) { Temp scratch = scratch_begin(0, 0); //- rjf: grab next path & unpack String8 exe_path = dbgi_u2p_dequeue_exe_path(scratch.arena); + StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); ProfBegin("begin task for \"%.*s\"", str8_varg(exe_path)); - U64 hash = dbgi_hash_from_string(exe_path); + U64 hash = dbgi_hash_from_string(exe_path, path_match_flags_from_os(operating_system_from_context())); U64 slot_idx = hash%dbgi_shared->binary_slots_count; U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; @@ -656,7 +660,7 @@ dbgi_parse_thread_entry_point(void *p) DBGI_Binary *binary = 0; for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0)) + if(str8_match(bin->exe_path, exe_path, match_flags)) { binary = bin; break; @@ -686,7 +690,7 @@ dbgi_parse_thread_entry_point(void *p) void *exe_file_base = 0; if(do_task) { - exe_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, exe_path); + exe_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, exe_path); exe_file_props = os_properties_from_file(exe_file); exe_file_map = os_file_map_open(OS_AccessFlag_Read, exe_file); exe_file_base = os_file_map_view_open(exe_file_map, OS_AccessFlag_Read, r1u64(0, exe_file_props.size)); @@ -769,7 +773,7 @@ dbgi_parse_thread_entry_point(void *p) } if(!og_dbg_format_is_known) { - if(data.size >= 8 && *(U64 *)data.str == RADDBG_MAGIC_CONSTANT) + if(data.size >= 8 && *(U64 *)data.str == RDI_MAGIC_CONSTANT) { og_dbg_format_is_known = 1; og_dbg_is_raddbg = 1; @@ -801,54 +805,54 @@ dbgi_parse_thread_entry_point(void *p) } //- rjf: given O.G. path & analysis, determine RADDBG file path - String8 raddbg_path = {0}; + String8 raddbgi_path = {0}; if(do_task) { if(og_dbg_is_raddbg) { - raddbg_path = og_dbg_path; + raddbgi_path = og_dbg_path; } else if(og_dbg_format_is_known && og_dbg_is_pdb) { - raddbg_path = push_str8f(scratch.arena, "%S.raddbg", str8_chop_last_dot(og_dbg_path)); + raddbgi_path = push_str8f(scratch.arena, "%S.raddbgi", str8_chop_last_dot(og_dbg_path)); } } //- rjf: check if raddbg file is up-to-date - B32 raddbg_file_is_up_to_date = 0; + B32 raddbgi_file_is_up_to_date = 0; if(do_task) { - if(raddbg_path.size != 0) + if(raddbgi_path.size != 0) { - FileProperties props = os_properties_from_file_path(raddbg_path); - raddbg_file_is_up_to_date = (props.modified > og_dbg_props.modified); + FileProperties props = os_properties_from_file_path(raddbgi_path); + raddbgi_file_is_up_to_date = (props.modified > og_dbg_props.modified); } } //- rjf: if raddbg file is up to date based on timestamp, check the - // encoding generation number, to see if we need to regenerate it + // encoding generation number & size, to see if we need to regenerate it // regardless - if(do_task && raddbg_file_is_up_to_date) + if(do_task && raddbgi_file_is_up_to_date) { OS_Handle file = {0}; OS_Handle file_map = {0}; FileProperties file_props = {0}; void *file_base = 0; - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, raddbg_path); + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, raddbgi_path); file_map = os_file_map_open(OS_AccessFlag_Read, file); file_props = os_properties_from_file(file); file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); - if(sizeof(RADDBG_Header) <= file_props.size) + if(sizeof(RDI_Header) <= file_props.size) { - RADDBG_Header *header = (RADDBG_Header*)file_base; - if(header->encoding_version != RADDBG_ENCODING_VERSION) + RDI_Header *header = (RDI_Header*)file_base; + if(header->encoding_version != RDI_ENCODING_VERSION) { - raddbg_file_is_up_to_date = 0; + raddbgi_file_is_up_to_date = 0; } } else { - raddbg_file_is_up_to_date = 0; + raddbgi_file_is_up_to_date = 0; } os_file_map_view_close(file_map, file_base); os_file_map_close(file_map); @@ -858,14 +862,14 @@ dbgi_parse_thread_entry_point(void *p) //- rjf: raddbg file not up-to-date? we need to generate it if(do_task) { - if(!raddbg_file_is_up_to_date) ProfScope("generate raddbg file") + if(!raddbgi_file_is_up_to_date) ProfScope("generate raddbg file") { if(og_dbg_is_pdb) { // rjf: push conversion task begin event { DBGI_Event event = {DBGI_EventKind_ConversionStarted}; - event.string = raddbg_path; + event.string = raddbgi_path; dbgi_p2u_push_event(&event); } @@ -882,7 +886,7 @@ dbgi_parse_thread_entry_point(void *p) //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); str8_list_pushf(scratch.arena, &opts.cmd_line, "--exe:%S", exe_path); str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_dbg_path); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", raddbg_path); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", raddbgi_path); os_launch_process(&opts, &process); } @@ -894,7 +898,7 @@ dbgi_parse_thread_entry_point(void *p) B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); if(wait_done) { - raddbg_file_is_up_to_date = 1; + raddbgi_file_is_up_to_date = 1; break; } if(os_now_microseconds()-start_wait_t > 10000000 && og_dbg_props.size < MB(64)) @@ -907,7 +911,7 @@ dbgi_parse_thread_entry_point(void *p) // rjf: push conversion task end event { DBGI_Event event = {DBGI_EventKind_ConversionEnded}; - event.string = raddbg_path; + event.string = raddbgi_path; dbgi_p2u_push_event(&event); } } @@ -917,7 +921,7 @@ dbgi_parse_thread_entry_point(void *p) // rjf: push conversion task failure event { DBGI_Event event = {DBGI_EventKind_ConversionFailureUnsupportedFormat}; - event.string = raddbg_path; + event.string = raddbgi_path; dbgi_p2u_push_event(&event); } } @@ -925,16 +929,16 @@ dbgi_parse_thread_entry_point(void *p) } //- rjf: open raddbg file & gather info - OS_Handle raddbg_file = {0}; - OS_Handle raddbg_file_map = {0}; - FileProperties raddbg_file_props = {0}; - void *raddbg_file_base = 0; - if(do_task && raddbg_file_is_up_to_date) + OS_Handle raddbgi_file = {0}; + OS_Handle raddbgi_file_map = {0}; + FileProperties raddbgi_file_props = {0}; + void *raddbgi_file_base = 0; + if(do_task && raddbgi_file_is_up_to_date) { - raddbg_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, raddbg_path); - raddbg_file_map = os_file_map_open(OS_AccessFlag_Read, raddbg_file); - raddbg_file_props = os_properties_from_file(raddbg_file); - raddbg_file_base = os_file_map_view_open(raddbg_file_map, OS_AccessFlag_Read, r1u64(0, raddbg_file_props.size)); + raddbgi_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, raddbgi_path); + raddbgi_file_map = os_file_map_open(OS_AccessFlag_Read, raddbgi_file); + raddbgi_file_props = os_properties_from_file(raddbgi_file); + raddbgi_file_base = os_file_map_view_open(raddbgi_file_map, OS_AccessFlag_Read, r1u64(0, raddbgi_file_props.size)); } //- rjf: cache write, step 0: busy-loop-wait for all scope touches to be done @@ -944,7 +948,7 @@ dbgi_parse_thread_entry_point(void *p) { OS_MutexScopeR(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0) && + if(str8_match(bin->exe_path, exe_path, match_flags) && bin->scope_touch_count == 0) { done = 1; @@ -958,22 +962,22 @@ dbgi_parse_thread_entry_point(void *p) // either EXE or raddbg file is new. if so, clear all old results & // store new top-level info B32 binary_refcount_is_zero = 0; - B32 raddbg_or_exe_file_is_updated = 0; + B32 raddbgi_or_exe_file_is_updated = 0; if(do_task) ProfScope("cache write, step 1: check if raddbg is new & clear") { OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0)) + if(str8_match(bin->exe_path, exe_path, match_flags)) { if(bin->refcount == 0) { binary_refcount_is_zero = 1; break; } - if(bin->parse.dbg_props.modified != raddbg_file_props.modified || + if(bin->parse.dbg_props.modified != raddbgi_file_props.modified || bin->parse.exe_props.modified != exe_file_props.modified) { - raddbg_or_exe_file_is_updated = 1; + raddbgi_or_exe_file_is_updated = 1; // rjf: clean up old stuff if(bin->parse.arena != 0) { arena_release(bin->parse.arena); } @@ -991,10 +995,10 @@ dbgi_parse_thread_entry_point(void *p) bin->exe_file_map = exe_file_map; bin->parse.exe_base = exe_file_base; bin->parse.exe_props = exe_file_props; - bin->dbg_file = raddbg_file; - bin->dbg_file_map = raddbg_file_map; - bin->parse.dbg_base = raddbg_file_base; - bin->parse.dbg_props = raddbg_file_props; + bin->dbg_file = raddbgi_file; + bin->dbg_file_map = raddbgi_file_map; + bin->parse.dbg_base = raddbgi_file_base; + bin->parse.dbg_props = raddbgi_file_props; bin->gen += 1; } break; @@ -1004,11 +1008,11 @@ dbgi_parse_thread_entry_point(void *p) //- rjf: raddbg file or exe is not new? cache can stay unmodified, close // handles & skip to end. - if(do_task) if((!raddbg_or_exe_file_is_updated && raddbg_file_is_up_to_date) || binary_refcount_is_zero) + if(do_task) if((!raddbgi_or_exe_file_is_updated && raddbgi_file_is_up_to_date) || binary_refcount_is_zero) { - os_file_map_view_close(raddbg_file_map, raddbg_file_base); - os_file_map_close(raddbg_file_map); - os_file_close(raddbg_file); + os_file_map_view_close(raddbgi_file_map, raddbgi_file_base); + os_file_map_close(raddbgi_file_map); + os_file_close(raddbgi_file); os_file_map_view_close(exe_file_map, exe_file_base); os_file_map_close(exe_file_map); os_file_close(exe_file); @@ -1017,14 +1021,14 @@ dbgi_parse_thread_entry_point(void *p) } //- rjf: parse raddbg info - RADDBG_Parsed raddbg_parsed = dbgi_parse_nil.rdbg; + RDI_Parsed rdi_parsed = dbgi_parse_nil.rdi; U64 arch_addr_size = 8; if(do_task) { - RADDBG_ParseStatus parse_status = raddbg_parse((U8 *)raddbg_file_base, raddbg_file_props.size, &raddbg_parsed); - if(raddbg_parsed.top_level_info != 0) + RDI_ParseStatus parse_status = rdi_parse((U8 *)raddbgi_file_base, raddbgi_file_props.size, &rdi_parsed); + if(rdi_parsed.top_level_info != 0) { - arch_addr_size = raddbg_addr_size_from_arch(raddbg_parsed.top_level_info->architecture); + arch_addr_size = rdi_addr_size_from_arch(rdi_parsed.top_level_info->architecture); } } @@ -1034,7 +1038,7 @@ dbgi_parse_thread_entry_point(void *p) { OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0)) + if(str8_match(bin->exe_path, exe_path, match_flags)) { String8 dbg_path = og_dbg_path; if(dbg_path.size == 0) @@ -1053,7 +1057,7 @@ dbgi_parse_thread_entry_point(void *p) bin->parse.arena = parse_arena; bin->parse.dbg_path = push_str8_copy(parse_arena, dbg_path); MemoryCopyStruct(&bin->parse.pe, &exe_pe_info); - MemoryCopyStruct(&bin->parse.rdbg, &raddbg_parsed); + MemoryCopyStruct(&bin->parse.rdi, &rdi_parsed); bin->parse.gen = bin->gen; break; } @@ -1071,7 +1075,7 @@ dbgi_parse_thread_entry_point(void *p) { OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) { - if(str8_match(bin->exe_path, exe_path, 0)) + if(str8_match(bin->exe_path, exe_path, match_flags)) { bin->flags &= ~DBGI_BinaryFlag_ParseInFlight; break; @@ -1154,9 +1158,7 @@ dbgi_qsort_compare_fuzzy_search_items(DBGI_FuzzySearchItem *a, DBGI_FuzzySearchI internal void dbgi_fuzzy_thread__entry_point(void *p) { - TCTX tctx_; - tctx_init_and_equip(&tctx_); - ProfThreadName("[dbgi] fuzzy search #%I64U", (U64)p); + ThreadNameF("[dbgi] fuzzy search #%I64U", (U64)p); DBGI_FuzzySearchThread *thread = &dbgi_shared->fuzzy_threads[(U64)p]; for(;;) { @@ -1197,9 +1199,9 @@ dbgi_fuzzy_thread__entry_point(void *p) //- rjf: exe_path -> dbgi_parse, raddbg DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; - //- rjf: rdbg * query -> item list + //- rjf: rdi * query -> item list U64 table_ptr_off = 0; U64 element_name_idx_off = 0; U64 element_count = 0; @@ -1210,49 +1212,49 @@ dbgi_fuzzy_thread__entry_point(void *p) case DBGI_FuzzySearchTarget_COUNT:{}break; case DBGI_FuzzySearchTarget_Procedures: { - table_ptr_off = OffsetOf(RADDBG_Parsed, procedures); - element_name_idx_off = OffsetOf(RADDBG_Procedure, name_string_idx); - element_count = rdbg->procedures_count; - element_size = sizeof(RADDBG_Procedure); + table_ptr_off = OffsetOf(RDI_Parsed, procedures); + element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); + element_count = rdi->procedures_count; + element_size = sizeof(RDI_Procedure); }break; case DBGI_FuzzySearchTarget_GlobalVariables: { - table_ptr_off = OffsetOf(RADDBG_Parsed, global_variables); - element_name_idx_off = OffsetOf(RADDBG_GlobalVariable, name_string_idx); - element_count = rdbg->global_variables_count; - element_size = sizeof(RADDBG_GlobalVariable); + table_ptr_off = OffsetOf(RDI_Parsed, global_variables); + element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); + element_count = rdi->global_variables_count; + element_size = sizeof(RDI_GlobalVariable); }break; case DBGI_FuzzySearchTarget_ThreadVariables: { - table_ptr_off = OffsetOf(RADDBG_Parsed, thread_variables); - element_name_idx_off = OffsetOf(RADDBG_ThreadVariable, name_string_idx); - element_count = rdbg->thread_variables_count; - element_size = sizeof(RADDBG_ThreadVariable); + table_ptr_off = OffsetOf(RDI_Parsed, thread_variables); + element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); + element_count = rdi->thread_variables_count; + element_size = sizeof(RDI_ThreadVariable); }break; case DBGI_FuzzySearchTarget_UDTs: { - table_ptr_off = OffsetOf(RADDBG_Parsed, udts); - element_count = rdbg->udts_count; - element_size = sizeof(RADDBG_UDT); + table_ptr_off = OffsetOf(RDI_Parsed, udts); + element_count = rdi->udts_count; + element_size = sizeof(RDI_UDT); }break; } DBGI_FuzzySearchItemChunkList items_list = {0}; if(task_is_good) { - void *table_base = (U8*)rdbg + table_ptr_off; + void *table_base = (U8*)rdi + table_ptr_off; for(U64 idx = 1; task_is_good && idx < element_count; idx += 1) { void *element = (U8 *)(*(void **)table_base) + element_size*idx; U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off); if(target == DBGI_FuzzySearchTarget_UDTs) { - RADDBG_UDT *udt = (RADDBG_UDT *)element; - RADDBG_TypeNode *type_node = raddbg_element_from_idx(rdbg, type_nodes, udt->self_type_idx); + RDI_UDT *udt = (RDI_UDT *)element; + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); name_idx_ptr = &type_node->user_defined.name_string_idx; } U32 name_idx = *name_idx_ptr; U64 name_size = 0; - U8 *name_base = raddbg_string_from_idx(rdbg, name_idx, &name_size); + U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); String8 name = str8(name_base, name_size); if(name.size == 0) { continue; } FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name); diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h index 50511f79..2ca9952e 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbgi/dbgi.h @@ -18,7 +18,7 @@ struct DBGI_Parse void *dbg_base; FileProperties dbg_props; PE_BinInfo pe; - RADDBG_Parsed rdbg; + RDI_Parsed rdi; }; //////////////////////////////// @@ -341,24 +341,24 @@ global DBGI_Parse dbgi_parse_nil = 0, 0, 0, - &raddbg_binary_section_nil, 1, - &raddbg_file_path_node_nil, 1, - &raddbg_source_file_nil, 1, - &raddbg_unit_nil, 1, - &raddbg_vmap_entry_nil, 1, - &raddbg_type_node_nil, 1, - &raddbg_udt_nil, 1, - &raddbg_member_nil, 1, - &raddbg_enum_member_nil, 1, - &raddbg_global_variable_nil, 1, - &raddbg_vmap_entry_nil, 1, - &raddbg_thread_variable_nil, 1, - &raddbg_procedure_nil, 1, - &raddbg_scope_nil, 1, - &raddbg_voff_nil, 1, - &raddbg_vmap_entry_nil, 1, - &raddbg_local_nil, 1, - &raddbg_location_block_nil, 1, + &rdi_binary_section_nil, 1, + &rdi_file_path_node_nil, 1, + &rdi_source_file_nil, 1, + &rdi_unit_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_type_node_nil, 1, + &rdi_udt_nil, 1, + &rdi_member_nil, 1, + &rdi_enum_member_nil, 1, + &rdi_global_variable_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_thread_variable_nil, 1, + &rdi_procedure_nil, 1, + &rdi_scope_nil, 1, + &rdi_voff_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_local_nil, 1, + &rdi_location_block_nil, 1, 0, 0, 0, 0, }, @@ -377,9 +377,9 @@ internal void dbgi_ensure_tctx_inited(void); //////////////////////////////// //~ rjf: Helpers -internal U64 dbgi_hash_from_string(String8 string); +internal U64 dbgi_hash_from_string(String8 string, StringMatchFlags match_flags); internal U64 dbgi_fuzzy_item_num_from_array_element_idx__linear_search(DBGI_FuzzySearchItemArray *array, U64 element_idx); -internal String8 dbgi_fuzzy_item_string_from_rdbg_target_element_idx(RADDBG_Parsed *rdbg, DBGI_FuzzySearchTarget target, U64 element_idx); +internal String8 dbgi_fuzzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, DBGI_FuzzySearchTarget target, U64 element_idx); //////////////////////////////// //~ rjf: Forced Override Cache Functions diff --git a/src/demon/demon_accel.c b/src/demon/demon_accel.c deleted file mode 100644 index c9b9ede4..00000000 --- a/src/demon/demon_accel.c +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//- allen: Acceleration Layer Functions - -//- accel helpers -internal DEMON_AccelModule* -demon_accel_module_alloc(void){ - DEMON_AccelModule *result = demon_free_module_accel; - if (result != 0){ - SLLStackPop(demon_free_module_accel); - } - else{ - result = push_array_no_zero(demon_ent_arena, DEMON_AccelModule, 1); - } - MemoryZeroStruct(result); - return(result); -} - -internal void -demon_accel_module_free(DEMON_AccelModule *module){ - SLLStackPush(demon_free_module_accel, module); -} - -internal DEMON_AccelThread* -demon_accel_thread_alloc(void){ - DEMON_AccelThread *result = demon_free_thread_accel; - if (result != 0){ - SLLStackPop(demon_free_thread_accel); - } - else{ - result = push_array_no_zero(demon_ent_arena, DEMON_AccelThread, 1); - } - MemoryZeroStruct(result); - return(result); -} - -internal void -demon_accel_thread_free(DEMON_AccelThread *thread){ - SLLStackPush(demon_free_thread_accel, thread); -} - -internal DEMON_AccelThread* -demon_accel_from_thread(DEMON_Entity *thread){ - DEMON_AccelThread *accel = (DEMON_AccelThread*)thread->accel; - if (accel == 0){ - accel = demon_accel_thread_alloc(); - thread->accel = accel; - } - return(accel); -} - -//- operations on demon objects -internal String8 -demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module){ - DEMON_AccelModule *accel = (DEMON_AccelModule*)module->accel; - - String8 result = {0}; - - // first time - if (accel == 0){ - result = demon_os_full_path_from_module(arena, module); - - // build chain - DEMON_AccelModule *last_accel = 0; - - U8 *ptr = result.str; - U8 *opl = result.str + result.size; - for (;ptr < opl;){ - U64 size = (U64)(ptr - opl); - U64 clamped_size = ClampTop(result.size, sizeof(Member(DEMON_AccelModule, buf))); - - DEMON_AccelModule *node = demon_accel_module_alloc(); - SLLQueuePush(accel, last_accel, node); - node->total_size = result.size; - MemoryCopy(node->buf, ptr, clamped_size); - - ptr += clamped_size; - } - - // store in module - module->accel = accel; - } - - // read from accel - else{ - U64 size = accel->total_size; - U8 *str = push_array_no_zero(arena, U8, size + 1); - - // copy chain contents to buffer - U8 *ptr = str; - for (DEMON_AccelModule *node = accel; - node != 0; - node = node->next){ - U64 total_size = node->total_size; - U64 clamped_size = ClampTop(total_size, sizeof(node->buf)); - MemoryCopy(ptr, node->buf, clamped_size); - ptr += clamped_size; - } - *ptr = 0; - - // fill result - result.str = str; - result.size = size; - } - - return(result); -} - -internal U64 -demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread){ - // get accel data - DEMON_AccelThread *accel = demon_accel_from_thread(thread); - - // fill stack base - if (!accel->has_stack_base){ - accel->has_stack_base = 1; - accel->stack_base = demon_os_stack_base_vaddr_from_thread(thread); - } - - return(accel->stack_base); -} - -internal U64 -demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread){ - // get accel data - DEMON_AccelThread *accel = demon_accel_from_thread(thread); - - // fill tls root - if (!accel->has_tls_root){ - accel->has_tls_root = 1; - accel->tls_root = demon_os_tls_root_vaddr_from_thread(thread); - } - - return(accel->tls_root); -} - -internal void* -demon_accel_read_regs(DEMON_Entity *thread){ - // get accel data - DEMON_AccelThread *accel = demon_accel_from_thread(thread); - - // update reg cache - if (accel->reg_cache_time != demon_time){ - accel->reg_cache_time = demon_time; - B32 success = demon_os_read_regs(thread, &accel->regs); - if (!success){ - MemoryZeroStruct(&accel->regs); - } - } - - return(&accel->regs); -} - -internal void -demon_accel_write_regs(DEMON_Entity *thread, void *data){ - // get accel data - DEMON_AccelThread *accel = demon_accel_from_thread(thread); - - // low level write - B32 success = 0; - U64 data_size = 0; - switch (thread->arch){ - case Architecture_x86: - { - data_size = sizeof(REGS_RegBlockX86); - success = demon_os_write_regs_x86(thread, (REGS_RegBlockX86*)data); - }break; - case Architecture_x64: - { - data_size = sizeof(REGS_RegBlockX64); - success = demon_os_write_regs_x64(thread, (REGS_RegBlockX64*)data); - }break; - } - - // update cache - if (success){ - accel->reg_cache_time = demon_time; - MemoryCopy(&accel->regs, data, data_size); - } -} - -internal void -demon_accel_low_level_write_regs(DEMON_Entity *thread){ - // NOTE(allen): This is a tricky one. It's just a way to enable some internal - // optimizations. Instead of forcing the user to pass in register data - // to write out and copy to the cache, the "user" is other demon code that - // knows what it's doing. So it grabs the cache memory (through a call to - // `demon_accel_read_regs`) modifies it in place and then calls this. - // So we just have to write the cache contents directly out to OS. - - // get accel data - DEMON_AccelThread *accel = demon_accel_from_thread(thread); - switch (thread->arch){ - case Architecture_x86: - { - demon_os_write_regs_x86(thread, &accel->regs.x86); - }break; - case Architecture_x64: - { - demon_os_write_regs_x64(thread, &accel->regs.x64); - }break; - } -} - - -//- entity accel free -internal void -demon_accel_free(DEMON_Entity *entity){ - switch (entity->kind){ - case DEMON_EntityKind_Module: - { - if (entity->accel != 0){ - for (DEMON_AccelModule *node = (DEMON_AccelModule*)entity->accel, *next = 0; - node != 0; - node = next){ - next = node->next; - demon_accel_module_free(node); - } - } - }break; - - case DEMON_EntityKind_Thread: - { - if (entity->accel != 0){ - demon_accel_thread_free((DEMON_AccelThread*)entity->accel); - } - }break; - } -} diff --git a/src/demon/demon_accel.h b/src/demon/demon_accel.h deleted file mode 100644 index 863f028d..00000000 --- a/src/demon/demon_accel.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef DEMON_ACCEL_H -#define DEMON_ACCEL_H - -//////////////////////////////// -//~ allen: Acceleration Data - -typedef struct DEMON_AccelModule DEMON_AccelModule; -struct DEMON_AccelModule -{ - DEMON_AccelModule *next; - U64 total_size; - U8 buf[240]; -}; - -typedef union DEMON_AccelThread DEMON_AccelThread; -union DEMON_AccelThread -{ - DEMON_AccelThread *next; - struct{ - B32 has_stack_base; - B32 has_tls_root; - U64 stack_base; - U64 tls_root; - - U64 reg_cache_time; - union{ - REGS_RegBlockX64 x64; - REGS_RegBlockX86 x86; - } regs; - }; -}; - -//////////////////////////////// -//~ allen: Acceleration Globals - -global DEMON_AccelModule *demon_free_module_accel = 0; -global DEMON_AccelThread *demon_free_thread_accel = 0; - -//////////////////////////////// -//~ allen: Acceleration Layer Functions - -//- accel helpers -internal DEMON_AccelModule *demon_accel_module_alloc(void); -internal void demon_accel_module_free(DEMON_AccelModule *module); - -internal DEMON_AccelThread *demon_accel_thread_alloc(void); -internal void demon_accel_thread_free(DEMON_AccelThread *thread); -internal DEMON_AccelThread *demon_accel_from_thread(DEMON_Entity *thread); - -//- operations on demon objects -internal String8 demon_accel_full_path_from_module(Arena *arena, DEMON_Entity *module); -internal U64 demon_accel_stack_base_vaddr_from_thread(DEMON_Entity *thread); -internal U64 demon_accel_tls_root_vaddr_from_thread(DEMON_Entity *thread); - -internal void* demon_accel_read_regs(DEMON_Entity *thread); -internal void demon_accel_write_regs(DEMON_Entity *thread, void *data); - -internal void demon_accel_low_level_write_regs(DEMON_Entity *thread); - -//- entity accel free -internal void demon_accel_free(DEMON_Entity *entity); - -#endif //DEMON_ACCEL_H diff --git a/src/demon/demon_common.c b/src/demon/demon_common.c deleted file mode 100644 index 15e7df8a..00000000 --- a/src/demon/demon_common.c +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -// NOTE(allen): State Safety Helper - -internal B32 -demon_access_begin(void){ - B32 result = 0; - if (demon_primary_thread){ - Assert(demon_run_state); - result = 1; - } - else{ - os_mutex_take(demon_state_mutex); - if (demon_run_state){ - os_mutex_drop(demon_state_mutex); - } - else{ - result = 1; - } - } - return(result); -} - -internal void -demon_access_end(void){ - if (!demon_primary_thread){ - os_mutex_drop(demon_state_mutex); - } -} - -//////////////////////////////// -// NOTE(allen): Entity System - -internal void -demon_common_init(void){ - // access control mechanism - demon_state_mutex = os_mutex_alloc(); - - // time - demon_time = 1; - - // setup arena - demon_ent_arena = arena_alloc(); - - // setup map - demon_ent_map = push_array(demon_ent_arena, DEMON_Map, 1); - demon_ent_map->bucket_count = 4093; - demon_ent_map->buckets = push_array(demon_ent_arena, DEMON_MapSlot*, demon_ent_map->bucket_count); - - // setup entity memory - U64 reserve_size_unaligned = (DEMON_ENTITY_CAP)*sizeof(DEMON_Entity); - U64 reserve_size = AlignPow2(reserve_size_unaligned, DEMON_ENTITY_CMT_SIZE); - demon_ent_cmt = demon_ent_pos = demon_ent_base = (DEMON_Entity*)os_reserve(reserve_size); - demon_ent_opl = demon_ent_base + (reserve_size/sizeof(DEMON_Entity)); - - Assert(demon_ent_base != 0); - - // setup root - demon_ent_root = demon_ent_alloc(); - demon_ent_root->kind = DEMON_EntityKind_Root; -} - -internal DEMON_Entity* -demon_ent_alloc(void){ - DEMON_Entity *result = demon_ent_free; - if (result != 0){ - SLLStackPop(demon_ent_free); - } - else{ - if (demon_ent_pos < demon_ent_opl){ - if (ensure_commit(&demon_ent_cmt, demon_ent_pos + 1, DEMON_ENTITY_CMT_SIZE)){ - result = demon_ent_pos; - demon_ent_pos += 1; - } - } - } - if (result != 0){ - U32 gen = result->gen; - MemoryZeroStruct(result); - result->gen = gen; - } - return(result); -} - -//- handle <-> entity pointer - -internal DEMON_Entity* -demon_ent_ptr_from_handle(DEMON_Handle handle){ - Assert(demon_ent_base != 0); - DEMON_Entity *result = 0; - U32 index = (U32)(handle & 0xFFFFFFFF); - U64 count = (U64)(demon_ent_pos - demon_ent_base); - if (0 < index && index < count){ - DEMON_Entity *entity = demon_ent_base + index; - U32 gen = (U32)(handle >> 32); - if (gen == entity->gen){ - result = entity; - } - } - return(result); -} - -internal DEMON_Handle -demon_ent_handle_from_ptr(DEMON_Entity *entity){ - Assert(demon_ent_base != 0); - DEMON_Handle result = {0}; - if (demon_ent_base < entity && entity < demon_ent_pos){ - U32 index = (U32)(entity - demon_ent_base); - U64 gen = entity->gen; - result = (gen << 32) | index; - } - return(result); -} - -//- high level entity alloc,init,release - -internal DEMON_Entity* -demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id){ - Assert(demon_ent_base != 0); - DEMON_Entity *result = demon_ent_alloc(); - if (result != 0){ - result->kind = kind; - result->id = id; - result->arch = parent->arch; - result->parent = parent; - DLLPushBack(parent->first, parent->last, result); - demon_ent_map_save(kind, id, result); - } - return(result); -} - -internal void -demon_ent_release_single(DEMON_Entity *entity){ - switch (entity->kind){ - case DEMON_EntityKind_Process: demon_proc_count -= 1; break; - case DEMON_EntityKind_Thread: demon_thread_count -= 1; break; - case DEMON_EntityKind_Module: demon_module_count -= 1; break; - } - demon_accel_free(entity); - demon_os_entity_cleanup(entity); - DEMON_MapRef ref = demon_ent_map_find(entity->kind, entity->id); - demon_ent_map_erase(ref); - entity->gen += 1; -} - -internal void -demon_ent_release_children(DEMON_Entity *root){ - Assert(demon_ent_base != 0); - if (root->first != 0){ - for (DEMON_Entity *node = root->first; - node != 0; - node = node->next){ - demon_ent_release_children(node); - demon_ent_release_single(node); - } - root->last->next = demon_ent_free; - demon_ent_free = root->first; - root->first = 0; - root->last = 0; - } -} - -internal void -demon_ent_release_root_and_children(DEMON_Entity *root){ - Assert(demon_ent_base != 0); - Assert(root->parent != 0); - - // release children - demon_ent_release_children(root); - - // release root - DEMON_Entity *parent = root->parent; - demon_ent_release_single(root); - DLLRemove(parent->first, parent->last, root); - SLLStackPush(demon_ent_free, root); -} - -//- entity map - -internal U64 -demon_ent_map_hash(U16 kind, U64 id){ - U64 result = ((U64)kind << 32) ^ id; - return(result); -} - -internal void -demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity){ - Assert(demon_ent_base != 0); - DEMON_Map *map = demon_ent_map; - - // allocate a new slot - DEMON_MapSlot *slot = map->free_slots; - if (slot != 0){ - SLLStackPop(map->free_slots); - } - else{ - slot = push_array_no_zero(demon_ent_arena, DEMON_MapSlot, 1); - } - - // fill slot - slot->kind = kind; - slot->id = id; - slot->entity = entity; - - // insert into bucket - U64 hash = demon_ent_map_hash(kind, id); - U64 bucket_index = hash%map->bucket_count; - SLLStackPush(map->buckets[bucket_index], slot); -} - -internal DEMON_MapRef -demon_ent_map_find(U16 kind, U64 id){ - Assert(demon_ent_base != 0); - DEMON_Map *map = demon_ent_map; - - // scan bucket - DEMON_MapRef result = {0}; - U64 hash = demon_ent_map_hash(kind, id); - U64 bucket_index = hash%map->bucket_count; - for (DEMON_MapSlot **ptr = &map->buckets[bucket_index], *slot = 0; - *ptr != 0; - ptr = &slot->next){ - slot = *ptr; - if (slot->kind == kind && slot->id == id){ - result.slot = slot; - result.ptr_to_slot = ptr; - break; - } - } - - return(result); -} - -internal DEMON_Entity* -demon_ent_map_entity_from_id(U16 kind, U64 id){ - DEMON_Entity *result = 0; - DEMON_MapRef ref = demon_ent_map_find(kind, id); - if (ref.slot != 0){ - result = ref.slot->entity; - } - return(result); -} - -internal void -demon_ent_map_erase(DEMON_MapRef ref){ - Assert(demon_ent_base != 0); - DEMON_Map *map = demon_ent_map; - - // move slot to free list - if (ref.slot != 0){ - *ref.ptr_to_slot = ref.slot->next; - SLLStackPush(map->free_slots, ref.slot); - } -} - -//////////////////////////////// -// NOTE(allen): Event Helpers - -internal DEMON_Event* -demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind){ - DEMON_EventNode *n = push_array(arena, DEMON_EventNode, 1); - DEMON_Event *result = &n->v; - SLLQueuePush(list->first, list->last, n); - list->count += 1; - result->kind = kind; - return(result); -} - diff --git a/src/demon/demon_common.h b/src/demon/demon_common.h deleted file mode 100644 index 07ec4765..00000000 --- a/src/demon/demon_common.h +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef DEMON_COMMON_H -#define DEMON_COMMON_H - -//////////////////////////////// -//~ allen: DEMON Entity System - -typedef enum DEMON_EntityKind -{ - DEMON_EntityKind_NULL, - - DEMON_EntityKind_Root, - DEMON_EntityKind_Process, - DEMON_EntityKind_Thread, - DEMON_EntityKind_Module, - - DEMON_EntityKind_COUNT -} -DEMON_EntityKind; - -typedef struct DEMON_Entity DEMON_Entity; -struct DEMON_Entity -{ - // TODO(allen): these could be U32s - DEMON_Entity *next; - DEMON_Entity *prev; - DEMON_Entity *parent; - DEMON_Entity *first; - DEMON_Entity *last; - - DEMON_EntityKind kind; - Architecture arch; - U32 gen; - U64 id; - U64 addr_range_dim; - - // each OS backend decides how to use `ext` for each entity kind - union{ - void *ext; - U64 ext_u64; - }; - - // the accel layer attaches some extra information to some entities - void *accel; -}; - -//- id -> entity map -typedef struct DEMON_MapSlot DEMON_MapSlot; -struct DEMON_MapSlot -{ - DEMON_MapSlot *next; - U16 kind; - U64 id; - DEMON_Entity *entity; -}; - -typedef struct DEMON_Map DEMON_Map; -struct DEMON_Map -{ - DEMON_MapSlot **buckets; - U64 bucket_count; - DEMON_MapSlot *free_slots; -}; - -typedef struct DEMON_MapRef DEMON_MapRef; -struct DEMON_MapRef -{ - DEMON_MapSlot *slot; - DEMON_MapSlot **ptr_to_slot; -}; - -//- rjf: entity extrusive list - -typedef struct DEMON_EntityNode DEMON_EntityNode; -struct DEMON_EntityNode -{ - DEMON_EntityNode *next; - DEMON_Entity *entity; -}; - -//////////////////////////////// -//~ allen: Demon Globals - -thread_static B32 demon_primary_thread = 0; -global B32 demon_run_state = 0; -global OS_Handle demon_state_mutex = {0}; - -global U64 demon_time = 0; - -global Arena *demon_ent_arena = 0; -global DEMON_Map *demon_ent_map = 0; - -global DEMON_Entity *demon_ent_free = 0; -global DEMON_Entity *demon_ent_root = 0; - -global DEMON_Entity *demon_ent_base = 0; -global DEMON_Entity *demon_ent_pos = 0; -global DEMON_Entity *demon_ent_opl = 0; -global void *demon_ent_cmt = 0; - -global U64 demon_proc_count = 0; -global U64 demon_thread_count = 0; -global U64 demon_module_count = 0; - -#if !defined(DEMON_ENTITY_CMT_SIZE) -# define DEMON_ENTITY_CMT_SIZE KB(64) -#endif -#if !defined(DEMON_ENTITY_CAP) -# define DEMON_ENTITY_CAP 65536 -#endif - -StaticAssert(IsPow2(DEMON_ENTITY_CMT_SIZE), check_demon_entity_cmt_size); - -//////////////////////////////// -//~ allen: State Safety Helper - -internal B32 demon_access_begin(void); -internal void demon_access_end(void); - -//////////////////////////////// -//~ allen: Entity System - -internal void demon_common_init(void); -internal DEMON_Entity* demon_ent_alloc(void); - -//- handle <-> entity pointer -internal DEMON_Entity* demon_ent_ptr_from_handle(DEMON_Handle handle); -internal DEMON_Handle demon_ent_handle_from_ptr(DEMON_Entity *entity); - -//- high level entity alloc,init,release -internal DEMON_Entity* demon_ent_new(DEMON_Entity *parent, DEMON_EntityKind kind, U64 id); -internal void demon_ent_release_single(DEMON_Entity *entity); -internal void demon_ent_release_children(DEMON_Entity *root); -internal void demon_ent_release_root_and_children(DEMON_Entity *root); - -//- entity map -internal U64 demon_ent_map_hash(U16 kind, U64 id); -internal void demon_ent_map_save(U16 kind, U64 id, DEMON_Entity *entity); -internal DEMON_MapRef demon_ent_map_find(U16 kind, U64 id); -internal DEMON_Entity* demon_ent_map_entity_from_id(U16 kind, U64 id); -internal void demon_ent_map_erase(DEMON_MapRef map_ref); - -//////////////////////////////// -//~ allen: Event Helpers - -internal DEMON_Event* demon_push_event(Arena *arena, DEMON_EventList *list, DEMON_EventKind kind); - -#endif //DEMON_COMMON_H diff --git a/src/demon/demon_core.c b/src/demon/demon_core.c index 43077629..86c1c3c6 100644 --- a/src/demon/demon_core.c +++ b/src/demon/demon_core.c @@ -2,148 +2,34 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: Main Layer Initialization +//~ rjf: Basic Type Functions (Helpers, Implemented Once) -internal void -demon_init(void){ - demon_common_init(); - demon_os_init(); +//- rjf: handles + +internal DMN_Handle +dmn_handle_zero(void) +{ + DMN_Handle h = {0}; + return h; } -//////////////////////////////// -//~ rjf: Basic Type Functions - -//- rjf: stringizing - -internal String8 -demon_string_from_event_kind(DEMON_EventKind kind){ - String8 result = str8_lit("unknown"); - switch (kind){ - default: break; - case DEMON_EventKind_Error: result = str8_lit("Error"); break; - case DEMON_EventKind_HandshakeComplete: result = str8_lit("HandshakeComplete"); break; - case DEMON_EventKind_CreateProcess: result = str8_lit("CreateProcess"); break; - case DEMON_EventKind_ExitProcess: result = str8_lit("ExitProcess"); break; - case DEMON_EventKind_CreateThread: result = str8_lit("CreateThread"); break; - case DEMON_EventKind_ExitThread: result = str8_lit("ExitThread"); break; - case DEMON_EventKind_LoadModule: result = str8_lit("LoadModule"); break; - case DEMON_EventKind_UnloadModule: result = str8_lit("UnloadModule"); break; - case DEMON_EventKind_Breakpoint: result = str8_lit("Breakpoint"); break; - case DEMON_EventKind_Trap: result = str8_lit("Trap"); break; - case DEMON_EventKind_SingleStep: result = str8_lit("SingleStep"); break; - case DEMON_EventKind_Exception: result = str8_lit("Exception"); break; - case DEMON_EventKind_Halt: result = str8_lit("Halt"); break; - case DEMON_EventKind_Memory: result = str8_lit("Memory"); break; - case DEMON_EventKind_DebugString: result = str8_lit("DebugString"); break; - case DEMON_EventKind_SetThreadName: result = str8_lit("SetThreadName"); break; - } - return(result); -} - -internal String8 -demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind){ - String8 result = str8_lit("unknown"); - switch (kind){ - default: break; - case DEMON_MemoryEventKind_Commit: result = str8_lit("Commit"); break; - case DEMON_MemoryEventKind_Reserve: result = str8_lit("Reserve"); break; - case DEMON_MemoryEventKind_Decommit: result = str8_lit("Decommit"); break; - case DEMON_MemoryEventKind_Release: result = str8_lit("Release"); break; - } - return(result); -} - -internal String8 -demon_string_from_exception_kind(DEMON_ExceptionKind kind){ - String8 result = str8_lit("unknown"); - switch (kind){ - default: break; - case DEMON_ExceptionKind_MemoryRead: result = str8_lit("MemoryRead"); break; - case DEMON_ExceptionKind_MemoryWrite: result = str8_lit("MemoryWrite"); break; - case DEMON_ExceptionKind_MemoryExecute: result = str8_lit("MemoryExecute"); break; - case DEMON_ExceptionKind_CppThrow: result = str8_lit("CppThrow"); break; - } - return(result); -} - -internal void -demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event){ - B32 need_exception_info = (event->kind == DEMON_EventKind_Exception || - event->kind == DEMON_EventKind_Breakpoint || - event->kind == DEMON_EventKind_Halt || - event->kind == DEMON_EventKind_SingleStep); - - // allen: kind - String8 kind_string = demon_string_from_event_kind(event->kind); - str8_list_pushf(arena, out, "%S: { (%i)", kind_string, event->kind); - - // rjf: basics - { - str8_list_pushf(arena, out, " process: (%I64x)", event->process); - str8_list_pushf(arena, out, " thread: (%I64x)", event->thread); - str8_list_pushf(arena, out, " module: (%I64x)", event->module); - str8_list_pushf(arena, out, " address: (%I64x)", event->address, event->address); - str8_list_pushf(arena, out, " size: (0x%I64x, %I64u)", event->size, event->size); - } - - // rjf: string - if (event->string.size != 0){ - str8_list_pushf(arena, out, " string: \"%S\"", event->string); - } - - // rjf: exception info - if (need_exception_info){ - str8_list_pushf(arena, out, " code: (0x%x, %i)", event->code, event->code); - str8_list_pushf(arena, out, " flags: (0x%x, %i)", event->flags, event->flags); - str8_list_pushf(arena, out, " signo: (0x%x, %i)", event->signo, event->signo); - str8_list_pushf(arena, out, " sigcode: (0x%x, %i)", event->sigcode, event->sigcode); - } - - // rjf: need error info - if (event->kind == DEMON_EventKind_Error){ - str8_list_pushf(arena, out, " error_kind: (0x%x, %i)", event->error_kind, event->error_kind); - } - - // rjf: memory event kind info - if (event->memory_kind != DEMON_MemoryEventKind_Null){ - String8 memory_kind_string = demon_string_from_memory_event_kind(event->memory_kind); - str8_list_pushf(arena, out, " memory_kind: (%S, %i)", - memory_kind_string, event->memory_kind); - } - - // rjf: exception kind - if (need_exception_info){ - String8 exception_kind_string = demon_string_from_exception_kind(event->exception_kind); - str8_list_pushf(arena, out, " exception_kind: (%S, %i)", - exception_kind_string, event->exception_kind); - } - - // rjf: instruction ptr - if (event->instruction_pointer != 0){ - str8_list_pushf(arena, out, " instruction_pointer: (%I64x)", event->instruction_pointer); - } - - // rjf: stack ptr - if (event->stack_pointer != 0){ - str8_list_pushf(arena, out, " stack_pointer: (%I64x)", event->stack_pointer); - } - - str8_list_pushf(arena, out, " user_data: (0x%I64x, %I64u)", - event->user_data, event->user_data); - str8_list_pushf(arena, out, "}"); +internal B32 +dmn_handle_match(DMN_Handle a, DMN_Handle b) +{ + return a.u32[0] == b.u32[0] && a.u32[1] == b.u32[1]; } //- rjf: trap chunk lists internal void -demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap) +dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap) { - DEMON_TrapChunkNode *node = list->last; + DMN_TrapChunkNode *node = list->last; if(node == 0 || node->count >= node->cap) { - node = push_array(arena, DEMON_TrapChunkNode, 1); + node = push_array(arena, DMN_TrapChunkNode, 1); node->cap = cap; - node->v = push_array_no_zero(arena, DEMON_Trap, node->cap); + node->v = push_array_no_zero(arena, DMN_Trap, node->cap); SLLQueuePush(list->first, list->last, node); list->node_count += 1; } @@ -153,7 +39,7 @@ demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEM } internal void -demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push) +dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push) { if(dst->last == 0) { @@ -170,11 +56,11 @@ demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkL } internal void -demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push) +dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push) { - for(DEMON_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next) + for(DMN_TrapChunkNode *src_n = to_push->first; src_n != 0; src_n = src_n->next) { - DEMON_TrapChunkNode *dst_n = push_array(arena, DEMON_TrapChunkNode, 1); + DMN_TrapChunkNode *dst_n = push_array(arena, DMN_TrapChunkNode, 1); dst_n->v = src_n->v; dst_n->cap = src_n->cap; dst_n->count = src_n->count; @@ -187,685 +73,81 @@ demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst //- rjf: handle lists internal void -demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle) +dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle) { - DEMON_HandleNode *node = push_array(arena, DEMON_HandleNode, 1); + DMN_HandleNode *node = push_array(arena, DMN_HandleNode, 1); SLLQueuePush(list->first, list->last, node); node->v = handle; list->count += 1; } -internal DEMON_HandleArray -demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list) +internal DMN_HandleArray +dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list) { - DEMON_HandleArray array = {0}; + DMN_HandleArray array = {0}; array.count = list->count; - array.handles = push_array_no_zero(arena, DEMON_Handle, array.count); + array.handles = push_array_no_zero(arena, DMN_Handle, array.count); U64 idx = 0; - for(DEMON_HandleNode *n = list->first; n != 0; n = n->next, idx += 1) + for(DMN_HandleNode *n = list->first; n != 0; n = n->next, idx += 1) { array.handles[idx] = n->v; } return array; } -internal DEMON_HandleArray -demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src) +internal DMN_HandleArray +dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src) { - DEMON_HandleArray dst = {0}; + DMN_HandleArray dst = {0}; dst.count = src->count; - dst.handles = push_array_no_zero(arena, DEMON_Handle, dst.count); - MemoryCopy(dst.handles, src->handles, sizeof(DEMON_Handle)*dst.count); + dst.handles = push_array_no_zero(arena, DMN_Handle, dst.count); + MemoryCopy(dst.handles, src->handles, sizeof(DMN_Handle)*dst.count); return dst; } -//////////////////////////////// -//~ rjf: Primary Thread & Exclusive Mode Controls +//- rjf: event list building -internal void -demon_primary_thread_begin(void){ - demon_primary_thread = 1; -} - -internal void -demon_exclusive_mode_begin(void){ - Assert(demon_primary_thread); - os_mutex_take(demon_state_mutex); - demon_run_state = 1; - os_mutex_drop(demon_state_mutex); -} - -internal void -demon_exclusive_mode_end(void){ - Assert(demon_primary_thread); - os_mutex_take(demon_state_mutex); - demon_run_state = 0; - os_mutex_drop(demon_state_mutex); -} - -//////////////////////////////// -//~ rjf: Running/Halting - -internal DEMON_EventList -demon_run(Arena *arena, DEMON_RunCtrls *ctrls) +internal DMN_Event * +dmn_event_list_push(Arena *arena, DMN_EventList *list) { - Assert(demon_primary_thread); - Temp scratch = scratch_begin(&arena, 1); - - // convert controls to os controls - B32 full_conversion = 1; - DEMON_OS_RunCtrls os_ctrls = {0}; + DMN_EventNode *n = push_array(arena, DMN_EventNode, 1); + SLLQueuePush(list->first, list->last, n); + list->count += 1; + DMN_Event *result = &n->v; + return result; +} + +//////////////////////////////// +//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once) + +internal U64 +dmn_rip_from_thread(DMN_Handle thread) +{ + U64 result = 0; + Temp scratch = scratch_begin(0, 0); { - // convert single_step_thread - if (ctrls->single_step_thread != 0){ - DEMON_Entity *sst_entity = demon_ent_ptr_from_handle(ctrls->single_step_thread); - if (sst_entity != 0 && - sst_entity->kind == DEMON_EntityKind_Thread){ - os_ctrls.single_step_thread = sst_entity; - } - else{ - full_conversion = 0; - goto finish_conversion; - } - } - - // convert exception handling flag - os_ctrls.ignore_previous_exception = ctrls->ignore_previous_exception; - - // convert fronzen threads - os_ctrls.run_entities_are_unfrozen = ctrls->run_entities_are_unfrozen; - os_ctrls.run_entities_are_processes = ctrls->run_entities_are_processes; - os_ctrls.run_entity_count = ctrls->run_entity_count; - os_ctrls.run_entities = push_array_no_zero(scratch.arena, DEMON_Entity*, ctrls->run_entity_count); - { - DEMON_EntityKind expected_entity_kind = DEMON_EntityKind_Thread; - if (os_ctrls.run_entities_are_processes){ - expected_entity_kind = DEMON_EntityKind_Process; - } - - DEMON_Handle *src = ctrls->run_entities; - DEMON_Entity **dst = os_ctrls.run_entities; - for (U64 i = 0; i < ctrls->run_entity_count; i += 1, src += 1, dst += 1){ - DEMON_Entity *frozen_thread = demon_ent_ptr_from_handle(*src); - if (frozen_thread != 0 && - frozen_thread->kind == expected_entity_kind){ - *dst = frozen_thread; - } - else{ - full_conversion = 0; - goto finish_conversion; - } - } - } - - // convert traps - os_ctrls.traps = push_array_no_zero(scratch.arena, DEMON_OS_Trap, ctrls->traps.trap_count); - { - DEMON_OS_Trap *dst = os_ctrls.traps; - - for (DEMON_TrapChunkNode *node = ctrls->traps.first; - node != 0; - node = node->next){ - DEMON_Trap *src = node->v; - U64 node_trap_count = node->count; - for (U64 i = 0; i < node_trap_count; i += 1, src += 1){ - if (src->process != 0){ - DEMON_Entity *trap_process = demon_ent_ptr_from_handle(src->process); - if (trap_process != 0 && - trap_process->kind == DEMON_EntityKind_Process){ - dst->process = trap_process; - dst->address = src->address; - dst += 1; - } - else{ - full_conversion = 0; - goto finish_conversion; - } - } - } - } - - os_ctrls.trap_count = (U64)(dst - os_ctrls.traps); - } - - finish_conversion:; + Architecture arch = dmn_arch_from_thread(thread); + U64 reg_block_size = regs_block_size_from_architecture(arch); + void *reg_block = push_array(scratch.arena, U8, reg_block_size); + dmn_thread_read_reg_block(thread, reg_block); + result = regs_rip_from_arch_block(arch, reg_block); } - - // call the OS implementation of run - DEMON_EventList result = {0}; - if (full_conversion){ - result = demon_os_run(arena, &os_ctrls); - } - else{ - DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error); - event->error_kind = DEMON_ErrorKind_InvalidHandle; - } - scratch_end(scratch); - return(result); -} - -internal void -demon_halt(U64 code, U64 user_data){ - demon_os_halt(code, user_data); + return result; } internal U64 -demon_get_time_counter(void){ - return(demon_time); -} - -//////////////////////////////// -//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting - -internal U32 -demon_launch_process(OS_LaunchOptions *options){ - Assert(demon_primary_thread); - U32 result = demon_os_launch_process(options); - return(result); -} - -internal B32 -demon_attach_process(U32 pid){ - Assert(demon_primary_thread); - B32 result = demon_os_attach_process(pid); - return(result); -} - -internal B32 -demon_kill_process(DEMON_Handle process, U32 exit_code){ - Assert(demon_primary_thread); - B32 result = 0; - DEMON_Entity *entity = demon_ent_ptr_from_handle(process); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Process){ - result = demon_os_kill_process(entity, exit_code); - } - return(result); -} - -internal B32 -demon_detach_process(DEMON_Handle process){ - Assert(demon_primary_thread); - B32 result = 0; - DEMON_Entity *entity = demon_ent_ptr_from_handle(process); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Process){ - result = demon_os_detach_process(entity); - } - return(result); -} - -//////////////////////////////// -//~ rjf: Entity Functions - -//- rjf: basics - -internal B32 -demon_object_exists(DEMON_Handle object){ - B32 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(object); - result = (entity != 0); - demon_access_end(); - } - return(result); -} - -//- rjf: introspection - -internal Architecture -demon_arch_from_object(DEMON_Handle object){ - Architecture result = Architecture_Null; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(object); - if (entity != 0){ - result = (Architecture)entity->arch; - } - demon_access_end(); - } - return(result); -} - -internal U64 -demon_base_vaddr_from_module(DEMON_Handle module){ - U64 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(module); - if (entity != 0 && entity->kind == DEMON_EntityKind_Module){ - result = entity->id; - } - demon_access_end(); - } - return(result); -} - -internal Rng1U64 -demon_vaddr_range_from_module(DEMON_Handle module) +dmn_rsp_from_thread(DMN_Handle thread) { - Rng1U64 result = {0}; - if(demon_access_begin()) + U64 result = 0; + Temp scratch = scratch_begin(0, 0); { - DEMON_Entity *entity = demon_ent_ptr_from_handle(module); - if(entity != 0 && entity->kind == DEMON_EntityKind_Module) - { - result = r1u64(entity->id, entity->id+entity->addr_range_dim); - } - demon_access_end(); + Architecture arch = dmn_arch_from_thread(thread); + U64 reg_block_size = regs_block_size_from_architecture(arch); + void *reg_block = push_array(scratch.arena, U8, reg_block_size); + dmn_thread_read_reg_block(thread, reg_block); + result = regs_rsp_from_arch_block(arch, reg_block); } - return(result); -} - -internal String8 -demon_full_path_from_module(Arena *arena, DEMON_Handle module){ - String8 result = {0}; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(module); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Module){ - result = demon_accel_full_path_from_module(arena, entity); - } - demon_access_end(); - } - return(result); -} - -internal U64 -demon_stack_base_vaddr_from_thread(DEMON_Handle thread){ - U64 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); - if (entity != 0 && entity->kind == DEMON_EntityKind_Thread){ - result = demon_accel_stack_base_vaddr_from_thread(entity); - } - demon_access_end(); - } - return(result); -} - -internal U64 -demon_tls_root_vaddr_from_thread(DEMON_Handle handle){ - U64 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(handle); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Thread){ - result = demon_accel_tls_root_vaddr_from_thread(entity); - } - demon_access_end(); - } - return(result); -} - -internal DEMON_HandleArray -demon_all_processes(Arena *arena){ - DEMON_HandleArray result = {0}; - - if (demon_access_begin()){ - DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_proc_count); - DEMON_Handle *handle_opl = handles + demon_proc_count; - DEMON_Handle *handle_ptr = handles; - - for (DEMON_Entity *process = demon_ent_root->first; - process != 0 && handle_ptr < handle_opl; - process = process->next){ - if (process->kind == DEMON_EntityKind_Process){ - *handle_ptr = demon_ent_handle_from_ptr(process); - handle_ptr += 1; - } - } - - result.handles = handles; - result.count = (U64)(handle_ptr - handles); - - U64 unused_count = demon_proc_count - result.count; - arena_put_back(arena, sizeof(DEMON_Handle)*unused_count); - demon_access_end(); - } - - return(result); -} - -internal DEMON_HandleArray -demon_threads_from_process(Arena *arena, DEMON_Handle process){ - DEMON_HandleArray result = {0}; - - if (demon_access_begin()){ - DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_thread_count); - DEMON_Handle *handle_opl = handles + demon_thread_count; - DEMON_Handle *handle_ptr = handles; - - DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process); - - if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){ - for (DEMON_Entity *thread = process_ptr->first; - thread != 0 && handle_ptr < handle_opl; - thread = thread->next){ - if (thread->kind == DEMON_EntityKind_Thread){ - *handle_ptr = demon_ent_handle_from_ptr(thread); - handle_ptr += 1; - } - } - } - - result.handles = handles; - result.count = (U64)(handle_ptr - handles); - - U64 unused_count = demon_thread_count - result.count; - arena_put_back(arena, sizeof(DEMON_Handle)*unused_count); - demon_access_end(); - } - - return(result); -} - -internal DEMON_HandleArray -demon_modules_from_process(Arena *arena, DEMON_Handle process){ - DEMON_HandleArray result = {0}; - - if (demon_access_begin()){ - DEMON_Handle *handles = push_array_no_zero(arena, DEMON_Handle, demon_module_count); - DEMON_Handle *handle_opl = handles + demon_module_count; - DEMON_Handle *handle_ptr = handles; - - DEMON_Entity *process_ptr = demon_ent_ptr_from_handle(process); - - if (process_ptr != 0 && process_ptr->kind == DEMON_EntityKind_Process){ - for (DEMON_Entity *module = process_ptr->first; - module != 0 && handle_ptr < handle_opl; - module = module->next){ - if (module->kind == DEMON_EntityKind_Module){ - *handle_ptr = demon_ent_handle_from_ptr(module); - handle_ptr += 1; - } - } - } - - result.handles = handles; - result.count = (U64)(handle_ptr - handles); - - U64 unused_count = demon_module_count - result.count; - arena_put_back(arena, sizeof(DEMON_Handle)*unused_count); - demon_access_end(); - } - - return(result); -} - -//- rjf: target process memory allocation/protection - -internal U64 -demon_reserve_memory(DEMON_Handle process, U64 size){ - U64 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(process); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Process){ - result = demon_os_reserve_memory(entity, size); - } - demon_access_end(); - } - return(result); -} - -internal B32 -demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags){ - B32 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(process); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Process){ - demon_os_set_memory_protect_flags(entity, page_vaddr, size, flags); - result = 1; - } - demon_access_end(); - } - return(result); -} - -internal B32 -demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size){ - B32 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(process); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Process){ - demon_os_release_memory(entity, vaddr, size); - result = 1; - } - demon_access_end(); - } - return(result); -} - -//- rjf: target process memory reading/writing - -internal U64 -demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size){ - U64 bytes_read = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(process); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Process){ - bytes_read = demon_os_read_memory(entity, dst, src_address, size); - } - demon_access_end(); - } - return(bytes_read); -} - -internal B32 -demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size){ - B32 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(process); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Process){ - result = demon_os_write_memory(entity, dst_address, src, size); - } - demon_access_end(); - } - return(result); -} - -#define READ_BLOCK_SIZE 4096 - -internal U64 -demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size){ - // Algorithm: - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // ^ ^ ^ - // MIN MAX SMAX - // [MIN,MAX) - range attempting to read - // [MAX,SMAX) - range not yet proven to be impossible to read - - Assert(src_address%READ_BLOCK_SIZE == 0); - Assert(size%READ_BLOCK_SIZE == 0); - - U64 read_size = 0; - U64 min = 0; - U64 max = size; - U64 smax = max; - - for (;;){ - if (max <= min){ - break; - } - - // attempt to read range - U64 attempt_size = max - min; - B32 success = demon_read_memory(process, (U8*)dst + min, src_address + min, attempt_size); - - if (success){ - // increase successful read size - read_size += attempt_size; - // adjust range up - min = max; - max = smax; - } - else{ - // mark this point as too far - smax = max - READ_BLOCK_SIZE; - // bisect the range for the next read attempt - U64 mid = (min + max)/2; - U64 aligned_mid = AlignDownPow2(mid, READ_BLOCK_SIZE); - max = aligned_mid; - } - } - - U64 result = read_size; - return(result); -} - -internal U64 -demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size){ - U64 read_size = 0; - - if (demon_access_begin()){ - B32 done = 0; - U64 read_opl = src_address + size; - - // pre-aligned part -- [SRC,PRE_OPL) - U64 src_block_opl = AlignPow2(src_address, READ_BLOCK_SIZE); - U64 pre_opl = Min(src_block_opl, read_opl); - if(src_address < pre_opl) - { - U64 attempt_size = pre_opl - src_address; - if(!demon_read_memory(process, dst, src_address, attempt_size)) - { - done = 1; - } - else - { - read_size += attempt_size; - } - } - - // aligned part -- [PRE_OPL,POST_FIRST) - U64 read_opl_block_base = AlignDownPow2(read_opl, READ_BLOCK_SIZE); - U64 post_first = Max(read_opl_block_base, pre_opl); - if (!done && pre_opl < post_first){ - U64 off = pre_opl - src_address; - U64 attempt_size = post_first - pre_opl; - U64 actual_size = demon_read_memory_amap_aligned(process, (U8*)dst + off, - pre_opl, attempt_size); - read_size += actual_size; - if (actual_size < attempt_size){ - done = 1; - } - } - - // post-aligned part -- [POST_FIRST,READ_OPL) - if (!done && post_first < read_opl){ - U64 off = post_first - src_address; - U64 attempt_size = read_opl - post_first; - if (!demon_read_memory(process, (U8*)dst + off, post_first, attempt_size)){ - done = 1; - } - else - { - read_size += attempt_size; - } - } - - demon_access_end(); - } - - U64 result = read_size; - return(result); -} - -#undef READ_BLOCK_SIZE - -//- rjf: thread registers reading/writing - -internal void* -demon_read_regs(DEMON_Handle thread){ - void *result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Thread){ - result = demon_accel_read_regs(entity); - } - demon_access_end(); - } - return(result); -} - -internal B32 -demon_write_regs(DEMON_Handle thread, void *data){ - B32 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Thread){ - demon_accel_write_regs(entity, data); - result = 1; - } - demon_access_end(); - } - return(result); -} - -internal U64 -demon_read_ip(DEMON_Handle thread){ - U64 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Thread){ - void *regs = demon_accel_read_regs(entity); - result = regs_rip_from_arch_block((Architecture)entity->arch, regs); - } - demon_access_end(); - } - return(result); -} - -internal U64 -demon_read_sp(DEMON_Handle thread){ - U64 result = 0; - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Thread){ - void *regs = demon_accel_read_regs(entity); - result = regs_rsp_from_arch_block((Architecture)entity->arch, regs); - } - demon_access_end(); - } - return(result); -} - -internal void -demon_write_ip(DEMON_Handle thread, U64 ip){ - if (demon_access_begin()){ - DEMON_Entity *entity = demon_ent_ptr_from_handle(thread); - if (entity != 0 && - entity->kind == DEMON_EntityKind_Thread){ - void *regs = demon_accel_read_regs(entity); - regs_arch_block_write_rip((Architecture)entity->arch, regs, ip); - demon_accel_write_regs(entity, regs); - } - demon_access_end(); - } -} - -//////////////////////////////// -//~ rjf: Process Listing - -internal void -demon_proc_iter_begin(DEMON_ProcessIter *iter){ - demon_os_proc_iter_begin(iter); -} - -internal B32 -demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out){ - return(demon_os_proc_iter_next(arena, iter, info_out)); -} - -internal void -demon_proc_iter_end(DEMON_ProcessIter *iter){ - demon_os_proc_iter_end(iter); + scratch_end(scratch); + return result; } diff --git a/src/demon/demon_core.h b/src/demon/demon_core.h index f164fcd1..48a2cb63 100644 --- a/src/demon/demon_core.h +++ b/src/demon/demon_core.h @@ -5,111 +5,70 @@ #define DEMON_CORE_H //////////////////////////////// -//~ allen: Demon Low Level Entities +//~ rjf: Control-Thread-Only Context +// +// An instance of this struct must ONLY be returned by dmn_ctrl_begin, and only +// used by the thread which called it. All APIs which can ONLY run on the +// control thread, which blocks to control & receive events, will take this +// parameter. All other APIs can be called from any thread. -typedef U64 DEMON_Handle; - -typedef struct DEMON_HandleNode DEMON_HandleNode; -struct DEMON_HandleNode +typedef struct DMN_CtrlCtx DMN_CtrlCtx; +struct DMN_CtrlCtx { - DEMON_HandleNode *next; - DEMON_Handle v; + U64 u64 [1]; }; -typedef struct DEMON_HandleList DEMON_HandleList; -struct DEMON_HandleList +//////////////////////////////// +//~ rjf: Handle Types + +typedef union DMN_Handle DMN_Handle; +union DMN_Handle { - DEMON_HandleNode *first; - DEMON_HandleNode *last; + U32 u32[2]; + U64 u64[1]; +}; + +typedef struct DMN_HandleNode DMN_HandleNode; +struct DMN_HandleNode +{ + DMN_HandleNode *next; + DMN_Handle v; +}; + +typedef struct DMN_HandleList DMN_HandleList; +struct DMN_HandleList +{ + DMN_HandleNode *first; + DMN_HandleNode *last; U64 count; }; -typedef struct DEMON_HandleArray DEMON_HandleArray; -struct DEMON_HandleArray +typedef struct DMN_HandleArray DMN_HandleArray; +struct DMN_HandleArray { - DEMON_Handle *handles; + DMN_Handle *handles; U64 count; }; //////////////////////////////// -//~ rjf: Memory Protection Flags +//~ rjf: Generated Code -typedef U32 DEMON_MemoryProtectFlags; -enum{ - DEMON_MemoryProtectFlag_Read = (1<<0), - DEMON_MemoryProtectFlag_Write = (1<<1), - DEMON_MemoryProtectFlag_Execute = (1<<2), -}; +#include "generated/demon.meta.h" //////////////////////////////// -//~ allen: Demon Event Types +//~ rjf: Event Types -typedef enum DEMON_EventKind +typedef struct DMN_Event DMN_Event; +struct DMN_Event { - DEMON_EventKind_Null, - DEMON_EventKind_Error, - DEMON_EventKind_HandshakeComplete, - DEMON_EventKind_CreateProcess, - DEMON_EventKind_ExitProcess, - DEMON_EventKind_CreateThread, - DEMON_EventKind_ExitThread, - DEMON_EventKind_LoadModule, - DEMON_EventKind_UnloadModule, - DEMON_EventKind_Breakpoint, - DEMON_EventKind_Trap, - DEMON_EventKind_SingleStep, - DEMON_EventKind_Exception, - DEMON_EventKind_Halt, - DEMON_EventKind_Memory, - DEMON_EventKind_DebugString, - DEMON_EventKind_SetThreadName, - DEMON_EventKind_COUNT -} -DEMON_EventKind; - -typedef enum DEMON_ErrorKind -{ - DEMON_ErrorKind_Null, - DEMON_ErrorKind_NotInitialized, - DEMON_ErrorKind_NotAttached, - DEMON_ErrorKind_UnexpectedFailure, - DEMON_ErrorKind_InvalidHandle, -} -DEMON_ErrorKind; - -typedef enum DEMON_MemoryEventKind -{ - DEMON_MemoryEventKind_Null, - DEMON_MemoryEventKind_Commit, - DEMON_MemoryEventKind_Reserve, - DEMON_MemoryEventKind_Decommit, - DEMON_MemoryEventKind_Release, - DEMON_MemoryEventKind_COUNT -} -DEMON_MemoryEventKind; - -typedef enum DEMON_ExceptionKind -{ - DEMON_ExceptionKind_Null, - DEMON_ExceptionKind_MemoryRead, - DEMON_ExceptionKind_MemoryWrite, - DEMON_ExceptionKind_MemoryExecute, - DEMON_ExceptionKind_CppThrow, - DEMON_ExceptionKind_COUNT -} -DEMON_ExceptionKind; - -typedef struct DEMON_Event DEMON_Event; -struct DEMON_Event -{ - // TODO(allen): condense - DEMON_EventKind kind; - DEMON_ErrorKind error_kind; - DEMON_MemoryEventKind memory_kind; - DEMON_ExceptionKind exception_kind; - DEMON_Handle process; - DEMON_Handle thread; - DEMON_Handle module; + DMN_EventKind kind; + DMN_ErrorKind error_kind; + DMN_MemoryEventKind memory_kind; + DMN_ExceptionKind exception_kind; + DMN_Handle process; + DMN_Handle thread; + DMN_Handle module; + Architecture arch; U64 address; U64 size; String8 string; @@ -123,171 +82,156 @@ struct DEMON_Event B32 exception_repeated; }; -typedef struct DEMON_EventNode DEMON_EventNode; -struct DEMON_EventNode +typedef struct DMN_EventNode DMN_EventNode; +struct DMN_EventNode { - DEMON_EventNode *next; - DEMON_Event v; + DMN_EventNode *next; + DMN_Event v; }; -typedef struct DEMON_EventList DEMON_EventList; -struct DEMON_EventList +typedef struct DMN_EventList DMN_EventList; +struct DMN_EventList { - DEMON_EventNode *first; - DEMON_EventNode *last; + DMN_EventNode *first; + DMN_EventNode *last; U64 count; }; //////////////////////////////// -//~ allen: Demon Run Control Types +//~ rjf: Run Control Types -typedef struct DEMON_Trap DEMON_Trap; -struct DEMON_Trap +typedef struct DMN_Trap DMN_Trap; +struct DMN_Trap { - DEMON_Handle process; - U64 address; + DMN_Handle process; + U64 vaddr; U64 id; }; -typedef struct DEMON_TrapChunkNode DEMON_TrapChunkNode; -struct DEMON_TrapChunkNode +typedef struct DMN_TrapChunkNode DMN_TrapChunkNode; +struct DMN_TrapChunkNode { - DEMON_TrapChunkNode *next; - DEMON_Trap *v; + DMN_TrapChunkNode *next; + DMN_Trap *v; U64 cap; U64 count; }; -typedef struct DEMON_TrapChunkList DEMON_TrapChunkList; -struct DEMON_TrapChunkList +typedef struct DMN_TrapChunkList DMN_TrapChunkList; +struct DMN_TrapChunkList { - DEMON_TrapChunkNode *first; - DEMON_TrapChunkNode *last; + DMN_TrapChunkNode *first; + DMN_TrapChunkNode *last; U64 node_count; U64 trap_count; }; -typedef struct DEMON_RunCtrls DEMON_RunCtrls; -struct DEMON_RunCtrls +typedef struct DMN_RunCtrls DMN_RunCtrls; +struct DMN_RunCtrls { - DEMON_Handle single_step_thread; + DMN_Handle single_step_thread; B8 ignore_previous_exception; B8 run_entities_are_unfrozen; B8 run_entities_are_processes; - DEMON_Handle *run_entities; + DMN_Handle *run_entities; U64 run_entity_count; - DEMON_TrapChunkList traps; + DMN_TrapChunkList traps; }; //////////////////////////////// -//~ allen: Demon Process Listing +//~ rjf: System Process Listing Types -typedef struct DEMON_ProcessIter DEMON_ProcessIter; -struct DEMON_ProcessIter +typedef struct DMN_ProcessIter DMN_ProcessIter; +struct DMN_ProcessIter { U64 v[2]; }; -typedef struct DEMON_ProcessInfo DEMON_ProcessInfo; -struct DEMON_ProcessInfo +typedef struct DMN_ProcessInfo DMN_ProcessInfo; +struct DMN_ProcessInfo { String8 name; U32 pid; }; //////////////////////////////// -//~ rjf: Main Layer Initialization +//~ rjf: Basic Type Functions (Helpers, Implemented Once) -internal void demon_init(void); - -//////////////////////////////// -//~ rjf: Basic Type Functions - -//- rjf: stringizing -internal String8 demon_string_from_event_kind(DEMON_EventKind kind); -internal String8 demon_string_from_memory_event_kind(DEMON_MemoryEventKind kind); -internal String8 demon_string_from_exception_kind(DEMON_ExceptionKind kind); -internal void demon_string_list_from_event(Arena *arena, String8List *out, DEMON_Event *event); +//- rjf: handles +internal DMN_Handle dmn_handle_zero(void); +internal B32 dmn_handle_match(DMN_Handle a, DMN_Handle b); //- rjf: trap chunk lists -internal void demon_trap_chunk_list_push(Arena *arena, DEMON_TrapChunkList *list, U64 cap, DEMON_Trap *trap); -internal void demon_trap_chunk_list_concat_in_place(DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push); -internal void demon_trap_chunk_list_concat_shallow_copy(Arena *arena, DEMON_TrapChunkList *dst, DEMON_TrapChunkList *to_push); +internal void dmn_trap_chunk_list_push(Arena *arena, DMN_TrapChunkList *list, U64 cap, DMN_Trap *trap); +internal void dmn_trap_chunk_list_concat_in_place(DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push); +internal void dmn_trap_chunk_list_concat_shallow_copy(Arena *arena, DMN_TrapChunkList *dst, DMN_TrapChunkList *to_push); //- rjf: handle lists -internal void demon_handle_list_push(Arena *arena, DEMON_HandleList *list, DEMON_Handle handle); -internal DEMON_HandleArray demon_handle_array_from_list(Arena *arena, DEMON_HandleList *list); -internal DEMON_HandleArray demon_handle_array_copy(Arena *arena, DEMON_HandleArray *src); +internal void dmn_handle_list_push(Arena *arena, DMN_HandleList *list, DMN_Handle handle); +internal DMN_HandleArray dmn_handle_array_from_list(Arena *arena, DMN_HandleList *list); +internal DMN_HandleArray dmn_handle_array_copy(Arena *arena, DMN_HandleArray *src); + +//- rjf: event list building +internal DMN_Event *dmn_event_list_push(Arena *arena, DMN_EventList *list); //////////////////////////////// -//~ rjf: Primary Thread & Exclusive Mode Controls +//~ rjf: Thread Reading Helper Functions (Helpers, Implemented Once) -internal void demon_primary_thread_begin(void); -internal void demon_exclusive_mode_begin(void); -internal void demon_exclusive_mode_end(void); +internal U64 dmn_rip_from_thread(DMN_Handle thread); +internal U64 dmn_rsp_from_thread(DMN_Handle thread); //////////////////////////////// -//~ rjf: Running/Halting +//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS) -internal DEMON_EventList demon_run(Arena *arena, DEMON_RunCtrls *ctrls); -internal void demon_halt(U64 code, U64 user_data); -internal U64 demon_get_time_counter(void); +internal void dmn_init(void); //////////////////////////////// -//~ rjf: Target Process Launching/Attaching/Killing/Detaching/Halting +//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) -internal U32 demon_launch_process(OS_LaunchOptions *options); -internal B32 demon_attach_process(U32 pid); -internal B32 demon_kill_process(DEMON_Handle process, U32 exit_code); -internal B32 demon_detach_process(DEMON_Handle process); +internal DMN_CtrlCtx *dmn_ctrl_begin(void); +internal void dmn_ctrl_exclusive_access_begin(void); +internal void dmn_ctrl_exclusive_access_end(void); +#define DMN_CtrlExclusiveAccessScope DeferLoop(dmn_ctrl_exclusive_access_begin(), dmn_ctrl_exclusive_access_end()) +internal U32 dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options); +internal B32 dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid); +internal B32 dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code); +internal B32 dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process); +internal DMN_EventList dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls); //////////////////////////////// -//~ rjf: Entity Functions +//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) -//- rjf: basics -internal B32 demon_object_exists(DEMON_Handle object); - -//- rjf: introspection -internal Architecture demon_arch_from_object(DEMON_Handle object); -internal U64 demon_base_vaddr_from_module(DEMON_Handle module); -internal Rng1U64 demon_vaddr_range_from_module(DEMON_Handle module); -internal String8 demon_full_path_from_module(Arena *arena, DEMON_Handle module); -internal U64 demon_stack_base_vaddr_from_thread(DEMON_Handle thread); -internal U64 demon_tls_root_vaddr_from_thread(DEMON_Handle thread); -internal DEMON_HandleArray demon_all_processes(Arena *arena); -internal DEMON_HandleArray demon_threads_from_process(Arena *arena, DEMON_Handle process); -internal DEMON_HandleArray demon_modules_from_process(Arena *arena, DEMON_Handle process); - -//- rjf: target process memory allocation/protection -internal U64 demon_reserve_memory(DEMON_Handle process, U64 size); -internal B32 demon_set_memory_protect_flags(DEMON_Handle process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags); -internal B32 demon_release_memory(DEMON_Handle process, U64 vaddr, U64 size); - -//- rjf: target process memory reading/writing -internal U64 demon_read_memory(DEMON_Handle process, void *dst, U64 src_address, U64 size); -internal B32 demon_write_memory(DEMON_Handle process, U64 dst_address, void *src, U64 size); -internal U64 demon_read_memory_amap_aligned(DEMON_Handle process, void *dst, U64 src_address, U64 size); -internal U64 demon_read_memory_amap(DEMON_Handle process, void *dst, U64 src_address, U64 size); - -//- rjf: thread registers reading/writing -// IMPORTANT(allen): This API is _trusting_ you. You should never modify the data pointed -// at by that void pointer! It is pointing to the internal cache of the registers, so it -// will become invalid after a call to demon_write_regs, or demon_run. Use it to read -// what you need and be done ASAP and we can avoid an extra copy baked into the API. -internal void *demon_read_regs(DEMON_Handle thread); -internal B32 demon_write_regs(DEMON_Handle thread, void *data); -// TODO(allen): These might be a bad idea when we try to extend to ARM -// They make sense for x86/x64 abstraction, which often needs identical -// code paths except for these parts. Revisit this when ARM is integrated. -internal U64 demon_read_ip(DEMON_Handle thread); -internal U64 demon_read_sp(DEMON_Handle thread); -internal void demon_write_ip(DEMON_Handle thread, U64 ip); +internal void dmn_halt(U64 code, U64 user_data); //////////////////////////////// -//~ rjf: Process Listing +//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS) -internal void demon_proc_iter_begin(DEMON_ProcessIter *iter); -internal B32 demon_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out); -internal void demon_proc_iter_end(DEMON_ProcessIter *iter); +//- rjf: run/memory/register counters +internal U64 dmn_run_gen(void); +internal U64 dmn_mem_gen(void); +internal U64 dmn_reg_gen(void); -#endif //DEMON_CORE_H +//- rjf: non-blocking-control-thread access barriers +internal B32 dmn_access_open(void); +internal void dmn_access_close(void); +#define DMN_AccessScope DeferLoopChecked(dmn_access_open(), dmn_access_close()) + +//- rjf: processes +internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst); +internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); +#define dmn_process_read_struct(process, vaddr, ptr) dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) +#define dmn_process_write_struct(process, vaddr, ptr) dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) + +//- rjf: threads +internal Architecture dmn_arch_from_thread(DMN_Handle handle); +internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle); +internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle); +internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block); +internal B32 dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block); + +//- rjf: system process listing +internal void dmn_process_iter_begin(DMN_ProcessIter *iter); +internal B32 dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out); +internal void dmn_process_iter_end(DMN_ProcessIter *iter); + +#endif // DEMON_CORE_H diff --git a/src/demon/demon_core.mdesk b/src/demon/demon_core.mdesk new file mode 100644 index 00000000..3df0d2fd --- /dev/null +++ b/src/demon/demon_core.mdesk @@ -0,0 +1,80 @@ +//////////////////////////////// +//~ rjf: Event Kind Tables + +@table(name) +DMN_EventKindTable: +{ + {Null} + {Error} + {HandshakeComplete} + {CreateProcess} + {ExitProcess} + {CreateThread} + {ExitThread} + {LoadModule} + {UnloadModule} + {Breakpoint} + {Trap} + {SingleStep} + {Exception} + {Halt} + {Memory} + {DebugString} + {SetThreadName} +} + +@table(name) +DMN_ErrorKindTable: +{ + {Null} + {NotAttached} + {UnexpectedFailure} + {InvalidHandle} +} + +@table(name) +DMN_MemoryEventKindTable: +{ + {Null} + {Commit} + {Reserve} + {Decommit} + {Release} +} + +@table(name) +DMN_ExceptionKindTable: +{ + {Null} + {MemoryRead} + {MemoryWrite} + {MemoryExecute} + {CppThrow} +} + +//////////////////////////////// +//~ rjf: Generators + +@enum DMN_EventKind: +{ + @expand(DMN_EventKindTable a) `$(a.name)`, + COUNT +} + +@enum DMN_ErrorKind: +{ + @expand(DMN_ErrorKindTable a) `$(a.name)`, + COUNT +} + +@enum DMN_MemoryEventKind: +{ + @expand(DMN_MemoryEventKindTable a) `$(a.name)`, + COUNT +} + +@enum DMN_ExceptionKind: +{ + @expand(DMN_ExceptionKindTable a) `$(a.name)`, + COUNT +} diff --git a/src/demon/demon_inc.c b/src/demon/demon_inc.c index 64a45e09..daab75e2 100644 --- a/src/demon/demon_inc.c +++ b/src/demon/demon_inc.c @@ -2,14 +2,9 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) #include "demon_core.c" -#include "demon_common.c" -#include "demon_accel.c" -#include "demon_os.c" #if OS_WINDOWS -# include "win32/demon_os_win32.c" -#elif OS_LINUX -# include "linux/demon_os_linux.c" +# include "win32/demon_core_win32.c" #else -# error No Demon Implementation for This OS +# error Demon layer backend not defined for this operating system. #endif diff --git a/src/demon/demon_inc.h b/src/demon/demon_inc.h index daf2f65d..3328f9b6 100644 --- a/src/demon/demon_inc.h +++ b/src/demon/demon_inc.h @@ -5,16 +5,11 @@ #define DEMON_INC_H #include "demon_core.h" -#include "demon_common.h" -#include "demon_accel.h" -#include "demon_os.h" #if OS_WINDOWS -# include "win32/demon_os_win32.h" -#elif OS_LINUX -# include "linux/demon_os_linux.h" +# include "win32/demon_core_win32.h" #else -# error No Demon Implementation for This OS +# error Demon layer backend not defined for this operating system. #endif -#endif //DEMON_INC_H +#endif // DEMON_INC_H diff --git a/src/demon/demon_os.c b/src/demon/demon_os.c deleted file mode 100644 index 76c55a9b..00000000 --- a/src/demon/demon_os.c +++ /dev/null @@ -1,28 +0,0 @@ -//////////////////////////////// -//~ rjf: Helpers - -internal B32 -demon_os_read_regs(DEMON_Entity *thread, void *dst) -{ - B32 result = 0; - switch(thread->arch) - { - default:{}break; - case Architecture_x86:{result = demon_os_read_regs_x86(thread, (REGS_RegBlockX86 *)dst);}break; - case Architecture_x64:{result = demon_os_read_regs_x64(thread, (REGS_RegBlockX64 *)dst);}break; - } - return result; -} - -internal B32 -demon_os_write_regs(DEMON_Entity *thread, void *src) -{ - B32 result = 0; - switch(thread->arch) - { - default:{}break; - case Architecture_x86:{result = demon_os_write_regs_x86(thread, (REGS_RegBlockX86 *)src);}break; - case Architecture_x64:{result = demon_os_write_regs_x64(thread, (REGS_RegBlockX64 *)src);}break; - } - return result; -} diff --git a/src/demon/demon_os.h b/src/demon/demon_os.h deleted file mode 100644 index fd6aac59..00000000 --- a/src/demon/demon_os.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef DEMON_OS_H -#define DEMON_OS_H - -// NOTE(allen): -// These are the functions that the OS backends actually implement. -// Demon objects go through a handle validation layer but it is a lot more -// convenient in the OS backends to implement these versions which take the -// already validated DEMON_Entity*. These are also more convenient to call from -// the backend layer, which lets us avoid converting back and forth between -// handles and pointers a lot. - -//////////////////////////////// -//~ NOTE(allen): Demon OS Run Control Types - -typedef struct DEMON_OS_Trap DEMON_OS_Trap; -struct DEMON_OS_Trap -{ - DEMON_Entity *process; - U64 address; -}; - -typedef struct DEMON_OS_RunCtrls DEMON_OS_RunCtrls; -struct DEMON_OS_RunCtrls -{ - DEMON_Entity *single_step_thread; - B8 ignore_previous_exception; - B8 run_entities_are_unfrozen; - B8 run_entities_are_processes; - DEMON_Entity **run_entities; - U64 run_entity_count; - DEMON_OS_Trap *traps; - U64 trap_count; -}; - -//////////////////////////////// -//~ rjf: Helpers - -internal B32 demon_os_read_regs(DEMON_Entity *thread, void *dst); -internal B32 demon_os_write_regs(DEMON_Entity *thread, void *src); - -//////////////////////////////// -//~ rjf: @demon_os_hooks Main Layer Initialization - -internal void demon_os_init(void); - -//////////////////////////////// -//~ rjf: @demon_os_hooks Running/Halting - -internal DEMON_EventList demon_os_run(Arena *arena, DEMON_OS_RunCtrls *controls); -internal void demon_os_halt(U64 code, U64 user_data); - -//////////////////////////////// -//~ rjf: @demon_os_hooks Target Process Launching/Attaching/Killing/Detaching/Halting - -internal U32 demon_os_launch_process(OS_LaunchOptions *options); -internal B32 demon_os_attach_process(U32 pid); -internal B32 demon_os_kill_process(DEMON_Entity *process, U32 exit_code); -internal B32 demon_os_detach_process(DEMON_Entity *process); - -//////////////////////////////// -//~ rjf: @demon_os_hooks Entity Functions - -//- rjf: cleanup -internal void demon_os_entity_cleanup(DEMON_Entity *entity); - -//- rjf: introspection -internal String8 demon_os_full_path_from_module(Arena *arena, DEMON_Entity *module); -internal U64 demon_os_stack_base_vaddr_from_thread(DEMON_Entity *thread); -internal U64 demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread); - -//- rjf: target process memory allocation/protection -internal U64 demon_os_reserve_memory(DEMON_Entity *process, U64 size); -internal void demon_os_set_memory_protect_flags(DEMON_Entity *process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags); -internal void demon_os_release_memory(DEMON_Entity *process, U64 vaddr, U64 size); - -//- rjf: target process memory reading/writing -internal U64 demon_os_read_memory(DEMON_Entity *process, void *dst, U64 src_address, U64 size); -internal B32 demon_os_write_memory(DEMON_Entity *process, U64 dst_address, void *src, U64 size); -#define demon_os_read_struct(p,dst,src) demon_os_read_memory((p), (dst), (src), sizeof(*(dst))) -#define demon_os_write_struct(p,dst,src) demon_os_write_memory((p), (dst), (src), sizeof(*(src))) - -//- rjf: thread registers reading/writing -internal B32 demon_os_read_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *dst); -internal B32 demon_os_write_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *src); -internal B32 demon_os_read_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *dst); -internal B32 demon_os_write_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *src); - -//////////////////////////////// -//~ rjf: @demon_os_hooks Process Listing - -internal void demon_os_proc_iter_begin(DEMON_ProcessIter *iter); -internal B32 demon_os_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out); -internal void demon_os_proc_iter_end(DEMON_ProcessIter *iter); - -#endif //DEMON_OS_H diff --git a/src/regs/raddbg/regs_raddbg.c b/src/demon/generated/demon.meta.c similarity index 68% rename from src/regs/raddbg/regs_raddbg.c rename to src/demon/generated/demon.meta.c index 399ec8d3..32e20884 100644 --- a/src/regs/raddbg/regs_raddbg.c +++ b/src/demon/generated/demon.meta.c @@ -1,4 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include "regs/raddbg/generated/regs_raddbg.meta.c" +//- GENERATED CODE + +C_LINKAGE_BEGIN +C_LINKAGE_END + diff --git a/src/demon/generated/demon.meta.h b/src/demon/generated/demon.meta.h new file mode 100644 index 00000000..1db2313d --- /dev/null +++ b/src/demon/generated/demon.meta.h @@ -0,0 +1,63 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +#ifndef DEMON_META_H +#define DEMON_META_H + +typedef enum DMN_EventKind +{ +DMN_EventKind_Null, +DMN_EventKind_Error, +DMN_EventKind_HandshakeComplete, +DMN_EventKind_CreateProcess, +DMN_EventKind_ExitProcess, +DMN_EventKind_CreateThread, +DMN_EventKind_ExitThread, +DMN_EventKind_LoadModule, +DMN_EventKind_UnloadModule, +DMN_EventKind_Breakpoint, +DMN_EventKind_Trap, +DMN_EventKind_SingleStep, +DMN_EventKind_Exception, +DMN_EventKind_Halt, +DMN_EventKind_Memory, +DMN_EventKind_DebugString, +DMN_EventKind_SetThreadName, +DMN_EventKind_COUNT, +} DMN_EventKind; + +typedef enum DMN_ErrorKind +{ +DMN_ErrorKind_Null, +DMN_ErrorKind_NotAttached, +DMN_ErrorKind_UnexpectedFailure, +DMN_ErrorKind_InvalidHandle, +DMN_ErrorKind_COUNT, +} DMN_ErrorKind; + +typedef enum DMN_MemoryEventKind +{ +DMN_MemoryEventKind_Null, +DMN_MemoryEventKind_Commit, +DMN_MemoryEventKind_Reserve, +DMN_MemoryEventKind_Decommit, +DMN_MemoryEventKind_Release, +DMN_MemoryEventKind_COUNT, +} DMN_MemoryEventKind; + +typedef enum DMN_ExceptionKind +{ +DMN_ExceptionKind_Null, +DMN_ExceptionKind_MemoryRead, +DMN_ExceptionKind_MemoryWrite, +DMN_ExceptionKind_MemoryExecute, +DMN_ExceptionKind_CppThrow, +DMN_ExceptionKind_COUNT, +} DMN_ExceptionKind; + +C_LINKAGE_BEGIN +C_LINKAGE_END + +#endif // DEMON_META_H diff --git a/src/demon/test/demon_attach.cpp b/src/demon/test/demon_attach.cpp deleted file mode 100644 index ca9fb1ea..00000000 --- a/src/demon/test/demon_attach.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -// exe // - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "demon/demon_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "demon/demon_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Arena *arena = arena_alloc(); - demon_init(); - - //- rjf: find PID of mule_loop.exe - String8 attach_process_name = str8_lit("mule_loop.exe"); - U32 pid = 0; - { - DEMON_ProcessIter it = {0}; - demon_proc_iter_begin(&it); - for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(arena, &it, &info);) - { - if(str8_match(info.name, attach_process_name, 0)) - { - pid = info.pid; - break; - } - } - demon_proc_iter_end(&it); - } - - //- rjf: attach - B32 attach_good = demon_attach_process(pid); - - //- rjf: get events - DEMON_RunCtrls ctrls = {0}; - DEMON_EventList events = demon_run(arena, ctrls); - for(DEMON_Event *event = events.first; event != 0; event = event->next) - { - int x = 0; - } - -#if 0 - //- rjf: try to break in the loop - DEMON_RunCtrls ctrls = {0}; - DEMON_Trap trap = {0}; - { - U64 loop_bp = 0x0000000140001074; - ctrls.trap_count = 1; - ctrls.traps = &trap; - } -#endif -} diff --git a/src/demon/test/demon_regs_test.cpp b/src/demon/test/demon_regs_test.cpp deleted file mode 100644 index c5ef06b5..00000000 --- a/src/demon/test/demon_regs_test.cpp +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "demon/demon_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "demon/demon_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -internal SYMS_String8 -file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){ - String8 data = os_read_file(arena, str8_from_syms(file_name)); - SYMS_String8 result = syms_from_str8(data); - return(result); -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Temp scratch = scratch_begin(0, 0); - - // setup - demon_init(); - - // parse arguments - String8 executable_file_name = {0}; - U64 bp_address = 0; - - { - String8List command_line_arguments = os_get_command_line_arguments(); - CmdLine cmd_line = cmd_line_from_string_list(scratch.arena, command_line_arguments); - if (cmd_line.inputs.first != 0){ - executable_file_name = cmd_line.inputs.first->string; - } - String8 bp_string = cmd_line_string(cmd_line, str8_lit("bp")); - try_u64_from_str8_c_rules(bp_string, &bp_address); - } - - // check parameters - if (bp_address == 0 || executable_file_name.size == 0){ - printf("bad parameters\n"); - exit(0); - } - - // demon launch - OS_LaunchOptions launch_opts = {0}; - str8_list_push(scratch.arena, &launch_opts.cmd_line, executable_file_name); - launch_opts.path = os_get_path(scratch.arena, OS_SystemPath_Current); - U32 process_id = demon_launch_process(&launch_opts); - if (process_id == 0){ - printf("could not launch: '%.*s'\n", str8_varg(executable_file_name)); - exit(0); - } - - // demon loop - { - DEMON_Handle process = 0; - DEMON_Handle thread = 0; - - B32 hit_bp = false; - U64 single_step_counter = 0; - - U64 counter = 0; - for (;;){ - Temp temp = temp_begin(scratch.arena); - - DEMON_RunCtrls run_controls = {0}; - DEMON_Trap traps[1]; - - if (!hit_bp){ - if (process != 0){ - run_controls.trap_count = 1; - run_controls.traps = traps; - run_controls.traps[0].process = process; - run_controls.traps[0].address = bp_address; - } - } - else{ - run_controls.single_step_thread = thread; - } - - DEMON_EventList events = demon_run(temp.arena, run_controls); - - for (DEMON_Event *event = events.first; - event != 0; - event = event->next, counter += 1){ - // update tracking state - switch (event->kind){ - case DEMON_EventKind_CreateProcess: - { - process = event->process; - }break; - - case DEMON_EventKind_ExitProcess: - { - if (event->process == process){ - process = 0; - } - }break; - - case DEMON_EventKind_CreateThread: - { - thread = event->thread; - }break; - - case DEMON_EventKind_Breakpoint: - { - hit_bp = true; - }break; - - case DEMON_EventKind_SingleStep: - { - single_step_counter += 1; - - SYMS_RegX64 regs1 = {0}; - demon_read_x64_regs(thread, ®s1); - demon_write_x64_regs(thread, ®s1); - SYMS_RegX64 regs2 = {0}; - demon_read_x64_regs(thread, ®s2); - if (!MemoryMatchStruct(®s1, ®s2)){ - printf("mismatch at single_step_counter=%llu\n", single_step_counter); - } - - if (single_step_counter == 1000){ - goto end_loop; - } - }break; - - case DEMON_EventKind_NotAttached: - { - fprintf(stderr, "not attached - exiting\n"); - goto end_loop; - }break; - - case DEMON_EventKind_NotInitialized: - case DEMON_EventKind_UnexpectedFailure: - { - fprintf(stderr, "unexpected error - exiting\n"); - goto end_loop; - }break; - } - } - - goto end_it; - end_loop: - temp_end(temp); - goto loop_exit; - end_it:; - } - - loop_exit:; - } - - printf("[done]\n"); - scratch_end(scratch); -} - diff --git a/src/demon/test/demon_scratch.cpp b/src/demon/test/demon_scratch.cpp deleted file mode 100644 index beb1cc40..00000000 --- a/src/demon/test/demon_scratch.cpp +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "demon/demon_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "demon/demon_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -internal SYMS_String8 -file_load_func_for_syms(void *user, SYMS_Arena *arena, SYMS_String8 file_name){ - String8 data = os_read_file(arena, str8_from_syms(file_name)); - SYMS_String8 result = syms_from_str8(data); - return(result); -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - demon_init(); - - String8Node node[2]; - -#define TARGET_EXE "C:\\devel\\projects\\debugger\\build\\mule_unwind_20210511_clang11_lldlink.exe" - - OS_LaunchOptions options = {0}; -#if OS_WINDOWS - str8_list_push(&options.cmd_line, &node[0], str8_lit(TARGET_EXE)); - options.path = str8_lit("C:\\devel\\projects\\debugger\\build\\"); -#else - str8_list_push(&options.cmd_line, &node[0], str8_lit("/home/allenw/projects_copy/debugger/build/mule_main")); - options.path = str8_lit("/home/allenw/projects_copy/debugger/build/"); -#endif - U32 process_id = demon_launch_process(&options); - if (process_id == 0){ - printf("Could not launch process\n"); - exit(1); - } - -#if OS_WINDOWS - U64 bp_addr = 0x140001134; -#else - U64 bp_addr = 0x400918; -#endif - - DEMON_Handle process = 0; - DEMON_Handle thread = 0; - DEMON_Handle module = 0; - U64 module_base = 0; - SYMS_Group *group = 0; - - B32 hit_bp = false; - U64 counter = 0; - - for (;;){ - DEMON_RunCtrls run_controls = {0}; - DEMON_Trap trap_memory[2]; - - DEMON_Trap *trap_ptr = trap_memory; - if (process != 0 && !hit_bp){ - trap_ptr->process = process; - trap_ptr->address = bp_addr; - trap_ptr += 1; - } - run_controls.traps = trap_memory; - run_controls.trap_count = (U64)(trap_ptr - trap_memory); - - Temp scratch = scratch_begin(0, 0); - DEMON_EventList events = demon_run(scratch.arena, run_controls); - - for (DEMON_Event *event = events.first; - event != 0; - event = event->next){ - printf("STEP[%05llx] -- ", counter); - counter += 1; - - switch (event->kind){ - case DEMON_EventKind_NotInitialized: - { - printf("Not Initialized\n"); - exit(1); - }break; - - case DEMON_EventKind_NotAttached: - { - printf("Not Attached\n"); - exit(1); - }break; - - case DEMON_EventKind_UnexpectedFailure: - { - printf("Unexpected Failure\n"); - exit(1); - }break; - - case DEMON_EventKind_CreateProcess: - { - printf("Create Process\n"); - if (process == 0){ - process = event->process; - } - }break; - - case DEMON_EventKind_CreateThread: - { - printf("Create Thread\n"); - if (thread == 0){ - thread = event->thread; - } - }break; - - case DEMON_EventKind_LoadModule: - { - Temp temp = temp_begin(scratch.arena); - String8 file_name = demon_full_path_from_module(scratch.arena, event->module); - printf("Load Module: %.*s\n", str8_varg(file_name)); - if (module == 0 && str8_match(file_name, str8_lit(TARGET_EXE), 0)){ - module = event->module; - module_base = event->address; - - // setup syms group - group = syms_group_alloc(); - - SYMS_FileLoadCtx ctx = {0}; - ctx.file_load_func = file_load_func_for_syms; - - SYMS_String8List file_names = {0}; - syms_string_list_push(group->arena, &file_names, syms_from_str8(file_name)); - - SYMS_FileInfOptions opts = {0}; - - SYMS_FileInfResult inf_result = syms_file_inf_infer_from_file_list(group->arena, ctx, file_names, &opts); - syms_group_init(group, &inf_result.data_parsed); - } - temp_end(temp); - }break; - - case DEMON_EventKind_ExitProcess: - { - printf("Exit Process\n"); - exit(0); - }break; - - case DEMON_EventKind_ExitThread: - { - printf("Exit Thread\n"); - }break; - - case DEMON_EventKind_UnloadModule: - { - printf("Unload Module\n"); - }break; - - case DEMON_EventKind_Breakpoint: - { - Architecture arch = demon_arch_from_object(event->process); - U64 ip = event->instruction_pointer; - printf("Breakpoint: %llx\n", ip); - - hit_bp = true; - - //- unwind - - // setup bin - SYMS_String8 bin_data = group->bin_data; - SYMS_BinAccel *generic_bin = group->bin; - SYMS_PeBinAccel *pe_bin = 0; - if (generic_bin->format == SYMS_FileFormat_PE){ - pe_bin = (SYMS_PeBinAccel*)generic_bin; - } - - if (pe_bin != 0){ - // read regs - SYMS_RegX64 regs = {0}; - demon_read_x64_regs(event->thread, ®s); - - // read stack - SYMS_U64 sp = regs.rsp.u64; - SYMS_U64 sp_rounded_down = sp&~(KB(4) - 1); - - SYMS_String8 stack_memory = {0}; - stack_memory.size = KB(8); - stack_memory.str = push_array_no_zero(scratch.arena, U8, stack_memory.size); - - SYMS_U64 stack_memory_addr = sp_rounded_down; - stack_memory.size = demon_read_memory_amap(event->process, stack_memory.str, - stack_memory_addr, stack_memory.size); - - // unwind loop - U64 counter = 1; - for (;; counter += 1){ - printf("%02llu: ip=%llx; sp=%llx\n", counter, regs.rip.u64, regs.rsp.u64); - SYMS_MemoryView memview = syms_memory_view_make(stack_memory, stack_memory_addr); - SYMS_UnwindResult unwind_result = syms_unwind_pe_x64(bin_data, pe_bin, module_base, &memview, ®s); - if (unwind_result.dead){ - break; - } - } - } - }break; - - case DEMON_EventKind_Trap: - { - Architecture arch = demon_arch_from_object(event->process); - U64 ip = event->instruction_pointer; - printf("Trap: %llx\n", ip); - }break; - - case DEMON_EventKind_SingleStep: - { - printf("Single Step: %llx\n", event->instruction_pointer); - }break; - - case DEMON_EventKind_Exception: - { - printf("Exception: %llx\n", event->instruction_pointer); - }break; - - case DEMON_EventKind_Halt: - { - printf("Halt\n"); - }break; - - case DEMON_EventKind_Memory: - { - printf("Memory\n"); - }break; - - default: - { - printf("Unhandled Event\n"); - exit(1); - }break; - } - } - scratch_end(scratch); - } - - printf("Done\n"); -} - diff --git a/src/demon/test/demon_win32_freeze_test.cpp b/src/demon/test/demon_win32_freeze_test.cpp deleted file mode 100644 index 86b564ba..00000000 --- a/src/demon/test/demon_win32_freeze_test.cpp +++ /dev/null @@ -1,935 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -// NOTE(rjf): (18 October 2021) Notes on Win32 process halting via -// DebugBreakProcess: -// -// Calling DebugBreakProcess seems to cause a few events to come back: -// 1. Thread Creation Event -// 2. Breakpoint Event (with the thread matching that of #1) -// 3. Thread Exiting Event (matching #1) -// -// Having done this experiment on a single-threaded program (mule_loop.exe), -// I can only infer that what is happening here is that when DebugBreakProcess -// is called, it first injects a thread into the target process that runs -// code with an int3. This is very similar to the old approach that Demon -// took. -// -// It's going to be difficult to distinguish between these CreateThreads and -// ExitThreads from others (not caused by halting), even though we can match -// the hit breakpoint to the associated thread. -// -// What could be possible (in order to distinguish the hit breakpoint as a -// halt event, instead of an arbitrary breakpoint) is looking at the breakpoint -// address. This injected thread has a breakpoint that's different from the -// initial breakpoint that the kernel automatically hits when a process is -// first being debugged. -// -// With DebugBreakProcess: -// - first breakpoint that is hit: 0x7ff8ad9806b0 in kernel code -// - last breakpoint that is hit: 0x7ff8ad950860 in kernel code (halt) -// -// Without DebugBreakProcess: -// - first breakpoint that is hit: 0x7ff8ad9806b0 -// - -// NOTE(rjf): (18 October 2021) Notes on suspending processes via -// NtSuspendProcess: -// -// NtSuspendProcess is an undocumented API that is exported by ntdll. It is -// fairly simple but could be unstable. To call it, the main trick is that -// you need a handle with certain privileges (PROCESS_SUSPEND_RESUME), so -// you can't just take any handle and use it. -// -// To use it, we can manually load it from ntdll, grab an elevated handle -// for a given process HANDLE, and then call it. We can resume, then, with -// NtResumeProcess. -// -// Other than this, our options seem to more-or-less lie in individually -// suspending all of the threads in the process-to-be-halted. - -#include - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -typedef LONG NtSuspendProcessFunction(HANDLE ProcessHandle); -global NtSuspendProcessFunction *NtSuspendProcess = 0; - -//////////////////////////////// -// NOTE(allen): Win32 Demon Exceptions - -#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u -#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u -#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u -#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u -#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu -#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u -#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u -#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du -#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu -#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu -#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u -#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u -#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u -#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u -#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u -#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u -#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u -#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du -#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u -#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u -#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u -#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu -#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u -#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u -#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u -#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u -#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u -#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u -#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u -#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u -#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u -#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u -#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u -#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u -#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u -#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u - -//////////////////////////////// -// NOTE(allen): Win32 Demon Register API Codes - -#define DEMON_W32_CTX_X86 0x00010000 -#define DEMON_W32_CTX_X64 0x00100000 - -#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 -#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 -#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 -#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 -#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 -#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 -#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 - -#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ -DEMON_W32_CTX_INTEL_EXTENDED) -#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ -DEMON_W32_CTX_INTEL_DEBUG) - -struct TEST_DebugEvent -{ - String8 name; - U64 process_id; - U64 thread_id; - HANDLE process; - HANDLE thread; - U64 addr; - DEBUG_EVENT evt; -}; - -struct TEST_Trap -{ - HANDLE process; - U64 address; -}; - -internal U16 -test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) -{ - U16 result = 0; - U32 top = (fxsave->StatusWord >> 11) & 7; - for (U32 fpr = 0; fpr < 8; fpr += 1){ - U32 tag = 3; - if (fxsave->TagWord & (1 << fpr)){ - U32 st = (fpr - top)&7; - - SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16]; - U16 exponent = fp->sign1_exp15 & bitmask15; - U64 integer_part = fp->int1_frac63 >> 63; - U64 fraction_part = fp->int1_frac63 & bitmask63; - - // tag: 0 - normal; 1 - zero; 2 - special - tag = 2; - if (exponent == 0){ - if (integer_part == 0 && fraction_part == 0){ - tag = 1; - } - } - else if (exponent != bitmask15 && integer_part != 0){ - tag = 0; - } - } - result |= tag << (2 * fpr); - } - return(result); -} - -internal U16 -test_w32_xsave_tag_word_from_real_tag_word(U16 ftw) -{ - U16 compact = 0; - for (U32 fpr = 0; fpr < 8; fpr++){ - U32 tag = (ftw >> (fpr * 2)) & 3; - if (tag != 3){ - compact |= (1 << fpr); - } - } - return(compact); -} - -internal B32 -test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - DWORD size = 0; - InitializeContext(0, ctx_flags, 0, &size); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ - void *ctx_memory = push_array(scratch.arena, U8, size); - if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ - ctx = 0; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - // get thread context - HANDLE thread_handle = thread; - if (!GetThreadContext(thread_handle, ctx)){ - ctx = 0; - } - - B32 result = false; - if (ctx != 0){ - result = true; - - // NOTE(allen): Convert CONTEXT -> SYMS_RegX64 - dst->rax.u64 = ctx->Rax; - dst->rcx.u64 = ctx->Rcx; - dst->rdx.u64 = ctx->Rdx; - dst->rbx.u64 = ctx->Rbx; - dst->rsp.u64 = ctx->Rsp; - dst->rbp.u64 = ctx->Rbp; - dst->rsi.u64 = ctx->Rsi; - dst->rdi.u64 = ctx->Rdi; - dst->r8.u64 = ctx->R8; - dst->r9.u64 = ctx->R9; - dst->r10.u64 = ctx->R10; - dst->r11.u64 = ctx->R11; - dst->r12.u64 = ctx->R12; - dst->r13.u64 = ctx->R13; - dst->r14.u64 = ctx->R14; - dst->r15.u64 = ctx->R15; - dst->rip.u64 = ctx->Rip; - dst->cs.u16 = ctx->SegCs; - dst->ds.u16 = ctx->SegDs; - dst->es.u16 = ctx->SegEs; - 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; - - // NOTE(allen): This bit is "supposed to always be 1" I guess. - // TODO(allen): Not sure what this is all about but I haven't investigated it yet. - // This might be totally not necessary or something. - dst->rflags.u64 = ctx->EFlags | 0x2; - - XSAVE_FORMAT *xsave = &ctx->FltSave; - dst->fcw.u16 = xsave->ControlWord; - dst->fsw.u16 = xsave->StatusWord; - dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave); - dst->fop.u16 = xsave->ErrorOpcode; - dst->fcs.u16 = xsave->ErrorSelector; - dst->fds.u16 = xsave->DataSelector; - dst->fip.u32 = xsave->ErrorOffset; - dst->fdp.u32 = xsave->DataOffset; - dst->mxcsr.u32 = xsave->MxCsr; - dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; - - M128A *float_s = xsave->FloatRegisters; - SYMS_Reg80 *float_d = &dst->fpr0; - for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, sizeof(*float_d)); - } - - if (!avx_available){ - M128A *xmm_s = xsave->XmmRegisters; - SYMS_Reg256 *xmm_d = &dst->ymm0; - for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &dst->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - ymm_d->u64[3] = part0->Low; - ymm_d->u64[2] = part0->High; - ymm_d->u64[1] = part1->Low; - ymm_d->u64[0] = part1->High; - } - } - - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - DWORD size = 0; - InitializeContext(0, ctx_flags, 0, &size); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ - void *ctx_memory = push_array(scratch.arena, U8, size); - if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ - ctx = 0; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - B32 result = false; - if (ctx != 0){ - // NOTE(allen): Convert SYMS_RegX64 -> CONTEXT - ctx->ContextFlags = ctx_flags; - - ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; - - ctx->Rax = src->rax.u64; - ctx->Rcx = src->rcx.u64; - ctx->Rdx = src->rdx.u64; - ctx->Rbx = src->rbx.u64; - ctx->Rsp = src->rsp.u64; - ctx->Rbp = src->rbp.u64; - ctx->Rsi = src->rsi.u64; - ctx->Rdi = src->rdi.u64; - ctx->R8 = src->r8.u64; - ctx->R9 = src->r9.u64; - ctx->R10 = src->r10.u64; - ctx->R11 = src->r11.u64; - ctx->R12 = src->r12.u64; - ctx->R13 = src->r13.u64; - ctx->R14 = src->r14.u64; - ctx->R15 = src->r15.u64; - ctx->Rip = src->rip.u64; - ctx->SegCs = src->cs.u16; - ctx->SegDs = src->ds.u16; - ctx->SegEs = src->es.u16; - 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->EFlags = src->rflags.u64; - - XSAVE_FORMAT *fxsave = &ctx->FltSave; - fxsave->ControlWord = src->fcw.u16; - fxsave->StatusWord = src->fsw.u16; - fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); - fxsave->ErrorOpcode = src->fop.u16; - fxsave->ErrorSelector = src->fcs.u16; - fxsave->DataSelector = src->fds.u16; - fxsave->ErrorOffset = src->fip.u32; - fxsave->DataOffset = src->fdp.u32; - - M128A *float_d = fxsave->FloatRegisters; - SYMS_Reg80 *float_s = &src->fpr0; - for (U32 n = 0; - n < 8; - n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, 10); - } - - if (!avx_available){ - M128A *xmm_d = fxsave->XmmRegisters; - SYMS_Reg256 *xmm_s = &src->ymm0; - for (U32 n = 0; - n < 8; - n += 1, xmm_d += 1, xmm_s += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &src->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - part0->Low = ymm_d->u64[3]; - part0->High = ymm_d->u64[2]; - part1->Low = ymm_d->u64[1]; - part1->High = ymm_d->u64[0]; - } - } - - //- set thread context - HANDLE thread_handle = thread; - if (SetThreadContext(thread_handle, ctx)){ - result = true; - } - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)dst; - U8 *opl = ptr + size; - U64 cursor = src_address; - for (;ptr < opl;){ - SIZE_T to_read = (SIZE_T)(opl - ptr); - SIZE_T actual_read = 0; - if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ - result = false; - break; - } - ptr += actual_read; - cursor += actual_read; - } - return(result); -} - -internal B32 -test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)src; - U8 *opl = ptr + size; - U64 cursor = dst_address; - for (;ptr < opl;){ - SIZE_T to_write = (SIZE_T)(opl - ptr); - SIZE_T actual_write = 0; - if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ - result = false; - break; - } - ptr += actual_write; - cursor += actual_write; - } - return(result); -} - -internal B32 -test_launch_process(OS_LaunchOptions *options) -{ - B32 result = false; - Temp scratch = scratch_begin(0, 0); - - StringJoin join_params = {0}; - join_params.pre = str8_lit("\""); - join_params.sep = str8_lit("\" \""); - join_params.post = str8_lit("\""); - String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); - - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - String8 env = str8_list_join(scratch.arena, &options->env, &join_params2); - - String16 cmd16 = str16_from_8(scratch.arena, cmd); - String16 dir16 = str16_from_8(scratch.arena, options->path); - String16 env16 = str16_from_8(scratch.arena, env); - - DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, - &startup_info, &process_info)) - { - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - result = true; - } - - scratch_end(scratch); - return(result); -} - -global HANDLE g_process_1 = 0; -global DWORD g_process_id_1 = 0; -global U64 g_process_injection_addr_1 = 0; -global HANDLE g_process_2 = 0; -global DWORD g_process_id_2 = 0; - -internal B32 -test_w32_inject_thread(HANDLE process, U64 start_address) -{ - B32 result = false; - LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)start_address; - HANDLE thread = CreateRemoteThread(process, 0, 0, start, 0, 0, 0); - if(thread != 0) - { - CloseHandle(thread); - result = true; - } - return result; -} - -internal void -test_halt(void) -{ - test_w32_inject_thread(g_process_1, g_process_injection_addr_1); -} - -internal TEST_DebugEvent -test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps) -{ - Temp scratch = scratch_begin(0, 0); - TEST_DebugEvent result = {0}; - - //- rjf: freeze thread - if(suspend_thread) - { - DWORD result = SuspendThread(suspend_thread); - DWORD error = GetLastError(); - int x = 0; - } - - //- rjf: write traps - U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count); - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)) - { - U8 int3 = 0xCC; - test_w32_write_memory(trap->process, trap->address, &int3, 1); - } - else - { - trap_swap_bytes[i] = 0xCC; - } - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 |= 0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: continue - local_persist B32 need_resume = 0; - local_persist DWORD resume_pid = 0; - local_persist DWORD resume_tid = 0; - - if(need_resume) - { - need_resume = 0; - ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE); - } - - //- rjf: get event - DEBUG_EVENT evt = {0}; - if(WaitForDebugEvent(&evt, INFINITE)) - { - need_resume = 1; - resume_pid = evt.dwProcessId; - resume_tid = evt.dwThreadId; - result.evt = evt; - - switch(evt.dwDebugEventCode) - { - default:break; - - case CREATE_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("create process"); - result.process_id = evt.dwProcessId; - result.process = evt.u.CreateProcessInfo.hProcess; - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateProcessInfo.hThread; - if(g_process_1 == 0) - { - g_process_1 = result.process; - g_process_id_1 = result.process_id; - - // injection memory - { - U8 injection_code[64]; - injection_code[0] = 0xCC; - injection_code[1] = 0xC3; - for (U64 i = 2; i < 64; i += 1){ - injection_code[i] = 0xCC; - } - - U64 injection_size = 64; - U64 injection_address = (U64)VirtualAllocEx(g_process_1, 0, injection_size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE); - test_w32_write_memory(g_process_1, injection_address, injection_code, sizeof(injection_code)); - g_process_injection_addr_1 = injection_address; - } - - - } - else - { - g_process_2 = result.process; - g_process_id_2 = result.process_id; - } - }break; - - case EXIT_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("exit process"); - result.process_id = evt.dwProcessId; - }break; - - case CREATE_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("create thread"); - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateThread.hThread; - }break; - - case EXIT_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("exit thread"); - result.thread_id = evt.dwThreadId; - }break; - - case LOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("load dll"); - }break; - - case UNLOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("unload dll"); - }break; - - case EXCEPTION_DEBUG_EVENT: - { - result.name = str8_lit("exception"); - - EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; - EXCEPTION_RECORD *exception = &edi->ExceptionRecord; - - switch(exception->ExceptionCode) - { - case DEMON_W32_EXCEPTION_BREAKPOINT: - { - result.name = str8_lit("breakpoint"); - result.addr = (U64)exception->ExceptionAddress; - }break; - - case DEMON_W32_EXCEPTION_SINGLE_STEP: - { - result.name = str8_lit("single_step"); - }break; - - case DEMON_W32_EXCEPTION_THROW: - { - result.name = str8_lit("exception throw"); - }break; - - case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: - case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: - { - result.name = str8_lit("exception access violation"); - }break; - - default: - { - }break; - } - - }break; - - case OUTPUT_DEBUG_STRING_EVENT: - { - Temp scratch = scratch_begin(0, 0); - result.name = str8_lit("output debug string"); - - U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; - U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; - - // TODO(allen): is the string in UTF-8 or UTF-16? - - U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1); - test_w32_read_memory(g_process_id_1 == evt.dwProcessId ? g_process_1 : g_process_2, buffer, string_address, string_size); - buffer[string_size] = 0; - - printf("%s\n", buffer); - scratch_end(scratch); - }break; - - case RIP_EVENT: - { - result.name = str8_lit("rip event"); - }break; - - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 &= ~0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: unset traps - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - U8 og_byte = trap_swap_bytes[i]; - if(og_byte != 0xCC) - { - test_w32_write_memory(trap->process, trap->address, &og_byte, 1); - } - } - } - - //- rjf: resume thread - if(suspend_thread) - { - ResumeThread(suspend_thread); - } - - scratch_end(scratch); - return result; -} - -internal DWORD -test_halter_thread(void *params) -{ - HANDLE original_process_handle = params; - Sleep(1500); - test_halt(); -#if 0 - DWORD process_id = GetProcessId(original_process_handle); - HANDLE elevated_process_handle = OpenProcess(PROCESS_SUSPEND_RESUME, 0, process_id); - LONG result = NtSuspendProcess(elevated_process_handle); - CloseHandle(elevated_process_handle); - DebugBreakProcess(process); -#endif - return 0; -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Arena *arena = arena_alloc(); - - NtSuspendProcess = (NtSuspendProcessFunction *)GetProcAddress(GetModuleHandle("ntdll"), "NtSuspendProcess"); - - // rjf: launch - { - OS_LaunchOptions opts = {0}; - opts.path = os_get_path(arena, OS_SystemPath_Current); - str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop.exe")); - B32 launch_good = test_launch_process(&opts); - int x = 0; - } - - // rjf: get process/thread handles - HANDLE process = 0; - HANDLE thread1 = 0; - U64 thread1_id = 0; - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.process) - { - process = evt.process; - } - if(evt.thread) - { - thread1 = evt.thread; - thread1_id = evt.thread_id; - } - if(process != 0 && thread1 != 0) - { - break; - } - } - } - - // rjf: get first breakpoint - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) - { - break; - } - } - } - - // rjf: launch halter thread - DWORD halter_id = 0; - { - CreateThread(0, 0, test_halter_thread, process, 0, &halter_id); - } - - // rjf: run + wait for event - for(;;) - { - TEST_DebugEvent evt = test_run_process(0, 0, 0, 0); - int x = 0; - } - -#if 0 - //- rjf: run until 2nd thread starts up - HANDLE thread2 = 0; - U64 thread2_id = 0; - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0/*ArrayCount(traps), traps*/); - if(evt.thread) - { - thread2 = evt.thread; - thread2_id = evt.thread_id; - break; - } - } - } - - //- rjf: wait for first output string - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.evt.dwDebugEventCode == OUTPUT_DEBUG_STRING_EVENT) - { - break; - } - } - } - - //- rjf: wait for bps - { - // U64 thread1_stop_vaddr = 0x0000000140001119; - // U64 thread2_stop_vaddr = 0x00000001400010C8; - // TEST_Trap traps[] = - { - // {process, thread1_stop_vaddr}, - //{process, thread2_stop_vaddr}, - }; - TEST_DebugEvent evt = {0}; - //for(;;) - { - evt = test_run_process(0, thread2, 0, 0/*ArrayCount(traps), traps*/); - int x = 0; - } - for(;;) {} - } -#endif -} diff --git a/src/demon/test/demon_win32_thread_test.cpp b/src/demon/test/demon_win32_thread_test.cpp deleted file mode 100644 index 6ecd4780..00000000 --- a/src/demon/test/demon_win32_thread_test.cpp +++ /dev/null @@ -1,874 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "syms_helpers/syms_internal_overrides.h" -#include "syms/syms_inc.h" -#include "syms_helpers/syms_helpers.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "syms_helpers/syms_internal_overrides.c" -#include "syms/syms_inc.c" -#include "syms_helpers/syms_helpers.c" - -//////////////////////////////// -// NOTE(allen): Win32 Demon Exceptions - -#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u -#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u -#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u -#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u -#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu -#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u -#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u -#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du -#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu -#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu -#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u -#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u -#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u -#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u -#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u -#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u -#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u -#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du -#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u -#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u -#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u -#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu -#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u -#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u -#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u -#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u -#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u -#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u -#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u -#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u -#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u -#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u -#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u -#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u -#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u -#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u - -//////////////////////////////// -// NOTE(allen): Win32 Demon Register API Codes - -#define DEMON_W32_CTX_X86 0x00010000 -#define DEMON_W32_CTX_X64 0x00100000 - -#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 -#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 -#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 -#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 -#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 -#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 -#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 - -#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ -DEMON_W32_CTX_INTEL_EXTENDED) -#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ -DEMON_W32_CTX_INTEL_DEBUG) - -struct TEST_DebugEvent -{ - String8 name; - U64 process_id; - U64 thread_id; - HANDLE process; - HANDLE thread; - U64 addr; - DEBUG_EVENT evt; -}; - -struct TEST_Trap -{ - HANDLE process; - U64 address; -}; - -internal U16 -test_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) -{ - U16 result = 0; - U32 top = (fxsave->StatusWord >> 11) & 7; - for (U32 fpr = 0; fpr < 8; fpr += 1){ - U32 tag = 3; - if (fxsave->TagWord & (1 << fpr)){ - U32 st = (fpr - top)&7; - - SYMS_Reg80 *fp = (SYMS_Reg80*)&fxsave->FloatRegisters[st*16]; - U16 exponent = fp->sign1_exp15 & bitmask15; - U64 integer_part = fp->int1_frac63 >> 63; - U64 fraction_part = fp->int1_frac63 & bitmask63; - - // tag: 0 - normal; 1 - zero; 2 - special - tag = 2; - if (exponent == 0){ - if (integer_part == 0 && fraction_part == 0){ - tag = 1; - } - } - else if (exponent != bitmask15 && integer_part != 0){ - tag = 0; - } - } - result |= tag << (2 * fpr); - } - return(result); -} - -internal U16 -test_w32_xsave_tag_word_from_real_tag_word(U16 ftw) -{ - U16 compact = 0; - for (U32 fpr = 0; fpr < 8; fpr++){ - U32 tag = (ftw >> (fpr * 2)) & 3; - if (tag != 3){ - compact |= (1 << fpr); - } - } - return(compact); -} - -internal B32 -test_w32_read_x64_regs(HANDLE thread, SYMS_RegX64 *dst) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - DWORD size = 0; - InitializeContext(0, ctx_flags, 0, &size); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ - void *ctx_memory = push_array(scratch.arena, U8, size); - if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ - ctx = 0; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - // get thread context - HANDLE thread_handle = thread; - if (!GetThreadContext(thread_handle, ctx)){ - ctx = 0; - } - - B32 result = false; - if (ctx != 0){ - result = true; - - // NOTE(allen): Convert CONTEXT -> SYMS_RegX64 - dst->rax.u64 = ctx->Rax; - dst->rcx.u64 = ctx->Rcx; - dst->rdx.u64 = ctx->Rdx; - dst->rbx.u64 = ctx->Rbx; - dst->rsp.u64 = ctx->Rsp; - dst->rbp.u64 = ctx->Rbp; - dst->rsi.u64 = ctx->Rsi; - dst->rdi.u64 = ctx->Rdi; - dst->r8.u64 = ctx->R8; - dst->r9.u64 = ctx->R9; - dst->r10.u64 = ctx->R10; - dst->r11.u64 = ctx->R11; - dst->r12.u64 = ctx->R12; - dst->r13.u64 = ctx->R13; - dst->r14.u64 = ctx->R14; - dst->r15.u64 = ctx->R15; - dst->rip.u64 = ctx->Rip; - dst->cs.u16 = ctx->SegCs; - dst->ds.u16 = ctx->SegDs; - dst->es.u16 = ctx->SegEs; - 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; - - // NOTE(allen): This bit is "supposed to always be 1" I guess. - // TODO(allen): Not sure what this is all about but I haven't investigated it yet. - // This might be totally not necessary or something. - dst->rflags.u64 = ctx->EFlags | 0x2; - - XSAVE_FORMAT *xsave = &ctx->FltSave; - dst->fcw.u16 = xsave->ControlWord; - dst->fsw.u16 = xsave->StatusWord; - dst->ftw.u16 = test_w32_real_tag_word_from_xsave(xsave); - dst->fop.u16 = xsave->ErrorOpcode; - dst->fcs.u16 = xsave->ErrorSelector; - dst->fds.u16 = xsave->DataSelector; - dst->fip.u32 = xsave->ErrorOffset; - dst->fdp.u32 = xsave->DataOffset; - dst->mxcsr.u32 = xsave->MxCsr; - dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; - - M128A *float_s = xsave->FloatRegisters; - SYMS_Reg80 *float_d = &dst->fpr0; - for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, sizeof(*float_d)); - } - - if (!avx_available){ - M128A *xmm_s = xsave->XmmRegisters; - SYMS_Reg256 *xmm_d = &dst->ymm0; - for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &dst->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - ymm_d->u64[3] = part0->Low; - ymm_d->u64[2] = part0->High; - ymm_d->u64[1] = part1->Low; - ymm_d->u64[0] = part1->High; - } - } - - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_write_x64_regs(HANDLE thread, SYMS_RegX64 *src) -{ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - DWORD size = 0; - InitializeContext(0, ctx_flags, 0, &size); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ - void *ctx_memory = push_array(scratch.arena, U8, size); - if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ - ctx = 0; - } - } - - B32 avx_available = false; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = true; - } - } - } - - B32 result = false; - if (ctx != 0){ - // NOTE(allen): Convert SYMS_RegX64 -> CONTEXT - ctx->ContextFlags = ctx_flags; - - ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; - - ctx->Rax = src->rax.u64; - ctx->Rcx = src->rcx.u64; - ctx->Rdx = src->rdx.u64; - ctx->Rbx = src->rbx.u64; - ctx->Rsp = src->rsp.u64; - ctx->Rbp = src->rbp.u64; - ctx->Rsi = src->rsi.u64; - ctx->Rdi = src->rdi.u64; - ctx->R8 = src->r8.u64; - ctx->R9 = src->r9.u64; - ctx->R10 = src->r10.u64; - ctx->R11 = src->r11.u64; - ctx->R12 = src->r12.u64; - ctx->R13 = src->r13.u64; - ctx->R14 = src->r14.u64; - ctx->R15 = src->r15.u64; - ctx->Rip = src->rip.u64; - ctx->SegCs = src->cs.u16; - ctx->SegDs = src->ds.u16; - ctx->SegEs = src->es.u16; - 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->EFlags = src->rflags.u64; - - XSAVE_FORMAT *fxsave = &ctx->FltSave; - fxsave->ControlWord = src->fcw.u16; - fxsave->StatusWord = src->fsw.u16; - fxsave->TagWord = test_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); - fxsave->ErrorOpcode = src->fop.u16; - fxsave->ErrorSelector = src->fcs.u16; - fxsave->DataSelector = src->fds.u16; - fxsave->ErrorOffset = src->fip.u32; - fxsave->DataOffset = src->fdp.u32; - - M128A *float_d = fxsave->FloatRegisters; - SYMS_Reg80 *float_s = &src->fpr0; - for (U32 n = 0; - n < 8; - n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, 10); - } - - if (!avx_available){ - M128A *xmm_d = fxsave->XmmRegisters; - SYMS_Reg256 *xmm_s = &src->ymm0; - for (U32 n = 0; - n < 8; - n += 1, xmm_d += 1, xmm_s += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - SYMS_Reg256 *ymm_d = &src->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - part0->Low = ymm_d->u64[3]; - part0->High = ymm_d->u64[2]; - part1->Low = ymm_d->u64[1]; - part1->High = ymm_d->u64[0]; - } - } - - //- set thread context - HANDLE thread_handle = thread; - if (SetThreadContext(thread_handle, ctx)){ - result = true; - } - } - - scratch_end(scratch); - return(result); -} - -internal B32 -test_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)dst; - U8 *opl = ptr + size; - U64 cursor = src_address; - for (;ptr < opl;){ - SIZE_T to_read = (SIZE_T)(opl - ptr); - SIZE_T actual_read = 0; - if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ - result = false; - break; - } - ptr += actual_read; - cursor += actual_read; - } - return(result); -} - -internal B32 -test_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size) -{ - B32 result = true; - U8 *ptr = (U8*)src; - U8 *opl = ptr + size; - U64 cursor = dst_address; - for (;ptr < opl;){ - SIZE_T to_write = (SIZE_T)(opl - ptr); - SIZE_T actual_write = 0; - if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ - result = false; - break; - } - ptr += actual_write; - cursor += actual_write; - } - return(result); -} - -internal B32 -test_launch_process(OS_LaunchOptions *options) -{ - B32 result = false; - Temp scratch = scratch_begin(0, 0); - - StringJoin join_params = {0}; - join_params.pre = str8_lit("\""); - join_params.sep = str8_lit("\" \""); - join_params.post = str8_lit("\""); - String8 cmd = str8_list_join(scratch.arena, &options->cmd_line, &join_params); - - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - String8 env = str8_list_join(scratch.arena, &options->env, &join_params2); - - String16 cmd16 = str16_from_8(scratch.arena, cmd); - String16 dir16 = str16_from_8(scratch.arena, options->path); - String16 env16 = str16_from_8(scratch.arena, env); - - DWORD access_flags = PROCESS_QUERY_INFORMATION | DEBUG_PROCESS | PROCESS_VM_READ | PROCESS_VM_WRITE; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 0, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, - &startup_info, &process_info)) - { - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - result = true; - } - - scratch_end(scratch); - return(result); -} - -global HANDLE g_process = 0; -global DWORD g_process_id = 0; -global HANDLE g_thread1 = 0; -global DWORD g_thread1_id = 0; -global HANDLE g_thread2 = 0; -global DWORD g_thread2_id = 0; - -internal TEST_DebugEvent -test_run_process(HANDLE step_thread, HANDLE suspend_thread, U64 traps_count, TEST_Trap *traps) -{ - Temp scratch = scratch_begin(0, 0); - TEST_DebugEvent result = {0}; - - //- rjf: freeze thread - if(suspend_thread) - { - DWORD result = SuspendThread(suspend_thread); - DWORD error = GetLastError(); - int x = 0; - } - - //- rjf: write traps - U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, traps_count); - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - if(test_w32_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)) - { - U8 int3 = 0xCC; - test_w32_write_memory(trap->process, trap->address, &int3, 1); - } - else - { - trap_swap_bytes[i] = 0xCC; - } - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 |= 0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: continue - local_persist B32 need_resume = 0; - local_persist DWORD resume_pid = 0; - local_persist DWORD resume_tid = 0; - - if(need_resume) - { - need_resume = 0; - ContinueDebugEvent(resume_pid, resume_tid, DBG_CONTINUE); - } - - //- rjf: get event - DEBUG_EVENT evt = {0}; - if(WaitForDebugEvent(&evt, INFINITE)) - { - need_resume = 1; - resume_pid = evt.dwProcessId; - resume_tid = evt.dwThreadId; - result.evt = evt; - - switch(evt.dwDebugEventCode) - { - default:break; - - case CREATE_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("create process"); - result.process_id = evt.dwProcessId; - result.process = evt.u.CreateProcessInfo.hProcess; - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateProcessInfo.hThread; - if(g_process == 0) - { - g_process = result.process; - g_process_id = result.process_id; - } - if(g_thread1 == 0) - { - g_thread1 = result.thread; - g_thread1_id = result.thread_id; - } - }break; - - case EXIT_PROCESS_DEBUG_EVENT: - { - result.name = str8_lit("exit process"); - result.process_id = evt.dwProcessId; - }break; - - case CREATE_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("create thread"); - result.thread_id = evt.dwThreadId; - result.thread = evt.u.CreateThread.hThread; - g_thread2 = result.thread; - g_thread2_id = result.thread_id; - }break; - - case EXIT_THREAD_DEBUG_EVENT: - { - result.name = str8_lit("exit thread"); - result.thread_id = evt.dwThreadId; - }break; - - case LOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("load dll"); - }break; - - case UNLOAD_DLL_DEBUG_EVENT: - { - result.name = str8_lit("unload dll"); - }break; - - case EXCEPTION_DEBUG_EVENT: - { - result.name = str8_lit("exception"); - - EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; - EXCEPTION_RECORD *exception = &edi->ExceptionRecord; - - switch(exception->ExceptionCode) - { - case DEMON_W32_EXCEPTION_BREAKPOINT: - { - result.name = str8_lit("breakpoint"); - result.addr = (U64)exception->ExceptionAddress; - - local_persist B32 did_first_bp = 0; - if(did_first_bp != 0) - { - HANDLE thread = evt.dwThreadId == g_thread1_id ? g_thread1 : g_thread2; - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(thread, ®s); - regs.rip.u64 = result.addr; - test_w32_write_x64_regs(thread, ®s); - } - did_first_bp = 1; - - }break; - - case DEMON_W32_EXCEPTION_SINGLE_STEP: - { - result.name = str8_lit("single_step"); - }break; - - case DEMON_W32_EXCEPTION_THROW: - { - result.name = str8_lit("exception throw"); - }break; - - case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: - case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: - { - result.name = str8_lit("exception access violation"); - }break; - - default: - { - }break; - } - - }break; - - case OUTPUT_DEBUG_STRING_EVENT: - { - Temp scratch = scratch_begin(0, 0); - result.name = str8_lit("output debug string"); - - U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; - U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; - - // TODO(allen): is the string in UTF-8 or UTF-16? - - U8 *buffer = push_array_no_zero(scratch.arena, U8, string_size + 1); - test_w32_read_memory(g_process, buffer, string_address, string_size); - buffer[string_size] = 0; - - printf("%s\n", buffer); - scratch_end(scratch); - }break; - - case RIP_EVENT: - { - result.name = str8_lit("rip event"); - }break; - - } - } - - //- rjf: set single step bit - if(step_thread != 0) - { - SYMS_RegX64 regs = {0}; - test_w32_read_x64_regs(step_thread, ®s); - regs.rflags.u64 &= ~0x100; - test_w32_write_x64_regs(step_thread, ®s); - } - - //- rjf: unset traps - { - TEST_Trap *trap = traps; - for(U64 i = 0; i < traps_count; i += 1, trap += 1) - { - U8 og_byte = trap_swap_bytes[i]; - if(og_byte != 0xCC) - { - test_w32_write_memory(trap->process, trap->address, &og_byte, 1); - } - } - } - - //- rjf: check for more events - for(int i = 0; i < 100; i += 1) - { - DEBUG_EVENT evt = {0}; - if(WaitForDebugEvent(&evt, 0)) - { - int x = 0; - } - } - - //- rjf: resume thread - if(suspend_thread) - { - ResumeThread(suspend_thread); - } - - scratch_end(scratch); - return result; -} - -int -main(int argument_count, char **arguments) -{ - os_init(argument_count, arguments); - Arena *arena = arena_alloc(); - - U64 before_loop_stop_vaddr = 0x0000000140001089; - U64 inner_loop_stop_vaddr = 0x0000000140001098; - - // rjf: launch - { - OS_LaunchOptions opts = {0}; - opts.path = os_get_path(arena, OS_SystemPath_Current); - str8_list_push(arena, &opts.cmd_line, str8_lit("R:\\projects\\debugger\\build\\mule_loop_threads_win32.exe")); - B32 launch_good = test_launch_process(&opts); - int x = 0; - } - - // rjf: get process/thread handles - HANDLE process = 0; - HANDLE thread1 = 0; - U64 thread1_id = 0; - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.process) - { - process = evt.process; - } - if(evt.thread) - { - thread1 = evt.thread; - thread1_id = evt.thread_id; - } - if(process != 0 && thread1 != 0) - { - break; - } - } - } - - // rjf: get first breakpoint - { - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, 0, 0); - if(evt.evt.dwDebugEventCode == EXCEPTION_DEBUG_EVENT) - { - break; - } - } - } - - //- rjf: run until 2nd thread starts up - HANDLE thread2 = 0; - U64 thread2_id = 0; - { - TEST_Trap traps[] = - { - {process, before_loop_stop_vaddr}, - }; - int trap_count = 0; //ArrayCount(traps); - for(TEST_DebugEvent evt = {0};;) - { - evt = test_run_process(0, 0, trap_count, traps); - if(str8_match(evt.name, str8_lit("breakpoint"), 0)) - { - trap_count = 0; - } - if(evt.thread) - { - thread2 = evt.thread; - thread2_id = evt.thread_id; - break; - } - } - } - - //- rjf: wait for bps - { - Temp scratch = scratch_begin(0, 0); - TEST_Trap traps[] = - { - {process, 0x0000000140001098}, - {process, 0x00000001400010fb}, - {process, 0x00000001400010bc}, - {process, 0x00000001400010d7}, - }; - - for(int i = 0;; i += 1) - { - TEST_DebugEvent evt = test_run_process(0, 0, 1, &traps[i % ArrayCount(traps)]); - - // rjf: check regs - { - U64 rip = 0; - SYMS_RegX64 *regs = push_array(scratch.arena, SYMS_RegX64, 1); - if(evt.evt.dwThreadId == g_thread1_id && test_w32_read_x64_regs(thread1, regs)) - { - rip = regs->rip.u64; - } - if(evt.evt.dwThreadId == g_thread2_id && test_w32_read_x64_regs(thread2, regs)) - { - rip = regs->rip.u64; - } - - for(int i = 0; i < ArrayCount(traps); i += 1) - { - if(traps[i].address == rip) - { - printf("WRONG BP! 0x%I64x\n", rip); - break; - } - } - } - - if(str8_match(evt.name, str8_lit("breakpoint"), 0)) - { - HANDLE step = 0; - HANDLE suspend = 0; - step = evt.evt.dwThreadId == thread2_id ? thread2 : thread1; - suspend = step == thread2 ? thread1 : thread2; - evt = test_run_process(step, suspend, 0, 0); - } - } - scratch_end(scratch); - } - - return 0; -} diff --git a/src/demon/win32/demon_core_win32.c b/src/demon/win32/demon_core_win32.c new file mode 100644 index 00000000..42035c76 --- /dev/null +++ b/src/demon/win32/demon_core_win32.c @@ -0,0 +1,2630 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 +dmn_w32_hash_from_string(String8 string) +{ + U64 result = 5381; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal U64 +dmn_w32_hash_from_id(U64 id) +{ + return dmn_w32_hash_from_string(str8_struct(&id)); +} + +//////////////////////////////// +//~ rjf: Entity Helpers + +//- rjf: entity <-> handle + +internal DMN_Handle +dmn_w32_handle_from_entity(DMN_W32_Entity *entity) +{ + U32 idx = (U32)(entity - dmn_w32_shared->entities_base); + U32 gen = entity->gen; + DMN_Handle handle = {idx, gen}; + return handle; +} + +internal DMN_W32_Entity * +dmn_w32_entity_from_handle(DMN_Handle handle) +{ + U32 idx = handle.u32[0]; + U32 gen = handle.u32[1]; + DMN_W32_Entity *entity = dmn_w32_shared->entities_base + idx; + if(entity->gen != gen) + { + entity = &dmn_w32_entity_nil; + } + return entity; +} + +//- rjf: entity allocation/deallocation + +internal DMN_W32_Entity * +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; + { + if(e != 0) + { + SLLStackPop(dmn_w32_shared->entities_first_free); + } + 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; + } + + // rjf: fill + { + e->kind = kind; + e->id = id; + e->parent = parent; + e->next = e->prev = e->first = e->last = &dmn_w32_entity_nil; + if(parent != &dmn_w32_entity_nil) + { + DLLPushBack_NPZ(&dmn_w32_entity_nil, parent->first, parent->last, e, next, prev); + } + } + + // rjf: insert into id -> entity map + if(id != 0) + { + U64 hash = dmn_w32_hash_from_id(id); + U64 slot_idx = hash%dmn_w32_shared->entities_id_hash_slots_count; + DMN_W32_EntityIDHashSlot *slot = &dmn_w32_shared->entities_id_hash_slots[slot_idx]; + DMN_W32_EntityIDHashNode *node = 0; + for(DMN_W32_EntityIDHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->id == id) + { + node = n; + break; + } + } + if(node == 0) + { + node = dmn_w32_shared->entities_id_hash_node_free; + if(node != 0) + { + SLLStackPop(dmn_w32_shared->entities_id_hash_node_free); + } + else + { + node = push_array(dmn_w32_shared->arena, DMN_W32_EntityIDHashNode, 1); + } + DLLPushBack(slot->first, slot->last, node); + } + node->id = id; + node->entity = e; + } + + return e; +} + +internal void +dmn_w32_entity_release(DMN_W32_Entity *entity) +{ + // rjf: unhook root + if(entity->parent != &dmn_w32_entity_nil) + { + DLLRemove_NPZ(&dmn_w32_entity_nil, entity->parent->first, entity->parent->last, entity, next, prev); + } + + // rjf: walk every entity in this tree, free each + if(entity != &dmn_w32_entity_nil) + { + Temp scratch = scratch_begin(0, 0); + typedef struct Task Task; + struct Task + { + Task *next; + DMN_W32_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(DMN_W32_Entity *child = t->e->first; child != &dmn_w32_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(dmn_w32_shared->entities_first_free, t->e); + t->e->gen += 1; + if(t->e->kind == DMN_W32_EntityKind_Module) + { + CloseHandle(t->e->handle); + } + + // rjf: remove from id -> entity map + if(t->e->id != 0) + { + U64 hash = dmn_w32_hash_from_id(t->e->id); + U64 slot_idx = hash%dmn_w32_shared->entities_id_hash_slots_count; + DMN_W32_EntityIDHashSlot *slot = &dmn_w32_shared->entities_id_hash_slots[slot_idx]; + DMN_W32_EntityIDHashNode *node = 0; + for(DMN_W32_EntityIDHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->id == t->e->id && n->entity == t->e) + { + DLLRemove(slot->first, slot->last, n); + SLLStackPush(dmn_w32_shared->entities_id_hash_node_free, n); + break; + } + } + } + } + scratch_end(scratch); + } +} + +//- rjf: kind*id -> entity + +internal DMN_W32_Entity * +dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id) +{ + DMN_W32_Entity *result = &dmn_w32_entity_nil; + U64 hash = dmn_w32_hash_from_id(id); + U64 slot_idx = hash%dmn_w32_shared->entities_id_hash_slots_count; + DMN_W32_EntityIDHashSlot *slot = &dmn_w32_shared->entities_id_hash_slots[slot_idx]; + DMN_W32_EntityIDHashNode *node = 0; + for(DMN_W32_EntityIDHashNode *n = slot->first; n != 0; n = n->next) + { + if(n->entity->kind == kind && n->id == id) + { + node = n; + break; + } + } + if(node != 0) + { + result = node->entity; + } + return result; +} + +//////////////////////////////// +//~ rjf: Module Info Extraction + +internal String8 +dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: extract path from module + String16 path16 = {0}; + String8 path8 = {0}; + { + // rjf: handle -> full path + if(module->handle != 0) + { + DWORD cap16 = GetFinalPathNameByHandleW(module->handle, 0, 0, VOLUME_NAME_DOS); + U16 *buffer16 = push_array_no_zero(scratch.arena, U16, cap16); + DWORD size16 = GetFinalPathNameByHandleW(module->handle, (WCHAR*)buffer16, cap16, VOLUME_NAME_DOS); + path16 = str16(buffer16, size16); + } + + // rjf: fallback (main module only): process -> full path + if(path16.size == 0 && module->module.is_main) + { + DMN_W32_Entity *process = module->parent; + DWORD size = KB(4); + U16 *buf = push_array_no_zero(scratch.arena, U16, size); + if(QueryFullProcessImageNameW(process->handle, 0, (WCHAR*)buf, &size)) + { + path16 = str16(buf, size); + } + } + + // rjf: fallback (any module - no guarantee): address_of_name -> full path + if(path16.size == 0 && module->module.address_of_name_pointer != 0) + { + DMN_W32_Entity *process = module->parent; + U64 ptr_size = bit_size_from_arch(process->arch)/8; + U64 name_pointer = 0; + if(dmn_w32_process_read(process->handle, r1u64(module->module.address_of_name_pointer, module->module.address_of_name_pointer+ptr_size), &name_pointer)) + { + if(name_pointer != 0) + { + if(module->module.name_is_unicode) + { + path16 = dmn_w32_read_memory_str16(scratch.arena, process->handle, name_pointer); + } + else + { + path8 = dmn_w32_read_memory_str(scratch.arena, process->handle, name_pointer); + } + } + } + } + } + + // rjf: produce finalized result + String8 result = {0}; + { + if(path16.size > 0) + { + // rjf: skip the extended path thing if necessary + if(path16.size >= 4 && + path16.str[0] == L'\\' && + path16.str[1] == L'\\' && + path16.str[2] == L'?' && + path16.str[3] == L'\\') + { + path16.size -= 4; + path16.str += 4; + } + + // rjf: convert to UTF-8 + result = str8_from_16(arena, path16); + } + else + { + // rjf: skip the extended path thing if necessary + if (path8.size >= 4 && + path8.str[0] == L'\\' && + path8.str[1] == L'\\' && + path8.str[2] == L'?' && + path8.str[3] == L'\\') + { + path8.size -= 4; + path8.str += 4; + } + + // rjf: copy to output arena + result = push_str8_copy(arena, path8); + } + } + + scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: Win32-Level Process/Thread Reads/Writes + +//- rjf: processes + +internal U64 +dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst) +{ + U64 bytes_read = 0; + U8 *ptr = (U8*)dst; + U8 *opl = ptr + dim_1u64(range); + U64 cursor = range.min; + for(;ptr < opl;) + { + SIZE_T to_read = (SIZE_T)(opl - ptr); + SIZE_T actual_read = 0; + if(!ReadProcessMemory(process, (LPCVOID)cursor, ptr, to_read, &actual_read)) + { + bytes_read += actual_read; + break; + } + ptr += actual_read; + cursor += actual_read; + bytes_read += actual_read; + } + return bytes_read; +} + +internal B32 +dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src) +{ + B32 result = 1; + U8 *ptr = (U8*)src; + U8 *opl = ptr + dim_1u64(range); + U64 cursor = range.min; + for(;ptr < opl;) + { + SIZE_T to_write = (SIZE_T)(opl - ptr); + SIZE_T actual_write = 0; + if(!WriteProcessMemory(process, (LPVOID)cursor, ptr, to_write, &actual_write)) + { + result = 0; + break; + } + ptr += actual_write; + cursor += actual_write; + } + ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen); + return result; +} + +internal String8 +dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address) +{ + // TODO(rjf): @rewrite + // + // OLD: this could be done better with a demon_w32_read_memory + // that returns a read amount instead of a success/fail. + // + // (dmn_w32_process_read now does this, so we can switch to it) + + // scan piece by piece + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + U64 max_cap = 256; + U64 cap = max_cap; + U64 read_p = address; + for (;;){ + U8 *block = push_array(scratch.arena, U8, cap); + for (;cap > 0;){ + if (dmn_w32_process_read(process_handle, r1u64(read_p, read_p+cap), block)){ + break; + } + cap /= 2; + } + read_p += cap; + + U64 block_opl = 0; + for (;block_opl < cap; block_opl += 1){ + if (block[block_opl] == 0){ + break; + } + } + + if (block_opl > 0){ + str8_list_push(scratch.arena, &list, str8(block, block_opl)); + } + + if (block_opl < cap || cap == 0){ + break; + } + } + + // assemble results + String8 result = str8_list_join(arena, &list, 0); + scratch_end(scratch); + return(result); +} + +internal String16 +dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address) +{ + // TODO(rjf): @rewrite + // + // OLD: this could be done better with a demon_w32_read_memory + // that returns a read amount instead of a success/fail. + // + // (dmn_w32_process_read now does this, so we can switch to it) + + // scan piece by piece + Temp scratch = scratch_begin(&arena, 1); + String8List list = {0}; + + U64 max_cap = 256; + U64 cap = max_cap; + U64 read_p = address; + for (;;){ + U8 *block = push_array(scratch.arena, U8, cap); + for (;cap > 1;){ + if (dmn_w32_process_read(process_handle, r1u64(read_p, read_p+cap), block)){ + break; + } + cap /= 2; + } + read_p += cap; + + U16 *block16 = (U16*)block; + (void)block16; + U64 block_opl = 0; + for (;block_opl < cap; block_opl += 2){ + if (*(U16*)(block + block_opl) == 0){ + break; + } + } + + if (block_opl > 0){ + str8_list_push(scratch.arena, &list, str8(block, block_opl)); + } + + if (block_opl < cap || cap == 0){ + break; + } + } + + // assemble results + String8 joined = str8_list_join(arena, &list, 0); + String16 result = {(U16*)joined.str, joined.size/2}; + scratch_end(scratch); + return(result); +} + +internal DMN_W32_ImageInfo +dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr) +{ + // rjf: find PE offset + U32 pe_offset = 0; + { + U64 dos_magic_off = base_vaddr; + U16 dos_magic = 0; + dmn_w32_process_read_struct(process, dos_magic_off, &dos_magic); + if(dos_magic == PE_DOS_MAGIC) + { + U64 pe_offset_off = base_vaddr + OffsetOf(PE_DosHeader, coff_file_offset); + dmn_w32_process_read_struct(process, pe_offset_off, &pe_offset); + } + } + + // rjf: get COFF header + B32 got_coff_header = 0; + U64 coff_header_off = 0; + COFF_Header coff_header = {0}; + if(pe_offset > 0) + { + U64 pe_magic_off = base_vaddr + pe_offset; + U32 pe_magic = 0; + dmn_w32_process_read_struct(process, pe_magic_off, &pe_magic); + if(pe_magic == PE_MAGIC) + { + coff_header_off = pe_magic_off + sizeof(pe_magic); + if(dmn_w32_process_read_struct(process, coff_header_off, &coff_header)) + { + got_coff_header = 1; + } + } + } + + // rjf: get arch and size + DMN_W32_ImageInfo result = zero_struct; + if(got_coff_header) + { + U64 optional_size_off = 0; + Architecture arch = Architecture_Null; + switch(coff_header.machine) + { + case COFF_MachineType_X86: + { + arch = Architecture_x86; + optional_size_off = OffsetOf(PE_OptionalHeader32, sizeof_image); + }break; + case COFF_MachineType_X64: + { + arch = Architecture_x64; + optional_size_off = OffsetOf(PE_OptionalHeader32Plus, sizeof_image); + }break; + default: + {}break; + } + if(arch != Architecture_Null) + { + 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)) + { + result.arch = arch; + result.size = size; + } + } + } + + return result; +} + +//- rjf: threads + +internal U16 +dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave) +{ + U16 result = 0; + U32 top = (fxsave->StatusWord >> 11) & 7; + for(U32 fpr = 0; fpr < 8; fpr += 1) + { + U32 tag = 3; + if(fxsave->TagWord & (1 << fpr)) + { + U32 st = (fpr - top)&7; + + REGS_Reg80 *fp = (REGS_Reg80*)&fxsave->FloatRegisters[st*16]; + U16 exponent = fp->sign1_exp15 & bitmask15; + U64 integer_part = fp->int1_frac63 >> 63; + U64 fraction_part = fp->int1_frac63 & bitmask63; + + // tag: 0 - normal; 1 - zero; 2 - special + tag = 2; + if(exponent == 0) + { + if(integer_part == 0 && fraction_part == 0) + { + tag = 1; + } + } + else if(exponent != bitmask15 && integer_part != 0) + { + tag = 0; + } + } + result |= tag << (2 * fpr); + } + return result; +} + +internal U16 +dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw) +{ + U16 compact = 0; + for(U32 fpr = 0; fpr < 8; fpr++) + { + U32 tag = (ftw >> (fpr * 2)) & 3; + if(tag != 3) + { + compact |= (1 << fpr); + } + } + return compact; +} + +internal B32 +dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block) +{ + B32 result = 0; + switch(arch) + { + //////////////////////////// + //- rjf: unimplemented win32/arch combos + // + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + + //////////////////////////// + //- rjf: x86 + // + case Architecture_x86: + { + REGS_RegBlockX86 *dst = (REGS_RegBlockX86 *)reg_block; + + //- rjf: get thread context + WOW64_CONTEXT ctx = {0}; + ctx.ContextFlags = DMN_W32_CTX_X86_ALL; + if(!Wow64GetThreadContext(thread, (WOW64_CONTEXT *)&ctx)) + { + break; + } + result = 1; + + //- rjf: convert WOW64_CONTEXT -> REGS_RegBlockX86 + XSAVE_FORMAT *fxsave = (XSAVE_FORMAT *)ctx.ExtendedRegisters; + dst->eax.u32 = ctx.Eax; + dst->ebx.u32 = ctx.Ebx; + dst->ecx.u32 = ctx.Ecx; + dst->edx.u32 = ctx.Edx; + dst->esi.u32 = ctx.Esi; + dst->edi.u32 = ctx.Edi; + dst->esp.u32 = ctx.Esp; + dst->ebp.u32 = ctx.Ebp; + dst->eip.u32 = ctx.Eip; + dst->cs.u16 = ctx.SegCs; + dst->ds.u16 = ctx.SegDs; + dst->es.u16 = ctx.SegEs; + 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; + // NOTE(rjf): this bit is "supposed to always be 1", according to old info. + // may need to be investigated. + dst->eflags.u32 = ctx.EFlags | 0x2; + dst->fcw.u16 = fxsave->ControlWord; + dst->fsw.u16 = fxsave->StatusWord; + dst->ftw.u16 = dmn_w32_real_tag_word_from_xsave(fxsave); + dst->fop.u16 = fxsave->ErrorOpcode; + dst->fip.u32 = fxsave->ErrorOffset; + dst->fcs.u16 = fxsave->ErrorSelector; + dst->fdp.u32 = fxsave->DataOffset; + dst->fds.u16 = fxsave->DataSelector; + dst->mxcsr.u32 = fxsave->MxCsr; + dst->mxcsr_mask.u32 = fxsave->MxCsr_Mask; + { + M128A *float_s = fxsave->FloatRegisters; + REGS_Reg80 *float_d = &dst->fpr0; + for(U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1) + { + MemoryCopy(float_d, float_s, sizeof(*float_d)); + } + } + { + M128A *xmm_s = fxsave->XmmRegisters; + REGS_Reg256 *xmm_d = &dst->ymm0; + for(U32 n = 0; n < 8; n += 1, xmm_s += 1, xmm_d += 1) + { + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); + } + } + + //- rjf: read FS/GS base + WOW64_LDT_ENTRY ldt = {0}; + if(Wow64GetThreadSelectorEntry(thread, ctx.SegFs, &ldt)) + { + U32 base = (ldt.BaseLow) | (ldt.HighWord.Bytes.BaseMid << 16) | (ldt.HighWord.Bytes.BaseHi << 24); + dst->fsbase.u32 = base; + } + if(Wow64GetThreadSelectorEntry(thread, ctx.SegGs, &ldt)) + { + U32 base = (ldt.BaseLow) | (ldt.HighWord.Bytes.BaseMid << 16) | (ldt.HighWord.Bytes.BaseHi << 24); + dst->gsbase.u32 = base; + } + }break; + + //////////////////////////// + //- rjf: x64 + // + case Architecture_x64: + { + Temp scratch = scratch_begin(0, 0); + REGS_RegBlockX64 *dst = (REGS_RegBlockX64 *)reg_block; + + //- rjf: unpack info about available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + //- rjf: set up context + CONTEXT *ctx = 0; + U32 ctx_flags = DMN_W32_CTX_X64_ALL; + if(avx_enabled) + { + ctx_flags |= DMN_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + void *ctx_memory = push_array(scratch.arena, U8, size); + if(!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)) + { + ctx = 0; + } + } + + //- rjf: unpack features available on this context + B32 avx_available = 0; + if(ctx != 0) + { + if(avx_enabled) + { + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + DWORD64 xstate_flags = 0; + if(GetXStateFeaturesMask(ctx, &xstate_flags)) + { + avx_available = !!(xstate_flags & XSTATE_MASK_AVX); + } + } + + //- rjf: get thread context + if(!GetThreadContext(thread, ctx)) + { + ctx = 0; + } + + //- rjf: bad context -> abort + if(ctx == 0) + { + break; + } + result = 1; + + //- rjf: convert context -> REGS_RegBlockX64 + XSAVE_FORMAT *xsave = &ctx->FltSave; + dst->rax.u64 = ctx->Rax; + dst->rcx.u64 = ctx->Rcx; + dst->rdx.u64 = ctx->Rdx; + dst->rbx.u64 = ctx->Rbx; + dst->rsp.u64 = ctx->Rsp; + dst->rbp.u64 = ctx->Rbp; + dst->rsi.u64 = ctx->Rsi; + dst->rdi.u64 = ctx->Rdi; + dst->r8.u64 = ctx->R8; + dst->r9.u64 = ctx->R9; + dst->r10.u64 = ctx->R10; + dst->r11.u64 = ctx->R11; + dst->r12.u64 = ctx->R12; + dst->r13.u64 = ctx->R13; + dst->r14.u64 = ctx->R14; + dst->r15.u64 = ctx->R15; + dst->rip.u64 = ctx->Rip; + dst->cs.u16 = ctx->SegCs; + dst->ds.u16 = ctx->SegDs; + dst->es.u16 = ctx->SegEs; + 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; + // 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; + dst->fcw.u16 = xsave->ControlWord; + dst->fsw.u16 = xsave->StatusWord; + dst->ftw.u16 = dmn_w32_real_tag_word_from_xsave(xsave); + dst->fop.u16 = xsave->ErrorOpcode; + dst->fcs.u16 = xsave->ErrorSelector; + dst->fds.u16 = xsave->DataSelector; + dst->fip.u32 = xsave->ErrorOffset; + dst->fdp.u32 = xsave->DataOffset; + dst->mxcsr.u32 = xsave->MxCsr; + dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; + { + M128A *float_s = xsave->FloatRegisters; + REGS_Reg80 *float_d = &dst->fpr0; + for(U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1) + { + MemoryCopy(float_d, float_s, sizeof(*float_d)); + } + } + if(!avx_available) + { + M128A *xmm_s = xsave->XmmRegisters; + REGS_Reg256 *xmm_d = &dst->ymm0; + for(U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1) + { + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); + } + } + if(avx_available) + { + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + REGS_Reg256 *ymm_d = &dst->ymm0; + for (DWORD i = 0; i < count; i += 1, part0 += 1, part1 += 1, ymm_d += 1) + { + // TODO(rjf): confirm ordering of writes + ymm_d->u64[3] = part0->Low; + ymm_d->u64[2] = part0->High; + ymm_d->u64[1] = part1->Low; + ymm_d->u64[0] = part1->High; + } + } + + scratch_end(scratch); + }break; + } + return result; +} + +internal B32 +dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block) +{ + B32 result = 0; + switch(arch) + { + //////////////////////////// + //- rjf: unimplemented win32/arch combos + // + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + + //////////////////////////// + //- rjf: x86 + // + case Architecture_x86: + { + REGS_RegBlockX86 *src = (REGS_RegBlockX86 *)reg_block; + + //- rjf: convert REGS_RegBlockX86 -> WOW64_CONTEXT + WOW64_CONTEXT ctx = {0}; + XSAVE_FORMAT *fxsave = (XSAVE_FORMAT*)ctx.ExtendedRegisters; + ctx.ContextFlags = DMN_W32_CTX_X86_ALL; + ctx.Eax = src->eax.u32; + ctx.Ebx = src->ebx.u32; + ctx.Ecx = src->ecx.u32; + ctx.Edx = src->edx.u32; + ctx.Esi = src->esi.u32; + ctx.Edi = src->edi.u32; + ctx.Esp = src->esp.u32; + ctx.Ebp = src->ebp.u32; + ctx.Eip = src->eip.u32; + ctx.SegCs = src->cs.u16; + ctx.SegDs = src->ds.u16; + ctx.SegEs = src->es.u16; + 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.EFlags = src->eflags.u32; + fxsave->ControlWord = src->fcw.u16; + fxsave->StatusWord = src->fsw.u16; + fxsave->TagWord = dmn_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); + fxsave->ErrorOpcode = src->fop.u16; + fxsave->ErrorSelector = src->fcs.u16; + fxsave->DataSelector = src->fds.u16; + fxsave->ErrorOffset = src->fip.u32; + fxsave->DataOffset = src->fdp.u32; + fxsave->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; + fxsave->MxCsr_Mask = src->mxcsr_mask.u32; + { + M128A *float_d = fxsave->FloatRegisters; + REGS_Reg80 *float_s = &src->fpr0; + for(U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1) + { + MemoryCopy(float_d, float_s, 10); + } + } + { + M128A *xmm_d = fxsave->XmmRegisters; + REGS_Reg256 *xmm_s = &src->ymm0; + for(U32 n = 0; n < 8; n += 1, xmm_d += 1, xmm_s += 1) + { + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); + } + } + + //- rjf: set thread context + B32 result = 0; + if(Wow64SetThreadContext(thread, &ctx)) + { + result = 1; + } + }break; + + //////////////////////////// + //- rjf: x64 + // + case Architecture_x64: + { + Temp scratch = scratch_begin(0, 0); + REGS_RegBlockX64 *src = (REGS_RegBlockX64 *)reg_block; + + //- rjf: unpack info about available features + U32 feature_mask = GetEnabledXStateFeatures(); + B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); + + //- rjf: set up context + CONTEXT *ctx = 0; + U32 ctx_flags = DMN_W32_CTX_X64_ALL; + if(avx_enabled) + { + ctx_flags |= DMN_W32_CTX_INTEL_XSTATE; + } + DWORD size = 0; + InitializeContext(0, ctx_flags, 0, &size); + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + void *ctx_memory = push_array(scratch.arena, U8, size); + if(!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)) + { + ctx = 0; + } + } + + //- rjf: unpack features available on this context + B32 avx_available = 0; + if(ctx != 0) + { + if(avx_enabled) + { + SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); + } + DWORD64 xstate_flags = 0; + if(GetXStateFeaturesMask(ctx, &xstate_flags)) + { + avx_available = !!(xstate_flags & XSTATE_MASK_AVX); + } + } + + //- rjf: get thread context + if(!GetThreadContext(thread, ctx)) + { + ctx = 0; + } + + //- rjf: bad context -> abort + if(ctx == 0) + { + DWORD error = GetLastError(); + break; + } + + //- rjf: convert REGS_RegBlockX64 -> CONTEXT + XSAVE_FORMAT *fxsave = &ctx->FltSave; + ctx->ContextFlags = ctx_flags; + ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; + ctx->Rax = src->rax.u64; + ctx->Rcx = src->rcx.u64; + ctx->Rdx = src->rdx.u64; + ctx->Rbx = src->rbx.u64; + ctx->Rsp = src->rsp.u64; + ctx->Rbp = src->rbp.u64; + ctx->Rsi = src->rsi.u64; + ctx->Rdi = src->rdi.u64; + ctx->R8 = src->r8.u64; + ctx->R9 = src->r9.u64; + ctx->R10 = src->r10.u64; + ctx->R11 = src->r11.u64; + ctx->R12 = src->r12.u64; + ctx->R13 = src->r13.u64; + ctx->R14 = src->r14.u64; + ctx->R15 = src->r15.u64; + ctx->Rip = src->rip.u64; + ctx->SegCs = src->cs.u16; + ctx->SegDs = src->ds.u16; + ctx->SegEs = src->es.u16; + 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->EFlags = src->rflags.u64; + fxsave->ControlWord = src->fcw.u16; + fxsave->StatusWord = src->fsw.u16; + fxsave->TagWord = dmn_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); + fxsave->ErrorOpcode = src->fop.u16; + fxsave->ErrorSelector = src->fcs.u16; + fxsave->DataSelector = src->fds.u16; + fxsave->ErrorOffset = src->fip.u32; + fxsave->DataOffset = src->fdp.u32; + { + M128A *float_d = fxsave->FloatRegisters; + REGS_Reg80 *float_s = &src->fpr0; + for(U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1) + { + MemoryCopy(float_d, float_s, 10); + } + } + if(!avx_available) + { + M128A *xmm_d = fxsave->XmmRegisters; + REGS_Reg256 *xmm_s = &src->ymm0; + for(U32 n = 0; n < 8; n += 1, xmm_d += 1, xmm_s += 1) + { + MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); + } + } + if(avx_available) + { + DWORD part0_length = 0; + M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); + DWORD part1_length = 0; + M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); + Assert(part0_length == part1_length); + DWORD count = part0_length/sizeof(part0[0]); + count = ClampTop(count, 16); + REGS_Reg256 *ymm_d = &src->ymm0; + for(DWORD i = 0; i < count; i += 1, part0 += 1, part1 += 1, ymm_d += 1) + { + // TODO(allen): Are we writing these out in the right order? Seems weird right? + part0->Low = ymm_d->u64[3]; + part0->High = ymm_d->u64[2]; + part1->Low = ymm_d->u64[1]; + part1->High = ymm_d->u64[0]; + } + } + + //- rjf: set thread context + if(SetThreadContext(thread, ctx)) + { + result = 1; + } + scratch_end(scratch); + }break; + } + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); + return result; +} + +//- rjf: remote thread injection + +internal DWORD +dmn_w32_inject_thread(HANDLE process, U64 start_address) +{ + LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)start_address; + DWORD thread_id = 0; + HANDLE thread = CreateRemoteThread(process, 0, 0, start, 0, 0, &thread_id); + if(thread != 0) + { + CloseHandle(thread); + } + return thread_id; +} + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Main Layer Initialization (Implemented Per-OS) + +internal void +dmn_init(void) +{ + Arena *arena = arena_alloc(); + dmn_w32_shared = push_array(arena, DMN_W32_Shared, 1); + dmn_w32_shared->arena = arena; + dmn_w32_shared->access_mutex = os_mutex_alloc(); + dmn_w32_shared->detach_arena = arena_alloc(); + dmn_w32_shared->entities_arena = arena_alloc__sized(GB(8), KB(64)); + dmn_w32_shared->entities_base = dmn_w32_entity_alloc(&dmn_w32_entity_nil, DMN_W32_EntityKind_Root, 0); + dmn_w32_shared->entities_id_hash_slots_count = 4096; + dmn_w32_shared->entities_id_hash_slots = push_array(arena, DMN_W32_EntityIDHashSlot, dmn_w32_shared->entities_id_hash_slots_count); + + // rjf: load Windows 10+ GetThreadDescription API + { + dmn_w32_GetThreadDescription = (DMN_W32_GetThreadDescriptionFunctionType *)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "GetThreadDescription"); + } + + // rjf: setup environment variables + { + 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(dmn_w32_shared->arena, string16); + str8_list_push(dmn_w32_shared->arena, &dmn_w32_shared->env_strings, string); + start_idx = idx+1; + } + } + } + } +} + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Blocking Control Thread Operations (Implemented Per-OS) + +internal DMN_CtrlCtx * +dmn_ctrl_begin(void) +{ + DMN_CtrlCtx *ctx = (DMN_CtrlCtx *)1; + dmn_w32_ctrl_thread = 1; + return ctx; +} + +internal void +dmn_ctrl_exclusive_access_begin(void) +{ + OS_MutexScope(dmn_w32_shared->access_mutex) + { + dmn_w32_shared->access_run_state = 1; + } +} + +internal void +dmn_ctrl_exclusive_access_end(void) +{ + OS_MutexScope(dmn_w32_shared->access_mutex) + { + dmn_w32_shared->access_run_state = 0; + } +} + +internal U32 +dmn_ctrl_launch(DMN_CtrlCtx *ctx, OS_LaunchOptions *options) +{ + Temp scratch = scratch_begin(0, 0); + U32 result = 0; + DMN_AccessScope + { + //- rjf: produce exe / arguments string + String8 cmd = {0}; + if(options->cmd_line.first != 0) + { + String8List args = {0}; + String8 exe_path = options->cmd_line.first->string; + str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); + for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &args, n->string); + } + StringJoin join_params = {0}; + join_params.sep = str8_lit(" "); + cmd = str8_list_join(scratch.arena, &args, &join_params); + } + + //- rjf: produce environment strings + String8 env = {0}; + { + String8List all_opts = options->env; + if(options->inherit_env != 0) + { + MemoryZeroStruct(&all_opts); + str8_list_push(scratch.arena, &all_opts, str8_lit("_NO_DEBUG_HEAP=1")); + for(String8Node *n = options->env.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + for(String8Node *n = dmn_w32_shared->env_strings.first; n != 0; n = n->next) + { + str8_list_push(scratch.arena, &all_opts, n->string); + } + } + StringJoin join_params2 = {0}; + join_params2.sep = str8_lit("\0"); + join_params2.post = str8_lit("\0"); + env = str8_list_join(scratch.arena, &all_opts, &join_params2); + } + + //- rjf: produce utf-16 strings + String16 cmd16 = str16_from_8(scratch.arena, cmd); + String16 dir16 = str16_from_8(scratch.arena, options->path); + String16 env16 = str16_from_8(scratch.arena, env); + + //- rjf: launch + DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; + STARTUPINFOW startup_info = {sizeof(startup_info)}; + PROCESS_INFORMATION process_info = {0}; + AllocConsole(); + if(CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, &startup_info, &process_info)) + { + // check if we are 32-bit app, and just close it immediately + BOOL is_wow = 0; + IsWow64Process(process_info.hProcess, &is_wow); + if(is_wow) + { + MessageBox(0, "Sorry, The RAD Debugger only debugs 64-bit applications currently.", "Process error", MB_OK|MB_ICONSTOP); + DebugActiveProcessStop(process_info.dwProcessId); + TerminateProcess(process_info.hProcess,0xffffffff); + } + else + { + result = process_info.dwProcessId; + dmn_w32_shared->new_process_pending = 1; + } + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + } + 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); + } + } + scratch_end(scratch); + return result; +} + +internal B32 +dmn_ctrl_attach(DMN_CtrlCtx *ctx, U32 pid) +{ + B32 result = 0; + DMN_AccessScope if(DebugActiveProcess((DWORD)pid)) + { + result = 1; + dmn_w32_shared->new_process_pending = 1; + } + return result; +} + +internal B32 +dmn_ctrl_kill(DMN_CtrlCtx *ctx, DMN_Handle process, U32 exit_code) +{ + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + if(TerminateProcess(process_entity->handle, exit_code)) + { + result = 1; + } + } + return result; +} + +internal B32 +dmn_ctrl_detach(DMN_CtrlCtx *ctx, DMN_Handle process) +{ + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *process_entity = dmn_w32_entity_from_handle(process); + + // rjf: resume threads + for(DMN_W32_Entity *child = process_entity->first; + child != &dmn_w32_entity_nil; + child = child->next) + { + if(child->kind == DMN_W32_EntityKind_Thread) + { + DWORD resume_result = ResumeThread(child->handle); + (void)resume_result; + } + } + + // rjf: detach + { + DWORD pid = (DWORD)process_entity->id; + if(DebugActiveProcessStop(pid)) + { + result = 1; + } + } + + // rjf: push into list of processes to generate events for later + if(result != 0) + { + dmn_handle_list_push(dmn_w32_shared->detach_arena, &dmn_w32_shared->detach_processes, process); + } + } + return result; +} + +internal DMN_EventList +dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls) +{ + DMN_EventList events = {0}; + dmn_access_open(); + + ////////////////////////////// + //- rjf: determine event generation path + // + typedef enum DMN_W32_EventGenPath + { + DMN_W32_EventGenPath_NotAttached, + DMN_W32_EventGenPath_Run, + DMN_W32_EventGenPath_DetachProcesses, + } + DMN_W32_EventGenPath; + DMN_W32_EventGenPath event_gen_path = DMN_W32_EventGenPath_Run; + if(dmn_w32_shared->detach_processes.first != 0) + { + event_gen_path = DMN_W32_EventGenPath_DetachProcesses; + } + else + { + B32 any_processes_live = dmn_w32_shared->new_process_pending; + if(!any_processes_live) + { + for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; process != &dmn_w32_entity_nil; process = process->next) + { + if(process->kind == DMN_W32_EntityKind_Process) + { + any_processes_live = 1; + break; + } + } + } + if(!any_processes_live) + { + event_gen_path = DMN_W32_EventGenPath_NotAttached; + } + } + + ////////////////////////////// + //- rjf: produce debug events + // + switch(event_gen_path) + { + //////////////////////////// + //- rjf: produce not-attached error events + // + case DMN_W32_EventGenPath_NotAttached: + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_Error; + e->error_kind = DMN_ErrorKind_NotAttached; + }break; + + //////////////////////////// + //- rjf: produce debug events from regular running + // + case DMN_W32_EventGenPath_Run: + { + Temp scratch = scratch_begin(&arena, 1); + + ////////////////////////// + //- rjf: set single step bit + // + if(!dmn_handle_match(ctrls->single_step_thread, dmn_handle_zero())) + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(ctrls->single_step_thread); + Architecture arch = thread->arch; + switch(arch) + { + //- rjf: unimplemented win32/arch combos + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + + //- rjf: x86/64 + case Architecture_x86: + { + REGS_RegBlockX86 regs = {0}; + dmn_thread_read_reg_block(ctrls->single_step_thread, ®s); + regs.eflags.u32 |= 0x100; + dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); + }break; + case Architecture_x64: + { + REGS_RegBlockX64 regs = {0}; + dmn_thread_read_reg_block(ctrls->single_step_thread, ®s); + regs.rflags.u64 |= 0x100; + dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); + }break; + } + } + + ////////////////////////// + //- rjf: write all traps into memory + // + U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, ctrls->traps.trap_count); + { + U64 trap_idx = 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, 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); + } + } + } + + ////////////////////////// + //- rjf: produce list of threads which will run + // + DMN_W32_EntityNode *first_run_thread = 0; + DMN_W32_EntityNode *last_run_thread = 0; + { + //- rjf: scan all processes + for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; + process != &dmn_w32_entity_nil; + process = process->next) + { + if(process->kind != DMN_W32_EntityKind_Process) {continue;} + + //- rjf: determine if this process is frozen + B32 process_is_frozen = 0; + if(ctrls->run_entities_are_processes) + { + for(U64 idx = 0; idx < ctrls->run_entity_count; idx += 1) + { + if(dmn_handle_match(ctrls->run_entities[idx], dmn_w32_handle_from_entity(process))) + { + process_is_frozen = 1; + break; + } + } + } + + //- rjf: scan all threads in this process + for(DMN_W32_Entity *thread = process->first; + thread != &dmn_w32_entity_nil; + thread = thread->next) + { + if(thread->kind != DMN_W32_EntityKind_Thread) {continue;} + + //- rjf: determine if this thread is frozen + B32 is_frozen = 0; + { + // rjf: single-step? freeze if not the single-step thread. + if(!dmn_handle_match(dmn_handle_zero(), ctrls->single_step_thread) && + !dmn_handle_match(dmn_w32_handle_from_entity(thread), ctrls->single_step_thread)) + { + is_frozen = 1; + } + + // rjf: not single-stepping? determine based on run controls freezing info + else + { + if(ctrls->run_entities_are_processes) + { + is_frozen = process_is_frozen; + } + else for(U64 idx = 0; idx < ctrls->run_entity_count; idx += 1) + { + if(dmn_handle_match(ctrls->run_entities[idx], dmn_w32_handle_from_entity(thread))) + { + is_frozen = 1; + break; + } + } + if(ctrls->run_entities_are_unfrozen) + { + is_frozen ^= 1; + } + } + } + + //- rjf: disregard all other rules if this is the halter thread + if(dmn_w32_shared->halter_tid == thread->id) + { + is_frozen = 0; + } + + //- rjf: add to list + if(!is_frozen) + { + DMN_W32_EntityNode *n = push_array(scratch.arena, DMN_W32_EntityNode, 1); + n->v = thread; + SLLQueuePush(first_run_thread, last_run_thread, n); + } + } + } + } + + ////////////////////////// + //- rjf: resume threads which will run + // + for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next) + { + DMN_W32_Entity *thread = n->v; + DWORD resume_result = ResumeThread(thread->handle); + switch(resume_result) + { + case 0xffffffffu: + { + // TODO(rjf): error - unknown cause. need to do GetLastError, FormatMessage + }break; + default: + { + DWORD desired_counter = 0; + DWORD current_counter = resume_result - 1; + if(current_counter != desired_counter) + { + // NOTE(rjf): Warning. The user has manually suspended this thread, + // so even though from Demon's perspective it thinks this thread + // should run, it will not, because the user has manually called + // SuspendThread or used CREATE_SUSPENDED or whatever. + } + }break; + } + } + + ////////////////////////// + //- rjf: if run threads are marked as having reported an explicit trap + // on their last run, shift their RIPs past that trap instruction, so + // that they may continue + // + for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next) + { + DMN_W32_Entity *thread = n->v; + if(thread->thread.last_run_reported_trap) + { + Temp temp = temp_begin(scratch.arena); + U64 regs_block_size = regs_block_size_from_architecture(thread->arch); + void *regs_block = push_array(temp.arena, U8, regs_block_size); + B32 good = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, regs_block); + U64 pre_rip = regs_rip_from_arch_block(thread->arch, regs_block); + if(good && pre_rip == thread->thread.last_run_reported_trap_pre_rip) + { + regs_arch_block_write_rip(thread->arch, regs_block, thread->thread.last_run_reported_trap_post_rip); + dmn_w32_thread_write_reg_block(thread->arch, thread->handle, regs_block); + } + temp_end(temp); + thread->thread.last_run_reported_trap = 0; + thread->thread.last_run_reported_trap_post_rip = 0; + } + } + + ////////////////////////// + //- rjf: choose win32 resume code + // + DWORD resume_code = DBG_CONTINUE; + { + if(dmn_w32_shared->exception_not_handled && !ctrls->ignore_previous_exception) + { + dmn_w32_shared->exception_not_handled = 0; + resume_code = DBG_EXCEPTION_NOT_HANDLED; + } + } + + ////////////////////////// + //- rjf: inform windows that we're resuming, run, & obtain next debug event + // + DEBUG_EVENT evt = {0}; + B32 evt_good = 0; + { + B32 resume_good = 1; + if(dmn_w32_shared->resume_needed) + { + dmn_w32_shared->resume_needed = 0; + resume_good = !!ContinueDebugEvent(dmn_w32_shared->resume_pid, dmn_w32_shared->resume_tid, resume_code); + dmn_w32_shared->resume_needed = 0; + dmn_w32_shared->resume_tid = 0; + dmn_w32_shared->resume_pid = 0; + } + if(resume_good) + { + evt_good = !!WaitForDebugEvent(&evt, INFINITE); + if(evt_good) + { + dmn_w32_shared->resume_needed = 1; + dmn_w32_shared->resume_pid = evt.dwProcessId; + dmn_w32_shared->resume_tid = evt.dwThreadId; + } + ins_atomic_u64_inc_eval(&dmn_w32_shared->run_gen); + ins_atomic_u64_inc_eval(&dmn_w32_shared->mem_gen); + ins_atomic_u64_inc_eval(&dmn_w32_shared->reg_gen); + } + } + + ////////////////////////// + //- rjf: suspend threads which ran + // + if(evt_good) for(DMN_W32_EntityNode *n = first_run_thread; n != 0; n = n->next) + { + DMN_W32_Entity *thread = n->v; + DWORD suspend_result = SuspendThread(thread->handle); + switch(suspend_result) + { + case 0xffffffffu: + { + // TODO(rjf): error - unknown cause. need to do do GetLastError, FormatMessage + // + // NOTE(rjf): this can happen when the event is EXIT_THREAD_DEBUG_EVENT + // or EXIT_PROCESS_DEBUG_EVENT. after such an event, SuspendThread + // gives error code 5 (access denied). this has no adverse effects, but + // if we want to start reporting errors we should take care to avoid + // calling SuspendThread in that case. + }break; + default: + { + DWORD desired_counter = 1; + DWORD current_counter = suspend_result + 1; + if(current_counter != desired_counter) + { + // NOTE(rjf): Warning. We've suspended to something higher than 1. + // In this case, it means the user probably created the thread in + // a suspended state, or they called SuspendThread. + } + }break; + } + } + + ////////////////////////// + //- rjf: process the new event + // + if(evt_good) + { + switch(evt.dwDebugEventCode) + { + ////////////////////// + //- rjf: process was created + // + case CREATE_PROCESS_DEBUG_EVENT: + { + // rjf: zero out "process pending" state + dmn_w32_shared->new_process_pending = 0; + + // rjf: unpack event + HANDLE process_handle = evt.u.CreateProcessInfo.hProcess; + HANDLE thread_handle = evt.u.CreateProcessInfo.hThread; + HANDLE module_handle = evt.u.CreateProcessInfo.hFile; + U64 tls_base = (U64)evt.u.CreateProcessInfo.lpThreadLocalBase; + U64 module_base = (U64)evt.u.CreateProcessInfo.lpBaseOfImage; + U64 module_name_vaddr = (U64)evt.u.CreateProcessInfo.lpImageName; + B32 module_name_is_unicode = (evt.u.CreateProcessInfo.fUnicode != 0); + DMN_W32_ImageInfo image_info = dmn_w32_image_info_from_process_base_vaddr(process_handle, module_base); + + // rjf: create entities (thread/module are implied for initial - they are not reported by win32) + DMN_W32_Entity *process = dmn_w32_entity_alloc(dmn_w32_shared->entities_base, DMN_W32_EntityKind_Process, evt.dwProcessId); + DMN_W32_Entity *thread = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Thread, evt.dwThreadId); + DMN_W32_Entity *module = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Module, module_base); + { + process->handle = process_handle; + process->arch = image_info.arch; + thread->handle = thread_handle; + thread->arch = image_info.arch; + thread->thread.thread_local_base = tls_base; + module->handle = module_handle; + module->module.vaddr_range = r1u64(module_base, image_info.size); + module->module.is_main = 1; + module->module.address_of_name_pointer = module_name_vaddr; + module->module.name_is_unicode = module_name_is_unicode; + } + + // rjf: put thread into suspended state, so it matches expected initial state + SuspendThread(thread_handle); + + // rjf: set up per-process injected code (to run halter threads on & + // generate debug events) + { + U8 injection_code[DMN_W32_INJECTED_CODE_SIZE]; + MemorySet(injection_code, 0xCC, DMN_W32_INJECTED_CODE_SIZE); + injection_code[0] = 0xC3; + U64 injection_size = DMN_W32_INJECTED_CODE_SIZE + sizeof(DMN_W32_InjectedBreak); + U64 injection_address = (U64)VirtualAllocEx(process_handle, 0, injection_size, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE); + dmn_w32_process_write(process_handle, r1u64(injection_address, injection_address+sizeof(injection_code)), injection_code); + process->proc.injection_address = injection_address; + } + + // rjf: generate events + { + // rjf: create process + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_CreateProcess; + e->process = dmn_w32_handle_from_entity(process); + e->arch = image_info.arch; + e->code = evt.dwProcessId; + } + + // rjf: create thread + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_CreateThread; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(thread); + e->arch = image_info.arch; + e->code = evt.dwThreadId; + } + + // rjf: load module + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_LoadModule; + e->process = dmn_w32_handle_from_entity(process); + e->module = dmn_w32_handle_from_entity(module); + e->arch = image_info.arch; + e->address = module_base; + e->size = image_info.size; + e->string = dmn_w32_full_path_from_module(arena, module); + } + } + }break; + + ////////////////////// + //- rjf: process exited + // + case EXIT_PROCESS_DEBUG_EVENT: + { + DMN_W32_Entity *process = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Process, evt.dwProcessId); + + // rjf: generate events for children + for(DMN_W32_Entity *child = process->first; child != &dmn_w32_entity_nil; child = child->next) + { + switch(child->kind) + { + case DMN_W32_EntityKind_Thread: + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_ExitThread; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(child); + }break; + case DMN_W32_EntityKind_Module: + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_UnloadModule; + e->process = dmn_w32_handle_from_entity(process); + e->module = dmn_w32_handle_from_entity(child); + e->string = dmn_w32_full_path_from_module(arena, child); + }break; + } + } + + // rjf: generate event for process + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_ExitProcess; + e->process = dmn_w32_handle_from_entity(process); + e->code = evt.u.ExitProcess.dwExitCode; + } + + // rjf: release entity storage + dmn_w32_entity_release(process); + + // rjf: detach + DebugActiveProcessStop(evt.dwProcessId); + }break; + + ////////////////////// + //- rjf: thread was created + // + case CREATE_THREAD_DEBUG_EVENT: + { + DMN_W32_Entity *process = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Process, evt.dwProcessId); + + // rjf: create thread entity + DMN_W32_Entity *thread = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Thread, evt.dwThreadId); + { + thread->handle = evt.u.CreateThread.hThread; + thread->arch = process->arch; + thread->thread.thread_local_base = (U64)evt.u.CreateThread.lpThreadLocalBase; + } + + // rjf: suspend thread immediately upon creation, to match with expected suspension state + DWORD sus_result = SuspendThread(thread->handle); + (void)sus_result; + + // rjf: unpack thread name + String8 thread_name = {0}; + if(dmn_w32_GetThreadDescription != 0) + { + WCHAR *thread_name_w = 0; + HRESULT hr = dmn_w32_GetThreadDescription(thread->handle, &thread_name_w); + if(SUCCEEDED(hr)) + { + thread_name = str8_from_16(arena, str16_cstring((U16 *)thread_name_w)); + LocalFree(thread_name_w); + } + } + + // rjf: determine if this is a "halter thread" - the threads we spawn to halt processes + B32 is_halter = (evt.dwThreadId == dmn_w32_shared->halter_tid); + + // rjf: generate events for non-halter threads + if(!is_halter) + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_CreateThread; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(thread); + e->arch = thread->arch; + e->code = evt.dwThreadId; + e->string = thread_name; + } + }break; + + ////////////////////// + //- rjf: thread exited + // + case EXIT_THREAD_DEBUG_EVENT: + { + DMN_W32_Entity *thread = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Thread, evt.dwThreadId); + DMN_W32_Entity *process = thread->parent; + + // rjf: determine if this is the halter thread + B32 is_halter = (evt.dwThreadId == dmn_w32_shared->halter_tid); + + // rjf: generate a halt event if this thread is the halter + if(is_halter) + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_Halt; + dmn_w32_shared->halter_process = dmn_handle_zero(); + dmn_w32_shared->halter_tid = 0; + } + + // rjf: if this thread is *not* the halter, then generate a regular exit-thread event + if(!is_halter) + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_ExitThread; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(thread); + e->code = evt.u.ExitThread.dwExitCode; + } + + // rjf: release entity storage + dmn_w32_entity_release(thread); + }break; + + ////////////////////// + //- rjf: DLL was loaded + // + case LOAD_DLL_DEBUG_EVENT: + { + DMN_W32_Entity *process = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Process, evt.dwProcessId); + + // rjf: extract image info + U64 module_base = (U64)evt.u.LoadDll.lpBaseOfDll; + DMN_W32_ImageInfo image_info = dmn_w32_image_info_from_process_base_vaddr(process->handle, module_base); + + // rjf: create module entity + DMN_W32_Entity *module = dmn_w32_entity_alloc(process, DMN_W32_EntityKind_Module, module_base); + { + module->handle = evt.u.LoadDll.hFile; + module->arch = image_info.arch; + module->module.vaddr_range = r1u64(module_base, module_base+image_info.size); + module->module.address_of_name_pointer = (U64)evt.u.LoadDll.lpImageName; + module->module.name_is_unicode = (evt.u.LoadDll.fUnicode != 0); + } + + // rjf: generate event + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_LoadModule; + e->process = dmn_w32_handle_from_entity(process); + e->module = dmn_w32_handle_from_entity(module); + e->arch = module->arch; + e->address = module_base; + e->size = image_info.size; + e->string = dmn_w32_full_path_from_module(arena, module); + } + }break; + + ////////////////////// + //- rjf: DLL was unloaded + // + case UNLOAD_DLL_DEBUG_EVENT: + { + U64 module_base = (U64)evt.u.UnloadDll.lpBaseOfDll; + DMN_W32_Entity *module = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Module, module_base); + DMN_W32_Entity *process = module->parent; + + // rjf: generate event + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_UnloadModule; + e->process = dmn_w32_handle_from_entity(process); + e->module = dmn_w32_handle_from_entity(module); + e->string = dmn_w32_full_path_from_module(arena, module); + } + + // rjf: release entity storage + dmn_w32_entity_release(module); + }break; + + ////////////////////// + //- rjf: exception was hit + // + case EXCEPTION_DEBUG_EVENT: + { + // NOTE(rjf): Notes on multithreaded breakpoint events + // (2021/11/1): + // + // When many threads are simultaneously running, multiple threads + // may hit a trap "at the same time". When this happens there will be + // multiple events in an internal queue that we cannot see. If there + // is another event in the queue we will not see it until we call + // ContinueDebugEvent again, in a subsequent call to demon_os_run. + // + // When we get a trap event, the instruction pointer stored + // in the event will have the address of the int 3 instruction that + // was hit. Our RIP register, however, will be one byte past that. + // So, to get the behavior we want, we need to set the RIP register + // back to the address of the int 3. + // + // To deal with the fact that we may get breakpoint events later that + // were actually from this run what we do is: + // + // #1. If we get a trap event, and it corresponds to a user submitted + // trap, then we treat it is a breakpoint event. + // #2. If we get a trap event, and it does NOT correspond to a user + // trap in this call: + // #A. If the actual unmodified instruction byte is NOT an int 3, + // then this is a queued event from a previous run that is no + // longer applicable and we skip it. + // #B. If the actual unmodified instruction is an int 3, then this + // becomes a trap event and we do not reset RIP. + + // NOTE(rjf): The exception record struct has a 32-bit version and a + // 64-bit version. We only currently handle the 64-bit version. + + //- rjf: unpack + DMN_W32_Entity *thread = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Thread, evt.dwThreadId); + DMN_W32_Entity *process = thread->parent; + EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; + EXCEPTION_RECORD *exception = &edi->ExceptionRecord; + U64 instruction_pointer = (U64)exception->ExceptionAddress; + + //- rjf: determine if this is the first breakpoint in a process + // (breakpoint notifying us that the debugger is attached) + B32 first_bp = 0; + if(!process->proc.did_first_bp && exception->ExceptionCode == DMN_W32_EXCEPTION_BREAKPOINT) + { + process->proc.did_first_bp = 1; + first_bp = 1; + } + + //- rjf: determine if this exception is a trap + B32 is_trap = (!first_bp && + (exception->ExceptionCode == DMN_W32_EXCEPTION_BREAKPOINT || + exception->ExceptionCode == DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN)); + + //- rjf: check if this trap is a usage-code-specified trap or something else + B32 hit_user_trap = 0; + if(is_trap) + { + for(DMN_TrapChunkNode *n = ctrls->traps.first; n != 0; n = n->next) + { + for(U64 idx = 0; idx < n->count; idx += 1) + { + if(dmn_handle_match(n->v[idx].process, dmn_w32_handle_from_entity(process)) && n->v[idx].vaddr == instruction_pointer) + { + hit_user_trap = 1; + break; + } + } + } + } + + //- rjf: check if trap is explicit in the actual code memory + B32 hit_explicit_trap = 0; + if(is_trap && !hit_user_trap) + { + U8 instruction_byte = 0; + if(dmn_w32_process_read_struct(process->handle, instruction_pointer, &instruction_byte)) + { + hit_explicit_trap = (instruction_byte == 0xCC || instruction_byte == 0xCD); + } + } + + //- rjf: determine whether to roll back instruction pointer + B32 should_do_rollback = (is_trap); + + //- rjf: roll back thread's instruction pointer + U64 post_trap_rip = 0; + if(should_do_rollback) + { + Temp temp = temp_begin(scratch.arena); + U64 regs_block_size = regs_block_size_from_architecture(thread->arch); + void *regs_block = push_array(scratch.arena, U8, regs_block_size); + if(dmn_w32_thread_read_reg_block(thread->arch, thread->handle, regs_block)) + { + post_trap_rip = regs_rip_from_arch_block(thread->arch, regs_block); + regs_arch_block_write_rip(thread->arch, regs_block, instruction_pointer); + dmn_w32_thread_write_reg_block(thread->arch, thread->handle, regs_block); + } + temp_end(temp); + } + + //- rjf: not a user trap, not an explicit trap, then it's a trap that + // this thread hit previously but has since skipped + B32 hit_previous_trap = (is_trap && !hit_user_trap && !hit_explicit_trap); + + //- rjf: determine whether to skip this event + B32 skip_event = (hit_previous_trap); + + //- rjf: generate event + if(!skip_event) + { + // rjf: fill top-level info + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_Exception; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(thread); + e->code = exception->ExceptionCode; + e->flags = exception->ExceptionFlags; + e->instruction_pointer = (U64)exception->ExceptionAddress; + + // rjf: explicit trap -> mark this thread as having reported this trap + if(hit_explicit_trap) + { + thread->thread.last_run_reported_trap = 1; + thread->thread.last_run_reported_trap_pre_rip = instruction_pointer; + thread->thread.last_run_reported_trap_post_rip = post_trap_rip; + } + + //- rjf: fill according to exception code + switch(exception->ExceptionCode) + { + //- rjf: fill breakpoint event info + case DMN_W32_EXCEPTION_BREAKPOINT: + { + DMN_EventKind report_event_kind = DMN_EventKind_Trap; + if(first_bp) + { + report_event_kind = DMN_EventKind_HandshakeComplete; + } + else if(hit_user_trap) + { + report_event_kind = DMN_EventKind_Breakpoint; + } + e->kind = report_event_kind; + }break; + + //- rjf: fill stack buffer overrun event info + case DMN_W32_EXCEPTION_STACK_BUFFER_OVERRUN: + { + e->kind = DMN_EventKind_Trap; + }break; + + //- rjf: fill single-step event info + case DMN_W32_EXCEPTION_SINGLE_STEP: + { + e->kind = DMN_EventKind_SingleStep; + }break; + + //- rjf: fill throw info + case DMN_W32_EXCEPTION_THROW: + { + U64 exception_sp = 0; + U64 exception_ip = 0; + if(exception->NumberParameters >= 3) + { + exception_sp = (U64)exception->ExceptionInformation[1]; + exception_ip = (U64)exception->ExceptionInformation[2]; + } + e->stack_pointer = exception_sp; + e->exception_kind = DMN_ExceptionKind_CppThrow; + e->exception_repeated = (edi->dwFirstChance == 0); + dmn_w32_shared->exception_not_handled = (edi->dwFirstChance != 0); + }break; + + //- rjf: fill access violation info + case DMN_W32_EXCEPTION_ACCESS_VIOLATION: + case DMN_W32_EXCEPTION_IN_PAGE_ERROR: + { + U64 exception_address = 0; + DMN_ExceptionKind exception_kind = DMN_ExceptionKind_Null; + if(exception->NumberParameters >= 2) + { + switch(exception->ExceptionInformation[0]) + { + case 0: exception_kind = DMN_ExceptionKind_MemoryRead; break; + case 1: exception_kind = DMN_ExceptionKind_MemoryWrite; break; + case 8: exception_kind = DMN_ExceptionKind_MemoryExecute; break; + } + exception_address = exception->ExceptionInformation[1]; + } + e->address = exception_address; + e->exception_kind = exception_kind; + e->exception_repeated = (edi->dwFirstChance == 0); + dmn_w32_shared->exception_not_handled = (edi->dwFirstChance != 0); + }break; + + //- rjf: fill set-thread-name info + case DMN_W32_EXCEPTION_SET_THREAD_NAME: + if(exception->NumberParameters >= 2) + { + U64 thread_name_address = exception->ExceptionInformation[1]; + DMN_W32_Entity *process = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Process, evt.dwProcessId); + String8List thread_name_strings = {0}; + { + U64 read_addr = thread_name_address; + U64 total_string_size = 0; + for(;total_string_size < KB(4);) + { + U8 *buffer = push_array_no_zero(scratch.arena, U8, 256); + B32 good_read = dmn_w32_process_read(process->handle, r1u64(read_addr, read_addr+256), buffer); + if(good_read) + { + U64 size = 256; + for(U64 idx = 0; idx < 256; idx += 1) + { + if(buffer[idx] == 0) + { + size = idx; + break; + } + } + String8 string_part = str8(buffer, size); + str8_list_push(scratch.arena, &thread_name_strings, string_part); + total_string_size += size; + read_addr += size; + if(size < 256) + { + break; + } + } + } + } + e->kind = DMN_EventKind_SetThreadName; + e->string = str8_list_join(arena, &thread_name_strings, 0); + if(exception->NumberParameters > 2) + { + e->code = exception->ExceptionInformation[2]; + } + }break; + + //- rjf: unhandled exception case + default: + { + e->exception_repeated = (edi->dwFirstChance == 0); + dmn_w32_shared->exception_not_handled = (edi->dwFirstChance != 0); + }break; + } + } + }break; + + ////////////////////// + //- rjf: output debug string was gathered + // + case OUTPUT_DEBUG_STRING_EVENT: + { + // rjf: unpack event + DMN_W32_Entity *process = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Process, evt.dwProcessId); + DMN_W32_Entity *thread = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Thread, evt.dwThreadId); + U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; + U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; + + // rjf: read memory + U8 *buffer = push_array_no_zero(arena, U8, string_size + 1); + dmn_w32_process_read(process->handle, r1u64(string_address, string_address+string_size), buffer); + buffer[string_size] = 0; + + // rjf: generate event + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_DebugString; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(thread); + e->string = str8(buffer, string_size); + if(string_size != 0 && buffer[string_size-1] == 0) + { + e->string.size -= 1; + } + } + }break; + + ////////////////////// + //- rjf: a "rip event" - a "system debugging error". + // + case RIP_EVENT: + { + DMN_W32_Entity *process = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Process, evt.dwProcessId); + DMN_W32_Entity *thread = dmn_w32_entity_from_kind_id(DMN_W32_EntityKind_Thread, evt.dwThreadId); + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_Exception; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(thread); + }break; + + ////////////////////// + //- rjf: default case - some kind of debugging event that we don't currently consume. + // + default: + { + NoOp; + }break; + } + } + + //- rjf: gather new thread-names + if(dmn_w32_GetThreadDescription != 0) + { + for(DMN_W32_Entity *process = dmn_w32_shared->entities_base->first; + process != &dmn_w32_entity_nil; + process = process->next) + { + if(process->kind != DMN_W32_EntityKind_Process) { continue; } + for(DMN_W32_Entity *thread = process->first; + thread != &dmn_w32_entity_nil; + thread = thread->next) + { + if(thread->kind != DMN_W32_EntityKind_Thread) { continue; } + if(thread->thread.last_name_hash == 0 || + thread->thread.name_gather_time_us+1000000 <= os_now_microseconds()) + { + String8 name = {0}; + { + WCHAR *thread_name_w = 0; + HRESULT hr = dmn_w32_GetThreadDescription(thread->handle, &thread_name_w); + if(SUCCEEDED(hr)) + { + name = str8_from_16(scratch.arena, str16_cstring((U16 *)thread_name_w)); + LocalFree(thread_name_w); + } + } + U64 name_hash = dmn_w32_hash_from_string(name); + if(name.size != 0 && name_hash != thread->thread.last_name_hash) + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_SetThreadName; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(thread); + e->string = push_str8_copy(arena, name); + } + thread->thread.name_gather_time_us = os_now_microseconds(); + thread->thread.last_name_hash = name_hash; + } + } + } + } + + ////////////////////////// + //- rjf: restore original memory at trap locations + // + { + U64 trap_idx = 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, trap_idx += 1) + { + DMN_Trap *trap = n->v+n_idx; + 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: unset single step bit + // + if(!dmn_handle_match(ctrls->single_step_thread, dmn_handle_zero())) + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(ctrls->single_step_thread); + Architecture arch = thread->arch; + switch(arch) + { + //- rjf: unimplemented win32/arch combos + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + + //- rjf: x86/64 + case Architecture_x86: + { + REGS_RegBlockX86 regs = {0}; + dmn_thread_read_reg_block(ctrls->single_step_thread, ®s); + regs.eflags.u32 &= ~0x100; + dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); + }break; + case Architecture_x64: + { + REGS_RegBlockX64 regs = {0}; + dmn_thread_read_reg_block(ctrls->single_step_thread, ®s); + regs.rflags.u64 &= ~0x100; + dmn_thread_write_reg_block(ctrls->single_step_thread, ®s); + }break; + } + } + + scratch_end(scratch); + }break; + + //////////////////////////// + //- rjf: produce debug events from queued up detached processes + // + case DMN_W32_EventGenPath_DetachProcesses: + { + for(DMN_HandleNode *n = dmn_w32_shared->detach_processes.first; n != 0; n = n->next) + { + DMN_W32_Entity *process = dmn_w32_entity_from_handle(n->v); + + // rjf: push exit thread events + for(DMN_W32_Entity *child = process->first; child != &dmn_w32_entity_nil; child = child->next) + { + if(child->kind == DMN_W32_EntityKind_Thread) + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_ExitThread; + e->process = dmn_w32_handle_from_entity(process); + e->thread = dmn_w32_handle_from_entity(child); + } + } + + // rjf: push unload module events + for(DMN_W32_Entity *child = process->first; child != &dmn_w32_entity_nil; child = child->next) + { + if(child->kind == DMN_W32_EntityKind_Module) + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_UnloadModule; + e->process = dmn_w32_handle_from_entity(process); + e->module = dmn_w32_handle_from_entity(child); + e->string = dmn_w32_full_path_from_module(arena, child); + } + } + + // rjf: push exit process event + { + DMN_Event *e = dmn_event_list_push(arena, &events); + e->kind = DMN_EventKind_ExitProcess; + e->process = dmn_w32_handle_from_entity(process); + } + + // rjf: free process + dmn_w32_entity_release(process); + } + + // rjf: reset queued up detached processes + MemoryZeroStruct(&dmn_w32_shared->detach_processes); + arena_clear(dmn_w32_shared->detach_arena); + }break; + } + + dmn_access_close(); + return events; +} + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Halting (Implemented Per-OS) + +internal void +dmn_halt(U64 code, U64 user_data) +{ + if(dmn_handle_match(dmn_handle_zero(), dmn_w32_shared->halter_process)) + { + DMN_W32_Entity *process = &dmn_w32_entity_nil; + for(DMN_W32_Entity *entity = dmn_w32_shared->entities_base->first; + entity != &dmn_w32_entity_nil; + entity = entity->next) + { + if(entity->kind == DMN_W32_EntityKind_Process) + { + process = entity; + break; + } + } + if(process != &dmn_w32_entity_nil) + { + dmn_w32_shared->halter_process = dmn_w32_handle_from_entity(process); + DMN_W32_InjectedBreak injection = {code, user_data}; + U64 data_injection_address = process->proc.injection_address + DMN_W32_INJECTED_CODE_SIZE; + dmn_w32_process_write_struct(process->handle, data_injection_address, &injection); + dmn_w32_shared->halter_tid = dmn_w32_inject_thread(process->handle, process->proc.injection_address); + } + } +} + +//////////////////////////////// +//~ rjf: @dmn_os_hooks Introspection Functions (Implemented Per-OS) + +//- rjf: run/memory/register counters + +internal U64 +dmn_run_gen(void) +{ + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->run_gen); + return result; +} + +internal U64 +dmn_mem_gen(void) +{ + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->mem_gen); + return result; +} + +internal U64 +dmn_reg_gen(void) +{ + U64 result = ins_atomic_u64_eval(&dmn_w32_shared->reg_gen); + return result; +} + +//- rjf: non-blocking-control-thread access barriers + +internal B32 +dmn_access_open(void) +{ + B32 result = 0; + if(dmn_w32_ctrl_thread) + { + result = 1; + } + else + { + os_mutex_take(dmn_w32_shared->access_mutex); + result = !dmn_w32_shared->access_run_state; + } + return result; +} + +internal void +dmn_access_close(void) +{ + if(!dmn_w32_ctrl_thread) + { + os_mutex_drop(dmn_w32_shared->access_mutex); + } +} + +//- rjf: processes + +internal U64 +dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst) +{ + U64 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); + result = dmn_w32_process_read(entity->handle, range, dst); + } + return result; +} + +internal B32 +dmn_process_write(DMN_Handle process, Rng1U64 range, void *src) +{ + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(process); + result = dmn_w32_process_write(entity->handle, range, src); + } + return result; +} + +//- rjf: threads + +internal Architecture +dmn_arch_from_thread(DMN_Handle handle) +{ + Architecture arch = Architecture_Null; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); + arch = entity->arch; + } + return arch; +} + +internal U64 +dmn_stack_base_vaddr_from_thread(DMN_Handle handle) +{ + U64 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + if(thread->kind == DMN_W32_EntityKind_Thread) + { + DMN_W32_Entity *process = thread->parent; + U64 tlb = thread->thread.thread_local_base; + switch(thread->arch) + { + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + case Architecture_x64: + { + U64 stack_base_addr = tlb + 0x8; + dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+8), &result); + }break; + case Architecture_x86: + { + U64 stack_base_addr = tlb + 0x4; + dmn_w32_process_read(process->handle, r1u64(stack_base_addr, stack_base_addr+4), &result); + }break; + } + } + } + return result; +} + +internal U64 +dmn_tls_root_vaddr_from_thread(DMN_Handle handle) +{ + U64 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *entity = dmn_w32_entity_from_handle(handle); + if(entity->kind == DMN_W32_EntityKind_Thread) + { + result = entity->thread.thread_local_base; + switch(entity->arch) + { + case Architecture_Null: + case Architecture_COUNT: + {}break; + case Architecture_arm64: + case Architecture_arm32: + {NotImplemented;}break; + case Architecture_x64: + { + result += 88; + }break; + case Architecture_x86: + { + result += 44; + }break; + } + } + } + return result; +} + +internal B32 +dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block) +{ + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + result = dmn_w32_thread_read_reg_block(thread->arch, thread->handle, reg_block); + } + return result; +} + +internal B32 +dmn_thread_write_reg_block(DMN_Handle handle, void *reg_block) +{ + B32 result = 0; + DMN_AccessScope + { + DMN_W32_Entity *thread = dmn_w32_entity_from_handle(handle); + result = dmn_w32_thread_write_reg_block(thread->arch, thread->handle, reg_block); + } + return result; +} + +//- rjf: system process listing + +internal void +dmn_process_iter_begin(DMN_ProcessIter *iter) +{ + MemoryZeroStruct(iter); + iter->v[0] = (U64)CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); +} + +internal B32 +dmn_process_iter_next(Arena *arena, DMN_ProcessIter *iter, DMN_ProcessInfo *info_out) +{ + B32 result = 0; + + //- rjf: get the next process entry + PROCESSENTRY32W process_entry = {sizeof(process_entry)}; + HANDLE snapshot = (HANDLE)iter->v[0]; + if(iter->v[1] == 0) + { + if(Process32FirstW(snapshot, &process_entry)) + { + result = 1; + } + } + else + { + if(Process32NextW(snapshot, &process_entry)) + { + result = 1; + } + } + + //- rjf: increment counter + iter->v[1] += 1; + + //- rjf: convert to process info + if(result) + { + info_out->name = str8_from_16(arena, str16_cstring((U16*)process_entry.szExeFile)); + info_out->pid = (U32)process_entry.th32ProcessID; + } + + return result; +} + +internal void +dmn_process_iter_end(DMN_ProcessIter *iter) +{ + CloseHandle((HANDLE)iter->v[0]); + MemoryZeroStruct(iter); +} diff --git a/src/demon/win32/demon_core_win32.h b/src/demon/win32/demon_core_win32.h new file mode 100644 index 00000000..02dd05d1 --- /dev/null +++ b/src/demon/win32/demon_core_win32.h @@ -0,0 +1,287 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef DEMON_CORE_WIN32_H +#define DEMON_CORE_WIN32_H + +//////////////////////////////// +//~ rjf: Windows Includes + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +//////////////////////////////// +//~ 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 + +//////////////////////////////// +//~ rjf: Win32 Register Codes + +#define DMN_W32_CTX_X86 0x00010000 +#define DMN_W32_CTX_X64 0x00100000 + +#define DMN_W32_CTX_INTEL_CONTROL 0x0001 +#define DMN_W32_CTX_INTEL_INTEGER 0x0002 +#define DMN_W32_CTX_INTEL_SEGMENTS 0x0004 +#define DMN_W32_CTX_INTEL_FLOATS 0x0008 +#define DMN_W32_CTX_INTEL_DEBUG 0x0010 +#define DMN_W32_CTX_INTEL_EXTENDED 0x0020 +#define DMN_W32_CTX_INTEL_XSTATE 0x0040 + +#define DMN_W32_CTX_X86_ALL (DMN_W32_CTX_X86 | \ +DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \ +DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_DEBUG | \ +DMN_W32_CTX_INTEL_EXTENDED) +#define DMN_W32_CTX_X64_ALL (DMN_W32_CTX_X64 | \ +DMN_W32_CTX_INTEL_CONTROL | DMN_W32_CTX_INTEL_INTEGER | \ +DMN_W32_CTX_INTEL_SEGMENTS | DMN_W32_CTX_INTEL_FLOATS | \ +DMN_W32_CTX_INTEL_DEBUG) + +//////////////////////////////// +//~ rjf: Per-Entity State + +typedef enum DMN_W32_EntityKind +{ + DMN_W32_EntityKind_Null, + DMN_W32_EntityKind_Root, + DMN_W32_EntityKind_Process, + DMN_W32_EntityKind_Thread, + DMN_W32_EntityKind_Module, + DMN_W32_EntityKind_COUNT +} +DMN_W32_EntityKind; + +typedef struct DMN_W32_Entity DMN_W32_Entity; +struct DMN_W32_Entity +{ + DMN_W32_Entity *first; + DMN_W32_Entity *last; + DMN_W32_Entity *next; + DMN_W32_Entity *prev; + DMN_W32_Entity *parent; + DMN_W32_EntityKind kind; + U32 gen; + U64 id; + HANDLE handle; + Architecture arch; + union + { + struct + { + U64 injection_address; + B32 did_first_bp; + } + proc; + struct + { + U64 thread_local_base; + U64 last_name_hash; + U64 name_gather_time_us; + B32 last_run_reported_trap; + U64 last_run_reported_trap_pre_rip; + U64 last_run_reported_trap_post_rip; + } + thread; + struct + { + Rng1U64 vaddr_range; + U64 address_of_name_pointer; + B32 is_main; + B32 name_is_unicode; + } + module; + }; +}; + +typedef struct DMN_W32_EntityNode DMN_W32_EntityNode; +struct DMN_W32_EntityNode +{ + DMN_W32_EntityNode *next; + DMN_W32_Entity *v; +}; + +typedef struct DMN_W32_EntityIDHashNode DMN_W32_EntityIDHashNode; +struct DMN_W32_EntityIDHashNode +{ + DMN_W32_EntityIDHashNode *next; + DMN_W32_EntityIDHashNode *prev; + U64 id; + DMN_W32_Entity *entity; +}; + +typedef struct DMN_W32_EntityIDHashSlot DMN_W32_EntityIDHashSlot; +struct DMN_W32_EntityIDHashSlot +{ + DMN_W32_EntityIDHashNode *first; + DMN_W32_EntityIDHashNode *last; +}; + +//////////////////////////////// +//~ rjf: Injection Types + +typedef struct DMN_W32_InjectedBreak DMN_W32_InjectedBreak; +struct DMN_W32_InjectedBreak +{ + U64 code; + U64 user_data; +}; + +#define DMN_W32_INJECTED_CODE_SIZE 32 + +//////////////////////////////// +//~ rjf: Image Info Types + +typedef struct DMN_W32_ImageInfo DMN_W32_ImageInfo; +struct DMN_W32_ImageInfo +{ + Architecture arch; + U32 size; +}; + +//////////////////////////////// +//~ rjf: Dynamically-Loaded Win32 Function Types + +typedef HRESULT DMN_W32_GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription); + +//////////////////////////////// +//~ rjf: Shared State Bundle + +typedef struct DMN_W32_Shared DMN_W32_Shared; +struct DMN_W32_Shared +{ + // rjf: top-level info + Arena *arena; + String8List env_strings; + + // rjf: access locking mechanism + OS_Handle access_mutex; + B32 access_run_state; + + // rjf: run/mem/reg gens + U64 run_gen; + U64 mem_gen; + U64 reg_gen; + + // rjf: detaching info + Arena *detach_arena; + DMN_HandleList detach_processes; + + // rjf: entity state + Arena *entities_arena; + DMN_W32_Entity *entities_base; + DMN_W32_Entity *entities_first_free; + U64 entities_count; + DMN_W32_EntityIDHashSlot *entities_id_hash_slots; + U64 entities_id_hash_slots_count; + DMN_W32_EntityIDHashNode *entities_id_hash_node_free; + + // rjf: launch state + B32 new_process_pending; + + // rjf: run results + B32 resume_needed; + U32 resume_pid; + U32 resume_tid; + B32 exception_not_handled; + + // rjf: halting info + DMN_Handle halter_process; + U32 halter_tid; +}; + +//////////////////////////////// +//~ rjf: Globals + +global DMN_W32_Shared *dmn_w32_shared = 0; +global DMN_W32_Entity dmn_w32_entity_nil = {&dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil, &dmn_w32_entity_nil}; +global DMN_W32_GetThreadDescriptionFunctionType *dmn_w32_GetThreadDescription = 0; +thread_static B32 dmn_w32_ctrl_thread = 0; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 dmn_w32_hash_from_string(String8 string); +internal U64 dmn_w32_hash_from_id(U64 id); + +//////////////////////////////// +//~ rjf: Entity Helpers + +//- rjf: entity <-> handle +internal DMN_Handle dmn_w32_handle_from_entity(DMN_W32_Entity *entity); +internal DMN_W32_Entity *dmn_w32_entity_from_handle(DMN_Handle handle); + +//- rjf: entity allocation/deallocation +internal DMN_W32_Entity *dmn_w32_entity_alloc(DMN_W32_Entity *parent, DMN_W32_EntityKind kind, U64 id); +internal void dmn_w32_entity_release(DMN_W32_Entity *entity); + +//- rjf: kind*id -> entity +internal DMN_W32_Entity *dmn_w32_entity_from_kind_id(DMN_W32_EntityKind kind, U64 id); + +//////////////////////////////// +//~ rjf: Module Info Extraction + +internal String8 dmn_w32_full_path_from_module(Arena *arena, DMN_W32_Entity *module); + +//////////////////////////////// +//~ rjf: Win32-Level Process/Thread Reads/Writes + +//- rjf: processes +internal U64 dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst); +internal B32 dmn_w32_process_write(HANDLE process, Rng1U64 range, void *src); +internal String8 dmn_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address); +internal String16 dmn_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address); +#define dmn_w32_process_read_struct(process, vaddr, ptr) dmn_w32_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) +#define dmn_w32_process_write_struct(process, vaddr, ptr) dmn_w32_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) +internal DMN_W32_ImageInfo dmn_w32_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr); + +//- rjf: threads +internal U16 dmn_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave); +internal U16 dmn_w32_xsave_tag_word_from_real_tag_word(U16 ftw); +internal B32 dmn_w32_thread_read_reg_block(Architecture arch, HANDLE thread, void *reg_block); +internal B32 dmn_w32_thread_write_reg_block(Architecture arch, HANDLE thread, void *reg_block); + +//- rjf: remote thread injection +internal DWORD dmn_w32_inject_thread(HANDLE process, U64 start_address); + +#endif // DEMON_CORE_WIN32_H diff --git a/src/demon/win32/demon_os_win32.c b/src/demon/win32/demon_os_win32.c deleted file mode 100644 index 435d13ee..00000000 --- a/src/demon/win32/demon_os_win32.c +++ /dev/null @@ -1,2147 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Globals - -global GetThreadDescriptionFunctionType *demon_w32_GetThreadDescription = 0; - -global B32 demon_w32_resume_needed = 0; -global DWORD demon_w32_resume_pid = 0; -global DWORD demon_w32_resume_tid = 0; - -global B32 demon_w32_exception_not_handled = 0; -global DEMON_Entity* demon_w32_halter_process = 0; -global DWORD demon_w32_halter_thread_id = 0; - -global B32 demon_w32_new_process_pending = 0; - -global Arena *demon_w32_ext_arena = 0 ; -global DEMON_W32_Ext *demon_w32_proc_ext_free = 0; - -global Arena *demon_w32_detach_proc_arena = 0; -global DEMON_EntityNode *demon_w32_first_detached_proc = 0; -global DEMON_EntityNode *demon_w32_last_detached_proc = 0; - -global String8List demon_w32_environment = {0}; - -//////////////////////////////// -//~ rjf: Helpers - -internal U64 -demon_w32_hash_from_string(String8 string) -{ - U64 result = 5381; - for(U64 i = 0; i < string.size; i += 1) - { - result = ((result << 5) + result) + string.str[i]; - } - return result; -} - -internal DEMON_W32_Ext* -demon_w32_ext_alloc(void){ - DEMON_W32_Ext *result = demon_w32_proc_ext_free; - if (result != 0){ - SLLStackPop(demon_w32_proc_ext_free); - } - else{ - result = push_array_no_zero(demon_w32_ext_arena, DEMON_W32_Ext, 1); - } - MemoryZeroStruct(result); - return(result); -} - -internal DEMON_W32_Ext* -demon_w32_ext(DEMON_Entity *entity){ - DEMON_W32_Ext *result = (DEMON_W32_Ext*)entity->ext; - return(result); -} - -internal U64 -demon_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size){ - U64 bytes_read = 0; - U8 *ptr = (U8*)dst; - U8 *opl = ptr + size; - U64 cursor = src_address; - for (;ptr < opl;){ - SIZE_T to_read = (SIZE_T)(opl - ptr); - SIZE_T actual_read = 0; - if (!ReadProcessMemory(process_handle, (LPCVOID)cursor, ptr, to_read, &actual_read)){ - bytes_read += actual_read; - break; - } - ptr += actual_read; - cursor += actual_read; - bytes_read += actual_read; - } - return bytes_read; -} - -internal B32 -demon_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size){ - B32 result = 1; - U8 *ptr = (U8*)src; - U8 *opl = ptr + size; - U64 cursor = dst_address; - for (;ptr < opl;){ - SIZE_T to_write = (SIZE_T)(opl - ptr); - SIZE_T actual_write = 0; - if (!WriteProcessMemory(process_handle, (LPVOID)cursor, ptr, to_write, &actual_write)){ - result = 0; - break; - } - ptr += actual_write; - cursor += actual_write; - } - return(result); -} - -internal String8 -demon_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address){ - // TODO(allen): this could be done better with a demon_w32_read_memory - // that returns a read amount instead of a success/fail. - - // scan piece by piece - Temp scratch = scratch_begin(&arena, 1); - String8List list = {0}; - - U64 max_cap = 256; - U64 cap = max_cap; - U64 read_p = address; - for (;;){ - U8 *block = push_array(scratch.arena, U8, cap); - for (;cap > 0;){ - if (demon_w32_read_memory(process_handle, block, read_p, cap)){ - break; - } - cap /= 2; - } - read_p += cap; - - U64 block_opl = 0; - for (;block_opl < cap; block_opl += 1){ - if (block[block_opl] == 0){ - break; - } - } - - if (block_opl > 0){ - str8_list_push(scratch.arena, &list, str8(block, block_opl)); - } - - if (block_opl < cap || cap == 0){ - break; - } - } - - // assemble results - String8 result = str8_list_join(arena, &list, 0); - scratch_end(scratch); - return(result); -} - -internal String16 -demon_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address){ - // TODO(allen): this could be done better with a demon_w32_read_memory - // that returns a read amount instead of a success/fail. - - // scan piece by piece - Temp scratch = scratch_begin(&arena, 1); - String8List list = {0}; - - U64 max_cap = 256; - U64 cap = max_cap; - U64 read_p = address; - for (;;){ - U8 *block = push_array(scratch.arena, U8, cap); - for (;cap > 1;){ - if (demon_w32_read_memory(process_handle, block, read_p, cap)){ - break; - } - cap /= 2; - } - read_p += cap; - - U16 *block16 = (U16*)block; - (void)block16; - U64 block_opl = 0; - for (;block_opl < cap; block_opl += 2){ - if (*(U16*)(block + block_opl) == 0){ - break; - } - } - - if (block_opl > 0){ - str8_list_push(scratch.arena, &list, str8(block, block_opl)); - } - - if (block_opl < cap || cap == 0){ - break; - } - } - - // assemble results - String8 joined = str8_list_join(arena, &list, 0); - String16 result = {(U16*)joined.str, joined.size/2}; - scratch_end(scratch); - return(result); -} - -internal DEMON_W32_ImageInfo -demon_w32_image_info_from_base(HANDLE process_handle, U64 base){ - // find pe offset in dos header - U32 pe_offset = 0; - - { - U64 dos_magic_off = base; - U16 dos_magic = 0; - demon_w32_read_struct(process_handle, &dos_magic, dos_magic_off); - if (dos_magic == DEMON_DOS_MAGIC){ - U64 pe_offset_off = base + OffsetOf(DEMON_DosHeader, coff_file_offset); - demon_w32_read_struct(process_handle, &pe_offset, pe_offset_off); - } - } - - // get coff header - B32 got_coff_header = 0; - U64 coff_header_off = 0; - DEMON_CoffHeader coff_header = {0}; - - if (pe_offset > 0){ - U64 pe_magic_off = base + pe_offset; - U32 pe_magic = 0; - demon_w32_read_struct(process_handle, &pe_magic, pe_magic_off); - if (pe_magic == DEMON_PE_MAGIC){ - coff_header_off = pe_magic_off + sizeof(pe_magic); - if (demon_w32_read_struct(process_handle, &coff_header, coff_header_off)){ - got_coff_header = 1; - } - } - } - - // get arch and size - DEMON_W32_ImageInfo result = zero_struct; - if (got_coff_header){ - U64 optional_size_off = 0; - - Architecture arch = Architecture_Null; - switch (coff_header.machine){ - case DEMON_CoffMachineType_X86: - { - arch = Architecture_x86; - optional_size_off = OffsetOf(DEMON_PeOptionalHeader32, sizeof_image); - }break; - - case DEMON_CoffMachineType_X64: - { - arch = Architecture_x64; - optional_size_off = OffsetOf(DEMON_PeOptionalHeader32Plus, sizeof_image); - }break; - - default: - {}break; - } - - if (arch != Architecture_Null){ - U64 optional_off = coff_header_off + sizeof(coff_header); - U32 size = 0; - if (demon_w32_read_struct(process_handle, &size, optional_off + optional_size_off)){ - result.arch = arch; - result.size = size; - } - } - } - - return(result); -} - -internal DWORD -demon_w32_inject_thread(DEMON_Entity *process, U64 start_address){ - LPTHREAD_START_ROUTINE start = (LPTHREAD_START_ROUTINE)start_address; - DEMON_Entity *entity = process; - DEMON_W32_Ext *process_ext = demon_w32_ext(entity); - DWORD thread_id = 0; - HANDLE thread = CreateRemoteThread(process_ext->proc.handle, 0, 0, start, 0, 0, &thread_id); - if (thread != 0){ - CloseHandle(thread); - } - return(thread_id); -} - -internal U16 -demon_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave){ - U16 result = 0; - U32 top = (fxsave->StatusWord >> 11) & 7; - for (U32 fpr = 0; fpr < 8; fpr += 1){ - U32 tag = 3; - if (fxsave->TagWord & (1 << fpr)){ - U32 st = (fpr - top)&7; - - REGS_Reg80 *fp = (REGS_Reg80*)&fxsave->FloatRegisters[st*16]; - U16 exponent = fp->sign1_exp15 & bitmask15; - U64 integer_part = fp->int1_frac63 >> 63; - U64 fraction_part = fp->int1_frac63 & bitmask63; - - // tag: 0 - normal; 1 - zero; 2 - special - tag = 2; - if (exponent == 0){ - if (integer_part == 0 && fraction_part == 0){ - tag = 1; - } - } - else if (exponent != bitmask15 && integer_part != 0){ - tag = 0; - } - } - result |= tag << (2 * fpr); - } - return(result); -} - -internal U16 -demon_w32_xsave_tag_word_from_real_tag_word(U16 ftw){ - U16 compact = 0; - for (U32 fpr = 0; fpr < 8; fpr++){ - U32 tag = (ftw >> (fpr * 2)) & 3; - if (tag != 3){ - compact |= (1 << fpr); - } - } - return(compact); -} - -internal DWORD -demon_w32_win32_from_memory_protect_flags(DEMON_MemoryProtectFlags flags){ - DWORD result = 0; - switch (flags){ - default: - case DEMON_MemoryProtectFlag_Read|DEMON_MemoryProtectFlag_Write: - case DEMON_MemoryProtectFlag_Write: - { - result = PAGE_READWRITE; - }break; - case DEMON_MemoryProtectFlag_Read|DEMON_MemoryProtectFlag_Write|DEMON_MemoryProtectFlag_Execute: - { - result = PAGE_EXECUTE_READWRITE; - }break; - case DEMON_MemoryProtectFlag_Execute: - { - result = PAGE_EXECUTE; - }break; - case DEMON_MemoryProtectFlag_Read: - { - result = PAGE_READONLY; - }break; - } - return(result); -} - -//////////////////////////////// -//~ rjf: Experiments - -internal void -demon_w32_peak_at_tls(DEMON_Handle thread_handle){ - DEMON_Entity *thread = demon_ent_ptr_from_handle(thread_handle); - if (thread != 0 && thread->kind == DEMON_EntityKind_Thread){ - - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - U64 tlb = thread_ext->thread.thread_local_base; - - U8 buffer[0x1000]; - demon_os_read_memory(thread->parent, buffer, tlb, 0x1000); - - int x = 0; - (void)x; - } -} - -//////////////////////////////// -//~ rjf: @demon_os_hooks Main Layer Initialization - -internal void -demon_os_init(void){ - demon_w32_ext_arena = arena_alloc(); - demon_w32_detach_proc_arena = arena_alloc(); - - // rjf: load Windows 10+ GetThreadDescription API - { - demon_w32_GetThreadDescription = (GetThreadDescriptionFunctionType *)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "GetThreadDescription"); - } - - // rjf: setup environment variables - { - CHAR *this_proc_env = GetEnvironmentStrings(); - U64 start_idx = 0; - for(U64 idx = 0;; idx += 1) - { - if(this_proc_env[idx] == 0) - { - if(start_idx == idx) - { - break; - } - else - { - String8 string = str8((U8 *)this_proc_env + start_idx, idx - start_idx); - str8_list_push(demon_w32_ext_arena, &demon_w32_environment, string); - start_idx = idx+1; - } - } - } - } -} - -//////////////////////////////// -//~ rjf: @demon_os_hooks Running/Halting - -internal DEMON_EventList -demon_os_run(Arena *arena, DEMON_OS_RunCtrls *ctrls){ - DEMON_EventList result = {0}; - - if (demon_ent_root == 0){ - DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error); - event->error_kind = DEMON_ErrorKind_NotInitialized; - } - else if (demon_ent_root->first == 0 && !demon_w32_new_process_pending){ - DEMON_Event *event = demon_push_event(arena, &result, DEMON_EventKind_Error); - event->error_kind = DEMON_ErrorKind_NotAttached; - } - else if(demon_w32_first_detached_proc != 0) - { - for(DEMON_EntityNode *n = demon_w32_first_detached_proc; n != 0; n = n->next) - { - DEMON_Entity *process = n->entity; - - // rjf: push exit thread events - for(DEMON_Entity *child = process->first; child != 0; child = child->next) - { - if(child->kind == DEMON_EntityKind_Thread) - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitThread); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(child); - } - } - - // rjf: push unload module events - for(DEMON_Entity *child = process->first; child != 0; child = child->next) - { - if(child->kind == DEMON_EntityKind_Module) - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_UnloadModule); - e->process = demon_ent_handle_from_ptr(process); - e->module = demon_ent_handle_from_ptr(child); - e->string = demon_os_full_path_from_module(arena, child); - } - } - - // rjf: push exit process event - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitProcess); - e->process = demon_ent_handle_from_ptr(process); - e->code = 0; - } - - // rjf: free process - demon_ent_release_root_and_children(process); - } - demon_w32_first_detached_proc = 0; - demon_w32_last_detached_proc = 0; - arena_clear(demon_w32_detach_proc_arena); - } - else{ - Temp scratch = scratch_begin(&arena, 1); - - // get the single step thread (if any) - DEMON_Entity *single_step_thread = ctrls->single_step_thread; - - // TODO(allen): dedup per architecture? - // set single step bit - if (single_step_thread != 0){ - // TODO(allen): possibly buggy - switch (single_step_thread->arch){ - case Architecture_x86: - { - REGS_RegBlockX86 regs = {0}; - demon_os_read_regs_x86(single_step_thread, ®s); - regs.eflags.u32 |= 0x100; - demon_os_write_regs_x86(single_step_thread, ®s); - }break; - - case Architecture_x64: - { - REGS_RegBlockX64 regs = {0}; - demon_os_read_regs_x64(single_step_thread, ®s); - regs.rflags.u64 |= 0x100; - demon_os_write_regs_x64(single_step_thread, ®s); - }break; - } - } - - // TODO(allen): per-Architecture implementation of traps - // set traps - U8 *trap_swap_bytes = push_array_no_zero(scratch.arena, U8, ctrls->trap_count); - - { - DEMON_OS_Trap *trap = ctrls->traps; - for (U64 i = 0; i < ctrls->trap_count; i += 1, trap += 1){ - if (demon_os_read_memory(trap->process, trap_swap_bytes + i, trap->address, 1)){ - U8 int3 = 0xCC; - demon_os_write_memory(trap->process, trap->address, &int3, 1); - } - else{ - trap_swap_bytes[i] = 0xCC; - } - } - } - - // determine how to resume from the last event - DWORD resume_code = DBG_CONTINUE; - if (demon_w32_exception_not_handled){ - if (!ctrls->ignore_previous_exception){ - resume_code = DBG_EXCEPTION_NOT_HANDLED; - } - } - demon_w32_exception_not_handled = 0; - - // list threads that run this time - DEMON_W32_EntityNode *first_run_thread = 0; - DEMON_W32_EntityNode *last_run_thread = 0; - - for(DEMON_Entity *process = demon_ent_root->first; - process != 0; - process = process->next){ - if (process->kind == DEMON_EntityKind_Process){ - - // determine if this process is frozen - B32 process_is_frozen = 0; - if (ctrls->run_entities_are_processes){ - for (U64 i = 0; i < ctrls->run_entity_count; i += 1){ - if (ctrls->run_entities[i] == process){ - process_is_frozen = 1; - break; - } - } - } - - for (DEMON_Entity *thread = process->first; - thread != 0; - thread = thread->next){ - if (thread->kind == DEMON_EntityKind_Thread){ - // determine if this thread is frozen - B32 is_frozen = 0; - - if (ctrls->single_step_thread != 0 && - ctrls->single_step_thread != thread){ - is_frozen = 1; - } - else{ - - if (ctrls->run_entities_are_processes){ - is_frozen = process_is_frozen; - } - else{ - for (U64 i = 0; i < ctrls->run_entity_count; i += 1){ - if (ctrls->run_entities[i] == thread){ - is_frozen = 1; - break; - } - } - } - - if (ctrls->run_entities_are_unfrozen){ - is_frozen = !is_frozen; - } - } - - // rjf: disregard all other rules if this is the halter thread - if(demon_w32_halter_thread_id == thread->id) - { - is_frozen = 0; - } - - // add this thread to the list - if (!is_frozen){ - DEMON_W32_EntityNode *node = push_array_no_zero(scratch.arena, DEMON_W32_EntityNode, 1); - SLLQueuePush(first_run_thread, last_run_thread, node); - node->entity = thread; - } - } - } - } - } - - // prep suspension state of threads that will be allowed to run - for(DEMON_W32_EntityNode *node = first_run_thread; - node != 0; - node = node->next) - { - DEMON_Entity *thread = node->entity; - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - DWORD resume_result = ResumeThread(thread_ext->thread.handle); - if(resume_result == max_U32) - { - // TODO(allen): Error. Unknown cause (do GetLastError, FromatMessage) - } - else - { - DWORD desired_counter = 0; - DWORD current_counter = resume_result - 1; - if(current_counter != desired_counter) - { - // NOTE(rjf): Warning. The user has manually suspended this thread, - // so even though from Demon's perspective it thinks this thread - // should run, it will not, because the user has manually called - // SuspendThread or used CREATE_SUSPENDED or whatever. - } - } - } - - // rjf: if run threads are marked as having reported an explicit trap - // on their last run, shift their RIPs past that trap instruction, so - // that they may continue - for(DEMON_W32_EntityNode *node = first_run_thread; - node != 0; - node = node->next) - { - DEMON_Entity *thread = node->entity; - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - if(thread_ext->thread.last_run_reported_trap) - { - Temp temp = temp_begin(scratch.arena); - U64 regs_block_size = regs_block_size_from_architecture(thread->arch); - void *regs_block = push_array(temp.arena, U8, regs_block_size); - B32 good = demon_os_read_regs(thread, regs_block); - U64 pre_rip = regs_rip_from_arch_block(thread->arch, regs_block); - if(good && pre_rip == thread_ext->thread.last_run_reported_trap_pre_rip) - { - regs_arch_block_write_rip(thread->arch, regs_block, thread_ext->thread.last_run_reported_trap_post_rip); - demon_os_write_regs(thread, regs_block); - } - temp_end(temp); - thread_ext->thread.last_run_reported_trap = 0; - thread_ext->thread.last_run_reported_trap_post_rip = 0; - } - } - - // send last saved continue signal - B32 good_state = 1; - if (demon_w32_resume_needed != 0){ - if (!ContinueDebugEvent(demon_w32_resume_pid, demon_w32_resume_tid, resume_code)){ - good_state = 0; - } - - demon_w32_resume_needed = 0; - demon_w32_resume_pid = 0; - demon_w32_resume_tid = 0; - } - - // wait for a new event from targets - DEBUG_EVENT evt = {0}; - B32 got_new_event = 0; - if (good_state){ - got_new_event = WaitForDebugEvent(&evt, INFINITE); - } - if (got_new_event){ - demon_w32_resume_needed = 1; - demon_w32_resume_pid = evt.dwProcessId; - demon_w32_resume_tid = evt.dwThreadId; - } - - // increment demon time - demon_time += 1; - - // reset all threads to paused state - if (got_new_event){ - for (DEMON_W32_EntityNode *node = first_run_thread; - node != 0; - node = node->next){ - DEMON_Entity *thread = node->entity; - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - DWORD suspend_result = SuspendThread(thread_ext->thread.handle); - if (suspend_result == max_U32){ - // TODO(allen): Error. Unknown cause (do GetLastError, FromatMessage) - // NOTE(allen): This can happen when the event is EXIT_THREAD_DEBUG_EVENT - // or EXIT_PROCESS_DEBUG_EVENT. After such an event SuspendThread - // gives error code 5 (access denied). This has no adverse effects, but if - // want to start reporting errors we should take care to avoid calling - // SuspendThread in that case. - } - else{ - DWORD desired_counter = 1; - DWORD current_counter = suspend_result + 1; - if (current_counter != desired_counter){ - // NOTE(rjf): Warning. We've suspended to something higher than 1. - // In this case, it means the user probably created the thread in - // a suspended state, or they called SuspendThread. - } - } - } - } - - // rjf: process event - if (got_new_event){ - got_new_event = 1; - - switch (evt.dwDebugEventCode){ - case CREATE_PROCESS_DEBUG_EVENT: - { - // pull outs - HANDLE process_handle = evt.u.CreateProcessInfo.hProcess; - HANDLE thread_handle = evt.u.CreateProcessInfo.hThread; - U64 module_base = (U64)evt.u.CreateProcessInfo.lpBaseOfImage; - DEMON_W32_ImageInfo image_info = demon_w32_image_info_from_base(process_handle, module_base); - - // init process entity - DEMON_Entity *process = demon_ent_new(demon_ent_root, DEMON_EntityKind_Process, evt.dwProcessId); - demon_proc_count += 1; - process->arch = image_info.arch; - DEMON_W32_Ext *process_ext = demon_w32_ext_alloc(); - process->ext = process_ext; - process_ext->proc.handle = process_handle; - - demon_w32_new_process_pending = 0; - - // init new associated entities - DEMON_Entity *thread = demon_ent_new(process, DEMON_EntityKind_Thread, evt.dwThreadId); - demon_thread_count += 1; - DEMON_W32_Ext *thread_ext = demon_w32_ext_alloc(); - thread->ext = thread_ext; - thread_ext->thread.handle = thread_handle; - thread_ext->thread.thread_local_base = (U64)evt.u.CreateProcessInfo.lpThreadLocalBase; - SuspendThread(thread_ext->thread.handle); - - DEMON_Entity *module = demon_ent_new(process, DEMON_EntityKind_Module, module_base); - demon_module_count += 1; - module->addr_range_dim = image_info.size; - DEMON_W32_Ext *module_ext = demon_w32_ext_alloc(); - module->ext = module_ext; - module_ext->module.handle = evt.u.CreateProcessInfo.hFile; - module_ext->module.address_of_name_pointer = (U64)evt.u.CreateProcessInfo.lpImageName; - module_ext->module.is_main = 1; - module_ext->module.name_is_unicode = (evt.u.CreateProcessInfo.fUnicode != 0); - - // injection memory - { - U8 injection_code[DEMON_W32_INJECTED_CODE_SIZE]; - injection_code[0] = 0xC3; - for (U64 i = 1; i < DEMON_W32_INJECTED_CODE_SIZE; i += 1){ - injection_code[i] = 0xCC; - } - - U64 injection_size = DEMON_W32_INJECTED_CODE_SIZE + sizeof(DEMON_W32_InjectedBreak); - U64 injection_address = (U64)VirtualAllocEx(process_ext->proc.handle, 0, injection_size, - MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE); - demon_os_write_memory(process, injection_address, injection_code, sizeof(injection_code)); - process_ext->proc.injection_address = injection_address; - } - - // generate events - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_CreateProcess); - e->process = demon_ent_handle_from_ptr(process); - e->code = evt.dwProcessId; - } - - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_CreateThread); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(thread); - e->code = evt.dwThreadId; - } - - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_LoadModule); - e->process = demon_ent_handle_from_ptr(process); - e->module = demon_ent_handle_from_ptr(module); - e->address = module_base; - e->size = image_info.size; - e->string = demon_os_full_path_from_module(arena, module); - } - }break; - - case EXIT_PROCESS_DEBUG_EVENT: - { - // get process entity - DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); - - if (process != 0){ - // update halter process pointer - if (process == demon_w32_halter_process){ - demon_w32_halter_process = 0; - } - - // generate events for threads & modules - for (DEMON_Entity *entity = process->first; - entity != 0; - entity = entity->next){ - if (entity->kind == DEMON_EntityKind_Thread){ - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitThread); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(entity); - } - else{ - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_UnloadModule); - e->process = demon_ent_handle_from_ptr(process); - e->module = demon_ent_handle_from_ptr(entity); - e->string = demon_os_full_path_from_module(arena, entity); - } - } - - // generate event for self - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitProcess); - e->process = demon_ent_handle_from_ptr(process); - e->code = evt.u.ExitProcess.dwExitCode; - - // free entity - demon_ent_release_root_and_children(process); - - // rjf: detach - { - DWORD pid = evt.dwProcessId; - DebugActiveProcessStop(pid); - } - } - }break; - - case CREATE_THREAD_DEBUG_EVENT: - { - // get process entity - DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); - - if (process != 0){ - // init new entity - DEMON_Entity *thread = demon_ent_new(process, DEMON_EntityKind_Thread, evt.dwThreadId); - demon_thread_count += 1; - DEMON_W32_Ext *thread_ext = demon_w32_ext_alloc(); - thread->ext = thread_ext; - thread_ext->thread.handle = evt.u.CreateThread.hThread; - thread_ext->thread.thread_local_base = (U64)evt.u.CreateThread.lpThreadLocalBase; - DWORD sus_result = SuspendThread(thread_ext->thread.handle); - (void)sus_result; - - // rjf: unpack thread name - String8 thread_name = {0}; - if(demon_w32_GetThreadDescription != 0) - { - WCHAR *thread_name_w = 0; - HRESULT hr = demon_w32_GetThreadDescription(evt.u.CreateThread.hThread, &thread_name_w); - if(SUCCEEDED(hr)) - { - thread_name = str8_from_16(arena, str16_cstring((U16 *)thread_name_w)); - LocalFree(thread_name_w); - } - } - - // rjf: determine if this is the halter thread - B32 is_halter = (evt.dwThreadId == demon_w32_halter_thread_id); - - // generate event for non-halters - if (is_halter == 0){ - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_CreateThread); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(thread); - e->code = evt.dwThreadId; - e->string = thread_name; - } - } - }break; - - case EXIT_THREAD_DEBUG_EVENT: - { - // get thread and process entity - DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); - - if (thread != 0){ - DEMON_Entity *process = thread->parent; - - // rjf: determine if this is the halter thread - B32 is_halter = (evt.dwThreadId == demon_w32_halter_thread_id); - - // rjf: generate a halt event if we're the halter - if (is_halter){ - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_Halt); - demon_w32_halter_process = 0; - (void)e; - } - - // rjf: generate normal thread exit event on non-halter-thread exist - if (!is_halter){ - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_ExitThread); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(thread); - e->code = evt.u.ExitThread.dwExitCode; - } - - // free entity - demon_ent_release_root_and_children(thread); - } - }break; - - case LOAD_DLL_DEBUG_EVENT: - { - // get process entity - DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); - - if (process != 0){ - // get image info - DEMON_W32_Ext *process_ext = demon_w32_ext(process); - HANDLE process_handle = process_ext->proc.handle; - U64 module_base = (U64)evt.u.LoadDll.lpBaseOfDll; - DEMON_W32_ImageInfo image_info = demon_w32_image_info_from_base(process_handle, module_base); - - // init new entity - DEMON_Entity *module = demon_ent_new(process, DEMON_EntityKind_Module, module_base); - module->addr_range_dim = image_info.size; - demon_module_count += 1; - DEMON_W32_Ext *module_ext = demon_w32_ext_alloc(); - module->ext = module_ext; - module_ext->module.handle = evt.u.LoadDll.hFile; - module_ext->module.address_of_name_pointer = (U64)evt.u.LoadDll.lpImageName; - module_ext->module.is_main = 0; - module_ext->module.name_is_unicode = (evt.u.LoadDll.fUnicode != 0); - - // generate events - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_LoadModule); - e->process = demon_ent_handle_from_ptr(process); - e->module = demon_ent_handle_from_ptr(module); - e->address = module_base; - e->size = image_info.size; - e->string = demon_os_full_path_from_module(arena, module); - } - } - }break; - - case UNLOAD_DLL_DEBUG_EVENT: - { - // get module and process entity - U64 module_base = (U64)evt.u.UnloadDll.lpBaseOfDll; - DEMON_Entity *module = demon_ent_map_entity_from_id(DEMON_EntityKind_Module, module_base); - - if (module != 0){ - DEMON_Entity *process = module->parent; - - // generate events - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_UnloadModule); - e->process = demon_ent_handle_from_ptr(process); - e->module = demon_ent_handle_from_ptr(module); - e->string = demon_os_full_path_from_module(arena, module); - } - - // free entity - demon_ent_release_root_and_children(module); - } - }break; - - case EXCEPTION_DEBUG_EVENT: - { - // NOTE(rjf): Notes on multithreaded breakpoint events - // (2021/11/1): - // - // When many threads are simultaneously running, multiple threads - // may hit a trap "at the same time". When this happens there will be - // multiple events in an internal queue that we cannot see. If there - // is another event in the queue we will not see it until we call - // ContinueDebugEvent again, in a subsequent call to demon_os_run. - // - // When we get a trap event, the instruction pointer stored - // in the event will have the address of the int 3 instruction that - // was hit. Our RIP register, however, will be one byte past that. - // So, to get the behavior we want, we need to set the RIP register - // back to the address of the int 3. - // - // To deal with the fact that we may get breakpoint events later that - // were actually from this run what we do is: - // - // #1. If we get a trap event, and it corresponds to a user submitted - // trap, then we treat it is a breakpoint event. - // #2. If we get a trap event, and it does NOT correspond to a user - // trap in this call: - // #A. If the actual unmodified instruction byte is NOT an int 3, - // then this is a queued event from a previous run that is no - // longer applicable and we skip it. - // #B. If the actual unmodified instruction is an int 3, then this - // becomes a trap event and we do not reset RIP. - - // get thread and process entity - DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); - - if (thread != 0){ - DEMON_Entity *process = thread->parent; - Assert(process->kind == DEMON_EntityKind_Process); - - DEMON_W32_Ext *process_ext = demon_w32_ext(process); - - // TODO(allen): the exception record has two forms, one for 32 bit and one for 64 bit mode. - - EXCEPTION_DEBUG_INFO *edi = &evt.u.Exception; - EXCEPTION_RECORD *exception = &edi->ExceptionRecord; - U64 instruction_pointer = (U64)exception->ExceptionAddress; - - // check if first BP - B32 first_bp = 0; - if (exception->ExceptionCode == DEMON_W32_EXCEPTION_BREAKPOINT && - !process_ext->proc.did_first_bp){ - process_ext->proc.did_first_bp = 1; - first_bp = 1; - } - - // rjf: check if trap - B32 is_trap = (!first_bp && - (exception->ExceptionCode == DEMON_W32_EXCEPTION_BREAKPOINT || - exception->ExceptionCode == DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN)); - - // rjf: check if this trap is currently registered - B32 hit_user_trap = 0; - if (is_trap){ - DEMON_OS_Trap *trap = ctrls->traps; - for (U64 i = 0; i < ctrls->trap_count; i += 1, trap += 1){ - if (trap->process == process && trap->address == instruction_pointer){ - hit_user_trap = 1; - break; - } - } - } - - // rjf: check if trap is explicit in the actual code memory - B32 hit_explicit_trap = 0; - if (is_trap && !hit_user_trap){ - U8 instruction_byte = 0; - if (demon_os_read_memory(process, &instruction_byte, instruction_pointer, 1)){ - // TODO(rjf): x86/x64 specific check - // TODO(rjf): do we need to check to make sure the instruction - // pointer has not changed? - hit_explicit_trap = (instruction_byte == 0xCC || - instruction_byte == 0xCD); - } - } - - // rjf: determine whether to roll back instruction pointer - B32 rollback = (is_trap); - - // rjf: roll back - U64 post_trap_rip = 0; - if(rollback) - { - Temp temp = temp_begin(scratch.arena); - U64 regs_block_size = regs_block_size_from_architecture(thread->arch); - void *regs_block = push_array(scratch.arena, U8, regs_block_size); - if(demon_os_read_regs(thread, regs_block)) - { - post_trap_rip = regs_rip_from_arch_block(thread->arch, regs_block); - regs_arch_block_write_rip(thread->arch, regs_block, instruction_pointer); - demon_os_write_regs(thread, regs_block); - } - temp_end(temp); - } - - // allen: if this is not a user trap or explicit trap it's a previous trap - B32 hit_previous_trap = (is_trap && !hit_user_trap && !hit_explicit_trap); - - // determine whether to skip this event - B32 skip_event = (hit_previous_trap); - - // emit event - if(!skip_event) - { - // rjf: fill top-level info - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_Exception); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(thread); - e->code = exception->ExceptionCode; - e->flags = exception->ExceptionFlags; - e->instruction_pointer = (U64)exception->ExceptionAddress; - - // rjf: explicit trap -> mark this thread as having reported this trap - if(hit_explicit_trap) - { - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - thread_ext->thread.last_run_reported_trap = 1; - thread_ext->thread.last_run_reported_trap_pre_rip = instruction_pointer; - thread_ext->thread.last_run_reported_trap_post_rip = post_trap_rip; - } - - // rjf: fill by exception code - switch (exception->ExceptionCode){ - case DEMON_W32_EXCEPTION_BREAKPOINT: - { - // rjf: determine event kind - DEMON_EventKind report_event_kind = DEMON_EventKind_Trap; - if (first_bp){ - report_event_kind = DEMON_EventKind_HandshakeComplete; - } - else if (hit_user_trap){ - report_event_kind = DEMON_EventKind_Breakpoint; - } - - // set event kind - e->kind = report_event_kind; - }break; - - case DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN: - { - e->kind = DEMON_EventKind_Trap; - }break; - - case DEMON_W32_EXCEPTION_SINGLE_STEP: - { - e->kind = DEMON_EventKind_SingleStep; - }break; - - case DEMON_W32_EXCEPTION_THROW: - { - U64 exception_sp = 0; - U64 exception_ip = 0; - if (exception->NumberParameters >= 3){ - exception_sp = (U64)exception->ExceptionInformation[1]; - exception_ip = (U64)exception->ExceptionInformation[2]; - } - e->stack_pointer = exception_sp; - e->exception_kind = DEMON_ExceptionKind_CppThrow; - e->exception_repeated = (edi->dwFirstChance == 0); - demon_w32_exception_not_handled = (edi->dwFirstChance != 0); - }break; - - case DEMON_W32_EXCEPTION_ACCESS_VIOLATION: - case DEMON_W32_EXCEPTION_IN_PAGE_ERROR: - { - U64 exception_address = 0; - DEMON_ExceptionKind exception_kind = DEMON_ExceptionKind_Null; - if (exception->NumberParameters >= 2){ - switch (exception->ExceptionInformation[0]){ - case 0: exception_kind = DEMON_ExceptionKind_MemoryRead; break; - case 1: exception_kind = DEMON_ExceptionKind_MemoryWrite; break; - case 8: exception_kind = DEMON_ExceptionKind_MemoryExecute; break; - } - exception_address = exception->ExceptionInformation[1]; - } - - e->address = exception_address; - e->exception_kind = exception_kind; - e->exception_repeated = (edi->dwFirstChance == 0); - demon_w32_exception_not_handled = (edi->dwFirstChance != 0); - }break; - - case DEMON_W32_EXCEPTION_SET_THREAD_NAME: - { - if(exception->NumberParameters >= 2) - { - U64 thread_name_address = exception->ExceptionInformation[1]; - DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); - String8List thread_name_strings = {0}; - { - U64 read_addr = thread_name_address; - U64 total_string_size = 0; - for(;total_string_size < KB(4);) - { - U8 *buffer = push_array_no_zero(scratch.arena, U8, 256); - B32 good_read = demon_os_read_memory(process, buffer, read_addr, 256); - if(good_read) - { - U64 size = 256; - for(U64 idx = 0; idx < 256; idx += 1) - { - if(buffer[idx] == 0) - { - size = idx; - break; - } - } - String8 string_part = str8(buffer, size); - str8_list_push(scratch.arena, &thread_name_strings, string_part); - total_string_size += size; - read_addr += size; - if(size < 256) - { - break; - } - } - } - } - e->kind = DEMON_EventKind_SetThreadName; - e->string = str8_list_join(arena, &thread_name_strings, 0); - if(exception->NumberParameters > 2) - { - e->code = exception->ExceptionInformation[2]; - } - } - }break; - - default: - { - demon_w32_exception_not_handled = (edi->dwFirstChance != 0); - }break; - } - } - } - }break; - - case OUTPUT_DEBUG_STRING_EVENT: - { - // get process entity - DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); - DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); - - U64 string_address = (U64)evt.u.DebugString.lpDebugStringData; - U64 string_size = (U64)evt.u.DebugString.nDebugStringLength; - - // TODO(allen): is the string in UTF-8 or UTF-16? - - U8 *buffer = push_array_no_zero(arena, U8, string_size + 1); - demon_os_read_memory(process, buffer, string_address, string_size); - buffer[string_size] = 0; - - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_DebugString); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(thread); - e->string = str8(buffer, string_size); - if(string_size != 0 && buffer[string_size-1] == 0) - { - e->string.size -= 1; - } - }break; - - case RIP_EVENT: - { - DEMON_Entity *process = demon_ent_map_entity_from_id(DEMON_EntityKind_Process, evt.dwProcessId); - DEMON_Entity *thread = demon_ent_map_entity_from_id(DEMON_EntityKind_Thread, evt.dwThreadId); - - // TODO(allen): this is not the right way to handle this event - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_Exception); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(thread); - e->flags = 0; - e->address = 0; - }break; - - default: - { - got_new_event = 0; - }break; - } - } - - //- rjf: gather new thread-names - if(demon_w32_GetThreadDescription != 0) - { - for(DEMON_Entity *process = demon_ent_root->first; - process != 0; - process = process->next) - { - if(process->kind != DEMON_EntityKind_Process) { continue; } - for(DEMON_Entity *thread = process->first; - thread != 0; - thread = thread->next) - { - if(thread->kind != DEMON_EntityKind_Thread) { continue; } - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - if(thread_ext->thread.last_name_hash == 0 || - thread_ext->thread.name_gather_time_us+1000000 <= os_now_microseconds()) - { - String8 name = {0}; - { - WCHAR *thread_name_w = 0; - HRESULT hr = demon_w32_GetThreadDescription(thread_ext->thread.handle, &thread_name_w); - if(SUCCEEDED(hr)) - { - name = str8_from_16(scratch.arena, str16_cstring((U16 *)thread_name_w)); - LocalFree(thread_name_w); - } - } - U64 name_hash = demon_w32_hash_from_string(name); - if(name.size != 0 && name_hash != thread_ext->thread.last_name_hash) - { - DEMON_Event *e = demon_push_event(arena, &result, DEMON_EventKind_SetThreadName); - e->process = demon_ent_handle_from_ptr(process); - e->thread = demon_ent_handle_from_ptr(thread); - e->string = push_str8_copy(arena, name); - } - thread_ext->thread.name_gather_time_us = os_now_microseconds(); - thread_ext->thread.last_name_hash = name_hash; - } - } - } - } - - // TODO(allen): handle errors? if (!got_new_event) ? if (!good_state) ? - - // TODO(allen): per-Architecture - // unset traps - { - DEMON_OS_Trap *trap = ctrls->traps; - for (U64 i = 0; i < ctrls->trap_count; i += 1, trap += 1){ - U8 og_byte = trap_swap_bytes[i]; - if (og_byte != 0xCC){ - demon_os_write_memory(trap->process, trap->address, &og_byte, 1); - } - } - } - - // TODO(allen): per-Architecture - // unset single step bit - // the single step bit is automatically unset whenever we single step - // but if *something else* happened, it will still be there ready to - // confound us later; so here we're just being sure it's taken out. - if (single_step_thread != 0){ - // TODO(allen): possibly buggy - switch (single_step_thread->arch){ - case Architecture_x86: - { - REGS_RegBlockX86 regs = {0}; - demon_os_read_regs_x86(single_step_thread, ®s); - regs.eflags.u32 &= ~0x100; - demon_os_write_regs_x86(single_step_thread, ®s); - }break; - - case Architecture_x64: - { - REGS_RegBlockX64 regs = {0}; - demon_os_read_regs_x64(single_step_thread, ®s); - regs.rflags.u64 &= ~0x100; - demon_os_write_regs_x64(single_step_thread, ®s); - }break; - } - } - - scratch_end(scratch); - } - - return(result); -} - -internal void -demon_os_halt(U64 code, U64 user_data){ - if (demon_ent_root != 0 && demon_w32_halter_process == 0){ - DEMON_Entity *process = demon_ent_root->first; - if (process != 0){ - DEMON_W32_Ext *process_ext = demon_w32_ext(process); - - demon_w32_halter_process = process; - DEMON_W32_InjectedBreak injection = {code, user_data}; - U64 data_injection_address = process_ext->proc.injection_address + DEMON_W32_INJECTED_CODE_SIZE; - demon_os_write_struct(process, data_injection_address, &injection); - demon_w32_halter_thread_id = demon_w32_inject_thread(process, process_ext->proc.injection_address); - } - } -} - -//////////////////////////////// -//~ rjf: @demon_os_hooks Target Process Launching/Attaching/Killing/Detaching/Halting - -internal U32 -demon_os_launch_process(OS_LaunchOptions *options){ - Temp scratch = scratch_begin(0, 0); - - // TODO(allen): maybe a good command line escaper/parser function pair? - String8 cmd = {0}; - if(options->cmd_line.first != 0) - { - String8List args = {0}; - String8 exe_path = options->cmd_line.first->string; - str8_list_pushf(scratch.arena, &args, "\"%S\"", exe_path); - for(String8Node *n = options->cmd_line.first->next; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &args, n->string); - } - StringJoin join_params = {0}; - join_params.sep = str8_lit(" "); - cmd = str8_list_join(scratch.arena, &args, &join_params); - } - - StringJoin join_params2 = {0}; - join_params2.sep = str8_lit("\0"); - join_params2.post = str8_lit("\0"); - String8List all_opts = options->env; - if(options->inherit_env != 0) - { - MemoryZeroStruct(&all_opts); - for(String8Node *n = options->env.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); - } - for(String8Node *n = demon_w32_environment.first; n != 0; n = n->next) - { - str8_list_push(scratch.arena, &all_opts, n->string); - } - } - String8 env = str8_list_join(scratch.arena, &all_opts, &join_params2); - - String16 cmd16 = str16_from_8(scratch.arena, cmd); - String16 dir16 = str16_from_8(scratch.arena, options->path); - String16 env16 = str16_from_8(scratch.arena, env); - - U32 result = 0; - - //- rjf: launch - DWORD access_flags = CREATE_UNICODE_ENVIRONMENT|DEBUG_PROCESS; - STARTUPINFOW startup_info = {sizeof(startup_info)}; - PROCESS_INFORMATION process_info = {0}; - AllocConsole(); - if (CreateProcessW(0, (WCHAR*)cmd16.str, 0, 0, 1, access_flags, (WCHAR*)env16.str, (WCHAR*)dir16.str, - &startup_info, &process_info)){ - // check if we are 32-bit app, and just close it immediately - BOOL is_wow = 0; - IsWow64Process(process_info.hProcess, &is_wow); - if ( is_wow ){ - MessageBox(0,"Sorry, The RAD Debugger only debugs 64-bit applications currently.","Process error",MB_OK|MB_ICONSTOP); - DebugActiveProcessStop(process_info.dwProcessId); - TerminateProcess(process_info.hProcess,0xffffffff); - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - } - else{ - CloseHandle(process_info.hProcess); - CloseHandle(process_info.hThread); - result = process_info.dwProcessId; - demon_w32_new_process_pending = 1; - } - } - 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); - } - - scratch_end(scratch); - return(result); -} - -internal B32 -demon_os_attach_process(U32 pid){ - B32 result = 0; - if (DebugActiveProcess((DWORD)pid)){ - result = 1; - demon_w32_new_process_pending = 1; - } - return(result); -} - -internal B32 -demon_os_kill_process(DEMON_Entity *process, U32 exit_code){ - B32 result = 0; - DEMON_W32_Ext *ext = demon_w32_ext(process); - if (TerminateProcess(ext->proc.handle, exit_code)){ - result = 1; - } - return(result); -} - -internal B32 -demon_os_detach_process(DEMON_Entity *process){ - B32 result = 0; - - // rjf: resume threads - for(DEMON_Entity *child = process->first; child != 0; child = child->next) - { - if(child->kind == DEMON_EntityKind_Thread) - { - DEMON_W32_Ext *thread_ext = demon_w32_ext(child); - DWORD resume_result = ResumeThread(thread_ext->thread.handle); - } - } - - // rjf: detach - { - DWORD pid = (DWORD)process->id; - if(DebugActiveProcessStop(pid)) - { - result = 1; - } - } - - // rjf: push into list - if(result != 0) - { - DEMON_EntityNode *n = push_array(demon_w32_detach_proc_arena, DEMON_EntityNode, 1); - n->entity = process; - SLLQueuePush(demon_w32_first_detached_proc, demon_w32_last_detached_proc, n); - } - - return(result); -} - -//////////////////////////////// -//~ rjf: @demon_os_hooks Entity Functions - -//- rjf: cleanup - -internal void -demon_os_entity_cleanup(DEMON_Entity *entity) -{ - if (entity->kind == DEMON_EntityKind_Process){ - DEMON_W32_Ext *ext = demon_w32_ext(entity); - SLLStackPush(demon_w32_proc_ext_free, ext); - } - else if(entity->kind == DEMON_EntityKind_Module) - { - DEMON_W32_Ext *ext = demon_w32_ext(entity); - CloseHandle(ext->module.handle); - } -} - -//- rjf: introspection - -internal String8 -demon_os_full_path_from_module(Arena *arena, DEMON_Entity *module){ - ProfBeginFunction(); - Temp scratch = scratch_begin(&arena, 1); - - // object -> handle - DEMON_W32_Ext *module_ext = (DEMON_W32_Ext*)module->ext; - HANDLE handle = module_ext->module.handle; - - String16 path16 = {0}; - String8 path8 = {0}; - - // handle -> full path - if (handle != 0){ - DWORD cap16 = GetFinalPathNameByHandleW(handle, 0, 0, VOLUME_NAME_DOS); - U16 *buffer16 = push_array_no_zero(scratch.arena, U16, cap16); - DWORD size16 = GetFinalPathNameByHandleW(handle, (WCHAR*)buffer16, cap16, VOLUME_NAME_DOS); - path16 = str16(buffer16, size16); - } - - // fallback (main module only): process -> full path - if (path16.size == 0 && module_ext->module.is_main){ - // process handle - DEMON_Entity *process = module->parent; - DEMON_W32_Ext *process_ext = (DEMON_W32_Ext*)process->ext; - HANDLE process_handle = process_ext->proc.handle; - - DWORD size = KB(4); - U16 *buf = push_array_no_zero(scratch.arena, U16, size); - if (QueryFullProcessImageNameW(process_handle, 0, (WCHAR*)buf, &size)){ - path16 = str16(buf, size); - } - } - - // fallback (any module - no gaurantee): address_of_name -> full path - if (path16.size == 0 && module_ext->module.address_of_name_pointer != 0){ - // process handle - DEMON_Entity *process = module->parent; - DEMON_W32_Ext *process_ext = (DEMON_W32_Ext*)process->ext; - HANDLE process_handle = process_ext->proc.handle; - - // TODO(allen): address size independence - U64 ptr_size = 8; - - U64 name_pointer = 0; - if (demon_w32_read_memory(process_handle, &name_pointer, module_ext->module.address_of_name_pointer, ptr_size)){ - if (name_pointer != 0){ - if (module_ext->module.name_is_unicode){ - path16 = demon_w32_read_memory_str16(scratch.arena, process_handle, name_pointer); - } - else{ - path8 = demon_w32_read_memory_str(scratch.arena, process_handle, name_pointer); - } - } - } - } - - // finalize the result - String8 result = {0}; - - if (path16.size > 0){ - // skip the extended path thing if necessary - if (path16.size >= 4 && - path16.str[0] == L'\\' && - path16.str[1] == L'\\' && - path16.str[2] == L'?' && - path16.str[3] == L'\\'){ - path16.size -= 4; - path16.str += 4; - } - - // convert result - result = str8_from_16(arena, path16); - } - else{ - // skip the extended path thing if necessary - if (path8.size >= 4 && - path8.str[0] == L'\\' && - path8.str[1] == L'\\' && - path8.str[2] == L'?' && - path8.str[3] == L'\\'){ - path8.size -= 4; - path8.str += 4; - } - - // copy the result - result = push_str8_copy(arena, path8); - } - - scratch_end(scratch); - ProfEnd(); - return(result); -} - -internal U64 -demon_os_stack_base_vaddr_from_thread(DEMON_Entity *thread){ - DEMON_Entity *process = thread->parent; - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - U64 tlb = thread_ext->thread.thread_local_base; - - U64 result = 0; - switch (thread->arch){ - case Architecture_x64: - { - U64 stack_base_addr = tlb + 0x8; - demon_os_read_memory(process, &result, stack_base_addr, 8); - }break; - - case Architecture_x86: - { - U64 stack_base_addr = tlb + 0x4; - demon_os_read_memory(process, &result, stack_base_addr, 4); - }break; - } - - return(result); -} - -internal U64 -demon_os_tls_root_vaddr_from_thread(DEMON_Entity *thread){ - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - U64 result = thread_ext->thread.thread_local_base; - switch (thread->arch){ - case Architecture_x64: - { - result += 88; - }break; - case Architecture_x86: - { - result += 44; - }break; - } - return(result); -} - -//- rjf: target process memory allocation/protection - -internal U64 -demon_os_reserve_memory(DEMON_Entity *process, U64 size){ - DEMON_W32_Ext *ext = demon_w32_ext(process); - void *ptr = VirtualAllocEx(ext->proc.handle, 0, size, MEM_RESERVE, PAGE_NOACCESS); - U64 result = (U64)ptr; - return(result); -} - -internal void -demon_os_set_memory_protect_flags(DEMON_Entity *process, U64 page_vaddr, U64 size, DEMON_MemoryProtectFlags flags){ - DEMON_W32_Ext *ext = demon_w32_ext(process); - DWORD w32_flags = demon_w32_win32_from_memory_protect_flags(flags); - DWORD old_flags = 0; - DWORD alloc_type = (flags == 0 ? MEM_DECOMMIT : MEM_COMMIT); - VirtualAllocEx(ext->proc.handle, (void *)page_vaddr, size, alloc_type, w32_flags); - (void)old_flags; -} - -internal void -demon_os_release_memory(DEMON_Entity *process, U64 vaddr, U64 size){ - DEMON_W32_Ext *ext = demon_w32_ext(process); - VirtualFreeEx(ext->proc.handle, (void *)vaddr, 0, MEM_RELEASE); -} - -//- rjf: target process memory reading/writing - -internal U64 -demon_os_read_memory(DEMON_Entity *process, void *dst, U64 src_address, U64 size){ - DEMON_W32_Ext *process_ext = demon_w32_ext(process); - HANDLE handle = process_ext->proc.handle; - U64 result = demon_w32_read_memory(handle, dst, src_address, size); - return(result); -} - -internal B32 -demon_os_write_memory(DEMON_Entity *process, U64 dst_address, void *src, U64 size){ - DEMON_W32_Ext *process_ext = demon_w32_ext(process); - HANDLE handle = process_ext->proc.handle; - B32 result = demon_w32_write_memory(handle, dst_address, src, size); - return(result); -} - -//- rjf: thread registers reading/writing - -internal B32 -demon_os_read_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *dst){ - B32 result = 0; - - // NOTE(allen): Get Thread Context - WOW64_CONTEXT ctx = {0}; - ctx.ContextFlags = DEMON_W32_CTX_X86_ALL; - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - HANDLE handle = thread_ext->thread.handle; - if (Wow64GetThreadContext(handle, (WOW64_CONTEXT *)&ctx)){ - result = 1; - - // NOTE(allen): Convert WOW64_CONTEXT -> REGS_RegBlockX86 - dst->eax.u32 = ctx.Eax; - dst->ebx.u32 = ctx.Ebx; - dst->ecx.u32 = ctx.Ecx; - dst->edx.u32 = ctx.Edx; - dst->esi.u32 = ctx.Esi; - dst->edi.u32 = ctx.Edi; - dst->esp.u32 = ctx.Esp; - dst->ebp.u32 = ctx.Ebp; - dst->eip.u32 = ctx.Eip; - dst->cs.u16 = ctx.SegCs; - dst->ds.u16 = ctx.SegDs; - dst->es.u16 = ctx.SegEs; - 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; - - // NOTE(allen): This bit is "supposed to always be 1" I guess. - // TODO(allen): Not sure what this is all about but I haven't investigated it yet. - // This might be totally not necessary or something. - dst->eflags.u32 = ctx.EFlags | 0x2; - - XSAVE_FORMAT *fxsave = (XSAVE_FORMAT*)ctx.ExtendedRegisters; - dst->fcw.u16 = fxsave->ControlWord; - dst->fsw.u16 = fxsave->StatusWord; - dst->ftw.u16 = demon_w32_real_tag_word_from_xsave(fxsave); - dst->fop.u16 = fxsave->ErrorOpcode; - dst->fip.u32 = fxsave->ErrorOffset; - dst->fcs.u16 = fxsave->ErrorSelector; - dst->fdp.u32 = fxsave->DataOffset; - dst->fds.u16 = fxsave->DataSelector; - dst->mxcsr.u32 = fxsave->MxCsr; - dst->mxcsr_mask.u32 = fxsave->MxCsr_Mask; - - M128A *float_s = fxsave->FloatRegisters; - REGS_Reg80 *float_d = &dst->fpr0; - for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, sizeof(*float_d)); - } - - M128A *xmm_s = fxsave->XmmRegisters; - REGS_Reg256 *xmm_d = &dst->ymm0; - for (U32 n = 0; n < 8; n += 1, xmm_s += 1, xmm_d += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); - } - - // read FS/GS base - WOW64_LDT_ENTRY ldt = {0}; - - if (Wow64GetThreadSelectorEntry(handle, ctx.SegFs, &ldt)){ - U32 base = (ldt.BaseLow) | (ldt.HighWord.Bytes.BaseMid << 16) | (ldt.HighWord.Bytes.BaseHi << 24); - dst->fsbase.u32 = base; - } - if (Wow64GetThreadSelectorEntry(handle, ctx.SegGs, &ldt)){ - U32 base = (ldt.BaseLow) | (ldt.HighWord.Bytes.BaseMid << 16) | (ldt.HighWord.Bytes.BaseHi << 24); - dst->gsbase.u32 = base; - } - } - - return(result); -} - -internal B32 -demon_os_write_regs_x86(DEMON_Entity *thread, REGS_RegBlockX86 *src){ - // NOTE(allen): Convert REGS_RegBlockX86 -> WOW64_CONTEXT - WOW64_CONTEXT ctx = {0}; - ctx.ContextFlags = DEMON_W32_CTX_X86_ALL; - ctx.Eax = src->eax.u32; - ctx.Ebx = src->ebx.u32; - ctx.Ecx = src->ecx.u32; - ctx.Edx = src->edx.u32; - ctx.Esi = src->esi.u32; - ctx.Edi = src->edi.u32; - ctx.Esp = src->esp.u32; - ctx.Ebp = src->ebp.u32; - ctx.Eip = src->eip.u32; - ctx.SegCs = src->cs.u16; - ctx.SegDs = src->ds.u16; - ctx.SegEs = src->es.u16; - 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.EFlags = src->eflags.u32; - - XSAVE_FORMAT *fxsave = (XSAVE_FORMAT*)ctx.ExtendedRegisters; - fxsave->ControlWord = src->fcw.u16; - fxsave->StatusWord = src->fsw.u16; - fxsave->TagWord = demon_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); - fxsave->ErrorOpcode = src->fop.u16; - fxsave->ErrorSelector = src->fcs.u16; - fxsave->DataSelector = src->fds.u16; - fxsave->ErrorOffset = src->fip.u32; - fxsave->DataOffset = src->fdp.u32; - fxsave->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; - fxsave->MxCsr_Mask = src->mxcsr_mask.u32; - - M128A *float_d = fxsave->FloatRegisters; - REGS_Reg80 *float_s = &src->fpr0; - for (U32 n = 0; - n < 8; - n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, 10); - } - - M128A *xmm_d = fxsave->XmmRegisters; - REGS_Reg256 *xmm_s = &src->ymm0; - for (U32 n = 0; - n < 8; - n += 1, xmm_d += 1, xmm_s += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); - } - - // set thread context - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - HANDLE handle = thread_ext->thread.handle; - B32 result = 0; - if (Wow64SetThreadContext(handle, &ctx)){ - result = 1; - } - - return(result); -} - -internal B32 -demon_os_read_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *dst){ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - DWORD size = 0; - InitializeContext(0, ctx_flags, 0, &size); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ - void *ctx_memory = push_array(scratch.arena, U8, size); - if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ - ctx = 0; - } - } - - B32 avx_available = 0; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = 1; - } - } - } - - // get thread context - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - HANDLE thread_handle = thread_ext->thread.handle; - if (!GetThreadContext(thread_handle, ctx)){ - ctx = 0; - } - - B32 result = 0; - if (ctx != 0){ - result = 1; - - // NOTE(allen): Convert CONTEXT -> REGS_RegBlockX64 - dst->rax.u64 = ctx->Rax; - dst->rcx.u64 = ctx->Rcx; - dst->rdx.u64 = ctx->Rdx; - dst->rbx.u64 = ctx->Rbx; - dst->rsp.u64 = ctx->Rsp; - dst->rbp.u64 = ctx->Rbp; - dst->rsi.u64 = ctx->Rsi; - dst->rdi.u64 = ctx->Rdi; - dst->r8.u64 = ctx->R8; - dst->r9.u64 = ctx->R9; - dst->r10.u64 = ctx->R10; - dst->r11.u64 = ctx->R11; - dst->r12.u64 = ctx->R12; - dst->r13.u64 = ctx->R13; - dst->r14.u64 = ctx->R14; - dst->r15.u64 = ctx->R15; - dst->rip.u64 = ctx->Rip; - dst->cs.u16 = ctx->SegCs; - dst->ds.u16 = ctx->SegDs; - dst->es.u16 = ctx->SegEs; - 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; - - // NOTE(allen): This bit is "supposed to always be 1" I guess. - // TODO(allen): Not sure what this is all about but I haven't investigated it yet. - // This might be totally not necessary or something. - dst->rflags.u64 = ctx->EFlags | 0x2; - - XSAVE_FORMAT *xsave = &ctx->FltSave; - dst->fcw.u16 = xsave->ControlWord; - dst->fsw.u16 = xsave->StatusWord; - dst->ftw.u16 = demon_w32_real_tag_word_from_xsave(xsave); - dst->fop.u16 = xsave->ErrorOpcode; - dst->fcs.u16 = xsave->ErrorSelector; - dst->fds.u16 = xsave->DataSelector; - dst->fip.u32 = xsave->ErrorOffset; - dst->fdp.u32 = xsave->DataOffset; - dst->mxcsr.u32 = xsave->MxCsr; - dst->mxcsr_mask.u32 = xsave->MxCsr_Mask; - - M128A *float_s = xsave->FloatRegisters; - REGS_Reg80 *float_d = &dst->fpr0; - for (U32 n = 0; n < 8; n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, sizeof(*float_d)); - } - - if (!avx_available){ - M128A *xmm_s = xsave->XmmRegisters; - REGS_Reg256 *xmm_d = &dst->ymm0; - for (U32 n = 0; n < 16; n += 1, xmm_s += 1, xmm_d += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_s)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - REGS_Reg256 *ymm_d = &dst->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - ymm_d->u64[3] = part0->Low; - ymm_d->u64[2] = part0->High; - ymm_d->u64[1] = part1->Low; - ymm_d->u64[0] = part1->High; - } - } - - } - - scratch_end(scratch); - return(result); -} - -internal B32 -demon_os_write_regs_x64(DEMON_Entity *thread, REGS_RegBlockX64 *src){ - Temp scratch = scratch_begin(0, 0); - - // NOTE(allen): Check available features - U32 feature_mask = GetEnabledXStateFeatures(); - B32 avx_enabled = !!(feature_mask & XSTATE_MASK_AVX); - - // NOTE(allen): Setup the context - CONTEXT *ctx = 0; - U32 ctx_flags = DEMON_W32_CTX_X64_ALL; - if (avx_enabled){ - ctx_flags |= DEMON_W32_CTX_INTEL_XSTATE; - } - DWORD size = 0; - InitializeContext(0, ctx_flags, 0, &size); - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER){ - void *ctx_memory = push_array(scratch.arena, U8, size); - if (!InitializeContext(ctx_memory, ctx_flags, &ctx, &size)){ - ctx = 0; - } - } - - B32 avx_available = 0; - - if (ctx != 0){ - // NOTE(allen): Finish Context Setup - if (avx_enabled){ - SetXStateFeaturesMask(ctx, XSTATE_MASK_AVX); - } - - // NOTE(allen): Determine what features are available on this particular ctx - // TODO(allen): Experiment carefully with this nonsense. - // Does avx_enabled = avx_available in all circumstances or not? - DWORD64 xstate_flags = 0; - if (GetXStateFeaturesMask(ctx, &xstate_flags)){ - if (xstate_flags & XSTATE_MASK_AVX){ - avx_available = 1; - } - } - } - - B32 result = 0; - if (ctx != 0){ - // NOTE(allen): Convert REGS_RegBlockX64 -> CONTEXT - ctx->ContextFlags = ctx_flags; - - ctx->MxCsr = src->mxcsr.u32 & src->mxcsr_mask.u32; - - ctx->Rax = src->rax.u64; - ctx->Rcx = src->rcx.u64; - ctx->Rdx = src->rdx.u64; - ctx->Rbx = src->rbx.u64; - ctx->Rsp = src->rsp.u64; - ctx->Rbp = src->rbp.u64; - ctx->Rsi = src->rsi.u64; - ctx->Rdi = src->rdi.u64; - ctx->R8 = src->r8.u64; - ctx->R9 = src->r9.u64; - ctx->R10 = src->r10.u64; - ctx->R11 = src->r11.u64; - ctx->R12 = src->r12.u64; - ctx->R13 = src->r13.u64; - ctx->R14 = src->r14.u64; - ctx->R15 = src->r15.u64; - ctx->Rip = src->rip.u64; - ctx->SegCs = src->cs.u16; - ctx->SegDs = src->ds.u16; - ctx->SegEs = src->es.u16; - 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->EFlags = src->rflags.u64; - - XSAVE_FORMAT *fxsave = &ctx->FltSave; - fxsave->ControlWord = src->fcw.u16; - fxsave->StatusWord = src->fsw.u16; - fxsave->TagWord = demon_w32_xsave_tag_word_from_real_tag_word(src->ftw.u16); - fxsave->ErrorOpcode = src->fop.u16; - fxsave->ErrorSelector = src->fcs.u16; - fxsave->DataSelector = src->fds.u16; - fxsave->ErrorOffset = src->fip.u32; - fxsave->DataOffset = src->fdp.u32; - - M128A *float_d = fxsave->FloatRegisters; - REGS_Reg80 *float_s = &src->fpr0; - for (U32 n = 0; - n < 8; - n += 1, float_s += 1, float_d += 1){ - MemoryCopy(float_d, float_s, 10); - } - - if (!avx_available){ - M128A *xmm_d = fxsave->XmmRegisters; - REGS_Reg256 *xmm_s = &src->ymm0; - for (U32 n = 0; - n < 8; - n += 1, xmm_d += 1, xmm_s += 1){ - MemoryCopy(xmm_d, xmm_s, sizeof(*xmm_d)); - } - } - - if (avx_available){ - DWORD part0_length = 0; - M128A *part0 = (M128A*)LocateXStateFeature(ctx, XSTATE_LEGACY_SSE, &part0_length); - DWORD part1_length = 0; - M128A *part1 = (M128A*)LocateXStateFeature(ctx, XSTATE_AVX, &part1_length); - Assert(part0_length == part1_length); - - DWORD count = part0_length/sizeof(part0[0]); - count = ClampTop(count, 16); - REGS_Reg256 *ymm_d = &src->ymm0; - for (DWORD i = 0; - i < count; - i += 1, part0 += 1, part1 += 1, ymm_d += 1){ - // TODO(allen): Are we writing these out in the right order? Seems weird right? - part0->Low = ymm_d->u64[3]; - part0->High = ymm_d->u64[2]; - part1->Low = ymm_d->u64[1]; - part1->High = ymm_d->u64[0]; - } - } - - //- set thread context - DEMON_W32_Ext *thread_ext = demon_w32_ext(thread); - HANDLE thread_handle = thread_ext->thread.handle; - if (SetThreadContext(thread_handle, ctx)){ - result = 1; - } - } - - scratch_end(scratch); - return(result); -} - -//////////////////////////////// -//~ rjf: @demon_os_hooks Process Listing - -internal void -demon_os_proc_iter_begin(DEMON_ProcessIter *iter){ - MemoryZeroStruct(iter); - iter->v[0] = (U64)CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); -} - -internal B32 -demon_os_proc_iter_next(Arena *arena, DEMON_ProcessIter *iter, DEMON_ProcessInfo *info_out){ - // get the next process entry - B32 result = 0; - PROCESSENTRY32W process_entry = {sizeof(process_entry)}; - HANDLE snapshot = (HANDLE)iter->v[0]; - if (iter->v[1] == 0){ - if (Process32FirstW(snapshot, &process_entry)){ - result = 1; - } - } - else{ - if (Process32NextW(snapshot, &process_entry)){ - result = 1; - } - } - - // increment counter - iter->v[1] += 1; - - // convert to process info - if (result){ - info_out->name = str8_from_16(arena, str16_cstring((U16*)process_entry.szExeFile)); - info_out->pid = (U32)process_entry.th32ProcessID; - } - - return(result); -} - -internal void -demon_os_proc_iter_end(DEMON_ProcessIter *iter){ - CloseHandle((HANDLE)iter->v[0]); - MemoryZeroStruct(iter); -} diff --git a/src/demon/win32/demon_os_win32.h b/src/demon/win32/demon_os_win32.h deleted file mode 100644 index 7233e0d0..00000000 --- a/src/demon/win32/demon_os_win32.h +++ /dev/null @@ -1,385 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef DEMON_OS_WIN32_H -#define DEMON_OS_WIN32_H - -//////////////////////////////// -//~ NOTE(allen): Win32 Demon Headers Negotation - -// windows headers -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -//////////////////////////////// -//~ NOTE(allen): Win32 Demon Types - -//- entities - -// Demon Win32 Entity Extensions -// Process: ext points to independently allocated DEMON_W32_Ext -// Thread : ext points to independently allocated DEMON_W32_Ext -// Module : ext set to HANDLE - -typedef union DEMON_W32_Ext DEMON_W32_Ext; -union DEMON_W32_Ext -{ - DEMON_W32_Ext *next; - struct{ - HANDLE handle; - U64 injection_address; - B32 did_first_bp; - } proc; - struct{ - HANDLE handle; - U64 thread_local_base; - U64 last_name_hash; - U64 name_gather_time_us; - B32 last_run_reported_trap; - U64 last_run_reported_trap_pre_rip; - U64 last_run_reported_trap_post_rip; - } thread; - struct{ - HANDLE handle; - U64 address_of_name_pointer; - B32 is_main; - B32 name_is_unicode; - } module; -}; - -//- helpers - -typedef struct DEMON_W32_InjectedBreak DEMON_W32_InjectedBreak; -struct DEMON_W32_InjectedBreak -{ - U64 code; - U64 user_data; -}; -#define DEMON_W32_INJECTED_CODE_SIZE 32 - -typedef struct DEMON_W32_ImageInfo DEMON_W32_ImageInfo; -struct DEMON_W32_ImageInfo -{ - Architecture arch; - U32 size; -}; - -typedef struct DEMON_W32_EntityNode DEMON_W32_EntityNode; -struct DEMON_W32_EntityNode -{ - DEMON_W32_EntityNode *next; - DEMON_Entity *entity; -}; - -typedef HRESULT GetThreadDescriptionFunctionType(HANDLE hThread, WCHAR **ppszThreadDescription); - -//////////////////////////////// -//~ NOTE(allen): Win32 Demon Exceptions - -#define DEMON_W32_EXCEPTION_BREAKPOINT 0x80000003u -#define DEMON_W32_EXCEPTION_SINGLE_STEP 0x80000004u -#define DEMON_W32_EXCEPTION_LONG_JUMP 0x80000026u -#define DEMON_W32_EXCEPTION_ACCESS_VIOLATION 0xC0000005u -#define DEMON_W32_EXCEPTION_ARRAY_BOUNDS_EXCEEDED 0xC000008Cu -#define DEMON_W32_EXCEPTION_DATA_TYPE_MISALIGNMENT 0x80000002u -#define DEMON_W32_EXCEPTION_GUARD_PAGE_VIOLATION 0x80000001u -#define DEMON_W32_EXCEPTION_FLT_DENORMAL_OPERAND 0xC000008Du -#define DEMON_W32_EXCEPTION_FLT_DEVIDE_BY_ZERO 0xC000008Eu -#define DEMON_W32_EXCEPTION_FLT_INEXACT_RESULT 0xC000008Fu -#define DEMON_W32_EXCEPTION_FLT_INVALID_OPERATION 0xC0000090u -#define DEMON_W32_EXCEPTION_FLT_OVERFLOW 0xC0000091u -#define DEMON_W32_EXCEPTION_FLT_STACK_CHECK 0xC0000092u -#define DEMON_W32_EXCEPTION_FLT_UNDERFLOW 0xC0000093u -#define DEMON_W32_EXCEPTION_INT_DIVIDE_BY_ZERO 0xC0000094u -#define DEMON_W32_EXCEPTION_INT_OVERFLOW 0xC0000095u -#define DEMON_W32_EXCEPTION_PRIVILEGED_INSTRUCTION 0xC0000096u -#define DEMON_W32_EXCEPTION_ILLEGAL_INSTRUCTION 0xC000001Du -#define DEMON_W32_EXCEPTION_IN_PAGE_ERROR 0xC0000006u -#define DEMON_W32_EXCEPTION_INVALID_DISPOSITION 0xC0000026u -#define DEMON_W32_EXCEPTION_NONCONTINUABLE 0xC0000025u -#define DEMON_W32_EXCEPTION_STACK_OVERFLOW 0xC00000FDu -#define DEMON_W32_EXCEPTION_INVALID_HANDLE 0xC0000008u -#define DEMON_W32_EXCEPTION_UNWIND_CONSOLIDATE 0x80000029u -#define DEMON_W32_EXCEPTION_DLL_NOT_FOUND 0xC0000135u -#define DEMON_W32_EXCEPTION_ORDINAL_NOT_FOUND 0xC0000138u -#define DEMON_W32_EXCEPTION_ENTRY_POINT_NOT_FOUND 0xC0000139u -#define DEMON_W32_EXCEPTION_DLL_INIT_FAILED 0xC0000142u -#define DEMON_W32_EXCEPTION_CONTROL_C_EXIT 0xC000013Au -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_FAULTS 0xC00002B4u -#define DEMON_W32_EXCEPTION_FLT_MULTIPLE_TRAPS 0xC00002B5u -#define DEMON_W32_EXCEPTION_NAT_CONSUMPTION 0xC00002C9u -#define DEMON_W32_EXCEPTION_HEAP_CORRUPTION 0xC0000374u -#define DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN 0xC0000409u -#define DEMON_W32_EXCEPTION_INVALID_CRUNTIME_PARAM 0xC0000417u -#define DEMON_W32_EXCEPTION_ASSERT_FAILURE 0xC0000420u -#define DEMON_W32_EXCEPTION_NO_MEMORY 0xC0000017u -#define DEMON_W32_EXCEPTION_THROW 0xE06D7363u -#define DEMON_W32_EXCEPTION_SET_THREAD_NAME 0x406d1388u - -//////////////////////////////// -//~ NOTE(allen): Win32 Demon Register API Codes - -#define DEMON_W32_CTX_X86 0x00010000 -#define DEMON_W32_CTX_X64 0x00100000 - -#define DEMON_W32_CTX_INTEL_CONTROL 0x0001 -#define DEMON_W32_CTX_INTEL_INTEGER 0x0002 -#define DEMON_W32_CTX_INTEL_SEGMENTS 0x0004 -#define DEMON_W32_CTX_INTEL_FLOATS 0x0008 -#define DEMON_W32_CTX_INTEL_DEBUG 0x0010 -#define DEMON_W32_CTX_INTEL_EXTENDED 0x0020 -#define DEMON_W32_CTX_INTEL_XSTATE 0x0040 - -#define DEMON_W32_CTX_X86_ALL (DEMON_W32_CTX_X86 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_DEBUG | \ -DEMON_W32_CTX_INTEL_EXTENDED) -#define DEMON_W32_CTX_X64_ALL (DEMON_W32_CTX_X64 | \ -DEMON_W32_CTX_INTEL_CONTROL | DEMON_W32_CTX_INTEL_INTEGER | \ -DEMON_W32_CTX_INTEL_SEGMENTS | DEMON_W32_CTX_INTEL_FLOATS | \ -DEMON_W32_CTX_INTEL_DEBUG) - -//////////////////////////////// -//~ rjf: DOS Header Types - -// this is the "MZ" as a 16-bit short -#define DEMON_DOS_MAGIC 0x5a4d - -#pragma pack(push,1) -typedef struct DEMON_DosHeader DEMON_DosHeader; -struct DEMON_DosHeader -{ - U16 magic; - U16 last_page_size; - U16 page_count; - U16 reloc_count; - U16 paragraph_header_size; - U16 min_paragraph; - U16 max_paragraph; - U16 init_ss; - U16 init_sp; - U16 checksum; - U16 init_ip; - U16 init_cs; - U16 reloc_table_file_off; - U16 overlay_number; - U16 reserved[4]; - U16 oem_id; - U16 oem_info; - U16 reserved2[10]; - U32 coff_file_offset; -}; -#pragma pack(pop) - -//////////////////////////////// -//~ rjf: Coff Header Types - -#define DEMON_PE_MAGIC 0x00004550u - -typedef U16 DEMON_CoffMachineType; -enum{ - DEMON_CoffMachineType_UNKNOWN = 0x0, - DEMON_CoffMachineType_X86 = 0x14c, - DEMON_CoffMachineType_X64 = 0x8664, - DEMON_CoffMachineType_ARM33 = 0x1d3, - DEMON_CoffMachineType_ARM = 0x1c0, - DEMON_CoffMachineType_ARM64 = 0xaa64, - DEMON_CoffMachineType_ARMNT = 0x1c4, - DEMON_CoffMachineType_EBC = 0xebc, - DEMON_CoffMachineType_IA64 = 0x200, - DEMON_CoffMachineType_M32R = 0x9041, - DEMON_CoffMachineType_MIPS16 = 0x266, - DEMON_CoffMachineType_MIPSFPU = 0x366, - DEMON_CoffMachineType_MIPSFPU16 = 0x466, - DEMON_CoffMachineType_POWERPC = 0x1f0, - DEMON_CoffMachineType_POWERPCFP = 0x1f1, - DEMON_CoffMachineType_R4000 = 0x166, - DEMON_CoffMachineType_RISCV32 = 0x5032, - DEMON_CoffMachineType_RISCV64 = 0x5064, - DEMON_CoffMachineType_RISCV128 = 0x5128, - DEMON_CoffMachineType_SH3 = 0x1a2, - DEMON_CoffMachineType_SH3DSP = 0x1a3, - DEMON_CoffMachineType_SH4 = 0x1a6, - DEMON_CoffMachineType_SH5 = 0x1a8, - DEMON_CoffMachineType_THUMB = 0x1c2, - DEMON_CoffMachineType_WCEMIPSV2 = 0x169, - DEMON_CoffMachineType_COUNT = 25 -}; - -typedef U16 DEMON_CoffFlags; -enum{ - DEMON_CoffFlag_RELOC_STRIPPED = (1 << 0), - DEMON_CoffFlag_EXECUTABLE_IMAGE = (1 << 1), - DEMON_CoffFlag_LINE_NUMS_STRIPPED = (1 << 2), - DEMON_CoffFlag_SYM_STRIPPED = (1 << 3), - DEMON_CoffFlag_RESERVED_0 = (1 << 4), - DEMON_CoffFlag_LARGE_ADDRESS_AWARE = (1 << 5), - DEMON_CoffFlag_RESERVED_1 = (1 << 6), - DEMON_CoffFlag_RESERVED_2 = (1 << 7), - DEMON_CoffFlag_32BIT_MACHINE = (1 << 8), - DEMON_CoffFlag_DEBUG_STRIPPED = (1 << 9), - DEMON_CoffFlag_REMOVABLE_RUN_FROM_SWAP = (1 << 10), - DEMON_CoffFlag_NET_RUN_FROM_SWAP = (1 << 11), - DEMON_CoffFlag_SYSTEM = (1 << 12), - DEMON_CoffFlag_DLL = (1 << 13), - DEMON_CoffFlag_UP_SYSTEM_ONLY = (1 << 14), - DEMON_CoffFlag_BYTES_RESERVED_HI = (1 << 15), -}; - -#pragma pack(push,1) -typedef struct DEMON_CoffHeader DEMON_CoffHeader; -struct DEMON_CoffHeader -{ - DEMON_CoffMachineType machine; - U16 section_count; - U32 time_date_stamp; - // TODO: rename to "unix_timestamp" - U32 pointer_to_symbol_table; - U32 number_of_symbols; - // TODO: rename to "symbol_count" - U16 size_of_optional_header; - // TODO: rename to "optional_header_size" - DEMON_CoffFlags flags; -}; -#pragma pack(pop) - -//////////////////////////////// -//~ rjf: PE Header Types - -#pragma pack(push, 1) - -typedef U16 DEMON_PeWindowsSubsystem; -enum{ - DEMON_PeWindowsSubsystem_UNKNOWN = 0, - DEMON_PeWindowsSubsystem_NATIVE = 1, - DEMON_PeWindowsSubsystem_WINDOWS_GUI = 2, - DEMON_PeWindowsSubsystem_WINDOWS_CUI = 3, - DEMON_PeWindowsSubsystem_OS2_CUI = 5, - DEMON_PeWindowsSubsystem_POSIX_CUI = 7, - DEMON_PeWindowsSubsystem_NATIVE_WINDOWS = 8, - DEMON_PeWindowsSubsystem_WINDOWS_CE_GUI = 9, - DEMON_PeWindowsSubsystem_EFI_APPLICATION = 10, - DEMON_PeWindowsSubsystem_EFI_BOOT_SERVICE_DRIVER = 11, - DEMON_PeWindowsSubsystem_EFI_RUNTIME_DRIVER = 12, - DEMON_PeWindowsSubsystem_EFI_ROM = 13, - DEMON_PeWindowsSubsystem_XBOX = 14, - DEMON_PeWindowsSubsystem_WINDOWS_BOOT_APPLICATION = 16, - DEMON_PeWindowsSubsystem_COUNT = 14 -}; - -typedef U16 DEMON_DllCharacteristics; -enum{ - DEMON_DllCharacteristic_HIGH_ENTROPY_VA = (1 << 5), - DEMON_DllCharacteristic_DYNAMIC_BASE = (1 << 6), - DEMON_DllCharacteristic_FORCE_INTEGRITY = (1 << 7), - DEMON_DllCharacteristic_NX_COMPAT = (1 << 8), - DEMON_DllCharacteristic_NO_ISOLATION = (1 << 9), - DEMON_DllCharacteristic_NO_SEH = (1 << 10), - DEMON_DllCharacteristic_NO_BIND = (1 << 11), - DEMON_DllCharacteristic_APPCONTAINER = (1 << 12), - DEMON_DllCharacteristic_WDM_DRIVER = (1 << 13), - DEMON_DllCharacteristic_GUARD_CF = (1 << 14), - DEMON_DllCharacteristic_TERMINAL_SERVER_AWARE = (1 << 15), -}; - -typedef struct DEMON_PeOptionalHeader32 DEMON_PeOptionalHeader32; -struct DEMON_PeOptionalHeader32 -{ - U16 magic; - U8 major_linker_version; - U8 minor_linker_version; - U32 sizeof_code; - U32 sizeof_inited_data; - U32 sizeof_uninited_data; - U32 entry_point_va; - U32 code_base; - U32 data_base; - U32 image_base; - U32 section_alignment; - U32 file_alignment; - U16 major_os_ver; - U16 minor_os_ver; - U16 major_img_ver; - U16 minor_img_ver; - U16 major_subsystem_ver; - U16 minor_subsystem_ver; - U32 win32_version_value; - U32 sizeof_image; - U32 sizeof_headers; - U32 check_sum; - DEMON_PeWindowsSubsystem subsystem; - DEMON_DllCharacteristics dll_characteristics; - U32 sizeof_stack_reserve; - U32 sizeof_stack_commit; - U32 sizeof_heap_reserve; - U32 sizeof_heap_commit; - U32 loader_flags; - U32 data_dir_count; -}; - -typedef struct DEMON_PeOptionalHeader32Plus DEMON_PeOptionalHeader32Plus; -struct DEMON_PeOptionalHeader32Plus -{ - U16 magic; - U8 major_linker_version; - U8 minor_linker_version; - U32 sizeof_code; - U32 sizeof_inited_data; - U32 sizeof_uninited_data; - U32 entry_point_va; - U32 code_base; - U64 image_base; - U32 section_alignment; - U32 file_alignment; - U16 major_os_ver; - U16 minor_os_ver; - U16 major_img_ver; - U16 minor_img_ver; - U16 major_subsystem_ver; - U16 minor_subsystem_ver; - U32 win32_version_value; - U32 sizeof_image; - U32 sizeof_headers; - U32 check_sum; - DEMON_PeWindowsSubsystem subsystem; - DEMON_DllCharacteristics dll_characteristics; - U64 sizeof_stack_reserve; - U64 sizeof_stack_commit; - U64 sizeof_heap_reserve; - U64 sizeof_heap_commit; - U32 loader_flags; - U32 data_dir_count; -}; - -#pragma pack(pop) - -//////////////////////////////// -//~ rjf: Helpers - -internal U64 demon_w32_hash_from_string(String8 string); -internal DEMON_W32_Ext* demon_w32_ext_alloc(void); -internal DEMON_W32_Ext* demon_w32_ext(DEMON_Entity *entity); - -internal U64 demon_w32_read_memory(HANDLE process_handle, void *dst, U64 src_address, U64 size); -internal B32 demon_w32_write_memory(HANDLE process_handle, U64 dst_address, void *src, U64 size); -internal String8 demon_w32_read_memory_str(Arena *arena, HANDLE process_handle, U64 address); -internal String16 demon_w32_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address); - -#define demon_w32_read_struct(h,dst,src) demon_w32_read_memory((h), (dst), (src), sizeof(*(dst))) - -internal DEMON_W32_ImageInfo demon_w32_image_info_from_base(HANDLE process_handle, U64 base); -internal DWORD demon_w32_inject_thread(DEMON_Entity *process, U64 start_address); - -internal U16 demon_w32_real_tag_word_from_xsave(XSAVE_FORMAT *fxsave); -internal U16 demon_w32_xsave_tag_word_from_real_tag_word(U16 ftw); - -internal DWORD demon_w32_win32_from_memory_protect_flags(DEMON_MemoryProtectFlags flags); - -//////////////////////////////// -//~ rjf: Experiments - -internal void demon_w32_peak_at_tls(DEMON_Handle handle); - -#endif //DEMON_OS_WIN32_H diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index a70712f6..f8659b66 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -1085,10 +1085,10 @@ df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams DF_Eval eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, query); if(eval.errors.count == 0) { - TG_Kind eval_type_kind = tg_kind_from_key(tg_unwrapped_from_graph_raddbg_key(parse_ctx.type_graph, parse_ctx.rdbg, eval.type_key)); + TG_Kind eval_type_kind = tg_kind_from_key(tg_unwrapped_from_graph_rdi_key(parse_ctx.type_graph, parse_ctx.rdi, eval.type_key)); if(eval_type_kind == TG_Kind_Ptr || eval_type_kind == TG_Kind_LRef || eval_type_kind == TG_Kind_RRef) { - eval = df_value_mode_eval_from_eval(parse_ctx.type_graph, parse_ctx.rdbg, ctrl_ctx, eval); + eval = df_value_mode_eval_from_eval(parse_ctx.type_graph, parse_ctx.rdi, ctrl_ctx, eval); prefer_imm = 1; } U64 u64 = !prefer_imm && eval.offset ? eval.offset : eval.imm_u64; @@ -1398,16 +1398,6 @@ df_txti_handle_from_entity(DF_Entity *entity) return handle; } -//- rjf: entity -> disasm info - -internal DASM_Handle -df_dasm_handle_from_process_vaddr(DF_Entity *process, U64 vaddr) -{ - Rng1U64 disasm_vaddr_rng = r1u64(AlignDownPow2(vaddr, KB(4)), AlignDownPow2(vaddr, KB(4)) + KB(16)); - DASM_Handle dasm_handle = dasm_handle_from_ctrl_process_range(process->ctrl_machine_id, process->ctrl_handle, disasm_vaddr_rng); - return dasm_handle; -} - //- rjf: full path building, from file/folder entities internal String8 @@ -1802,6 +1792,7 @@ df_entity_alloc(DF_StateDeltaHistory *hist, DF_Entity *parent, DF_EntityKind kin df_state->entities_id_gen += 1; entity->id = df_state->entities_id_gen; entity->generation += 1; + entity->alloc_time_us = os_now_microseconds(); // rjf: dirtify caches df_state->kind_alloc_gens[kind] += 1; @@ -2024,7 +2015,7 @@ df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id) } internal void -df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle) +df_entity_equip_ctrl_handle(DF_Entity *entity, DMN_Handle handle) { df_require_entity_nonnil(entity, return); entity->ctrl_handle = handle; @@ -2418,7 +2409,7 @@ df_machine_entity_from_machine_id(CTRL_MachineID machine_id) } internal DF_Entity * -df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle) +df_entity_from_ctrl_handle(CTRL_MachineID machine_id, DMN_Handle handle) { DF_Entity *result = &df_g_nil_entity; if(handle.u64[0] != 0) @@ -2519,11 +2510,13 @@ df_set_thread_freeze_state(DF_Entity *thread, B32 frozen) } node->handle = thread_handle; df_handle_list_push_node(&df_state->frozen_threads, node); + df_state->entities_mut_soft_halt = 1; } // rjf: frozen => not frozen if(is_frozen && !should_be_frozen) { + df_state->entities_mut_soft_halt = 1; df_handle_list_remove(&df_state->frozen_threads, already_frozen_node); SLLStackPush(df_state->free_handle_node, already_frozen_node); } @@ -2709,11 +2702,9 @@ df_debug_info_path_from_module(Arena *arena, DF_Entity *module) } else { - Temp scratch = scratch_begin(&arena, 1); String8 exe_path = module->name; - String8 dbg_path = ctrl_og_dbg_path_from_exe_path(arena, exe_path); + String8 dbg_path = push_str8f(arena, "%S.pdb", str8_chop_last_dot(exe_path)); result = dbg_path; - scratch_end(scratch); } ProfEnd(); return result; @@ -2823,14 +2814,14 @@ df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread) // rjf: thread => unpacked info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = df_rip_from_thread(thread); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => machine code String8 machine_code = {0}; { Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch)); - machine_code.str = push_array_no_zero(scratch.arena, U8, max_instruction_size_from_arch(arch)); - machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, rng, machine_code.str); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, rng, os_now_microseconds()+5000); + machine_code = machine_code_slice.data; } // rjf: build traps if machine code was read successfully @@ -2862,7 +2853,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) DF_Entity *module = df_module_from_thread(thread); DF_Entity *binary = df_binary_file_from_module(module); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = df_rip_from_thread(thread); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -2896,8 +2887,8 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng)); - machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+50000); + machine_code = machine_code_slice.data; } // rjf: machine code => ctrl flow analysis @@ -2987,7 +2978,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) DF_Entity *module = df_module_from_thread(thread); DF_Entity *binary = df_binary_file_from_module(module); Architecture arch = df_architecture_from_entity(thread); - U64 ip_vaddr = df_rip_from_thread(thread); + U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); // rjf: ip => line vaddr range Rng1U64 line_vaddr_rng = {0}; @@ -3021,8 +3012,8 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) String8 machine_code = {0}; if(good_line_info) { - machine_code.str = push_array_no_zero(scratch.arena, U8, dim_1u64(line_vaddr_rng)); - machine_code.size = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, machine_code.str); + CTRL_ProcessMemorySlice machine_code_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, line_vaddr_rng, os_now_microseconds()+5000); + machine_code = machine_code_slice.data; } // rjf: machine code => ctrl flow analysis @@ -3195,23 +3186,23 @@ df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff) DBGI_Scope *scope = dbgi_scope_open(); String8 path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - if(result.size == 0 && rdbg->scope_vmap != 0) + RDI_Parsed *rdi = &dbgi->rdi; + if(result.size == 0 && rdi->scope_vmap != 0) { - U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff); - RADDBG_Scope *scope = &rdbg->scopes[scope_idx]; + U64 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, voff); + RDI_Scope *scope = rdi_element_from_idx(rdi, scopes, scope_idx); U64 proc_idx = scope->proc_idx; - RADDBG_Procedure *procedure = &rdbg->procedures[proc_idx]; + RDI_Procedure *procedure = &rdi->procedures[proc_idx]; U64 name_size = 0; - U8 *name_ptr = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size); + U8 *name_ptr = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); result = push_str8_copy(arena, str8(name_ptr, name_size)); } - if(result.size == 0 && rdbg->global_vmap != 0) + if(result.size == 0 && rdi->global_vmap != 0) { - U64 global_idx = raddbg_vmap_idx_from_voff(rdbg->global_vmap, rdbg->global_vmap_count, voff); - RADDBG_GlobalVariable *global_var = &rdbg->global_variables[global_idx]; + U64 global_idx = rdi_vmap_idx_from_voff(rdi->global_vmap, rdi->global_vmap_count, voff); + RDI_GlobalVariable *global_var = rdi_element_from_idx(rdi, global_variables, global_idx); U64 name_size = 0; - U8 *name_ptr = raddbg_string_from_idx(rdbg, global_var->name_string_idx, &name_size); + 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)); } dbgi_scope_close(scope); @@ -3258,27 +3249,27 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit binary_n != 0; binary_n = binary_n->next) { - // rjf: binary -> rdbg + // rjf: binary -> rdi DF_Entity *binary = binary_n->entity; String8 binary_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; - // rjf: file_path_normalized * rdbg -> src_id + // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; U32 src_id = 0; if(dbgi != &dbgi_parse_nil) { - RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_NormalSourcePaths); + RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_NormalSourcePaths); if(mapptr != 0) { - RADDBG_ParsedNameMap map = {0}; - raddbg_name_map_parse(rdbg, mapptr, &map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, file_path_normalized.str, file_path_normalized.size); + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, file_path_normalized.str, file_path_normalized.size); if(node != 0) { U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); if(id_count > 0) { good_src_id = 1; @@ -3291,9 +3282,9 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit // rjf: good src-id -> look up line info for visible range if(good_src_id) { - RADDBG_SourceFile *src = rdbg->source_files+src_id; - RADDBG_ParsedLineMap line_map = {0}; - raddbg_line_map_from_source_file(rdbg, src, &line_map); + RDI_SourceFile *src = rdi->source_files+src_id; + RDI_ParsedLineMap line_map = {0}; + rdi_line_map_from_source_file(rdi, src, &line_map); U64 line_idx = 0; for(S64 line_num = line_num_range.min; line_num <= line_num_range.max; @@ -3301,15 +3292,15 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit { DF_TextLineSrc2DasmInfoList *src2dasm_list = &src2dasm_array.v[line_idx]; U32 voff_count = 0; - U64 *voffs = raddbg_line_voffs_from_num(&line_map, u32_from_u64_saturate((U64)line_num), &voff_count); + U64 *voffs = rdi_line_voffs_from_num(&line_map, u32_from_u64_saturate((U64)line_num), &voff_count); for(U64 idx = 0; idx < voff_count; idx += 1) { U64 base_voff = voffs[idx]; - U64 unit_idx = raddbg_vmap_idx_from_voff(rdbg->unit_vmap, rdbg->unit_vmap_count, base_voff); - RADDBG_Unit *unit = &rdbg->units[unit_idx]; - RADDBG_ParsedLineInfo unit_line_info = {0}; - raddbg_line_info_from_unit(rdbg, unit, &unit_line_info); - U64 line_info_idx = raddbg_line_info_idx_from_voff(&unit_line_info, base_voff); + U64 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, base_voff); + RDI_Unit *unit = &rdi->units[unit_idx]; + RDI_ParsedLineInfo unit_line_info = {0}; + rdi_line_info_from_unit(rdi, unit, &unit_line_info); + U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, base_voff); if(unit_line_info.voffs != 0) { Rng1U64 range = r1u64(base_voff, unit_line_info.voffs[line_info_idx+1]); @@ -3346,23 +3337,23 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) DBGI_Scope *scope = dbgi_scope_open(); String8 path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; DF_TextLineDasm2SrcInfo result = {0}; result.file = result.binary = &df_g_nil_entity; - if(rdbg->unit_vmap != 0 && rdbg->units != 0 && rdbg->source_files != 0) + if(rdi->unit_vmap != 0 && rdi->units != 0 && rdi->source_files != 0) { - U64 unit_idx = raddbg_vmap_idx_from_voff(rdbg->unit_vmap, rdbg->unit_vmap_count, voff); - RADDBG_Unit *unit = &rdbg->units[unit_idx]; - RADDBG_ParsedLineInfo unit_line_info = {0}; - raddbg_line_info_from_unit(rdbg, unit, &unit_line_info); - U64 line_info_idx = raddbg_line_info_idx_from_voff(&unit_line_info, voff); + U64 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, voff); + RDI_Unit *unit = &rdi->units[unit_idx]; + RDI_ParsedLineInfo unit_line_info = {0}; + rdi_line_info_from_unit(rdi, unit, &unit_line_info); + U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, voff); if(line_info_idx < unit_line_info.count) { - RADDBG_Line *line = &unit_line_info.lines[line_info_idx]; - RADDBG_Column *column = (line_info_idx < unit_line_info.col_count) ? &unit_line_info.cols[line_info_idx] : 0; - RADDBG_SourceFile *file = &rdbg->source_files[line->file_idx]; + RDI_Line *line = &unit_line_info.lines[line_info_idx]; + RDI_Column *column = (line_info_idx < unit_line_info.col_count) ? &unit_line_info.cols[line_info_idx] : 0; + RDI_SourceFile *file = &rdi->source_files[line->file_idx]; String8 file_normalized_full_path = {0}; - file_normalized_full_path.str = raddbg_string_from_idx(rdbg, file->normal_full_path_string_idx, &file_normalized_full_path.size); + file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); result.binary = binary; if(line->file_idx != 0 && file_normalized_full_path.size != 0) { @@ -3378,27 +3369,6 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) return result; } -internal DF_TextLineDasm2SrcInfoList -df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff) -{ - Temp scratch = scratch_begin(&arena, 1); - DF_TextLineDasm2SrcInfoList result = {0}; - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); - for(DF_EntityNode *n = binaries.first; n != 0; n = n->next) - { - DF_TextLineDasm2SrcInfo info = df_text_line_dasm2src_info_from_binary_voff(n->entity, voff); - if(!df_entity_is_nil(info.file)) - { - DF_TextLineDasm2SrcInfoNode *dst_n = push_array(arena, DF_TextLineDasm2SrcInfoNode, 1); - dst_n->v = info; - SLLQueuePush(result.first, result.last, dst_n); - result.count += 1; - } - } - scratch_end(scratch); - return result; -} - //- rjf: symbol -> voff lookups internal U64 @@ -3411,11 +3381,11 @@ df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) { String8 binary_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - RADDBG_NameMapKind name_map_kinds[] = + RDI_Parsed *rdi = &dbgi->rdi; + RDI_NameMapKind name_map_kinds[] = { - RADDBG_NameMapKind_GlobalVariables, - RADDBG_NameMapKind_Procedures, + RDI_NameMapKind_GlobalVariables, + RDI_NameMapKind_Procedures, }; if(dbgi != &dbgi_parse_nil) { @@ -3423,11 +3393,11 @@ df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) name_map_kind_idx < ArrayCount(name_map_kinds); name_map_kind_idx += 1) { - RADDBG_NameMapKind name_map_kind = name_map_kinds[name_map_kind_idx]; - RADDBG_NameMap *name_map = raddbg_name_map_from_kind(rdbg, name_map_kind); - RADDBG_ParsedNameMap parsed_name_map = {0}; - raddbg_name_map_parse(rdbg, name_map, &parsed_name_map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &parsed_name_map, symbol_name.str, symbol_name.size); + RDI_NameMapKind name_map_kind = name_map_kinds[name_map_kind_idx]; + RDI_NameMap *name_map = rdi_name_map_from_kind(rdi, name_map_kind); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_name_map_parse(rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, symbol_name.str, symbol_name.size); // rjf: node -> num U64 entity_num = 0; @@ -3442,7 +3412,7 @@ df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) default: { U32 num = 0; - U32 *run = raddbg_matches_from_map_node(rdbg, node, &num); + U32 *run = rdi_matches_from_map_node(rdi, node, &num); if(num != 0) { entity_num = run[0]+1; @@ -3456,16 +3426,16 @@ df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) if(entity_num != 0) switch(name_map_kind) { default:{}break; - case RADDBG_NameMapKind_GlobalVariables: + case RDI_NameMapKind_GlobalVariables: { - RADDBG_GlobalVariable *global_var = raddbg_element_from_idx(rdbg, global_variables, entity_num-1); + RDI_GlobalVariable *global_var = rdi_element_from_idx(rdi, global_variables, entity_num-1); voff = global_var->voff; }break; - case RADDBG_NameMapKind_Procedures: + case RDI_NameMapKind_Procedures: { - RADDBG_Procedure *procedure = raddbg_element_from_idx(rdbg, procedures, entity_num-1); - RADDBG_Scope *scope = raddbg_element_from_idx(rdbg, scopes, procedure->root_scope_idx); - voff = rdbg->scope_voffs[scope->voff_range_first]; + RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, entity_num-1); + RDI_Scope *scope = rdi_element_from_idx(rdi, scopes, procedure->root_scope_idx); + voff = rdi->scope_voffs[scope->voff_range_first]; }break; } @@ -3494,11 +3464,11 @@ df_type_num_from_binary_name(DF_Entity *binary, String8 name) { String8 binary_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - RADDBG_NameMap *name_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Types); - RADDBG_ParsedNameMap parsed_name_map = {0}; - raddbg_name_map_parse(rdbg, name_map, &parsed_name_map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &parsed_name_map, name.str, name.size); + RDI_Parsed *rdi = &dbgi->rdi; + RDI_NameMap *name_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Types); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_name_map_parse(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) { @@ -3511,7 +3481,7 @@ df_type_num_from_binary_name(DF_Entity *binary, String8 name) default: { U32 num = 0; - U32 *run = raddbg_matches_from_map_node(rdbg, node, &num); + U32 *run = rdi_matches_from_map_node(rdi, node, &num); if(num != 0) { entity_num = run[0]+1; @@ -3564,83 +3534,84 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 U64 base_vaddr = 0; Temp scratch = scratch_begin(0, 0); DBGI_Scope *scope = dbgi_scope_open(); - - //- rjf: unpack thread info - DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - PE_BinInfo *bin = &dbgi->pe; - B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF - U64 addr_size = bit_size_from_arch(bin->arch)/8; - - //- rjf: grab tls range - Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); - - //- rjf: read module's TLS index - U64 tls_index = 0; + if(!df_ctrl_targets_running()) { - U64 bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, &tls_index); - if(bytes_read < sizeof(U64)) - { - tls_index = 0; - } - } - - //- rjf: PE path - if(bin_is_pe) - { - 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->ctrl_machine_id, process->ctrl_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->ctrl_machine_id, process->ctrl_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) - { - MemoryCopy(&base_vaddr, result_data.str, sizeof(U64)); - } - } - - //- rjf: non-PE path (not implemented) - if(!bin_is_pe) - { - // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: -#if 0 - // TODO(nick): This code works only if the linked c runtime library is glibc. - // Implement CRT detection here. + //- rjf: unpack thread info + DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); + String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); + PE_BinInfo *bin = &dbgi->pe; + B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF + U64 addr_size = bit_size_from_arch(bin->arch)/8; - U64 dtv_addr = UINT64_MAX; - demon_read_memory(process->demon_handle, &dtv_addr, thread_info_addr, addr_size); + //- rjf: grab tls range + Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); - /* - union delta_thread_vector + //- rjf: read module's TLS index + U64 tls_index = 0; + { + CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0); + if(tls_index_slice.data.size >= addr_size) { - size_t counter; - struct - { - void *value; - void *to_free; - } pointer; - }; - */ - - U64 dtv_size = 16; - U64 dtv_count = 0; - demon_read_memory(process->demon_handle, &dtv_count, dtv_addr - dtv_size, addr_size); - - if (tls_index > 0 && tls_index < dtv_count) - { - demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); + tls_index = *(U64 *)tls_index_slice.data.str; + } } + + //- rjf: PE path + if(bin_is_pe) + { + 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->ctrl_machine_id, process->ctrl_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->ctrl_machine_id, process->ctrl_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) + { + MemoryCopy(&base_vaddr, result_data.str, sizeof(U64)); + } + } + + //- rjf: non-PE path (not implemented) + if(!bin_is_pe) + { + // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: +#if 0 + // TODO(nick): This code works only if the linked c runtime library is glibc. + // Implement CRT detection here. + + U64 dtv_addr = UINT64_MAX; + demon_read_memory(process->demon_handle, &dtv_addr, thread_info_addr, addr_size); + + /* + union delta_thread_vector + { + size_t counter; + struct + { + void *value; + void *to_free; + } pointer; + }; + */ + + U64 dtv_size = 16; + U64 dtv_count = 0; + demon_read_memory(process->demon_handle, &dtv_count, dtv_addr - dtv_size, addr_size); + + if (tls_index > 0 && tls_index < dtv_count) + { + demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); + } #endif + } } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); @@ -3653,51 +3624,14 @@ df_architecture_from_entity(DF_Entity *entity) return entity->arch; } -internal CTRL_Unwind -df_push_unwind_from_thread(Arena *arena, DF_Entity *thread) -{ - DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - CTRL_Unwind unwind = ctrl_unwind_from_process_thread(arena, thread->ctrl_machine_id, process->ctrl_handle, thread->ctrl_handle); - return unwind; -} - -internal U64 -df_rip_from_thread(DF_Entity *thread) -{ - U64 result = ctrl_rip_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); - return result; -} - -internal U64 -df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) -{ - Temp scratch = scratch_begin(0, 0); - U64 result = df_rip_from_thread(thread); - if(unwind_count != 0) - { - CTRL_Unwind unwind = df_push_unwind_from_thread(scratch.arena, thread); - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) - { - if(unwind_count == unwind_idx) - { - result = frame->rip; - break; - } - } - } - scratch_end(scratch); - return result; -} - internal EVAL_String2NumMap * df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) { Temp scratch = scratch_begin(&arena, 1); String8 binary_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - EVAL_String2NumMap *result = eval_push_locals_map_from_raddbg_voff(arena, rdbg, voff); + RDI_Parsed *rdi = &dbgi->rdi; + EVAL_String2NumMap *result = eval_push_locals_map_from_rdi_voff(arena, rdi, voff); scratch_end(scratch); return result; } @@ -3708,8 +3642,8 @@ df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity * Temp scratch = scratch_begin(&arena, 1); String8 binary_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; - EVAL_String2NumMap *result = eval_push_member_map_from_raddbg_voff(arena, rdbg, voff); + RDI_Parsed *rdi = &dbgi->rdi; + EVAL_String2NumMap *result = eval_push_member_map_from_rdi_voff(arena, rdi, voff); scratch_end(scratch); return result; } @@ -3717,26 +3651,33 @@ df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity * internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr) { - B32 result = ctrl_thread_write_rip(thread->ctrl_machine_id, thread->ctrl_handle, vaddr); + Temp scratch = scratch_begin(0, 0); + void *block = ctrl_query_cached_reg_block_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); + regs_arch_block_write_rip(thread->arch, block, vaddr); + B32 result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, block); // rjf: early mutation of unwind cache for immediate frontend effect if(result) { - DF_RunUnwindCache *unwind_cache = &df_state->unwind_cache; - DF_Handle thread_handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&thread_handle)); - U64 slot_idx = hash % unwind_cache->table_size; - DF_RunUnwindCacheSlot *slot = &unwind_cache->table[slot_idx]; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + DF_RunUnwindCache *unwind_cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; + if(unwind_cache->slots_count != 0) { - if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0) + DF_Handle thread_handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&thread_handle)); + U64 slot_idx = hash % unwind_cache->slots_count; + DF_RunUnwindCacheSlot *slot = &unwind_cache->slots[slot_idx]; + for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) { - n->unwind.first->rip = vaddr; - break; + if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0) + { + n->unwind.first->rip = vaddr; + break; + } } } } + scratch_end(scratch); return result; } @@ -3813,10 +3754,6 @@ df_push_ctrl_msg(CTRL_Msg *msg) { CTRL_Msg *dst = ctrl_msg_list_push(df_state->ctrl_msg_arena, &df_state->ctrl_msgs); ctrl_msg_deep_copy(df_state->ctrl_msg_arena, dst, msg); - if(dst->kind == CTRL_MsgKind_LaunchAndInit) - { - df_state->ctrl_is_running = 1; - } if(df_state->ctrl_soft_halt_issued == 0 && df_ctrl_targets_running()) { df_state->ctrl_soft_halt_issued = 1; @@ -3827,7 +3764,7 @@ df_push_ctrl_msg(CTRL_Msg *msg) //- rjf: control thread running internal void -df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_TrapList *run_traps) +df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_RunFlags flags, CTRL_TrapList *run_traps) { DBGI_Scope *scope = dbgi_scope_open(); Temp scratch = scratch_begin(0, 0); @@ -3837,6 +3774,7 @@ df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_TrapList *run_traps) { DF_EntityList user_bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); DF_Entity *process = df_entity_ancestor_from_kind(run_thread, DF_EntityKind_Process); + msg.run_flags = flags; msg.machine_id = run_thread->ctrl_machine_id; msg.entity = run_thread->ctrl_handle; msg.parent = process->ctrl_handle; @@ -3936,6 +3874,7 @@ df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_TrapList *run_traps) df_state->ctrl_last_run_kind = run; df_state->ctrl_last_run_frame_idx = df_frame_index(); df_state->ctrl_last_run_thread = df_handle_from_entity(run_thread); + df_state->ctrl_last_run_flags = flags; df_state->ctrl_last_run_traps = ctrl_trap_list_copy(df_state->ctrl_last_run_arena, &run_traps_copy); df_state->ctrl_is_running = 1; @@ -3986,7 +3925,7 @@ df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 DF_Entity *binary = df_binary_file_from_module(module); String8 binary_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; Architecture arch = df_architecture_from_entity(process); EVAL_String2NumMap *reg_map = ctrl_string2reg_from_arch(arch); EVAL_String2NumMap *reg_alias_map = ctrl_string2alias_from_arch(arch); @@ -3998,7 +3937,7 @@ df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 { ctx.arch = arch; ctx.ip_voff = voff; - ctx.rdbg = rdbg; + ctx.rdi = rdi; ctx.type_graph = tg_graph_begin(bit_size_from_arch(arch)/8, 256); ctx.regs_map = reg_map; ctx.reg_alias_map = reg_alias_map; @@ -4030,26 +3969,26 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) binary_n != 0; binary_n = binary_n->next) { - // rjf: binary -> rdbg + // rjf: binary -> rdi DF_Entity *binary = binary_n->entity; String8 binary_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; - // rjf: file_path_normalized * rdbg -> src_id + // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; U32 src_id = 0; { - RADDBG_NameMap *mapptr = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_NormalSourcePaths); + RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_NormalSourcePaths); if(mapptr != 0) { - RADDBG_ParsedNameMap map = {0}; - raddbg_name_map_parse(rdbg, mapptr, &map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, file_path_normalized.str, file_path_normalized.size); + RDI_ParsedNameMap map = {0}; + rdi_name_map_parse(rdi, mapptr, &map); + RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &map, file_path_normalized.str, file_path_normalized.size); if(node != 0) { U32 id_count = 0; - U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count); + U32 *ids = rdi_matches_from_map_node(rdi, node, &id_count); if(id_count > 0) { good_src_id = 1; @@ -4062,19 +4001,19 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) // rjf: good src-id -> look up line info for visible range if(good_src_id) { - RADDBG_SourceFile *src = rdbg->source_files+src_id; - RADDBG_ParsedLineMap line_map = {0}; - raddbg_line_map_from_source_file(rdbg, src, &line_map); + RDI_SourceFile *src = rdi->source_files+src_id; + RDI_ParsedLineMap line_map = {0}; + rdi_line_map_from_source_file(rdi, src, &line_map); U32 voff_count = 0; - U64 *voffs = raddbg_line_voffs_from_num(&line_map, (U32)pt.line, &voff_count); + U64 *voffs = rdi_line_voffs_from_num(&line_map, (U32)pt.line, &voff_count); for(U64 idx = 0; idx < voff_count; idx += 1) { U64 base_voff = voffs[idx]; - U64 unit_idx = raddbg_vmap_idx_from_voff(rdbg->unit_vmap, rdbg->unit_vmap_count, base_voff); - RADDBG_Unit *unit = &rdbg->units[unit_idx]; - RADDBG_ParsedLineInfo unit_line_info = {0}; - raddbg_line_info_from_unit(rdbg, unit, &unit_line_info); - U64 line_info_idx = raddbg_line_info_idx_from_voff(&unit_line_info, base_voff); + U64 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, base_voff); + RDI_Unit *unit = &rdi->units[unit_idx]; + RDI_ParsedLineInfo unit_line_info = {0}; + rdi_line_info_from_unit(rdi, unit, &unit_line_info); + U64 line_info_idx = rdi_line_info_idx_from_voff(&unit_line_info, base_voff); Rng1U64 range = r1u64(base_voff, unit_line_info.voffs[line_info_idx+1]); S64 actual_line = (S64)unit_line_info.lines[line_info_idx].line_num; DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(scratch.arena, DF_TextLineSrc2DasmInfoNode, 1); @@ -4112,7 +4051,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) //- rjf: bad ctx -> reset with graceful defaults if(good_ctx == 0) { - ctx.rdbg = &dbgi_parse_nil.rdbg; + ctx.rdi = &dbgi_parse_nil.rdi; ctx.type_graph = tg_graph_begin(8, 256); ctx.regs_map = &eval_string2num_map_nil; ctx.regs_map = &eval_string2num_map_nil; @@ -4133,7 +4072,7 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ //- rjf: unpack arguments DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); - U64 tls_root_vaddr = ctrl_tls_root_vaddr_from_thread(thread->ctrl_machine_id, thread->ctrl_handle); + U64 tls_root_vaddr = ctrl_query_cached_tls_root_vaddr_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); DF_Entity *process = thread->parent; U64 unwind_count = ctrl_ctx->unwind_count; CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); @@ -4178,7 +4117,7 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ EVAL_IRTreeAndType ir_tree_and_type = {&eval_irtree_nil}; if(parse_has_expr && errors.count == 0) { - ir_tree_and_type = eval_irtree_and_type_from_expr(arena, parse_ctx->type_graph, parse_ctx->rdbg, macro_map, parse.expr, &errors); + ir_tree_and_type = eval_irtree_and_type_from_expr(arena, parse_ctx->type_graph, parse_ctx->rdi, macro_map, parse.expr, &errors); } //- rjf: get list of ops @@ -4227,12 +4166,34 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ }break; } result.errors = errors; + if(EVAL_ResultCode_Good < eval.code && eval.code < EVAL_ResultCode_COUNT) + { + eval_error(arena, &result.errors, EVAL_ErrorKind_InterpretationError, 0, eval_result_code_display_strings[eval.code]); + } } //- rjf: apply dynamic type overrides if(parse.expr != 0 && parse.expr->kind != EVAL_ExprKind_Cast) { - result = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, result); + result = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, result); + } + + //- rjf: try to resolve basic integral values into symbols + if((result.mode == EVAL_EvalMode_Value || result.mode == EVAL_EvalMode_Reg) && parse.expr->kind != EVAL_ExprKind_Cast && + (tg_key_match(result.type_key, tg_key_basic(TG_Kind_S64)) || + tg_key_match(result.type_key, tg_key_basic(TG_Kind_U64)) || + tg_key_match(result.type_key, tg_key_basic(TG_Kind_S32)) || + tg_key_match(result.type_key, tg_key_basic(TG_Kind_U32)))) + { + U64 vaddr = result.imm_u64; + DF_Entity *module = df_module_from_process_vaddr(process, vaddr); + DF_Entity *binary = df_binary_file_from_module(module); + U64 voff = df_voff_from_vaddr(module, vaddr); + String8 symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, voff); + if(symbol_name.size != 0) + { + result.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, tg_key_basic(TG_Kind_Void), 0); + } } scratch_end(scratch); @@ -4241,7 +4202,7 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ } internal DF_Eval -df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval) +df_value_mode_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval) { ProfBeginFunction(); DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); @@ -4257,8 +4218,8 @@ df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *c { TG_Key type_key = eval.type_key; TG_Kind type_kind = tg_kind_from_key(type_key); - U64 type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); - if(!tg_key_match(type_key, tg_key_zero()) && type_byte_size <= 8) + U64 type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); + if(!tg_key_match(type_key, tg_key_zero()) && type_byte_size <= sizeof(U64)*2) { Temp scratch = scratch_begin(0, 0); Rng1U64 vaddr_range = r1u64(eval.offset, eval.offset + type_byte_size); @@ -4270,6 +4231,20 @@ df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *c MemoryCopy(eval.imm_u128, data.str, Min(data.size, sizeof(U64)*2)); eval.mode = EVAL_EvalMode_Value; + // rjf: mask&shift, for bitfields + if(type_kind == TG_Kind_Bitfield && type_byte_size <= sizeof(U64)) + { + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, type_key); + U64 valid_bits_mask = 0; + for(U64 idx = 0; idx < type->count; idx += 1) + { + valid_bits_mask |= (1<> type->off; + eval.imm_u64 = eval.imm_u64 & valid_bits_mask; + eval.type_key = type->direct_type_key; + } + // rjf: manually sign-extend switch(type_kind) { @@ -4287,7 +4262,7 @@ df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *c case EVAL_EvalMode_Reg: { TG_Key type_key = eval.type_key; - U64 type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + U64 type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); U64 reg_off = eval.offset; CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); if(unwind.first != 0) @@ -4311,7 +4286,7 @@ df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *c } internal DF_Eval -df_dynamically_typed_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval) +df_dynamically_typed_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); @@ -4325,11 +4300,11 @@ df_dynamically_typed_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_Ctr TG_Kind type_kind = tg_kind_from_key(type_key); if(type_kind == TG_Kind_Ptr) { - TG_Key ptee_type_key = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, type_key); + TG_Key ptee_type_key = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, type_key); TG_Kind ptee_type_kind = tg_kind_from_key(ptee_type_key); if(ptee_type_kind == TG_Kind_Struct || ptee_type_kind == TG_Kind_Class) { - TG_Type *ptee_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, ptee_type_key); + TG_Type *ptee_type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, ptee_type_key); B32 has_vtable = 0; for(U64 idx = 0; idx < ptee_type->count; idx += 1) { @@ -4358,13 +4333,13 @@ df_dynamically_typed_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_Ctr U64 vtable_vaddr = 0; MemoryCopy(&vtable_vaddr, vtable_base_ptr_memory.str, addr_size); U64 vtable_voff = df_voff_from_vaddr(module, vtable_vaddr); - U64 global_idx = raddbg_vmap_idx_from_voff(rdbg->global_vmap, rdbg->global_vmap_count, vtable_voff); - RADDBG_GlobalVariable *global_var = raddbg_element_from_idx(rdbg, global_variables, global_idx); - if(global_var->link_flags & RADDBG_LinkFlag_TypeScoped) + U64 global_idx = rdi_vmap_idx_from_voff(rdi->global_vmap, rdi->global_vmap_count, vtable_voff); + RDI_GlobalVariable *global_var = rdi_element_from_idx(rdi, global_variables, global_idx); + if(global_var->link_flags & RDI_LinkFlag_TypeScoped) { - RADDBG_UDT *udt = raddbg_element_from_idx(rdbg, udts, global_var->container_idx); - RADDBG_TypeNode *type = raddbg_element_from_idx(rdbg, type_nodes, udt->self_type_idx); - TG_Key derived_type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type->kind), (U64)udt->self_type_idx); + RDI_UDT *udt = rdi_element_from_idx(rdi, udts, global_var->container_idx); + RDI_TypeNode *type = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); + TG_Key derived_type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type->kind), (U64)udt->self_type_idx); TG_Key ptr_to_derived_type_key = tg_cons_type_make(graph, TG_Kind_Ptr, derived_type_key, 0); eval.type_key = ptr_to_derived_type_key; } @@ -4574,13 +4549,13 @@ df_string_from_ascii_value(Arena *arena, U8 val) } internal String8 -df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_EvalVizStringFlags flags, U32 radix, DF_Eval eval) +df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, DF_EvalVizStringFlags flags, U32 radix, DF_Eval eval) { ProfBeginFunction(); String8 result = {0}; - TG_Key type_key = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, eval.type_key); + TG_Key type_key = tg_unwrapped_from_graph_rdi_key(graph, rdi, eval.type_key); TG_Kind type_kind = tg_kind_from_key(type_key); - U64 type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + U64 type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); U8 digit_group_separator = 0; if(!(flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules)) { @@ -4648,7 +4623,7 @@ df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *r case TG_Kind_Enum: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, type_key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, type_key); String8 constant_name = {0}; for(U64 val_idx = 0; val_idx < type->count; val_idx += 1) { @@ -4688,7 +4663,7 @@ df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *r //- rjf: writing values back to child processes internal B32 -df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval dst_eval, DF_Eval src_eval) +df_commit_eval_value(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval dst_eval, DF_Eval src_eval) { B32 result = 0; Temp scratch = scratch_begin(0, 0); @@ -4700,8 +4675,8 @@ df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, TG_Key src_type_key = src_eval.type_key; TG_Kind dst_type_kind = tg_kind_from_key(dst_type_key); TG_Kind src_type_kind = tg_kind_from_key(src_type_key); - U64 dst_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, dst_type_key); - U64 src_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, src_type_key); + U64 dst_type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, dst_type_key); + U64 src_type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, src_type_key); //- rjf: get commit data based on destination type String8 commit_data = {0}; @@ -4721,7 +4696,7 @@ df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, case TG_Kind_LRef: if((TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) || src_type_kind == TG_Kind_Ptr) { - DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, src_eval); commit_data = str8((U8 *)&value_eval.imm_u64, dst_type_byte_size); commit_data = push_str8_copy(scratch.arena, commit_data); }break; @@ -4744,7 +4719,7 @@ df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, case TG_Kind_Bool: if(TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) { - DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, src_eval); commit_data = str8((U8 *)&value_eval.imm_u64, dst_type_byte_size); commit_data = push_str8_copy(scratch.arena, commit_data); }break; @@ -4756,7 +4731,7 @@ df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, src_type_kind == TG_Kind_F64) { F32 value = 0; - DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, src_eval); switch(src_type_kind) { case TG_Kind_F32:{value = value_eval.imm_f32;}break; @@ -4774,7 +4749,7 @@ df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, src_type_kind == TG_Kind_F64) { F64 value = 0; - DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, src_eval); switch(src_type_kind) { case TG_Kind_F32:{value = (F64)value_eval.imm_f32;}break; @@ -4789,7 +4764,7 @@ df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, case TG_Kind_Enum: if(TG_Kind_Char8 <= src_type_kind && src_type_kind <= TG_Kind_Bool) { - DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, src_eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, src_eval); commit_data = str8((U8 *)&value_eval.imm_u64, dst_type_byte_size); commit_data = push_str8_copy(scratch.arena, commit_data); }break; @@ -4909,7 +4884,7 @@ df_filtered_data_members_from_members_cfg_table(Arena *arena, TG_MemberArray mem } internal DF_EvalLinkBaseChunkList -df_eval_link_base_chunk_list_from_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key link_member_type_key, U64 link_member_off, DF_CtrlCtx *ctrl_ctx, DF_Eval eval, U64 cap) +df_eval_link_base_chunk_list_from_eval(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key link_member_type_key, U64 link_member_off, DF_CtrlCtx *ctrl_ctx, DF_Eval eval, U64 cap) { DF_EvalLinkBaseChunkList list = {0}; for(DF_Eval base_eval = eval, last_eval = zero_struct; list.count < cap;) @@ -4943,7 +4918,7 @@ df_eval_link_base_chunk_list_from_eval(Arena *arena, TG_Graph *graph, RADDBG_Par base_eval.mode, base_eval.offset + link_member_off, }; - DF_Eval link_member_value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, link_member_eval); + DF_Eval link_member_value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, link_member_eval); // rjf: advance to next link last_eval = base_eval; @@ -5042,13 +5017,13 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie ////////////////////////////// //- rjf: apply view rules & resolve eval // - eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval, cfg_table); ////////////////////////////// //- rjf: unpack eval // - TG_Key eval_type_key = tg_unwrapped_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, eval.type_key); + TG_Key eval_type_key = tg_unwrapped_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, eval.type_key); TG_Kind eval_type_kind = tg_kind_from_key(eval_type_key); ////////////////////////////// @@ -5079,9 +5054,9 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie TG_Kind ptr_type_kind = TG_Kind_Null; if(eval_type_kind == TG_Kind_Ptr || eval_type_kind == TG_Kind_LRef || eval_type_kind == TG_Kind_RRef) { - TG_Key direct_type_key = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, eval_type_key); + TG_Key direct_type_key = tg_ptee_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, eval_type_key); TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); - DF_Eval ptr_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + DF_Eval ptr_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); // rjf: ptrs to udts if(parent_is_expanded && @@ -5194,7 +5169,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie ProfScope("build viz blocks for UDT members") { //- rjf: type -> filtered data members - TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, udt_eval.type_key); + TG_MemberArray data_members = tg_data_members_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, udt_eval.type_key); TG_MemberArray filtered_data_members = df_filtered_data_members_from_members_cfg_table(scratch.arena, data_members, cfg_table); //- rjf: build blocks for all members, split by sub-expansions @@ -5250,7 +5225,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie ProfScope("build viz blocks for UDT type-eval enums") { //- rjf: type -> full type info - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, udt_eval.type_key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, udt_eval.type_key); //- rjf: build block for all members (cannot be expanded) DF_EvalVizBlock *last_vb = df_eval_viz_block_begin(arena, DF_EvalVizBlockKind_EnumMembers, key, df_expand_key_make(df_hash_from_expand_key(key), 0), depth+1); @@ -5272,7 +5247,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie ProfScope("(structs, unions, classes) descend to members & make block(s), with linked list view") { //- rjf: type -> data members - TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, udt_eval.type_key); + TG_MemberArray data_members = tg_data_members_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, udt_eval.type_key); //- rjf: find link member TG_Member *link_member = 0; @@ -5285,7 +5260,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie { link_member = mem; link_member_type_kind = tg_kind_from_key(link_member->type_key); - link_member_ptee_type_key = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, link_member->type_key); + link_member_ptee_type_key = tg_ptee_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, link_member->type_key); break; } } @@ -5303,7 +5278,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie DF_EvalLinkBaseChunkList link_bases = {0}; if(link_member_is_good) { - link_bases = df_eval_link_base_chunk_list_from_eval(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, link_member->type_key, link_member->off, ctrl_ctx, udt_eval, 512); + link_bases = df_eval_link_base_chunk_list_from_eval(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, link_member->type_key, link_member->off, ctrl_ctx, udt_eval, 512); } //- rjf: build blocks for all links, split by sub-expansions @@ -5366,10 +5341,10 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie ProfScope("(arrays) descend to elements & make block(s)") { //- rjf: unpack array type info - TG_Type *array_type = tg_type_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, arr_eval.type_key); + TG_Type *array_type = tg_type_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, arr_eval.type_key); U64 array_count = array_type->count; TG_Key element_type_key = array_type->direct_type_key; - U64 element_type_byte_size = tg_byte_size_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, element_type_key); + U64 element_type_byte_size = tg_byte_size_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, element_type_key); //- rjf: build blocks for all elements, split by sub-expansions DF_EvalVizBlock *last_vb = df_eval_viz_block_begin(arena, DF_EvalVizBlockKind_Elements, key, df_expand_key_make(df_hash_from_expand_key(key), 0), depth+1); @@ -5429,13 +5404,11 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie } internal DF_EvalVizBlockList -df_eval_viz_block_list_from_eval_view_expr_num(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, U64 num) +df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key) { ProfBeginFunction(); DF_EvalVizBlockList blocks = {0}; { - DF_ExpandKey start_parent_key = df_expand_key_make(5381, num); - DF_ExpandKey start_key = df_expand_key_make(df_hash_from_expand_key(start_parent_key), df_hash_from_string(expr)); DF_Eval eval = df_eval_from_string(arena, scope, ctrl_ctx, parse_ctx, macro_map, expr); U64 expr_comma_pos = str8_find_needle(expr, 0, str8_lit(","), 0); String8List default_view_rules = {0}; @@ -5460,14 +5433,14 @@ df_eval_viz_block_list_from_eval_view_expr_num(Arena *arena, DBGI_Scope *scope, str8_list_pushf(arena, &default_view_rules, "array:{%S}", expr_extension); } } - String8 view_rule_string = df_eval_view_rule_from_key(eval_view, start_key); + String8 view_rule_string = df_eval_view_rule_from_key(eval_view, key); DF_CfgTable view_rule_table = {0}; for(String8Node *n = default_view_rules.first; n != 0; n = n->next) { df_cfg_table_push_unparsed_string(arena, &view_rule_table, n->string, DF_CfgSrc_User); } df_cfg_table_push_unparsed_string(arena, &view_rule_table, view_rule_string, DF_CfgSrc_User); - df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, macro_map, start_parent_key, start_key, expr, eval, 0, &view_rule_table, 0, &blocks); + df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, macro_map, parent_key, key, expr, eval, 0, &view_rule_table, 0, &blocks); } ProfEnd(); return blocks; @@ -5609,7 +5582,7 @@ df_eval_viz_row_list_push_new(Arena *arena, EVAL_ParseCtx *parse_ctx, DF_EvalViz // rjf: determine exandability, editability if(tg_kind_from_key(eval.type_key) != TG_Kind_Null) { - for(TG_Key t = eval.type_key;; t = tg_unwrapped_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, t)) + for(TG_Key t = eval.type_key;; t = tg_unwrapped_direct_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, t)) { TG_Kind kind = tg_kind_from_key(t); if(kind == TG_Kind_Null) @@ -5639,6 +5612,10 @@ df_eval_viz_row_list_push_new(Arena *arena, EVAL_ParseCtx *parse_ctx, DF_EvalViz { break; } + if(kind == TG_Kind_Function) + { + break; + } } } @@ -6185,37 +6162,57 @@ df_push_active_target_list(Arena *arena) internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread) { - ProfBeginFunction(); CTRL_Unwind result = {0}; - DF_RunUnwindCache *cache = &df_state->unwind_cache; - if(cache->table_size != 0) + DF_Handle handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&handle)); + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1) { - DF_Handle handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&handle)); - U64 slot_idx = hash % cache->table_size; - DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx]; + DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)]; + if(cache_idx == 0 && cache->slots_count == 0) + { + cache->slots_count = 1024; + cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); + } + else if(cache->slots_count == 0) + { + break; + } + U64 slot_idx = hash%cache->slots_count; + DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; + DF_RunUnwindCacheNode *node = 0; for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) { if(df_handle_match(n->thread, handle)) { - result = n->unwind; + node = n; + break; + } + } + if(node != 0) + { + result = node->unwind; + break; + } + else + { + result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); + if(!result.error) + { + node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + node->thread = handle; + node->unwind = result; break; } } } - ProfEnd(); return result; } internal U64 df_query_cached_rip_from_thread(DF_Entity *thread) { - U64 result = 0; - CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - if(unwind.first != 0) - { - result = unwind.first->rip; - } + U64 result = df_query_cached_rip_from_thread_unwind(thread, 0); return result; } @@ -6223,14 +6220,21 @@ internal U64 df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) { U64 result = 0; - CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) + if(unwind_count == 0) { - if(unwind_idx == unwind_count) + result = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); + } + else + { + CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); + U64 unwind_idx = 0; + for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) { - result = frame->rip; - break; + if(unwind_idx == unwind_count) + { + result = frame->rip; + break; + } } } return result; @@ -6240,13 +6244,18 @@ internal U64 df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr) { U64 result = 0; + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->tls_base_caches); cache_idx += 1) { - DF_RunTLSBaseCache *cache = &df_state->tls_base_cache; - if(cache->slots_count == 0) + DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[(df_state->tls_base_cache_gen+cache_idx)%ArrayCount(df_state->tls_base_caches)]; + if(cache_idx == 0 && cache->slots_count == 0) { cache->slots_count = 256; cache->slots = push_array(cache->arena, DF_RunTLSBaseCacheSlot, cache->slots_count); } + else if(cache->slots_count == 0) + { + break; + } DF_Handle handle = df_handle_from_entity(process); U64 hash = df_hash_from_seed_string(df_hash_from_string(str8_struct(&handle)), str8_struct(&rip_vaddr)); U64 slot_idx = hash%cache->slots_count; @@ -6262,14 +6271,22 @@ df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 roo } if(node == 0) { - node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1); - SLLQueuePush_N(slot->first, slot->last, node, hash_next); - node->process = handle; - node->root_vaddr = root_vaddr; - node->rip_vaddr = rip_vaddr; - node->tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr); + U64 tls_base_vaddr = df_tls_base_vaddr_from_process_root_rip(process, root_vaddr, rip_vaddr); + if(tls_base_vaddr != 0) + { + node = push_array(cache->arena, DF_RunTLSBaseCacheNode, 1); + SLLQueuePush_N(slot->first, slot->last, node, hash_next); + node->process = handle; + node->root_vaddr = root_vaddr; + node->rip_vaddr = rip_vaddr; + node->tls_base_vaddr = tls_base_vaddr; + } + } + if(node != 0 && node->tls_base_vaddr != 0) + { + result = node->tls_base_vaddr; + break; } - result = node->tls_base_vaddr; } return result; } @@ -6279,13 +6296,18 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->locals_caches); cache_idx += 1) { - DF_RunLocalsCache *cache = &df_state->locals_cache; - if(cache->table_size == 0) + DF_RunLocalsCache *cache = &df_state->locals_caches[(df_state->locals_cache_gen+cache_idx)%ArrayCount(df_state->locals_caches)]; + if(cache_idx == 0 && cache->table_size == 0) { cache->table_size = 256; cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); } + else if(cache->table_size == 0) + { + break; + } DF_Handle handle = df_handle_from_entity(binary); U64 hash = df_hash_from_string(str8_struct(&handle)); U64 slot_idx = hash % cache->table_size; @@ -6313,9 +6335,10 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) } dbgi_scope_close(scope); } - if(node != 0) + if(node != 0 && node->locals_map->slots_count != 0) { map = node->locals_map; + break; } } ProfEnd(); @@ -6327,13 +6350,18 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; + for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->member_caches); cache_idx += 1) { - DF_RunLocalsCache *cache = &df_state->member_cache; - if(cache->table_size == 0) + DF_RunLocalsCache *cache = &df_state->member_caches[(df_state->member_cache_gen+cache_idx)%ArrayCount(df_state->member_caches)]; + if(cache_idx == 0 && cache->table_size == 0) { cache->table_size = 256; cache->table = push_array(cache->arena, DF_RunLocalsCacheSlot, cache->table_size); } + else if(cache->table_size == 0) + { + break; + } DF_Handle handle = df_handle_from_entity(binary); U64 hash = df_hash_from_string(str8_struct(&handle)); U64 slot_idx = hash % cache->table_size; @@ -6361,9 +6389,10 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) } dbgi_scope_close(scope); } - if(node != 0) + if(node != 0 && node->locals_map->slots_count != 0) { map = node->locals_map; + break; } } ProfEnd(); @@ -6382,7 +6411,7 @@ df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec) //~ rjf: Main Layer Top-Level Calls internal void -df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist) +df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) { Arena *arena = arena_alloc(); df_state = push_array(arena, DF_State, 1); @@ -6393,6 +6422,7 @@ df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist df_state->entities_base = push_array(df_state->entities_arena, DF_Entity, 0); df_state->entities_count = 0; df_state->ctrl_msg_arena = arena_alloc(); + df_state->ctrl_entity_store = ctrl_entity_store_alloc(); df_state->ctrl_stop_arena = arena_alloc(); df_state->entities_root = df_entity_alloc(0, &df_g_nil_entity, DF_EntityKind_Root); df_state->cmd_spec_table_size = 1024; @@ -6414,7 +6444,7 @@ df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist // rjf: set up initial entities { DF_Entity *local_machine = df_entity_alloc(0, df_state->entities_root, DF_EntityKind_Machine); - df_entity_equip_ctrl_machine_id(local_machine, CTRL_MachineID_Client); + df_entity_equip_ctrl_machine_id(local_machine, CTRL_MachineID_Local); df_entity_equip_name(0, local_machine, str8_lit("This PC")); } @@ -6431,10 +6461,22 @@ df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist } // rjf: set up per-run caches - df_state->unwind_cache.arena = arena_alloc(); - df_state->tls_base_cache.arena = arena_alloc(); - df_state->locals_cache.arena = arena_alloc(); - df_state->member_cache.arena = arena_alloc(); + for(U64 idx = 0; idx < ArrayCount(df_state->unwind_caches); idx += 1) + { + df_state->unwind_caches[idx].arena = arena_alloc(); + } + for(U64 idx = 0; idx < ArrayCount(df_state->tls_base_caches); idx += 1) + { + df_state->tls_base_caches[idx].arena = arena_alloc(); + } + for(U64 idx = 0; idx < ArrayCount(df_state->locals_caches); idx += 1) + { + df_state->locals_caches[idx].arena = arena_alloc(); + } + for(U64 idx = 0; idx < ArrayCount(df_state->member_caches); idx += 1) + { + df_state->member_caches[idx].arena = arena_alloc(); + } // rjf: set up eval view cache df_state->eval_view_cache.slots_count = 4096; @@ -6447,8 +6489,25 @@ df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist { Temp scratch = scratch_begin(0, 0); + // rjf: unpack command line arguments + String8 user_cfg_path = cmd_line_string(cmdln, str8_lit("user")); + String8 profile_cfg_path = cmd_line_string(cmdln, str8_lit("profile")); + { + String8 user_program_data_path = os_string_from_system_path(scratch.arena, OS_SystemPath_UserProgramData); + String8 user_data_folder = push_str8f(scratch.arena, "%S/%S", user_program_data_path, str8_lit("raddbg")); + os_make_directory(user_data_folder); + if(user_cfg_path.size == 0) + { + user_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_user", user_data_folder); + } + if(profile_cfg_path.size == 0) + { + profile_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_profile", user_data_folder); + } + } + // rjf: set up config path state - String8 cfg_src_paths[DF_CfgSrc_COUNT] = {user_path, profile_path}; + String8 cfg_src_paths[DF_CfgSrc_COUNT] = {user_cfg_path, profile_cfg_path}; for(DF_CfgSrc src = (DF_CfgSrc)0; src < DF_CfgSrc_COUNT; src = (DF_CfgSrc)(src+1)) { df_state->cfg_path_arenas[src] = arena_alloc(); @@ -6522,11 +6581,12 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) Temp scratch = scratch_begin(&arena, 1); //- rjf: grab next reggen/memgen - U64 new_memgen_idx = ctrl_memgen_idx(); - U64 new_reggen_idx = ctrl_reggen_idx(); + U64 new_mem_gen = ctrl_mem_gen(); + U64 new_reg_gen = ctrl_reg_gen(); //- rjf: consume & process events CTRL_EventList events = ctrl_c2u_pop_events(scratch.arena); + ctrl_entity_store_apply_events(df_state->ctrl_entity_store, &events); for(CTRL_EventNode *event_n = events.first; event_n != 0; event_n = event_n->next) { CTRL_Event *event = &event_n->v; @@ -6563,10 +6623,23 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectThread)); } + // rjf: if no stop-causing thread, and if selected thread, snap to selected + if(df_entity_is_nil(stop_thread)) + { + DF_Entity *selected_thread = df_entity_from_handle(df_state->ctrl_ctx.thread); + if(!df_entity_is_nil(selected_thread)) + { + DF_CmdParams params = df_cmd_params_zero(); + params.entity = df_handle_from_entity(selected_thread); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); + } + } + // rjf: thread hit user breakpoint -> increment breakpoint hit count if(event->cause == CTRL_EventCause_UserBreakpoint) { - U64 stop_thread_vaddr = df_rip_from_thread(stop_thread); + U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, stop_thread->ctrl_machine_id, stop_thread->ctrl_handle); DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr); DF_Entity *binary = df_binary_file_from_module(module); @@ -6756,11 +6829,28 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) DF_Entity *binary = df_entity_from_path(bin_path, DF_EntityFromPathFlag_All); df_entity_equip_entity_handle(module, df_handle_from_entity(binary)); - // rjf: is first -> attach process color if applicable - if(is_first && parent->flags & DF_EntityFlag_HasColor) + // rjf: is first -> find target, equip process & module & first thread with target color + if(is_first) { - Vec4F32 rgba = df_rgba_from_entity(parent); - df_entity_equip_color_rgba(module, rgba); + DF_EntityList targets = df_query_cached_entity_list_with_kind(DF_EntityKind_Target); + for(DF_EntityNode *n = targets.first; n != 0; n = n->next) + { + DF_Entity *target = n->entity; + DF_Entity *exe = df_entity_child_from_kind(target, DF_EntityKind_Executable); + String8 exe_name = exe->name; + String8 exe_name_normalized = path_normalized_from_string(scratch.arena, exe_name); + String8 module_name_normalized = path_normalized_from_string(scratch.arena, module->name); + if(str8_match(exe_name_normalized, module_name_normalized, StringMatchFlag_CaseInsensitive) && + target->flags & DF_EntityFlag_HasColor) + { + DF_Entity *first_thread = df_entity_child_from_kind(parent, DF_EntityKind_Thread); + Vec4F32 rgba = df_rgba_from_entity(target); + df_entity_equip_color_rgba(parent, rgba); + df_entity_equip_color_rgba(first_thread, rgba); + df_entity_equip_color_rgba(module, rgba); + break; + } + } } }break; @@ -6838,114 +6928,58 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) case CTRL_EventKind_MemCommit:{}break; case CTRL_EventKind_MemDecommit:{}break; case CTRL_EventKind_MemRelease:{}break; - - //- rjf: ctrl requests - - case CTRL_EventKind_LaunchAndInitDone: - case CTRL_EventKind_LaunchAndHandshakeDone: - case CTRL_EventKind_AttachDone: - case CTRL_EventKind_KillDone: - case CTRL_EventKind_DetachDone: - { - // rjf: resolve request entities - DF_EntityID id = event->msg_id; - DF_Entity *request_entity = df_entity_from_id(id); - if(!df_entity_is_nil(request_entity)) - { - df_entity_mark_for_deletion(request_entity); - switch(request_entity->subkind) - { - case CTRL_MsgKind_LaunchAndInit: - case CTRL_MsgKind_LaunchAndHandshake: - { - DF_Entity *target = df_entity_from_handle(request_entity->entity_handle); - DF_Entity *process = df_entity_from_ctrl_id(event->machine_id, event->entity_id); - DF_Entity *thread = df_entity_child_from_kind(process, DF_EntityKind_Thread); - if(!df_entity_is_nil(target) && !df_entity_is_nil(process) && !df_entity_is_nil(thread)) - { - df_entity_equip_entity_handle(process, df_handle_from_entity(target)); - if(target->flags & DF_EntityFlag_HasColor) - { - Vec4F32 color = df_rgba_from_entity(target); - df_entity_equip_color_rgba(process, color); - df_entity_equip_color_rgba(thread, color); - } - } - }break; - } - } - - // rjf: collect s top info - arena_clear(df_state->ctrl_stop_arena); - MemoryCopyStruct(&df_state->ctrl_last_stop_event, event); - df_state->ctrl_last_stop_event.string = push_str8_copy(df_state->ctrl_stop_arena, df_state->ctrl_last_stop_event.string); - }break; } } - //- rjf: refresh unwind cache - if((df_state->unwind_cache_memgen_idx != new_memgen_idx || - df_state->unwind_cache_reggen_idx != new_reggen_idx) && + //- rjf: clear unwind cache + if((df_state->unwind_cache_memgen_idx != new_mem_gen || + df_state->unwind_cache_reggen_idx != new_reg_gen) && !df_ctrl_targets_running()) ProfScope("per-thread unwind gather") { - B32 good = 1; - DF_EntityList all_threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); - DF_RunUnwindCache *cache = &df_state->unwind_cache; - arena_clear(cache->arena); - cache->table_size = 1024; - cache->table = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->table_size); - for(DF_EntityNode *n = all_threads.first; n != 0; n = n->next) - { - DF_Entity *thread = n->entity; - DF_Handle thread_handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&thread_handle)); - U64 slot_idx = hash % cache->table_size; - DF_RunUnwindCacheSlot *slot = &cache->table[slot_idx]; - DF_RunUnwindCacheNode *cache_node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); - cache_node->thread = thread_handle; - cache_node->unwind = df_push_unwind_from_thread(cache->arena, thread); - SLLQueuePush_NZ(0, slot->first, slot->last, cache_node, hash_next); - if(cache_node->unwind.error != 0) - { - good = 0; - break; - } - } - df_state->unwind_cache_memgen_idx = new_memgen_idx; - df_state->unwind_cache_reggen_idx = new_reggen_idx; - } - - //- rjf: clear tls base cache - if((df_state->tls_base_cache_reggen_idx != new_reggen_idx || - df_state->tls_base_cache_memgen_idx != new_memgen_idx) && - !df_ctrl_targets_running()) - { - DF_RunTLSBaseCache *cache = &df_state->tls_base_cache; + df_state->unwind_cache_gen += 1; + DF_RunUnwindCache *cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; arena_clear(cache->arena); cache->slots_count = 0; cache->slots = 0; - df_state->tls_base_cache_reggen_idx = new_reggen_idx; - df_state->tls_base_cache_memgen_idx = new_memgen_idx; + df_state->unwind_cache_memgen_idx = new_mem_gen; + df_state->unwind_cache_reggen_idx = new_reg_gen; + } + + //- rjf: clear tls base cache + if((df_state->tls_base_cache_reggen_idx != new_reg_gen || + df_state->tls_base_cache_memgen_idx != new_mem_gen) && + !df_ctrl_targets_running()) + { + df_state->tls_base_cache_gen += 1; + DF_RunTLSBaseCache *cache = &df_state->tls_base_caches[df_state->tls_base_cache_gen%ArrayCount(df_state->tls_base_caches)]; + arena_clear(cache->arena); + cache->slots_count = 0; + cache->slots = 0; + df_state->tls_base_cache_reggen_idx = new_reg_gen; + df_state->tls_base_cache_memgen_idx = new_mem_gen; } //- rjf: clear locals cache - if(df_state->locals_cache_reggen_idx != new_reggen_idx && !df_ctrl_targets_running()) + if(df_state->locals_cache_reggen_idx != new_reg_gen && + !df_ctrl_targets_running()) { - DF_RunLocalsCache *cache = &df_state->locals_cache; + df_state->locals_cache_gen += 1; + DF_RunLocalsCache *cache = &df_state->locals_caches[df_state->locals_cache_gen%ArrayCount(df_state->locals_caches)]; arena_clear(cache->arena); cache->table_size = 0; cache->table = 0; - df_state->locals_cache_reggen_idx = new_reggen_idx; + df_state->locals_cache_reggen_idx = new_reg_gen; } //- rjf: clear members cache - if(df_state->member_cache_reggen_idx != new_reggen_idx && !df_ctrl_targets_running()) + if(df_state->member_cache_reggen_idx != new_reg_gen && !df_ctrl_targets_running()) { - DF_RunLocalsCache *cache = &df_state->member_cache; + df_state->member_cache_gen += 1; + DF_RunLocalsCache *cache = &df_state->member_caches[df_state->member_cache_gen%ArrayCount(df_state->member_caches)]; arena_clear(cache->arena); cache->table_size = 0; cache->table = 0; - df_state->member_cache_reggen_idx = new_reggen_idx; + df_state->member_cache_reggen_idx = new_reg_gen; } scratch_end(scratch); @@ -7110,31 +7144,20 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } } - // rjf: build corresponding request entity - DF_Entity *request_entity = df_entity_alloc(0, df_entity_root(), DF_EntityKind_CtrlRequest); - { - request_entity->subkind = CTRL_MsgKind_LaunchAndInit; - request_entity->entity_handle = df_handle_from_entity(target); - } - // rjf: push message to launch { - CTRL_Msg msg = {CTRL_MsgKind_LaunchAndInit}; - msg.msg_id = request_entity->id; + CTRL_Msg msg = {CTRL_MsgKind_Launch}; msg.path = path; msg.cmd_line_string_list = cmdln_strings; msg.env_inherit = 1; MemoryCopyArray(msg.exception_code_filters, df_state->ctrl_exception_code_filters); - str8_list_push(scratch.arena, &msg.strings, entry); + str8_list_push(scratch.arena, &msg.entry_points, entry); df_push_ctrl_msg(&msg); } } - // rjf: run if needed - if(core_cmd_kind == DF_CoreCmdKind_LaunchAndRun) - { - df_ctrl_run(DF_RunKind_Run, &df_g_nil_entity, 0); - } + // rjf: run + df_ctrl_run(DF_RunKind_Run, &df_g_nil_entity, CTRL_RunFlag_StopOnEntryPoint * (core_cmd_kind == DF_CoreCmdKind_LaunchAndInit), 0); } // rjf: no targets -> error @@ -7238,7 +7261,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } if(good_to_run) { - df_ctrl_run(DF_RunKind_Run, &df_g_nil_entity, 0); + df_ctrl_run(DF_RunKind_Run, &df_g_nil_entity, 0, 0); } else { @@ -7307,11 +7330,11 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } if(good && traps.count != 0) { - df_ctrl_run(DF_RunKind_Step, thread, &traps); + df_ctrl_run(DF_RunKind_Step, thread, 0, &traps); } if(good && traps.count == 0) { - df_ctrl_run(DF_RunKind_SingleStep, thread, &traps); + df_ctrl_run(DF_RunKind_SingleStep, thread, 0, &traps); } } }break; @@ -7324,7 +7347,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) { if(df_ctrl_targets_running()) { - df_ctrl_run(df_state->ctrl_last_run_kind, df_entity_from_handle(df_state->ctrl_last_run_thread), &df_state->ctrl_last_run_traps); + df_ctrl_run(df_state->ctrl_last_run_kind, df_entity_from_handle(df_state->ctrl_last_run_thread), df_state->ctrl_last_run_flags, &df_state->ctrl_last_run_traps); } }break; case DF_CoreCmdKind_SetThreadIP: @@ -7492,7 +7515,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) }break; case DF_CoreCmdKind_FreezeLocalMachine: { - CTRL_MachineID machine_id = CTRL_MachineID_Client; + CTRL_MachineID machine_id = CTRL_MachineID_Local; DF_CmdParams params = df_cmd_params_zero(); params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id)); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); @@ -7500,7 +7523,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) }break; case DF_CoreCmdKind_ThawLocalMachine: { - CTRL_MachineID machine_id = CTRL_MachineID_Client; + CTRL_MachineID machine_id = CTRL_MachineID_Local; DF_CmdParams params = df_cmd_params_zero(); params.entity = df_handle_from_entity(df_machine_entity_from_machine_id(machine_id)); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); @@ -8493,7 +8516,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) case DF_CoreCmdKind_RegisterAsJITDebugger: { #if OS_WINDOWS - String8 path_to_debugger_binary = os_get_command_line_arguments().first->string; + String8 path_to_debugger_binary = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); String8 name8 = str8_lit("Debugger"); String8 data8 = push_str8f(scratch.arena, "%S --jit_pid:%%ld --jit_code:%%ld --jit_addr:0x%%p", path_to_debugger_binary); String16 name16 = str16_from_8(scratch.arena, name8); diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 848f50a7..b038b254 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -430,6 +430,7 @@ struct DF_Entity DF_EntityFlags flags; DF_EntityID id; U64 generation; + U64 alloc_time_us; B32 deleted; F32 alive_t; @@ -446,7 +447,7 @@ struct DF_Entity // rjf: ctrl entity equipment CTRL_MachineID ctrl_machine_id; - CTRL_Handle ctrl_handle; + DMN_Handle ctrl_handle; Architecture arch; U32 ctrl_id; U64 stack_base; @@ -510,20 +511,7 @@ struct DF_EntityFuzzyItemArray }; //////////////////////////////// -//~ rjf: Text Slices (output type from data which can be used to produce readable text) - -//- rjf: text slice construction flags - -typedef U32 DF_TextSliceFlags; -enum -{ - DF_TextSliceFlag_CodeBytes = (1<<0), - DF_TextSliceFlag_Addresses = (1<<1), - DF_TextSliceFlag_Tokens = (1<<2), - DF_TextSliceFlag_Src2Dasm = (1<<3), - DF_TextSliceFlag_Dasm2Src = (1<<4), - DF_TextSliceFlag_VirtualOff= (1<<5), -}; +//~ rjf: Source <-> Disasm Types //- rjf: debug info for mapping src -> disasm @@ -939,7 +927,6 @@ struct DF_RunUnwindCacheNode DF_RunUnwindCacheNode *hash_next; DF_Handle thread; CTRL_Unwind unwind; - U64 tls_base_vaddr; }; typedef struct DF_RunUnwindCacheSlot DF_RunUnwindCacheSlot; @@ -953,8 +940,8 @@ typedef struct DF_RunUnwindCache DF_RunUnwindCache; struct DF_RunUnwindCache { Arena *arena; - U64 table_size; - DF_RunUnwindCacheSlot *table; + U64 slots_count; + DF_RunUnwindCacheSlot *slots; }; //- rjf: per-run tls-base-vaddr cache @@ -1135,14 +1122,18 @@ struct DF_State // rjf: per-run caches U64 unwind_cache_reggen_idx; U64 unwind_cache_memgen_idx; - DF_RunUnwindCache unwind_cache; + DF_RunUnwindCache unwind_caches[2]; + U64 unwind_cache_gen; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; - DF_RunTLSBaseCache tls_base_cache; + DF_RunTLSBaseCache tls_base_caches[2]; + U64 tls_base_cache_gen; U64 locals_cache_reggen_idx; - DF_RunLocalsCache locals_cache; + DF_RunLocalsCache locals_caches[2]; + U64 locals_cache_gen; U64 member_cache_reggen_idx; - DF_RunLocalsCache member_cache; + DF_RunLocalsCache member_caches[2]; + U64 member_cache_gen; // rjf: eval view cache DF_EvalViewCache eval_view_cache; @@ -1168,6 +1159,7 @@ struct DF_State DF_RunKind ctrl_last_run_kind; U64 ctrl_last_run_frame_idx; DF_Handle ctrl_last_run_thread; + CTRL_RunFlags ctrl_last_run_flags; CTRL_TrapList ctrl_last_run_traps; U64 ctrl_run_gen; B32 ctrl_is_running; @@ -1178,6 +1170,7 @@ struct DF_State B32 ctrl_solo_stepping_mode; // rjf: control thread ctrl -> user reading state + CTRL_EntityStore *ctrl_entity_store; Arena *ctrl_stop_arena; CTRL_Event ctrl_last_stop_event; @@ -1226,6 +1219,7 @@ read_only global DF_Entity df_g_nil_entity = 0, 0, 0, + 0, // rjf: allocationless, simple equipment {0}, @@ -1396,9 +1390,6 @@ internal DF_EntityFuzzyItemArray df_entity_fuzzy_item_array_from_entity_array_ne //- rjf: entity -> text info internal TXTI_Handle df_txti_handle_from_entity(DF_Entity *entity); -//- rjf: entity -> disasm info -internal DASM_Handle df_dasm_handle_from_process_vaddr(DF_Entity *process, U64 vaddr); - //- rjf: full path building, from file/folder entities internal String8 df_full_path_from_entity(Arena *arena, DF_Entity *entity); @@ -1445,7 +1436,7 @@ internal void df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src); //- rjf: control layer correllation equipment internal void df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id); -internal void df_entity_equip_ctrl_handle(DF_Entity *entity, CTRL_Handle handle); +internal void df_entity_equip_ctrl_handle(DF_Entity *entity, DMN_Handle handle); internal void df_entity_equip_arch(DF_Entity *entity, Architecture arch); internal void df_entity_equip_ctrl_id(DF_Entity *entity, U32 id); internal void df_entity_equip_stack_base(DF_Entity *entity, U64 stack_base); @@ -1466,7 +1457,7 @@ internal DF_Entity *df_entity_root(void); internal DF_EntityList df_push_entity_list_with_kind(Arena *arena, DF_EntityKind kind); internal DF_Entity *df_entity_from_id(DF_EntityID id); internal DF_Entity *df_machine_entity_from_machine_id(CTRL_MachineID machine_id); -internal DF_Entity *df_entity_from_ctrl_handle(CTRL_MachineID machine_id, CTRL_Handle handle); +internal DF_Entity *df_entity_from_ctrl_handle(CTRL_MachineID machine_id, DMN_Handle handle); internal DF_Entity *df_entity_from_ctrl_id(CTRL_MachineID machine_id, U32 id); internal DF_Entity *df_entity_from_name_and_kind(String8 string, DF_EntityKind kind); internal DF_Entity *df_entity_from_u64_and_kind(U64 u64, DF_EntityKind kind); @@ -1531,7 +1522,6 @@ internal DF_TextLineSrc2DasmInfoListArray df_text_line_src2dasm_info_list_array_ //- rjf: voff -> src lookups internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff); -internal DF_TextLineDasm2SrcInfoList df_text_line_dasm2src_info_from_voff(Arena *arena, U64 voff); //- rjf: symbol -> voff lookups internal U64 df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name); @@ -1545,9 +1535,6 @@ internal DF_Entity *df_module_from_process_vaddr(DF_Entity *process, U64 vaddr); internal DF_Entity *df_module_from_thread(DF_Entity *thread); internal U64 df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); internal Architecture df_architecture_from_entity(DF_Entity *entity); -internal CTRL_Unwind df_push_unwind_from_thread(Arena *arena, DF_Entity *thread); -internal U64 df_rip_from_thread(DF_Entity *thread); -internal U64 df_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); internal EVAL_String2NumMap *df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); internal EVAL_String2NumMap *df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr); @@ -1565,7 +1552,7 @@ internal DF_Entity *df_log_from_entity(DF_Entity *entity); internal void df_push_ctrl_msg(CTRL_Msg *msg); //- rjf: control thread running -internal void df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_TrapList *run_traps); +internal void df_ctrl_run(DF_RunKind run, DF_Entity *target, DF_Entity *run_thread, CTRL_RunFlags flags, CTRL_TrapList *run_traps); //- rjf: stopped info from the control thread internal CTRL_Event df_ctrl_last_stop_event(void); @@ -1577,8 +1564,8 @@ internal B32 df_eval_memory_read(void *u, void *out, U64 addr, U64 size); internal EVAL_ParseCtx df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 vaddr); internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt); internal DF_Eval df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string); -internal DF_Eval df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); -internal DF_Eval df_dynamically_typed_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); +internal DF_Eval df_value_mode_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); +internal DF_Eval df_dynamically_typed_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg); //////////////////////////////// @@ -1602,14 +1589,14 @@ internal String8 df_eval_view_rule_from_key(DF_EvalView *eval_view, DF_ExpandKey //- rjf: evaluation value string builder helpers internal String8 df_string_from_ascii_value(Arena *arena, U8 val); -internal String8 df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_EvalVizStringFlags flags, U32 radix, DF_Eval eval); +internal String8 df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, DF_EvalVizStringFlags flags, U32 radix, DF_Eval eval); //- rjf: writing values back to child processes -internal B32 df_commit_eval_value(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval dst_eval, DF_Eval src_eval); +internal B32 df_commit_eval_value(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval dst_eval, DF_Eval src_eval); //- rjf: type helpers internal TG_MemberArray df_filtered_data_members_from_members_cfg_table(Arena *arena, TG_MemberArray members, DF_CfgTable *cfg); -internal DF_EvalLinkBaseChunkList df_eval_link_base_chunk_list_from_eval(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key link_member_type_key, U64 link_member_off, DF_CtrlCtx *ctrl_ctx, DF_Eval eval, U64 cap); +internal DF_EvalLinkBaseChunkList df_eval_link_base_chunk_list_from_eval(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key link_member_type_key, U64 link_member_off, DF_CtrlCtx *ctrl_ctx, DF_Eval eval, U64 cap); internal DF_EvalLinkBase df_eval_link_base_from_chunk_list_index(DF_EvalLinkBaseChunkList *list, U64 idx); internal DF_EvalLinkBaseArray df_eval_link_base_array_from_chunk_list(Arena *arena, DF_EvalLinkBaseChunkList *chunks); @@ -1618,7 +1605,7 @@ internal DF_EvalVizBlock *df_eval_viz_block_begin(Arena *arena, DF_EvalVizBlockK internal DF_EvalVizBlock *df_eval_viz_block_split_and_continue(Arena *arena, DF_EvalVizBlockList *list, DF_EvalVizBlock *split_block, U64 split_idx); internal void df_eval_viz_block_end(DF_EvalVizBlockList *list, DF_EvalVizBlock *block); internal void df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalView *view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out); -internal DF_EvalVizBlockList df_eval_viz_block_list_from_eval_view_expr_num(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, U64 num); +internal DF_EvalVizBlockList df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key); internal void df_eval_viz_block_list_concat__in_place(DF_EvalVizBlockList *dst, DF_EvalVizBlockList *to_push); //- rjf: viz block list <-> table coordinates @@ -1688,7 +1675,7 @@ internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec); //////////////////////////////// //~ rjf: Main Layer Top-Level Calls -internal void df_core_init(String8 user_path, String8 profile_path, DF_StateDeltaHistory *hist); +internal void df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist); internal DF_CmdList df_core_gather_root_cmds(Arena *arena); internal void df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt); internal void df_core_end_frame(void); diff --git a/src/df/core/df_core.mdesk b/src/df/core/df_core.mdesk index f9586029..6cde1472 100644 --- a/src/df/core/df_core.mdesk +++ b/src/df/core/df_core.mdesk @@ -16,14 +16,6 @@ DF_CfgSrcTable: //////////////////////////////// //~ rjf: Entity Kind Tables -@table(name) -DF_NameKindTable: -{ - {Null} - {EntityName} - {EntityKindName} -} - @table(name name_lower op_delete op_freeze op_edit op_rename op_enable op_cond op_dup lf_mut_user_cfg tr_mut_user_cfg lf_mut_prof_cfg tr_mut_prof_cfg lf_mut_halt lf_mut_dbg tr_mut_halt tr_mut_dbg name_is_code user_lifetime name_label icon_kind display_string) DF_EntityKindTable: { @@ -61,7 +53,6 @@ DF_EntityKindTable: {Dest dest 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Path" Null "Destination" } //- rjf: control system entities - {CtrlRequest ctrl_request 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Control Request" } {Process process 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Threads "Process" } {Thread thread 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Thread "Thread" } {Module module 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Module "Module" } @@ -82,24 +73,24 @@ DF_EntityKindTable: @table(name, name_lower, c_type) DF_CmdParamSlotTable: { - {Window, window, `DF_Handle`} - {Panel, panel, `DF_Handle`} - {DestPanel, dest_panel, `DF_Handle`} - {PrevView, prev_view, `DF_Handle`} - {View, view, `DF_Handle`} - {Entity, entity, `DF_Handle`} - {EntityList, entity_list, `DF_HandleList`} - {String, string, `String8`} - {FilePath, file_path, `String8`} - {TextPoint, text_point, `TxtPt`} - {CmdSpec, cmd_spec, `struct DF_CmdSpec *`} - {ViewSpec, view_spec, `struct DF_ViewSpec *`} - {VirtualAddr, vaddr, `U64`} - {VirtualOff, voff, `U64`} - {Index, index, `U64`} - {ID, id, `U64`} - {PreferDisassembly, prefer_dasm, `B32`} - {ForceConfirm, force_confirm,`B32`} + {Window window `DF_Handle`} + {Panel panel `DF_Handle`} + {DestPanel dest_panel `DF_Handle`} + {PrevView prev_view `DF_Handle`} + {View view `DF_Handle`} + {Entity entity `DF_Handle`} + {EntityList entity_list `DF_HandleList`} + {String string `String8`} + {FilePath file_path `String8`} + {TextPoint text_point `TxtPt`} + {CmdSpec cmd_spec `struct DF_CmdSpec *`} + {ViewSpec view_spec `struct DF_ViewSpec *`} + {VirtualAddr vaddr `U64`} + {VirtualOff voff `U64`} + {Index index `U64`} + {ID id `U64`} + {PreferDisassembly prefer_dasm `B32`} + {ForceConfirm force_confirm `B32`} } @table(name lister_omit q_slot q_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 ) @@ -463,6 +454,13 @@ DF_CoreCmdTable:// | | | // rows, this stage offers the ability to build a ui // stretching over all of the rows. // +// whole ui build, "wu" -> sometimes, more sophisticated interfaces need to be +// provided for a view rule, that stretch beyond the +// limits of what could be offered inside a watch +// window block. in such cases, the eval/view-rule +// combo will be granted its own tab for example, and +// this stage is used to fill such a ui. +// // 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: // @@ -487,6 +485,7 @@ DF_CoreViewRuleTable: { {Null null "" - - - - "" - "" } {Array array "array" - - x - "Array" x "Specifies that a pointer points to N elements, rather than only 1." } + {Slice slice "slice" - - x - "Slice" x "Specifies that a struct to be rendered as a slice." } {List list "list" - - - x "List" x "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." } {ByteSwap bswap "bswap" x - x - "Byte Swap" x "Specifies that all integer primitives should be byte-swapped, such that their endianness is reversed." } {BaseDec base_dec "dec" x - - - "Decimal Base (Base 10)" x "Specifies that all integral evaluations should appear in base-10 form." } @@ -501,8 +500,7 @@ DF_CoreViewRuleTable: {Disasm disasm "disasm" - x - x "Disassembly" x "Displays as disassembled instructions, interpreting the data as raw machine code." } {Bitmap bitmap "bitmap" - x - x "Bitmap" x "Displays as a bitmap, interpreting the data as raw pixel data." } {Geo geo "geo" - x - x "Geometry" x "Displays as geometry, interpreting the data as vertex data." } - {Slice slice "slice" - - x - "Slice" x "Specifies that some struct is to be rendered as a slice." } - {OdinMap odin_map "odin_map" - - x - "Odin Map" x "Specifies that a struct to be rendered as an Odin map." } + {OdinMap odin_map "odin_map" - - x - "Odin map" x "Specifies that a struct to be rendered as an Odin map type." } } //////////////////////////////// @@ -1690,179 +1688,140 @@ DF_DevToggleTable: //- rjf: enums -@table_gen_enum -DF_CfgSrc: +@enum DF_CfgSrc: { - @expand(DF_CfgSrcTable a) `DF_CfgSrc_$(a.name),`; - `DF_CfgSrc_COUNT`; + @expand(DF_CfgSrcTable a) `$(a.name)`, + COUNT, } -@table_gen_enum -DF_EntityKind: +@enum DF_EntityKind: { - @expand(DF_EntityKindTable a) `DF_EntityKind_$(a.name),`; - `DF_EntityKind_COUNT`; + @expand(DF_EntityKindTable a) `$(a.name)`, + COUNT, } -@table_gen_enum -DF_NameKind: +@enum DF_CoreCmdKind: { - @expand(DF_NameKindTable, a) `DF_NameKind_$(a.name),`; - `DF_NameKind_COUNT`; + @expand(DF_CoreCmdTable, a) `$(a.name)`, + COUNT, } -@table_gen_enum -DF_CoreCmdKind: +@enum DF_IconKind: { - @expand(DF_CoreCmdTable, a) - `DF_CoreCmdKind_$(a.name),`, - `DF_CoreCmdKind_COUNT`, + @expand(DF_IconTable a) `$(a.name)`, + COUNT, } -@table_gen_enum -DF_IconKind: +@enum DF_CoreViewRuleKind: { - @expand(DF_IconTable a) - `DF_IconKind_$(a.name),`; - `DF_IconKind_COUNT`; -} - -@table_gen_enum -DF_CoreViewRuleKind: -{ - @expand(DF_CoreViewRuleTable a) `DF_CoreViewRuleKind_$(a.name),`; - `DF_CoreViewRuleKind_COUNT`; + @expand(DF_CoreViewRuleTable a) `$(a.name)`, + COUNT, } //- rjf: command params -@table_gen_enum -DF_CmdParamSlot: +@enum DF_CmdParamSlot: { - `DF_CmdParamSlot_Null,`; - @expand(DF_CmdParamSlotTable a) - `DF_CmdParamSlot_$(a.name),`; - `DF_CmdParamSlot_COUNT`; + Null, + @expand(DF_CmdParamSlotTable a) `$(a.name)`, + COUNT, } -@table_gen +@struct DF_CmdParams: { - `typedef struct DF_CmdParams DF_CmdParams;`; - `struct DF_CmdParams`; - `{`; - `U64 slot_props[(DF_CmdParamSlot_COUNT + 63) / 64];`; - @expand(DF_CmdParamSlotTable a) - `$(a.c_type) $(a.name_lower);`; - `};`; + `U64 slot_props[(DF_CmdParamSlot_COUNT + 63) / 64]`; + @expand(DF_CmdParamSlotTable a) `$(a.c_type) $(a.name_lower)`; } -@table_gen_data(type:Rng1U64, fallback:0) -df_g_cmd_param_slot_range_table: +@data(Rng1U64) df_g_cmd_param_slot_range_table: { - `{0},` - @expand(DF_CmdParamSlotTable a) - `{OffsetOf(DF_CmdParams, $(a.name_lower)), OffsetOf(DF_CmdParams, $(a.name_lower)) + sizeof($(a.c_type))},` + `{0}`, + @expand(DF_CmdParamSlotTable a) `{OffsetOf(DF_CmdParams, $(a.name_lower)), OffsetOf(DF_CmdParams, $(a.name_lower)) + sizeof($(a.c_type))}`, } //- rjf: entity kind tables -@table_gen_data(type: DF_IconKind, fallback: `DF_IconKind_Null`) -df_g_entity_kind_icon_kind_table: +@data(DF_IconKind) df_g_entity_kind_icon_kind_table: { - @expand(DF_EntityKindTable a) `DF_IconKind_$(a.icon_kind),`; + @expand(DF_EntityKindTable a) `DF_IconKind_$(a.icon_kind)`, } -@table_gen_data(type: String8, fallback: `{0}`) -df_g_entity_kind_display_string_table: +@data(String8) df_g_entity_kind_display_string_table: { - @expand(DF_EntityKindTable a) `str8_lit_comp("$(a.display_string)"),`; + @expand(DF_EntityKindTable a) `str8_lit_comp("$(a.display_string)")`, } -@table_gen_data(type: String8, fallback: `{0}`) -df_g_entity_kind_name_label_table: +@data(String8) df_g_entity_kind_name_label_table: { - @expand(DF_EntityKindTable a) `str8_lit_comp("$(a.name_label)"),`; + @expand(DF_EntityKindTable a) `str8_lit_comp("$(a.name_label)")`, } -@table_gen_data(type:DF_EntityKindFlags, fallback: `0`) -df_g_entity_kind_flags_table: +@data(DF_EntityKindFlags) df_g_entity_kind_flags_table: { - @expand(DF_EntityKindTable a) `($(a.lf_mut_user_cfg)*DF_EntityKindFlag_LeafMutationUserConfig | $(a.lf_mut_prof_cfg)*DF_EntityKindFlag_LeafMutationProfileConfig | $(a.lf_mut_halt)*DF_EntityKindFlag_LeafMutationSoftHalt | $(a.lf_mut_dbg)*DF_EntityKindFlag_LeafMutationDebugInfoMap | $(a.tr_mut_user_cfg)*DF_EntityKindFlag_TreeMutationUserConfig | $(a.tr_mut_prof_cfg)*DF_EntityKindFlag_TreeMutationProfileConfig | $(a.tr_mut_halt)*DF_EntityKindFlag_TreeMutationSoftHalt | $(a.tr_mut_dbg)*DF_EntityKindFlag_TreeMutationDebugInfoMap | $(a.name_is_code)*DF_EntityKindFlag_NameIsCode | $(a.user_lifetime)*DF_EntityKindFlag_UserDefinedLifetime),`; + @expand(DF_EntityKindTable a) `($(a.lf_mut_user_cfg)*DF_EntityKindFlag_LeafMutationUserConfig | $(a.lf_mut_prof_cfg)*DF_EntityKindFlag_LeafMutationProfileConfig | $(a.lf_mut_halt)*DF_EntityKindFlag_LeafMutationSoftHalt | $(a.lf_mut_dbg)*DF_EntityKindFlag_LeafMutationDebugInfoMap | $(a.tr_mut_user_cfg)*DF_EntityKindFlag_TreeMutationUserConfig | $(a.tr_mut_prof_cfg)*DF_EntityKindFlag_TreeMutationProfileConfig | $(a.tr_mut_halt)*DF_EntityKindFlag_TreeMutationSoftHalt | $(a.tr_mut_dbg)*DF_EntityKindFlag_TreeMutationDebugInfoMap | $(a.name_is_code)*DF_EntityKindFlag_NameIsCode | $(a.user_lifetime)*DF_EntityKindFlag_UserDefinedLifetime)`, } -@table_gen_data(type: DF_EntityOpFlags, fallback: `0`) -df_g_entity_kind_op_flags_table: +@data(DF_EntityOpFlags) df_g_entity_kind_op_flags_table: { - @expand(DF_EntityKindTable a) `($(a.op_delete)*DF_EntityOpFlag_Delete) | ($(a.op_freeze)*DF_EntityOpFlag_Freeze) | ($(a.op_edit)*DF_EntityOpFlag_Edit) | ($(a.op_rename)*DF_EntityOpFlag_Rename) | ($(a.op_enable)*DF_EntityOpFlag_Enable) | ($(a.op_cond)*DF_EntityOpFlag_Condition) | ($(a.op_dup)*DF_EntityOpFlag_Duplicate),`; + @expand(DF_EntityKindTable a) `($(a.op_delete)*DF_EntityOpFlag_Delete) | ($(a.op_freeze)*DF_EntityOpFlag_Freeze) | ($(a.op_edit)*DF_EntityOpFlag_Edit) | ($(a.op_rename)*DF_EntityOpFlag_Rename) | ($(a.op_enable)*DF_EntityOpFlag_Enable) | ($(a.op_cond)*DF_EntityOpFlag_Condition) | ($(a.op_dup)*DF_EntityOpFlag_Duplicate)`, } //- rjf: config source tables -@table_gen_data(type: String8, fallback: DF_CoreCmdKind_Null) -df_g_cfg_src_string_table: +@data(String8) df_g_cfg_src_string_table: { - @expand(DF_CfgSrcTable a) `str8_lit_comp("$(a.string)"),`; + @expand(DF_CfgSrcTable a) `str8_lit_comp("$(a.string)")`, } -@table_gen_data(type: DF_CoreCmdKind, fallback: DF_CoreCmdKind_Null) -df_g_cfg_src_load_cmd_kind_table: +@data(DF_CoreCmdKind) df_g_cfg_src_load_cmd_kind_table: { - @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.load_cmd),`; + @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.load_cmd)`, } -@table_gen_data(type: DF_CoreCmdKind, fallback: DF_CoreCmdKind_Null) -df_g_cfg_src_write_cmd_kind_table: +@data(DF_CoreCmdKind) df_g_cfg_src_write_cmd_kind_table: { - @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.write_cmd),`; + @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.write_cmd)`, } -@table_gen_data(type: DF_CoreCmdKind, fallback: DF_CoreCmdKind_Null) -df_g_cfg_src_apply_cmd_kind_table: +@data(DF_CoreCmdKind) df_g_cfg_src_apply_cmd_kind_table: { - @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.apply_cmd),`; + @expand(DF_CfgSrcTable a) `DF_CoreCmdKind_$(a.apply_cmd)`; } //- rjf: core view rule function prototypes -@table_gen +@gen { - ``; - @expand(DF_CoreViewRuleTable a) - `$(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(" .. a.name_lower .. ");")`; - @expand(DF_CoreViewRuleTable a) - `$(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(" .. a.name_lower .. ");")`; + @expand(DF_CoreViewRuleTable a) `$(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(" .. a.name_lower .. ");")`; + @expand(DF_CoreViewRuleTable a) `$(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(" .. a.name_lower .. ");")`; } //- rjf: core command kind tables -@table_gen_data(type: DF_CmdSpecInfo, fallback: `{0}`) @c_file -df_g_core_cmd_kind_spec_info_table: +@data(DF_CmdSpecInfo) @c_file df_g_core_cmd_kind_spec_info_table: { @expand(DF_CoreCmdTable, a) - ```{ str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.desc)"), str8_lit_comp("$(a.search_tags)"), str8_lit_comp("$(a.display_name)"), (DF_CmdSpecFlag_OmitFromLists*$(a.lister_omit)), {DF_CmdParamSlot_$(a.q_slot), DF_EntityKind_$(a.q_ent_kind), (DF_CmdQueryFlag_AllowFiles*$(a.q_allow_files))|(DF_CmdQueryFlag_AllowFolders*$(a.q_allow_folders))|(DF_CmdQueryFlag_CodeInput*$(a.q_is_code))|(DF_CmdQueryFlag_KeepOldInput*$(a.q_keep_oi))|(DF_CmdQueryFlag_SelectOldInput*$(a.q_select_oi))|(DF_CmdQueryFlag_Required*$(a.q_required))}, DF_IconKind_$(a.canonical_icon)},```; + ```{ str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.desc)"), str8_lit_comp("$(a.search_tags)"), str8_lit_comp("$(a.display_name)"), (DF_CmdSpecFlag_OmitFromLists*$(a.lister_omit)), {DF_CmdParamSlot_$(a.q_slot), DF_EntityKind_$(a.q_ent_kind), (DF_CmdQueryFlag_AllowFiles*$(a.q_allow_files))|(DF_CmdQueryFlag_AllowFolders*$(a.q_allow_folders))|(DF_CmdQueryFlag_CodeInput*$(a.q_is_code))|(DF_CmdQueryFlag_KeepOldInput*$(a.q_keep_oi))|(DF_CmdQueryFlag_SelectOldInput*$(a.q_select_oi))|(DF_CmdQueryFlag_Required*$(a.q_required))}, DF_IconKind_$(a.canonical_icon)}```; } //- rjf: core view rule tables -@table_gen_data(type: DF_CoreViewRuleSpecInfo, fallback: `{0}`) @c_file -df_g_core_view_rule_spec_info_table: +@data(DF_CoreViewRuleSpecInfo) @c_file df_g_core_view_rule_spec_info_table: { @expand(DF_CoreViewRuleTable a) - ```{str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.description)"), (DF_CoreViewRuleSpecInfoFlag_Inherited*$(a.ih == "x"))|(DF_CoreViewRuleSpecInfoFlag_Expandable*$(a.ex == "x"))|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*$(a.er == "x"))|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*$(a.vb == "x")), $(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME("..a.name_lower..")") $(a.er != "x" -> 0), $(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vb != "x" -> 0), },```; + ```{str8_lit_comp("$(a.string)"), str8_lit_comp("$(a.display_name)"), str8_lit_comp("$(a.description)"), (DF_CoreViewRuleSpecInfoFlag_Inherited*$(a.ih == "x"))|(DF_CoreViewRuleSpecInfoFlag_Expandable*$(a.ex == "x"))|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*$(a.er == "x"))|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*$(a.vb == "x")), $(a.er == "x" -> "DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME("..a.name_lower..")") $(a.er != "x" -> 0), $(a.vb == "x" -> "DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vb != "x" -> 0), }```; } //- rjf: icon kinds -@table_gen_data(type: String8, fallback: `{0}`) -df_g_icon_kind_text_table: +@data(String8) df_g_icon_kind_text_table: { - @expand(DF_IconTable a) - `str8_lit_comp("$(a.text)"),`; + @expand(DF_IconTable a) `str8_lit_comp("$(a.text)")`; } //- rjf: instruction metadata table -@table_gen +@gen { ``; `struct{String8 mnemonic; String8 summary;} df_g_inst_table_x64[] =`; @@ -1874,12 +1833,12 @@ df_g_icon_kind_text_table: //- rjf: developer toggles -@table_gen +@gen { @expand(DF_DevToggleTable a) `global B32 DEV_$(a.name) = 0;` } -@table_gen +@gen { `struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] =`; `{`; diff --git a/src/df/core/generated/df_core.meta.c b/src/df/core/generated/df_core.meta.c index f0a19b2e..4fd22249 100644 --- a/src/df/core/generated/df_core.meta.c +++ b/src/df/core/generated/df_core.meta.c @@ -3,7 +3,213 @@ //- GENERATED CODE -DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[] = +C_LINKAGE_BEGIN +Rng1U64 df_g_cmd_param_slot_range_table[19] = +{ +{0}, +{OffsetOf(DF_CmdParams, window), OffsetOf(DF_CmdParams, window) + sizeof(DF_Handle)}, +{OffsetOf(DF_CmdParams, panel), OffsetOf(DF_CmdParams, panel) + sizeof(DF_Handle)}, +{OffsetOf(DF_CmdParams, dest_panel), OffsetOf(DF_CmdParams, dest_panel) + sizeof(DF_Handle)}, +{OffsetOf(DF_CmdParams, prev_view), OffsetOf(DF_CmdParams, prev_view) + sizeof(DF_Handle)}, +{OffsetOf(DF_CmdParams, view), OffsetOf(DF_CmdParams, view) + sizeof(DF_Handle)}, +{OffsetOf(DF_CmdParams, entity), OffsetOf(DF_CmdParams, entity) + sizeof(DF_Handle)}, +{OffsetOf(DF_CmdParams, entity_list), OffsetOf(DF_CmdParams, entity_list) + sizeof(DF_HandleList)}, +{OffsetOf(DF_CmdParams, string), OffsetOf(DF_CmdParams, string) + sizeof(String8)}, +{OffsetOf(DF_CmdParams, file_path), OffsetOf(DF_CmdParams, file_path) + sizeof(String8)}, +{OffsetOf(DF_CmdParams, text_point), OffsetOf(DF_CmdParams, text_point) + sizeof(TxtPt)}, +{OffsetOf(DF_CmdParams, cmd_spec), OffsetOf(DF_CmdParams, cmd_spec) + sizeof(struct DF_CmdSpec *)}, +{OffsetOf(DF_CmdParams, view_spec), OffsetOf(DF_CmdParams, view_spec) + sizeof(struct DF_ViewSpec *)}, +{OffsetOf(DF_CmdParams, vaddr), OffsetOf(DF_CmdParams, vaddr) + sizeof(U64)}, +{OffsetOf(DF_CmdParams, voff), OffsetOf(DF_CmdParams, voff) + sizeof(U64)}, +{OffsetOf(DF_CmdParams, index), OffsetOf(DF_CmdParams, index) + sizeof(U64)}, +{OffsetOf(DF_CmdParams, id), OffsetOf(DF_CmdParams, id) + sizeof(U64)}, +{OffsetOf(DF_CmdParams, prefer_dasm), OffsetOf(DF_CmdParams, prefer_dasm) + sizeof(B32)}, +{OffsetOf(DF_CmdParams, force_confirm), OffsetOf(DF_CmdParams, force_confirm) + sizeof(B32)}, +}; + +DF_IconKind df_g_entity_kind_icon_kind_table[26] = +{ +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Machine, +DF_IconKind_FileOutline, +DF_IconKind_FileOutline, +DF_IconKind_FileOutline, +DF_IconKind_FileOutline, +DF_IconKind_Null, +DF_IconKind_Pin, +DF_IconKind_CircleFilled, +DF_IconKind_CircleFilled, +DF_IconKind_Target, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Threads, +DF_IconKind_Thread, +DF_IconKind_Module, +DF_IconKind_Null, +DF_IconKind_Threads, +DF_IconKind_Null, +DF_IconKind_Null, +DF_IconKind_Null, +}; + +String8 df_g_entity_kind_display_string_table[26] = +{ +str8_lit_comp("Nil"), +str8_lit_comp("Root"), +str8_lit_comp("Machine"), +str8_lit_comp("File"), +str8_lit_comp("Override File Link"), +str8_lit_comp("Pending File Change"), +str8_lit_comp("Diagnostics Log"), +str8_lit_comp("Flash Marker"), +str8_lit_comp("Watch Pin"), +str8_lit_comp("Breakpoint"), +str8_lit_comp("Condition"), +str8_lit_comp("Target"), +str8_lit_comp("Executable"), +str8_lit_comp("Arguments"), +str8_lit_comp("Execution Path"), +str8_lit_comp("Entry Point Name"), +str8_lit_comp("Source"), +str8_lit_comp("Destination"), +str8_lit_comp("Process"), +str8_lit_comp("Thread"), +str8_lit_comp("Module"), +str8_lit_comp("Debug Info Override"), +str8_lit_comp("Pending Thread Name"), +str8_lit_comp("Conversion Task"), +str8_lit_comp("Conversion Failure"), +str8_lit_comp("EndedProcess"), +}; + +String8 df_g_entity_kind_name_label_table[26] = +{ +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Expression"), +str8_lit_comp("Label"), +str8_lit_comp("Expression"), +str8_lit_comp("Label"), +str8_lit_comp("Executable"), +str8_lit_comp("Arguments"), +str8_lit_comp("Execution Path"), +str8_lit_comp("Symbol Name"), +str8_lit_comp("Path"), +str8_lit_comp("Path"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +str8_lit_comp("Label"), +}; + +DF_EntityKindFlags df_g_entity_kind_flags_table[26] = +{ +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(1*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 1*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 1*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 1*DF_EntityKindFlag_TreeMutationSoftHalt | 1*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +}; + +DF_EntityOpFlags df_g_entity_kind_op_flags_table[26] = +{ +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (1*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (1*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), +}; + +String8 df_g_cfg_src_string_table[4] = +{ +str8_lit_comp("user"), +str8_lit_comp("profile"), +str8_lit_comp("command_line"), +str8_lit_comp("transient"), +}; + +DF_CoreCmdKind df_g_cfg_src_load_cmd_kind_table[4] = +{ +DF_CoreCmdKind_OpenUser, +DF_CoreCmdKind_OpenProfile, +DF_CoreCmdKind_Null, +DF_CoreCmdKind_Null, +}; + +DF_CoreCmdKind df_g_cfg_src_write_cmd_kind_table[4] = +{ +DF_CoreCmdKind_WriteUserData, +DF_CoreCmdKind_WriteProfileData, +DF_CoreCmdKind_Null, +DF_CoreCmdKind_Null, +}; + +DF_CoreCmdKind df_g_cfg_src_apply_cmd_kind_table[4] = +{ +DF_CoreCmdKind_ApplyUserData, +DF_CoreCmdKind_ApplyProfileData, +DF_CoreCmdKind_Null, +DF_CoreCmdKind_Null, +}; + +DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[206] = { { str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, { str8_lit_comp("exit"), str8_lit_comp("Exits the debugger."), str8_lit_comp("quit,close,abort"), str8_lit_comp("Exit"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_X}, @@ -213,10 +419,11 @@ DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[] = { str8_lit_comp("toggle_dev_menu"), str8_lit_comp("Opens and closes the developer menu."), str8_lit_comp(""), str8_lit_comp("Toggle Developer Menu"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, }; -DF_CoreViewRuleSpecInfo df_g_core_view_rule_spec_info_table[] = +DF_CoreViewRuleSpecInfo df_g_core_view_rule_spec_info_table[18] = { {str8_lit_comp(""), str8_lit_comp(""), str8_lit_comp(""), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, {str8_lit_comp("array"), str8_lit_comp("Array"), str8_lit_comp("Specifies that a pointer points to N elements, rather than only 1."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(array) , 0, }, +{str8_lit_comp("slice"), str8_lit_comp("Slice"), str8_lit_comp("Specifies that a struct to be rendered as a slice."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(slice) , 0, }, {str8_lit_comp("list"), str8_lit_comp("List"), 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."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(list) , }, {str8_lit_comp("bswap"), str8_lit_comp("Byte Swap"), str8_lit_comp("Specifies that all integer primitives should be byte-swapped, such that their endianness is reversed."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(bswap) , 0, }, {str8_lit_comp("dec"), str8_lit_comp("Decimal Base (Base 10)"), str8_lit_comp("Specifies that all integral evaluations should appear in base-10 form."), (DF_CoreViewRuleSpecInfoFlag_Inherited*1)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), 0, 0, }, @@ -231,7 +438,81 @@ DF_CoreViewRuleSpecInfo df_g_core_view_rule_spec_info_table[] = {str8_lit_comp("disasm"), str8_lit_comp("Disassembly"), str8_lit_comp("Displays as disassembled instructions, interpreting the data as raw machine code."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(disasm) , }, {str8_lit_comp("bitmap"), str8_lit_comp("Bitmap"), str8_lit_comp("Displays as a bitmap, interpreting the data as raw pixel data."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(bitmap) , }, {str8_lit_comp("geo"), str8_lit_comp("Geometry"), str8_lit_comp("Displays as geometry, interpreting the data as vertex data."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*1)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*0)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*1), 0, DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(geo) , }, -{str8_lit_comp("slice"), str8_lit_comp("Slice"), str8_lit_comp("Specifies that some struct is to be rendered as a slice."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(slice) , 0, }, -{str8_lit_comp("odin_map"), str8_lit_comp("Odin Map"), str8_lit_comp("Specifies that a struct to be rendered as an Odin map."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(odin_map) , 0, }, +{str8_lit_comp("odin_map"), str8_lit_comp("Odin map"), str8_lit_comp("Specifies that a struct to be rendered as an Odin map type."), (DF_CoreViewRuleSpecInfoFlag_Inherited*0)|(DF_CoreViewRuleSpecInfoFlag_Expandable*0)|(DF_CoreViewRuleSpecInfoFlag_EvalResolution*1)|(DF_CoreViewRuleSpecInfoFlag_VizBlockProd*0), DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(odin_map) , 0, }, }; +String8 df_g_icon_kind_text_table[69] = +{ +str8_lit_comp(""), +str8_lit_comp("b"), +str8_lit_comp("c"), +str8_lit_comp("B"), +str8_lit_comp("C"), +str8_lit_comp("f"), +str8_lit_comp("F"), +str8_lit_comp("g"), +str8_lit_comp("h"), +str8_lit_comp("r"), +str8_lit_comp("s"), +str8_lit_comp("i"), +str8_lit_comp("w"), +str8_lit_comp("W"), +str8_lit_comp("k"), +str8_lit_comp("K"), +str8_lit_comp("L"), +str8_lit_comp("R"), +str8_lit_comp("U"), +str8_lit_comp("D"), +str8_lit_comp("G"), +str8_lit_comp("P"), +str8_lit_comp("3"), +str8_lit_comp("p"), +str8_lit_comp("O"), +str8_lit_comp("o"), +str8_lit_comp("!"), +str8_lit_comp("1"), +str8_lit_comp("<"), +str8_lit_comp(">"), +str8_lit_comp("^"), +str8_lit_comp("v"), +str8_lit_comp("9"), +str8_lit_comp("0"), +str8_lit_comp("7"), +str8_lit_comp("8"), +str8_lit_comp("+"), +str8_lit_comp("-"), +str8_lit_comp("'"), +str8_lit_comp("\""), +str8_lit_comp("M"), +str8_lit_comp("."), +str8_lit_comp("x"), +str8_lit_comp("q"), +str8_lit_comp("j"), +str8_lit_comp("u"), +str8_lit_comp("m"), +str8_lit_comp("n"), +str8_lit_comp("l"), +str8_lit_comp("a"), +str8_lit_comp("z"), +str8_lit_comp("y"), +str8_lit_comp("X"), +str8_lit_comp("Y"), +str8_lit_comp("S"), +str8_lit_comp("T"), +str8_lit_comp("Z"), +str8_lit_comp("d"), +str8_lit_comp("N"), +str8_lit_comp("E"), +str8_lit_comp("H"), +str8_lit_comp("e"), +str8_lit_comp("I"), +str8_lit_comp("J"), +str8_lit_comp("A"), +str8_lit_comp("?"), +str8_lit_comp("4"), +str8_lit_comp("5"), +str8_lit_comp("c"), +}; + +C_LINKAGE_END + diff --git a/src/df/core/generated/df_core.meta.h b/src/df/core/generated/df_core.meta.h index 7d1bb9ea..bcec746a 100644 --- a/src/df/core/generated/df_core.meta.h +++ b/src/df/core/generated/df_core.meta.h @@ -12,7 +12,7 @@ DF_CfgSrc_User, DF_CfgSrc_Profile, DF_CfgSrc_CommandLine, DF_CfgSrc_Transient, -DF_CfgSrc_COUNT +DF_CfgSrc_COUNT, } DF_CfgSrc; typedef enum DF_EntityKind @@ -35,7 +35,6 @@ DF_EntityKind_ExecutionPath, DF_EntityKind_EntryPointName, DF_EntityKind_Source, DF_EntityKind_Dest, -DF_EntityKind_CtrlRequest, DF_EntityKind_Process, DF_EntityKind_Thread, DF_EntityKind_Module, @@ -44,17 +43,9 @@ DF_EntityKind_PendingThreadName, DF_EntityKind_ConversionTask, DF_EntityKind_ConversionFail, DF_EntityKind_EndedProcess, -DF_EntityKind_COUNT +DF_EntityKind_COUNT, } DF_EntityKind; -typedef enum DF_NameKind -{ -DF_NameKind_Null, -DF_NameKind_EntityName, -DF_NameKind_EntityKindName, -DF_NameKind_COUNT -} DF_NameKind; - typedef enum DF_CoreCmdKind { DF_CoreCmdKind_Null, @@ -263,7 +254,7 @@ DF_CoreCmdKind_PickFileOrFolder, DF_CoreCmdKind_CompleteQuery, DF_CoreCmdKind_CancelQuery, DF_CoreCmdKind_ToggleDevMenu, -DF_CoreCmdKind_COUNT +DF_CoreCmdKind_COUNT, } DF_CoreCmdKind; typedef enum DF_IconKind @@ -337,13 +328,14 @@ DF_IconKind_QuestionMark, DF_IconKind_Person, DF_IconKind_Briefcase, DF_IconKind_Dot, -DF_IconKind_COUNT +DF_IconKind_COUNT, } DF_IconKind; typedef enum DF_CoreViewRuleKind { DF_CoreViewRuleKind_Null, DF_CoreViewRuleKind_Array, +DF_CoreViewRuleKind_Slice, DF_CoreViewRuleKind_List, DF_CoreViewRuleKind_ByteSwap, DF_CoreViewRuleKind_BaseDec, @@ -358,9 +350,8 @@ DF_CoreViewRuleKind_Text, DF_CoreViewRuleKind_Disasm, DF_CoreViewRuleKind_Bitmap, DF_CoreViewRuleKind_Geo, -DF_CoreViewRuleKind_Slice, DF_CoreViewRuleKind_OdinMap, -DF_CoreViewRuleKind_COUNT +DF_CoreViewRuleKind_COUNT, } DF_CoreViewRuleKind; typedef enum DF_CmdParamSlot @@ -384,7 +375,7 @@ DF_CmdParamSlot_Index, DF_CmdParamSlot_ID, DF_CmdParamSlot_PreferDisassembly, DF_CmdParamSlot_ForceConfirm, -DF_CmdParamSlot_COUNT +DF_CmdParamSlot_COUNT, } DF_CmdParamSlot; typedef struct DF_CmdParams DF_CmdParams; @@ -412,8 +403,8 @@ B32 force_confirm; }; DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array); -DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(bswap); DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(slice); +DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(bswap); DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(odin_map); DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(list); DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(only); @@ -1519,288 +1510,18 @@ struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = {&DEV_scratch_mouse_draw, str8_lit_comp("scratch_mouse_draw")}, {&DEV_updating_indicator, str8_lit_comp("updating_indicator")}, }; -Rng1U64 df_g_cmd_param_slot_range_table[] = -{ -{0}, -{OffsetOf(DF_CmdParams, window), OffsetOf(DF_CmdParams, window) + sizeof(DF_Handle)}, -{OffsetOf(DF_CmdParams, panel), OffsetOf(DF_CmdParams, panel) + sizeof(DF_Handle)}, -{OffsetOf(DF_CmdParams, dest_panel), OffsetOf(DF_CmdParams, dest_panel) + sizeof(DF_Handle)}, -{OffsetOf(DF_CmdParams, prev_view), OffsetOf(DF_CmdParams, prev_view) + sizeof(DF_Handle)}, -{OffsetOf(DF_CmdParams, view), OffsetOf(DF_CmdParams, view) + sizeof(DF_Handle)}, -{OffsetOf(DF_CmdParams, entity), OffsetOf(DF_CmdParams, entity) + sizeof(DF_Handle)}, -{OffsetOf(DF_CmdParams, entity_list), OffsetOf(DF_CmdParams, entity_list) + sizeof(DF_HandleList)}, -{OffsetOf(DF_CmdParams, string), OffsetOf(DF_CmdParams, string) + sizeof(String8)}, -{OffsetOf(DF_CmdParams, file_path), OffsetOf(DF_CmdParams, file_path) + sizeof(String8)}, -{OffsetOf(DF_CmdParams, text_point), OffsetOf(DF_CmdParams, text_point) + sizeof(TxtPt)}, -{OffsetOf(DF_CmdParams, cmd_spec), OffsetOf(DF_CmdParams, cmd_spec) + sizeof(struct DF_CmdSpec *)}, -{OffsetOf(DF_CmdParams, view_spec), OffsetOf(DF_CmdParams, view_spec) + sizeof(struct DF_ViewSpec *)}, -{OffsetOf(DF_CmdParams, vaddr), OffsetOf(DF_CmdParams, vaddr) + sizeof(U64)}, -{OffsetOf(DF_CmdParams, voff), OffsetOf(DF_CmdParams, voff) + sizeof(U64)}, -{OffsetOf(DF_CmdParams, index), OffsetOf(DF_CmdParams, index) + sizeof(U64)}, -{OffsetOf(DF_CmdParams, id), OffsetOf(DF_CmdParams, id) + sizeof(U64)}, -{OffsetOf(DF_CmdParams, prefer_dasm), OffsetOf(DF_CmdParams, prefer_dasm) + sizeof(B32)}, -{OffsetOf(DF_CmdParams, force_confirm), OffsetOf(DF_CmdParams, force_confirm) + sizeof(B32)}, -}; - -DF_IconKind df_g_entity_kind_icon_kind_table[] = -{ -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Machine, -DF_IconKind_FileOutline, -DF_IconKind_FileOutline, -DF_IconKind_FileOutline, -DF_IconKind_FileOutline, -DF_IconKind_Null, -DF_IconKind_Pin, -DF_IconKind_CircleFilled, -DF_IconKind_CircleFilled, -DF_IconKind_Target, -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Threads, -DF_IconKind_Thread, -DF_IconKind_Module, -DF_IconKind_Null, -DF_IconKind_Threads, -DF_IconKind_Null, -DF_IconKind_Null, -DF_IconKind_Null, -}; - -String8 df_g_entity_kind_display_string_table[] = -{ -str8_lit_comp("Nil"), -str8_lit_comp("Root"), -str8_lit_comp("Machine"), -str8_lit_comp("File"), -str8_lit_comp("Override File Link"), -str8_lit_comp("Pending File Change"), -str8_lit_comp("Diagnostics Log"), -str8_lit_comp("Flash Marker"), -str8_lit_comp("Watch Pin"), -str8_lit_comp("Breakpoint"), -str8_lit_comp("Condition"), -str8_lit_comp("Target"), -str8_lit_comp("Executable"), -str8_lit_comp("Arguments"), -str8_lit_comp("Execution Path"), -str8_lit_comp("Entry Point Name"), -str8_lit_comp("Source"), -str8_lit_comp("Destination"), -str8_lit_comp("Control Request"), -str8_lit_comp("Process"), -str8_lit_comp("Thread"), -str8_lit_comp("Module"), -str8_lit_comp("Debug Info Override"), -str8_lit_comp("Pending Thread Name"), -str8_lit_comp("Conversion Task"), -str8_lit_comp("Conversion Failure"), -str8_lit_comp("EndedProcess"), -}; - -String8 df_g_entity_kind_name_label_table[] = -{ -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Expression"), -str8_lit_comp("Label"), -str8_lit_comp("Expression"), -str8_lit_comp("Label"), -str8_lit_comp("Executable"), -str8_lit_comp("Arguments"), -str8_lit_comp("Execution Path"), -str8_lit_comp("Symbol Name"), -str8_lit_comp("Path"), -str8_lit_comp("Path"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), -}; - -DF_EntityKindFlags df_g_entity_kind_flags_table[] = -{ -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(1*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 1*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 1*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 1*DF_EntityKindFlag_TreeMutationSoftHalt | 1*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -}; - -DF_EntityOpFlags df_g_entity_kind_op_flags_table[] = -{ -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), -(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (1*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (1*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (1*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -}; - -String8 df_g_cfg_src_string_table[] = -{ -str8_lit_comp("user"), -str8_lit_comp("profile"), -str8_lit_comp("command_line"), -str8_lit_comp("transient"), -}; - -DF_CoreCmdKind df_g_cfg_src_load_cmd_kind_table[] = -{ -DF_CoreCmdKind_OpenUser, -DF_CoreCmdKind_OpenProfile, -DF_CoreCmdKind_Null, -DF_CoreCmdKind_Null, -}; - -DF_CoreCmdKind df_g_cfg_src_write_cmd_kind_table[] = -{ -DF_CoreCmdKind_WriteUserData, -DF_CoreCmdKind_WriteProfileData, -DF_CoreCmdKind_Null, -DF_CoreCmdKind_Null, -}; - -DF_CoreCmdKind df_g_cfg_src_apply_cmd_kind_table[] = -{ -DF_CoreCmdKind_ApplyUserData, -DF_CoreCmdKind_ApplyProfileData, -DF_CoreCmdKind_Null, -DF_CoreCmdKind_Null, -}; - -String8 df_g_icon_kind_text_table[] = -{ -str8_lit_comp(""), -str8_lit_comp("b"), -str8_lit_comp("c"), -str8_lit_comp("B"), -str8_lit_comp("C"), -str8_lit_comp("f"), -str8_lit_comp("F"), -str8_lit_comp("g"), -str8_lit_comp("h"), -str8_lit_comp("r"), -str8_lit_comp("s"), -str8_lit_comp("i"), -str8_lit_comp("w"), -str8_lit_comp("W"), -str8_lit_comp("k"), -str8_lit_comp("K"), -str8_lit_comp("L"), -str8_lit_comp("R"), -str8_lit_comp("U"), -str8_lit_comp("D"), -str8_lit_comp("G"), -str8_lit_comp("P"), -str8_lit_comp("3"), -str8_lit_comp("p"), -str8_lit_comp("O"), -str8_lit_comp("o"), -str8_lit_comp("!"), -str8_lit_comp("1"), -str8_lit_comp("<"), -str8_lit_comp(">"), -str8_lit_comp("^"), -str8_lit_comp("v"), -str8_lit_comp("9"), -str8_lit_comp("0"), -str8_lit_comp("7"), -str8_lit_comp("8"), -str8_lit_comp("+"), -str8_lit_comp("-"), -str8_lit_comp("'"), -str8_lit_comp("\""), -str8_lit_comp("M"), -str8_lit_comp("."), -str8_lit_comp("x"), -str8_lit_comp("q"), -str8_lit_comp("j"), -str8_lit_comp("u"), -str8_lit_comp("m"), -str8_lit_comp("n"), -str8_lit_comp("l"), -str8_lit_comp("a"), -str8_lit_comp("z"), -str8_lit_comp("y"), -str8_lit_comp("X"), -str8_lit_comp("Y"), -str8_lit_comp("S"), -str8_lit_comp("T"), -str8_lit_comp("Z"), -str8_lit_comp("d"), -str8_lit_comp("N"), -str8_lit_comp("E"), -str8_lit_comp("H"), -str8_lit_comp("e"), -str8_lit_comp("I"), -str8_lit_comp("J"), -str8_lit_comp("A"), -str8_lit_comp("?"), -str8_lit_comp("4"), -str8_lit_comp("5"), -str8_lit_comp("c"), -}; - +C_LINKAGE_BEGIN +extern Rng1U64 df_g_cmd_param_slot_range_table[19]; +extern DF_IconKind df_g_entity_kind_icon_kind_table[26]; +extern String8 df_g_entity_kind_display_string_table[26]; +extern String8 df_g_entity_kind_name_label_table[26]; +extern DF_EntityKindFlags df_g_entity_kind_flags_table[26]; +extern DF_EntityOpFlags df_g_entity_kind_op_flags_table[26]; +extern String8 df_g_cfg_src_string_table[4]; +extern DF_CoreCmdKind df_g_cfg_src_load_cmd_kind_table[4]; +extern DF_CoreCmdKind df_g_cfg_src_write_cmd_kind_table[4]; +extern DF_CoreCmdKind df_g_cfg_src_apply_cmd_kind_table[4]; +extern String8 df_g_icon_kind_text_table[69]; +C_LINKAGE_END #endif // DF_CORE_META_H diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index 517aa895..b3fffc7d 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -945,7 +945,7 @@ df_window_open(Vec2F32 size, OS_Handle preferred_monitor, DF_CfgSrc cfg_src) window->cfg_src = cfg_src; window->arena = arena_alloc(); { - String8 title = str8_lit_comp(RADDBG_TITLE_STRING_LITERAL); + String8 title = str8_lit_comp(BUILD_TITLE_STRING_LITERAL); window->os = os_window_open(size, title); } window->r = r_window_equip(window->os); @@ -1012,7 +1012,7 @@ df_window_from_os_handle(OS_Handle os) return result; } -#if defined(_MSC_VER) && !defined(__clang__) && defined(NDEBUG) +#if COMPILER_MSVC && !BUILD_DEBUG #pragma optimize("", off) #endif @@ -1249,6 +1249,10 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D DF_View *watch = &df_g_nil_view; DF_View *locals = &df_g_nil_view; DF_View *regs = &df_g_nil_view; + DF_View *globals = &df_g_nil_view; + DF_View *tlocals = &df_g_nil_view; + DF_View *types = &df_g_nil_view; + DF_View *procs = &df_g_nil_view; DF_View *callstack = &df_g_nil_view; DF_View *breakpoints = &df_g_nil_view; DF_View *watch_pins = &df_g_nil_view; @@ -1271,18 +1275,22 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D switch(view_kind) { default:{}break; - case DF_GfxViewKind_Watch: {if(df_view_is_nil(watch)) { needs_delete = 0; watch = view;} }break; - case DF_GfxViewKind_Locals: {if(df_view_is_nil(locals)) { needs_delete = 0; locals = view;} }break; - case DF_GfxViewKind_Registers: {if(df_view_is_nil(regs)) { needs_delete = 0; regs = view;} }break; - case DF_GfxViewKind_CallStack: {if(df_view_is_nil(callstack)) { needs_delete = 0; callstack = view;} }break; - case DF_GfxViewKind_Breakpoints:{if(df_view_is_nil(breakpoints)) { needs_delete = 0; breakpoints = view;} }break; - case DF_GfxViewKind_WatchPins: {if(df_view_is_nil(watch_pins)) { needs_delete = 0; watch_pins = view;} }break; - case DF_GfxViewKind_Output: {if(df_view_is_nil(output)) { needs_delete = 0; output = view;} }break; - case DF_GfxViewKind_Targets: {if(df_view_is_nil(targets)) { needs_delete = 0; targets = view;} }break; - case DF_GfxViewKind_Scheduler: {if(df_view_is_nil(scheduler)) { needs_delete = 0; scheduler = view;} }break; - case DF_GfxViewKind_Modules: {if(df_view_is_nil(modules)) { needs_delete = 0; modules = view;} }break; - case DF_GfxViewKind_Disassembly:{if(df_view_is_nil(disasm)) { needs_delete = 0; disasm = view;} }break; - case DF_GfxViewKind_Memory: {if(df_view_is_nil(memory)) { needs_delete = 0; memory = view;} }break; + case DF_GfxViewKind_Watch: {if(df_view_is_nil(watch)) { needs_delete = 0; watch = view;} }break; + case DF_GfxViewKind_Locals: {if(df_view_is_nil(locals)) { needs_delete = 0; locals = view;} }break; + case DF_GfxViewKind_Registers: {if(df_view_is_nil(regs)) { needs_delete = 0; regs = view;} }break; + case DF_GfxViewKind_Globals: {if(df_view_is_nil(globals)) { needs_delete = 0; globals = view;} }break; + case DF_GfxViewKind_ThreadLocals:{if(df_view_is_nil(tlocals)) { needs_delete = 0; tlocals = view;} }break; + case DF_GfxViewKind_Types: {if(df_view_is_nil(types)) { needs_delete = 0; types = view;} }break; + case DF_GfxViewKind_Procedures: {if(df_view_is_nil(procs)) { needs_delete = 0; procs = view;} }break; + case DF_GfxViewKind_CallStack: {if(df_view_is_nil(callstack)) { needs_delete = 0; callstack = view;} }break; + case DF_GfxViewKind_Breakpoints: {if(df_view_is_nil(breakpoints)) { needs_delete = 0; breakpoints = view;} }break; + case DF_GfxViewKind_WatchPins: {if(df_view_is_nil(watch_pins)) { needs_delete = 0; watch_pins = view;} }break; + case DF_GfxViewKind_Output: {if(df_view_is_nil(output)) { needs_delete = 0; output = view;} }break; + case DF_GfxViewKind_Targets: {if(df_view_is_nil(targets)) { needs_delete = 0; targets = view;} }break; + case DF_GfxViewKind_Scheduler: {if(df_view_is_nil(scheduler)) { needs_delete = 0; scheduler = view;} }break; + case DF_GfxViewKind_Modules: {if(df_view_is_nil(modules)) { needs_delete = 0; modules = view;} }break; + case DF_GfxViewKind_Disassembly: {if(df_view_is_nil(disasm)) { needs_delete = 0; disasm = view;} }break; + case DF_GfxViewKind_Memory: {if(df_view_is_nil(memory)) { needs_delete = 0; memory = view;} }break; case DF_GfxViewKind_Code: { needs_delete = 0; @@ -1328,6 +1336,26 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D regs = df_view_alloc(); df_view_equip_spec(regs, df_view_spec_from_gfx_view_kind(DF_GfxViewKind_Registers), &df_g_nil_entity, str8_lit(""), &df_g_nil_cfg_node); } + if(df_view_is_nil(globals)) + { + globals = df_view_alloc(); + df_view_equip_spec(globals, df_view_spec_from_gfx_view_kind(DF_GfxViewKind_Globals), &df_g_nil_entity, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(tlocals)) + { + tlocals = df_view_alloc(); + df_view_equip_spec(tlocals, df_view_spec_from_gfx_view_kind(DF_GfxViewKind_ThreadLocals), &df_g_nil_entity, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(types)) + { + types = df_view_alloc(); + df_view_equip_spec(types, df_view_spec_from_gfx_view_kind(DF_GfxViewKind_Types), &df_g_nil_entity, str8_lit(""), &df_g_nil_cfg_node); + } + if(df_view_is_nil(procs)) + { + procs = df_view_alloc(); + df_view_equip_spec(procs, df_view_spec_from_gfx_view_kind(DF_GfxViewKind_Procedures), &df_g_nil_entity, str8_lit(""), &df_g_nil_cfg_node); + } if(df_view_is_nil(callstack)) { callstack = df_view_alloc(); @@ -1442,6 +1470,10 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D df_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, watch); df_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, locals); df_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, regs); + df_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, globals); + df_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, tlocals); + df_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, types); + df_panel_insert_tab_view(root_0_1_0, root_0_1_0->last_tab_view, procs); root_0_1_0->selected_tab_view = df_handle_from_view(watch); root_0_1_0->tab_side = Side_Max; df_panel_insert_tab_view(root_0_1_1, root_0_1_1->last_tab_view, callstack); @@ -2099,7 +2131,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(thread->kind == DF_EntityKind_Thread) { // rjf: grab rip - U64 rip_vaddr = (unwind_count == 0 ? df_rip_from_thread(thread) : df_query_cached_rip_from_thread_unwind(thread, unwind_count)); + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); // rjf: extract thread/rip info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -2992,7 +3024,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D case DF_EntityKind_Module: { DF_Entity *bin_file = df_binary_file_from_module(entity); - if(df_icon_buttonf(DF_IconKind_Module, 0, "Inspect Binary File Memory").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Module, 0, "Inspect Binary File Memory"))) { DF_CmdParams params = df_cmd_params_from_panel(ws, panel); params.entity = df_handle_from_entity(bin_file); @@ -3000,7 +3032,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); ui_ctx_menu_close(); } - if(df_icon_buttonf(DF_IconKind_Module, 0, "View Binary File Disassembly").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Module, 0, "View Binary File Disassembly"))) { DF_CmdParams params = df_cmd_params_from_panel(ws, panel); params.entity = df_handle_from_entity(bin_file); @@ -3011,7 +3043,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D }break; case DF_EntityKind_Process: { - if(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Process Log").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Process Log"))) { DF_Entity *log = df_log_from_entity(entity); DF_CmdParams params = df_cmd_params_from_panel(ws, panel); @@ -3023,7 +3055,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D }break; case DF_EntityKind_Thread: { - if(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Thread Log").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Thread Log"))) { DF_Entity *log = df_log_from_entity(entity); DF_CmdParams params = df_cmd_params_from_panel(ws, panel); @@ -3047,7 +3079,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //- rjf: toggles for(U64 idx = 0; idx < ArrayCount(DEV_toggle_table); idx += 1) { - if(df_icon_button(*DEV_toggle_table[idx].value_ptr ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, 0, DEV_toggle_table[idx].name).clicked) + if(ui_clicked(df_icon_button(*DEV_toggle_table[idx].value_ptr ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, 0, DEV_toggle_table[idx].name))) { *DEV_toggle_table[idx].value_ptr ^= 1; } @@ -3079,8 +3111,8 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D avg_ui_hash_chain_length = chain_length_sum / chain_count; } ui_labelf("Target Hz: %.2f", 1.f/df_dt()); - ui_labelf("Ctrl Run Index: %I64u", ctrl_run_idx()); - ui_labelf("Ctrl Mem Gen Index: %I64u", ctrl_memgen_idx()); + 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_set_next_pref_width(ui_children_sum(1)); ui_set_next_pref_height(ui_children_sum(1)); @@ -3194,7 +3226,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(op_flags & DF_EntityOpFlag_Rename) { UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, entity->name, "%S###entity_name_edit_%p", df_g_entity_kind_name_label_table[entity->kind], entity); - if(sig.commit) + if(ui_committed(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3210,7 +3242,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { DF_Entity *condition = df_entity_child_from_kind(entity, DF_EntityKind_Condition); UI_Signal sig = df_line_editf(DF_LineEditFlag_Border|DF_LineEditFlag_CodeContents, 0, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, condition->name, "Condition###entity_cond_edit_%p", entity); - if(sig.commit) + if(ui_committed(sig)) { String8 new_string = str8(ws->entity_ctx_menu_input_buffer, ws->entity_ctx_menu_input_size); if(new_string.size != 0) @@ -3239,7 +3271,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { DF_Entity *exe = df_entity_child_from_kind(entity, DF_EntityKind_Executable); UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, exe->name, "Executable###entity_exe_edit_%p", entity); - if(sig.commit) + if(ui_committed(sig)) { String8 new_string = str8(ws->entity_ctx_menu_input_buffer, ws->entity_ctx_menu_input_size); if(new_string.size != 0) @@ -3268,7 +3300,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { DF_Entity *args = df_entity_child_from_kind(entity, DF_EntityKind_Arguments); UI_Signal sig = df_line_editf(DF_LineEditFlag_Border, 0, 0, &ws->entity_ctx_menu_input_cursor, &ws->entity_ctx_menu_input_mark, ws->entity_ctx_menu_input_buffer, sizeof(ws->entity_ctx_menu_input_buffer), &ws->entity_ctx_menu_input_size, 0, args->name, "Arguments###entity_args_edit_%p", entity); - if(sig.commit) + if(ui_committed(sig)) { String8 new_string = str8(ws->entity_ctx_menu_input_buffer, ws->entity_ctx_menu_input_size); if(new_string.size != 0) @@ -3293,20 +3325,20 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } // rjf: copy name - if(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Name").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Name"))) { os_set_clipboard_text(display_name); ui_ctx_menu_close(); } // rjf: is command line only? -> make permanent - if(entity->cfg_src == DF_CfgSrc_CommandLine && df_icon_buttonf(DF_IconKind_Save, 0, "Save To Profile").clicked) + if(entity->cfg_src == DF_CfgSrc_CommandLine && ui_clicked(df_icon_buttonf(DF_IconKind_Save, 0, "Save To Profile"))) { df_entity_equip_cfg_src(entity, DF_CfgSrc_Profile); } // rjf: duplicate - if(op_flags & DF_EntityOpFlag_Duplicate && df_icon_buttonf(DF_IconKind_XSplit, 0, "Duplicate").clicked) + if(op_flags & DF_EntityOpFlag_Duplicate && ui_clicked(df_icon_buttonf(DF_IconKind_XSplit, 0, "Duplicate"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3316,7 +3348,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } // rjf: edit - if(op_flags & DF_EntityOpFlag_Edit && df_icon_buttonf(DF_IconKind_Pencil, 0, "Edit").clicked) + if(op_flags & DF_EntityOpFlag_Edit && ui_clicked(df_icon_buttonf(DF_IconKind_Pencil, 0, "Edit"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3326,7 +3358,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } // rjf: deletion - if(op_flags & DF_EntityOpFlag_Delete && df_icon_buttonf(DF_IconKind_Trash, 0, "Delete").clicked) + if(op_flags & DF_EntityOpFlag_Delete && ui_clicked(df_icon_buttonf(DF_IconKind_Trash, 0, "Delete"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3339,14 +3371,14 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(op_flags & DF_EntityOpFlag_Enable) { B32 is_enabled = entity->b32; - if(!is_enabled && df_icon_buttonf(DF_IconKind_CheckHollow, 0, "Enable###enabler").clicked) + if(!is_enabled && ui_clicked(df_icon_buttonf(DF_IconKind_CheckHollow, 0, "Enable###enabler"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_EnableEntity)); } - if(is_enabled && df_icon_buttonf(DF_IconKind_CheckFilled, 0, "Disable###enabler").clicked) + if(is_enabled && ui_clicked(df_icon_buttonf(DF_IconKind_CheckFilled, 0, "Disable###enabler"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3364,14 +3396,14 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D color.y *= 0.7f; color.z *= 0.7f; ui_set_next_background_color(color); - if(is_frozen && df_icon_buttonf(DF_IconKind_Locked, 0, "Thaw###freeze_thaw").clicked) + if(is_frozen && ui_clicked(df_icon_buttonf(DF_IconKind_Locked, 0, "Thaw###freeze_thaw"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ThawEntity)); } - if(!is_frozen && df_icon_buttonf(DF_IconKind_Unlocked, 0, "Freeze###freeze_thaw").clicked) + if(!is_frozen && ui_clicked(df_icon_buttonf(DF_IconKind_Unlocked, 0, "Freeze###freeze_thaw"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3384,7 +3416,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(entity->flags & DF_EntityFlag_HasTextPoint) { DF_Entity *file_ancestor = df_entity_ancestor_from_kind(entity, DF_EntityKind_File); - if(!df_entity_is_nil(file_ancestor) && df_icon_buttonf(DF_IconKind_FileOutline, 0, "Go To Location").clicked) + if(!df_entity_is_nil(file_ancestor) && ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Go To Location"))) { Temp scratch = scratch_begin(&arena, 1); DF_CmdParams params = df_cmd_params_from_window(ws); @@ -3403,7 +3435,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { DF_CtrlCtx ctrl_ctx = df_ctrl_ctx(); DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); - if(entity->vaddr != 0 && !df_entity_is_nil(thread) && df_icon_buttonf(DF_IconKind_FileOutline, 0, "Go To Location").clicked) + if(entity->vaddr != 0 && !df_entity_is_nil(thread) && ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Go To Location"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(df_entity_ancestor_from_kind(thread, DF_EntityKind_Process)); @@ -3425,7 +3457,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D case DF_EntityKind_File: { if(entity->flags & DF_EntityFlag_IsFolder && - df_icon_buttonf(DF_IconKind_FolderOpenOutline, 0, "Open File In Folder").clicked) + ui_clicked(df_icon_buttonf(DF_IconKind_FolderOpenOutline, 0, "Open File In Folder"))) { String8 path = df_full_path_from_entity(scratch.arena, entity); String8 path_w_slash = push_str8f(scratch.arena, "%S/", path); @@ -3445,7 +3477,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } if(!(entity->flags & DF_EntityFlag_IsFolder) && !(entity->flags & DF_EntityFlag_IsMissing) && - df_icon_buttonf(DF_IconKind_FileOutline, 0, "Go To File").clicked) + ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Go To File"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.file_path = df_full_path_from_entity(scratch.arena, entity); @@ -3468,7 +3500,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { df_icon_buttonf(DF_IconKind_Thread, 0, "[Selected]###select_entity"); } - else if(df_icon_buttonf(DF_IconKind_Thread, 0, "Select###select_entity").clicked) + else if(ui_clicked(df_icon_buttonf(DF_IconKind_Thread, 0, "Select###select_entity"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3478,7 +3510,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } } - if(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy ID").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy ID"))) { U32 ctrl_id = entity->ctrl_id; String8 string = push_str8f(scratch.arena, "%i", (int)ctrl_id); @@ -3488,7 +3520,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(entity->kind == DF_EntityKind_Thread) { - if(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Instruction Pointer Address").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Instruction Pointer Address"))) { U64 rip = df_query_cached_rip_from_thread(entity); String8 string = push_str8f(scratch.arena, "0x%I64x", rip); @@ -3499,7 +3531,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(entity->kind == DF_EntityKind_Thread) { - if(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Call Stack").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Call Stack"))) { DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(entity); @@ -3531,7 +3563,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(entity->kind == DF_EntityKind_Thread) { - if(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Find").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Find"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3545,25 +3577,25 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D case DF_EntityKind_Module: { UI_Signal copy_full_path_sig = df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Full Path"); - if(copy_full_path_sig.clicked) + if(ui_clicked(copy_full_path_sig)) { String8 string = entity->name; os_set_clipboard_text(string); ui_ctx_menu_close(); } - if(copy_full_path_sig.hovering) UI_Tooltip + if(ui_hovering(copy_full_path_sig)) UI_Tooltip { String8 string = entity->name; ui_label(string); } - if(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Base Address").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Base Address"))) { Rng1U64 vaddr_rng = entity->vaddr_rng; String8 string = push_str8f(scratch.arena, "0x%I64x", vaddr_rng.min); os_set_clipboard_text(string); ui_ctx_menu_close(); } - if(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Address Range Size").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Address Range Size"))) { Rng1U64 vaddr_rng = entity->vaddr_rng; String8 string = push_str8f(scratch.arena, "0x%I64x", dim_1u64(vaddr_rng)); @@ -3574,7 +3606,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D case DF_EntityKind_Target: { - if(df_icon_buttonf(DF_IconKind_Play, 0, "Launch And Run").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Play, 0, "Launch And Run"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3582,7 +3614,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); ui_ctx_menu_close(); } - if(df_icon_buttonf(DF_IconKind_PlayStepForward, 0, "Launch And Initialize").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_PlayStepForward, 0, "Launch And Initialize"))) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -3627,7 +3659,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_BoxFlag_DrawActiveEffects, "###color_preset_%i", (int)preset_idx); UI_Signal sig = ui_signal_from_box(box); - if(sig.clicked) + 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); @@ -3653,7 +3685,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_Row UI_Padding(ui_pct(1, 0)) UI_PrefWidth(ui_em(12.f, 1.f)) UI_CornerRadius(8.f) { - if(df_icon_buttonf(DF_IconKind_Trash, 0, "Remove Color").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Trash, 0, "Remove Color###color_toggle"))) { entity->flags &= ~DF_EntityFlag_HasColor; } @@ -3661,7 +3693,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ui_spacer(ui_em(1.5f, 1.f)); } - if(!entity_has_color && df_icon_buttonf(DF_IconKind_Palette, 0, "Equip With Color").clicked) + if(!entity_has_color && ui_clicked(df_icon_buttonf(DF_IconKind_Palette, 0, "Apply Color###color_toggle"))) { df_entity_equip_color_rgba(entity, v4f32(1, 1, 1, 1)); } @@ -3701,7 +3733,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } // rjf: copy name - if(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Name").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Name"))) { os_set_clipboard_text(display_name); ui_ctx_menu_close(); @@ -3712,12 +3744,12 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { UI_Signal copy_full_path_sig = df_icon_buttonf(DF_IconKind_Clipboard, 0, "Copy Full Path"); String8 full_path = df_full_path_from_entity(scratch.arena, entity); - if(copy_full_path_sig.clicked) + if(ui_clicked(copy_full_path_sig)) { os_set_clipboard_text(full_path); ui_ctx_menu_close(); } - if(copy_full_path_sig.hovering) UI_Tooltip + if(ui_hovering(copy_full_path_sig)) UI_Tooltip { ui_label(full_path); } @@ -3726,7 +3758,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D // rjf: filter controls if(view->spec->info.flags & DF_ViewSpecFlag_CanFilter) { - if(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Filter)).clicked) + if(ui_clicked(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Filter)))) { DF_CmdParams params = df_cmd_params_from_window(ws); { @@ -3736,7 +3768,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Filter)); ui_ctx_menu_close(); } - if(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ClearFilter)).clicked) + if(ui_clicked(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ClearFilter)))) { DF_CmdParams params = df_cmd_params_from_window(ws); { @@ -3749,7 +3781,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } // rjf: close tab - if(df_icon_buttonf(DF_IconKind_X, 0, "Close Tab").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_X, 0, "Close Tab"))) { DF_CmdParams params = df_cmd_params_from_window(ws); { @@ -3793,21 +3825,21 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { UI_CornerRadius00(ui_top_font_size()*0.25f) UI_CornerRadius01(ui_top_font_size()*0.25f) - if(ui_buttonf("Cancel").clicked || os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) - { - DF_CmdParams p = df_cmd_params_zero(); - df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ConfirmCancel)); - } - UI_CornerRadius10(ui_top_font_size()*0.25f) - UI_CornerRadius11(ui_top_font_size()*0.25f) UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) - if(ui_buttonf("OK").clicked || os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) + if(ui_clicked(ui_buttonf("OK")) || os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) { DF_CmdParams p = df_cmd_params_zero(); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ConfirmAccept)); } + UI_CornerRadius10(ui_top_font_size()*0.25f) + UI_CornerRadius11(ui_top_font_size()*0.25f) + if(ui_clicked(ui_buttonf("Cancel")) || os_key_press(ui_events(), ui_window(), 0, OS_Key_Esc)) + { + DF_CmdParams p = df_cmd_params_zero(); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ConfirmCancel)); + } } ui_spacer(ui_em(3.f, 1.f)); } @@ -3989,7 +4021,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ui_label(item->kind_string); } UI_Signal item_sig = ui_signal_from_box(item_box); - if(item_sig.clicked) + if(ui_clicked(item_sig)) { UI_NavAction autocomp_action = {UI_NavActionFlag_ReplaceAndCommit, {0}, (UI_NavDeltaUnit)0, push_str8_copy(ui_build_arena(), item->string)}; ui_nav_action_list_push(ui_build_arena(), ui_nav_actions(), autocomp_action); @@ -4185,7 +4217,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_Signal sig = {0}; UI_TextColor(color) sig = df_icon_buttonf(DF_IconKind_Target, 0, "%S##%p", target_name, target); - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(target); @@ -4235,7 +4267,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_CtxMenu(help_menu_key) UI_PrefWidth(ui_em(40.f, 1.f)) { UI_Row UI_TextAlignment(UI_TextAlign_Center) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) - ui_label(str8_lit(RADDBG_TITLE_STRING_LITERAL)); + ui_label(str8_lit(BUILD_TITLE_STRING_LITERAL)); ui_spacer(ui_em(0.25f, 1.f)); UI_Row UI_PrefWidth(ui_text_dim(10, 1)) @@ -4254,11 +4286,11 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_TextAlignment(UI_TextAlign_Center) { UI_Signal url_sig = ui_buttonf("github.com/EpicGames/raddebugger"); - if(url_sig.hovering) UI_Tooltip + if(ui_hovering(url_sig)) UI_Tooltip { ui_labelf("Copy To Clipboard"); } - if(url_sig.clicked) + if(ui_clicked(url_sig)) { os_set_clipboard_text(str8_lit("https://github.com/EpicGames/raddebugger")); } @@ -4346,12 +4378,12 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_Signal sig = df_menu_bar_button(items[idx].name); if(menu_open) { - if((sig.hovering && !ui_ctx_menu_is_open(items[idx].menu_key)) || (open_menu_idx_prime == idx && open_menu_idx_prime != open_menu_idx)) + 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(sig.pressed || alt_fastpath_key) + else if(ui_pressed(sig) || alt_fastpath_key) { if(ui_ctx_menu_is_open(items[idx].menu_key)) { @@ -4376,17 +4408,20 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D for(DF_EntityNode *n = tasks.first; n != 0; n = n->next) { DF_Entity *task = n->entity; - String8 raddbg_path = task->name; - String8 raddbg_name = str8_skip_last_slash(raddbg_path); - String8 task_text = push_str8f(scratch.arena, "Creating %S...", raddbg_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); - UI_Signal sig = ui_signal_from_box(box); - if(sig.hovering) UI_Tooltip + if(task->alloc_time_us + 500000 < os_now_microseconds()) { - ui_label(raddbg_path); + String8 rdi_path = task->name; + 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); + 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); } - ui_box_equip_display_string(box, task_text); } scratch_end(scratch); } @@ -4412,7 +4447,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ui_label(str8_skip_last_slash(user_path)); } UI_Signal user_sig = ui_signal_from_box(user_box); - if(user_sig.clicked) + if(ui_clicked(user_sig)) { DF_CmdParams p = df_cmd_params_from_window(ws); p.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OpenUser); @@ -4442,7 +4477,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ui_label(str8_skip_last_slash(prof_path)); } UI_Signal prof_sig = ui_signal_from_box(prof_box); - if(prof_sig.clicked) + if(ui_clicked(prof_sig)) { DF_CmdParams p = df_cmd_params_from_window(ws); p.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OpenProfile); @@ -4470,14 +4505,14 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(can_play || !have_targets) UI_TextAlignment(UI_TextAlign_Center) UI_Flags((can_play ? 0 : UI_BoxFlag_Disabled)) { UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Play]); - if(sig.hovering && can_play == 0) + if(ui_hovering(sig) && !can_play) { UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) ui_labelf("Disabled: %s", have_targets ? "Targets are currently running" : "No active targets exist"); } - if(sig.hovering && can_play) + if(ui_hovering(sig) && can_play) { UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) @@ -4497,7 +4532,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } } } - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Run)); @@ -4507,7 +4542,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(!can_play && have_targets && !can_send_signal) UI_TextAlignment(UI_TextAlign_Center) { UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Redo]); - if(sig.hovering) + if(ui_hovering(sig)) { UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) @@ -4528,7 +4563,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } } } - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Restart)); @@ -4538,21 +4573,21 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_TextAlignment(UI_TextAlign_Center) UI_Flags(can_pause ? 0 : UI_BoxFlag_Disabled) { UI_Signal sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Pause]); - if(sig.hovering && can_pause == 0) + if(ui_hovering(sig) && !can_pause) { UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) ui_labelf("Disabled: Already halted"); } - if(sig.hovering && can_pause) + if(ui_hovering(sig) && can_pause) { UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) ui_labelf("Halt all target processes"); } - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Halt)); @@ -4565,21 +4600,21 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { sig = ui_button(df_g_icon_kind_text_table[DF_IconKind_Stop]); } - if(sig.hovering && can_stop == 0) + if(ui_hovering(sig) && !can_stop) { UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) ui_labelf("Disabled: No processes are running"); } - if(sig.hovering && can_stop) + if(ui_hovering(sig) && can_stop) { UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) ui_labelf("Kill all target processes"); } - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Kill)); @@ -4649,107 +4684,12 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D Temp scratch = scratch_begin(&arena, 1); DF_IconKind icon = DF_IconKind_Null; String8 explanation = str8_lit("Not running"); - DF_Entity *thread = df_entity_from_ctrl_handle(stop_event.machine_id, stop_event.entity); - String8 thread_display_string = df_display_string_from_entity(scratch.arena, thread); - switch(stop_event.kind) { - default: + String8 stop_explanation = df_stop_explanation_string_icon_from_ctrl_event(scratch.arena, &stop_event, &icon); + if(stop_explanation.size != 0) { - switch(stop_event.cause) - { - default:{}break; - case CTRL_EventCause_Finished: - { - if(!df_entity_is_nil(thread)) - { - explanation = push_str8f(scratch.arena, "%S completed step", thread_display_string); - } - else - { - explanation = str8_lit("Stopped"); - } - }break; - case CTRL_EventCause_UserBreakpoint: - { - if(!df_entity_is_nil(thread)) - { - icon = DF_IconKind_CircleFilled; - explanation = push_str8f(scratch.arena, "%S hit a breakpoint", thread_display_string); - } - }break; - case CTRL_EventCause_InterruptedByException: - { - if(!df_entity_is_nil(thread)) - { - icon = DF_IconKind_WarningBig; - switch(stop_event.exception_kind) - { - default: - { - explanation = push_str8f(scratch.arena, "%S interrupted - 0x%x", thread_display_string, stop_event.exception_code); - }break; - case CTRL_ExceptionKind_CppThrow: - { - explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x", thread_display_string, stop_event.exception_code); - }break; - case CTRL_ExceptionKind_MemoryRead: - { - explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x: Access violation reading 0x%I64x", - thread_display_string, - stop_event.exception_code, - stop_event.vaddr_rng.min); - }break; - case CTRL_ExceptionKind_MemoryWrite: - { - explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x: Access violation writing 0x%I64x", - thread_display_string, - stop_event.exception_code, - stop_event.vaddr_rng.min); - }break; - case CTRL_ExceptionKind_MemoryExecute: - { - explanation = push_str8f(scratch.arena, "Exception thrown on %S - 0x%x: Access violation executing 0x%I64x", - thread_display_string, - stop_event.exception_code, - stop_event.vaddr_rng.min); - }break; - } - } - else - { - icon = DF_IconKind_Pause; - explanation = str8_lit("Interrupted"); - } - }break; - case CTRL_EventCause_InterruptedByTrap: - { - icon = DF_IconKind_WarningBig; - explanation = push_str8f(scratch.arena, "%S interrupted by trap - 0x%x", thread_display_string, stop_event.exception_code); - }break; - case CTRL_EventCause_InterruptedByHalt: - { - icon = DF_IconKind_Pause; - explanation = str8_lit("Halted"); - }break; - } - }break; - case CTRL_EventKind_LaunchAndInitDone: - case CTRL_EventKind_LaunchAndHandshakeDone: - { - explanation = str8_lit("Launched"); - }break; - case CTRL_EventKind_AttachDone: - { - explanation = str8_lit("Attached"); - }break; - case CTRL_EventKind_DetachDone: - { - explanation = str8_lit("Detached"); - }break; - case CTRL_EventKind_KillDone: - { - explanation = str8_lit("Killed"); - }break; + explanation = stop_explanation; + } } if(icon != DF_IconKind_Null) { @@ -4975,7 +4915,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D 0, str8(view->query_buffer, view->query_string_size), str8_lit("###query_text_input")); - if(sig.pressed) + if(ui_pressed(sig)) { ws->query_view_selected = 1; } @@ -5022,7 +4962,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //- rjf: take fallthrough interaction in query view { UI_Signal sig = ui_signal_from_box(query_container_box); - if(sig.pressed) + if(ui_pressed(sig)) { ws->query_view_selected = 1; } @@ -5105,8 +5045,11 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D U64 expr_hash = df_hash_from_string(expr); DF_EvalViewKey eval_view_key = df_eval_view_key_from_stringf("eval_hover_%I64x", expr_hash); DF_EvalView *eval_view = df_eval_view_from_key(eval_view_key); - DF_EvalVizBlockList viz_blocks = df_eval_viz_block_list_from_eval_view_expr_num(scratch.arena, scope, &ctrl_ctx, &parse_ctx, macro_map, eval_view, expr, 1); - DF_EvalVizWindowedRowList viz_rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, macro_map, eval_view, 10, ui_top_font(), ui_top_font_size(), r1s64(0, 50), &viz_blocks); + DF_ExpandKey parent_key = df_expand_key_make(5381, 1); + DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), 1); + DF_EvalVizBlockList viz_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(scratch.arena, scope, &ctrl_ctx, &parse_ctx, macro_map, eval_view, expr, parent_key, key); + U32 default_radix = (eval.mode == EVAL_EvalMode_Reg ? 16 : 10); + DF_EvalVizWindowedRowList viz_rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, macro_map, eval_view, default_radix, ui_top_font(), ui_top_font_size(), r1s64(0, 50), &viz_blocks); //- rjf: animate { @@ -5195,7 +5138,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D default:{}break; case EVAL_EvalMode_Addr: { - U64 size = tg_byte_size_from_graph_raddbg_key(parse_ctx.type_graph, parse_ctx.rdbg, row->eval.type_key); + U64 size = tg_byte_size_from_graph_rdi_key(parse_ctx.type_graph, parse_ctx.rdi, row->eval.type_key); size = Min(size, 64); Rng1U64 vaddr_rng = r1u64(row->eval.offset, row->eval.offset+size); CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, vaddr_rng, 0); @@ -5219,7 +5162,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D B32 row_is_expanded = df_expand_key_is_set(&eval_view->expand_tree_table, row->key); if(row->flags & DF_EvalVizRowFlag_CanExpand) UI_PrefWidth(ui_em(1.5f, 1)) UI_Flags(UI_BoxFlag_DrawSideLeft*(row->depth>0)) - if(ui_expanderf(row_is_expanded, "###%I64x_%I64x_is_expanded", row->key.parent_hash, row->key.child_num).pressed) + if(ui_pressed(ui_expanderf(row_is_expanded, "###%I64x_%I64x_is_expanded", row->key.parent_hash, row->key.child_num))) { df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, row->parent_key, row->key, !row_is_expanded); } @@ -5248,11 +5191,11 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D DF_LineEditFlag_PreferDisplayString| DF_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(sig.commit) + if(ui_committed(sig)) { String8 commit_string = str8(ws->hover_eval_txt_buffer, ws->hover_eval_txt_size); DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, commit_string); - B32 success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdbg, &ctrl_ctx, row->eval, write_eval); + B32 success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, row->eval, write_eval); if(success == 0) { DF_CmdParams params = df_cmd_params_from_window(ws); @@ -5283,11 +5226,11 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_CornerRadius11(0) { UI_Signal watch_sig = df_icon_buttonf(DF_IconKind_List, 0, "###watch_hover_eval"); - if(watch_sig.hovering) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + if(ui_hovering(watch_sig)) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) { ui_labelf("Add the hovered expression to an opened watch view."); } - if(watch_sig.clicked) + if(ui_clicked(watch_sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.string = expr; @@ -5301,7 +5244,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_CornerRadius11(corner_radius) { UI_Signal pin_sig = df_icon_buttonf(DF_IconKind_Pin, 0, "###pin_hover_eval"); - if(pin_sig.hovering) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) + if(ui_hovering(pin_sig)) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Main)) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) UI_CornerRadius00(0) UI_CornerRadius01(0) UI_CornerRadius10(0) @@ -5309,7 +5252,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D { ui_labelf("Pin the hovered expression to this code location."); } - if(pin_sig.clicked) + if(ui_clicked(pin_sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); if(ws->hover_eval_vaddr != 0) @@ -5338,7 +5281,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //- rjf: interact { UI_Signal hover_eval_sig = ui_signal_from_box(hover_eval_box); - if(hover_eval_sig.mouse_over) + if(ui_mouse_over(hover_eval_sig)) { ws->hover_eval_last_frame_idx = df_frame_index(); } @@ -5393,19 +5336,19 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D 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_Signal sig = ui_signal_from_box(box); - if(sig.double_clicked) + if(ui_double_clicked(sig)) { ui_kill_action(); F32 sum_pct = min_child->size_pct_of_parent_target.v[split_axis] + max_child->size_pct_of_parent_target.v[split_axis]; min_child->size_pct_of_parent_target.v[split_axis] = 0.5f * sum_pct; max_child->size_pct_of_parent_target.v[split_axis] = 0.5f * sum_pct; } - else if(sig.pressed) + else if(ui_pressed(sig)) { Vec2F32 v = {min_child->size_pct_of_parent_target.v[split_axis], max_child->size_pct_of_parent_target.v[split_axis]}; ui_store_drag_struct(&v); } - else if(sig.dragging) + else if(ui_dragging(sig)) { Vec2F32 v = *ui_get_drag_struct(Vec2F32); Vec2F32 mouse_delta = ui_drag_delta(); @@ -5433,7 +5376,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D max_child->size_pct_of_parent.v[split_axis] = max_child->size_pct_of_parent_target.v[split_axis] = max_pct__after; is_changing_panel_boundaries = 1; } - if(sig.released || sig.double_clicked) + if(ui_released(sig) || ui_double_clicked(sig)) { df_panel_notify_mutation(ws, min_child); } @@ -5534,7 +5477,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D 0, str8(view->query_buffer, view->query_string_size), str8_lit("###filter_text_input")); - if(sig.pressed) + if(ui_pressed(sig)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); @@ -5745,7 +5688,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D //- rjf: consume panel fallthrough interaction events // UI_Signal panel_sig = ui_signal_from_box(panel_box); - if(panel_sig.pressed) + if(ui_pressed(panel_sig)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); @@ -5825,7 +5768,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ui_label(label); } UI_Signal sig = ui_signal_from_box(tab_list_item_box); - if(sig.clicked) + if(ui_clicked(sig)) { next_selected_tab_view = view; DF_CmdParams p = df_cmd_params_from_panel(ws, panel); @@ -5838,7 +5781,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D if(panel->tab_view_count > 5) UI_PrefWidth(ui_em(2.25f, 1.f)) UI_PrefHeight(ui_px(tab_bar_vheight, 1)) { UI_Signal sig = df_icon_buttonf(DF_IconKind_List, 0, "###tab_list_%p", panel); - if(sig.clicked) + if(ui_clicked(sig)) { if(ui_ctx_menu_is_open(tab_list_ctx_menu_key)) { @@ -5920,23 +5863,26 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D UI_BackgroundColor(v4f32(0, 0, 0, 0)) UI_CornerRadius00(0) UI_CornerRadius01(0) - if(ui_buttonf("%S###close_view_%p", df_g_icon_kind_text_table[DF_IconKind_X], view).clicked) { - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseTab)); + UI_Signal sig = ui_buttonf("%S###close_view_%p", df_g_icon_kind_text_table[DF_IconKind_X], view); + if(ui_clicked(sig) || ui_middle_clicked(sig)) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseTab)); + } } } // rjf: consume events for tab clicking { UI_Signal sig = ui_signal_from_box(tab_box); - if(sig.pressed) + if(ui_pressed(sig)) { next_selected_tab_view = view; DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } - else if(sig.dragging && !df_drag_is_active() && length_2f32(ui_drag_delta()) > 10.f) + else if(ui_dragging(sig) && !df_drag_is_active() && length_2f32(ui_drag_delta()) > 10.f) { DF_DragDropPayload payload = {0}; { @@ -5946,12 +5892,17 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D } df_drag_begin(&payload); } - else if(sig.right_clicked) + else if(ui_right_clicked(sig)) { ui_ctx_menu_open(ws->tab_ctx_menu_key, sig.box->key, v2f32(0, sig.box->rect.y1 - sig.box->rect.y0)); ws->tab_ctx_menu_view = df_handle_from_view(view); } - if(sig.released) + else if(ui_middle_clicked(sig)) + { + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CloseTab)); + } + if(ui_released(sig)) { df_panel_notify_mutation(ws, panel); } @@ -6674,7 +6625,22 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D // rjf: disabled overlay if(b->disabled_t >= 0.005f) { - R_Rect2DInst *inst = d_rect(b->rect, v4f32(0, 0, 0, 0.5f*b->disabled_t), 0, 0, 1); + // rhp: disabled overlay color blends from plain background and inactive panel overlay + Vec4F32 bg = df_rgba_from_theme_color(DF_ThemeColor_PlainBackground); + Vec4F32 ov = df_rgba_from_theme_color(DF_ThemeColor_InactivePanelOverlay); + Vec4F32 color = {}; + color.x = bg.x * bg.w + ov.x * ov.w * (1.0f - bg.w); + color.y = bg.y * bg.w + ov.y * ov.w * (1.0f - bg.w); + color.z = bg.z * bg.w + ov.z * ov.w * (1.0f - bg.w); + color.w = bg.w + ov.w * (1.0f - bg.w); + if (1.0f - color.w < 0.01f) + { + color.x *= color.w; + color.y *= color.w; + color.z *= color.w; + } + color.w = 0.60f * b->disabled_t; + R_Rect2DInst *inst = d_rect(b->rect, color, 0, 0, 1); MemoryCopyArray(inst->corner_radii, b->corner_radii); } @@ -6762,7 +6728,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D ProfEnd(); } -#if defined(_MSC_VER) && !defined(__clang__) && defined(NDEBUG) +#if COMPILER_MSVC && !BUILD_DEBUG #pragma optimize("", on) #endif @@ -6813,7 +6779,7 @@ df_eval_escaped_from_raw_string(Arena *arena, String8 raw) } internal String8List -df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table) +df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table) { ProfBeginFunction(); String8List list = {0}; @@ -6824,21 +6790,21 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags { if(opt_member != 0) { - U64 member_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, opt_member->type_key); - str8_list_pushf(arena, &list, "member (%I64u offset, %I64u byte%s)", opt_member->off, member_byte_size, member_byte_size > 1 ? "s" : ""); + U64 member_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, opt_member->type_key); + str8_list_pushf(arena, &list, "member (%I64u offset, %I64u byte%s)", opt_member->off, member_byte_size, member_byte_size == 1 ? "s" : ""); } else { String8 basic_type_kind_string = tg_kind_basic_string_table[tg_kind_from_key(eval.type_key)]; - U64 byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, eval.type_key); - str8_list_pushf(arena, &list, "%S (%I64u byte%s)", basic_type_kind_string, byte_size, byte_size > 1 ? "s" : ""); + U64 byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, eval.type_key); + str8_list_pushf(arena, &list, "%S (%I64u byte%s)", basic_type_kind_string, byte_size, byte_size == 1 ? "s" : ""); } } //- rjf: non-type path: descend recursively & produce single-line value strings else if(max_size > 0) { - TG_Kind eval_type_kind = tg_kind_from_key(tg_unwrapped_from_graph_raddbg_key(graph, rdbg, eval.type_key)); + TG_Kind eval_type_kind = tg_kind_from_key(tg_unwrapped_from_graph_rdi_key(graph, rdi, eval.type_key)); U32 radix = default_radix; DF_CfgVal *dec_cfg = df_cfg_val_from_string(cfg_table, str8_lit("dec")); DF_CfgVal *hex_cfg = df_cfg_val_from_string(cfg_table, str8_lit("hex")); @@ -6854,8 +6820,8 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags //- rjf: default - leaf cases default: { - DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, eval); - String8 string = df_string_from_simple_typed_eval(arena, graph, rdbg, flags, radix, value_eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, eval); + String8 string = df_string_from_simple_typed_eval(arena, graph, rdi, flags, radix, value_eval); space_taken += f_dim_from_tag_size_string(font, font_size, string).x; str8_list_push(arena, &list, string); }break; @@ -6875,11 +6841,11 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags B32 has_array = (array_cfg != &df_g_nil_cfg_val); // rjf: get ptr value - DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdbg, ctrl_ctx, eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(graph, rdi, ctrl_ctx, eval); // rjf: get pointed-at info TG_Kind type_kind = tg_kind_from_key(eval.type_key); - TG_Key direct_type_key = tg_ptee_from_graph_raddbg_key(graph, rdbg, eval.type_key); + TG_Key direct_type_key = tg_ptee_from_graph_rdi_key(graph, rdi, eval.type_key); TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); B32 direct_type_has_content = (direct_type_kind != TG_Kind_Null && direct_type_kind != TG_Kind_Void && value_eval.imm_u64 != 0); B32 direct_type_is_string = (direct_type_kind != TG_Kind_Null && value_eval.imm_u64 != 0 && @@ -6895,7 +6861,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags if(!no_addr || (direct_type_has_content == 0 && direct_type_is_string == 0)) { did_ptr_value = 1; - String8 string = df_string_from_simple_typed_eval(arena, graph, rdbg, flags, radix, value_eval); + String8 string = df_string_from_simple_typed_eval(arena, graph, rdi, flags, radix, value_eval); space_taken += f_dim_from_tag_size_string(font, font_size, string).x; str8_list_push(arena, &list, string); } @@ -6912,8 +6878,16 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags if(!has_array && direct_type_is_string && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules) && eval.mode == EVAL_EvalMode_Addr) { U64 string_memory_addr = value_eval.imm_u64; - CTRL_ProcessMemorySlice text_slice = ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(arena, process->ctrl_machine_id, process->ctrl_handle, string_memory_addr, 256, 0); - String8 text = df_eval_escaped_from_raw_string(arena, text_slice.data); + U64 element_size = tg_byte_size_from_graph_rdi_key(graph, rdi, direct_type_key); + CTRL_ProcessMemorySlice text_slice = ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(arena, process->ctrl_machine_id, process->ctrl_handle, string_memory_addr, 256, element_size, 0); + String8 raw_text = {0}; + switch(element_size) + { + default:{raw_text = text_slice.data;}break; + case 2: {raw_text = str8_from_16(arena, str16((U16 *)text_slice.data.str, text_slice.data.size/sizeof(U16)));}break; + case 4: {raw_text = str8_from_32(arena, str32((U32 *)text_slice.data.str, text_slice.data.size/sizeof(U32)));}break; + } + String8 text = df_eval_escaped_from_raw_string(arena, raw_text); space_taken += f_dim_from_tag_size_string(font, font_size, text).x; space_taken += 2*f_dim_from_tag_size_string(font, font_size, str8_lit("\"")).x; str8_list_push(arena, &list, str8_lit("\"")); @@ -6940,7 +6914,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags pted_eval.type_key = direct_type_key; pted_eval.mode = EVAL_EvalMode_Addr; pted_eval.offset = value_eval.imm_u64; - String8List pted_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdbg, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, pted_eval, opt_member, cfg_table); + String8List pted_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdi, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, pted_eval, opt_member, cfg_table); if(pted_strs.total_size == 0) { String8 unknown = str8_lit("???"); @@ -6966,7 +6940,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags case TG_Kind_Array: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *eval_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, eval.type_key); + TG_Type *eval_type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, eval.type_key); TG_Key direct_type_key = eval_type->direct_type_key; TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); U64 array_count = eval_type->count; @@ -6988,8 +6962,16 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags special_case = 1; DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - CTRL_ProcessMemorySlice text_slice = ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(arena, process->ctrl_machine_id, process->ctrl_handle, eval.offset, 256, 0); - String8 text = df_eval_escaped_from_raw_string(arena, text_slice.data); + U64 element_size = tg_byte_size_from_graph_rdi_key(graph, rdi, eval_type->direct_type_key); + CTRL_ProcessMemorySlice text_slice = ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(arena, process->ctrl_machine_id, process->ctrl_handle, eval.offset, 256, element_size, 0); + String8 raw_text = {0}; + switch(element_size) + { + default:{raw_text = text_slice.data;}break; + case 2: {raw_text = str8_from_16(arena, str16((U16 *)text_slice.data.str, text_slice.data.size/sizeof(U16)));}break; + case 4: {raw_text = str8_from_32(arena, str32((U32 *)text_slice.data.str, text_slice.data.size/sizeof(U32)));}break; + } + String8 text = df_eval_escaped_from_raw_string(arena, raw_text); space_taken += f_dim_from_tag_size_string(font, font_size, text).x; space_taken += 2*f_dim_from_tag_size_string(font, font_size, str8_lit("\"")).x; str8_list_push(arena, &list, str8_lit("\"")); @@ -7010,7 +6992,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags { if(depth < 3) { - U64 direct_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct_type_key); + U64 direct_type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, direct_type_key); for(U64 idx = 0; idx < array_count && max_size > space_taken; idx += 1) { DF_Eval element_eval = zero_struct; @@ -7018,7 +7000,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags element_eval.mode = eval.mode; element_eval.offset = eval.offset + direct_type_byte_size*idx; MemoryCopyArray(element_eval.imm_u128, eval.imm_u128); - String8List element_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdbg, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, element_eval, opt_member, cfg_table); + String8List element_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdi, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, element_eval, opt_member, cfg_table); space_taken += f_dim_from_tag_size_string_list(font, font_size, element_strs).x; str8_list_concat_in_place(&list, &element_strs); if(idx+1 < array_count) @@ -7066,7 +7048,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags if(depth < 4) { Temp scratch = scratch_begin(&arena, 1); - TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, graph, rdbg, eval.type_key); + TG_MemberArray data_members = tg_data_members_from_graph_rdi_key(scratch.arena, graph, rdi, eval.type_key); TG_MemberArray filtered_data_members = df_filtered_data_members_from_members_cfg_table(scratch.arena, data_members, cfg_table); for(U64 member_idx = 0; member_idx < filtered_data_members.count && max_size > space_taken; member_idx += 1) { @@ -7076,7 +7058,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags member_eval.mode = eval.mode; member_eval.offset = eval.offset + mem->off; MemoryCopyArray(member_eval.imm_u128, eval.imm_u128); - String8List member_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdbg, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, member_eval, opt_member, cfg_table); + String8List member_strs = df_single_line_eval_value_strings_from_eval(arena, flags, graph, rdi, ctrl_ctx, default_radix, font, font_size, max_size-space_taken, depth+1, member_eval, opt_member, cfg_table); space_taken += f_dim_from_tag_size_string_list(font, font_size, member_strs).x; str8_list_concat_in_place(&list, &member_strs); if(member_idx+1 < filtered_data_members.count) @@ -7241,8 +7223,8 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop case DF_EvalVizBlockKind_Root: if(visible_idx_range.max > visible_idx_range.min) { - String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, block->eval, block->member, &block->cfg_table); - String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, block->eval, block->member, &block->cfg_table); + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, block->eval, block->member, &block->cfg_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, block->eval, block->member, &block->cfg_table); DF_EvalVizRow *row = df_eval_viz_row_list_push_new(arena, parse_ctx, &list, block, block->key, block->eval); row->expr = block->string; row->display_value = str8_list_join(arena, &display_strings, 0); @@ -7267,7 +7249,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop case DF_EvalVizBlockKind_Members: if(block_type_kind != TG_Kind_Null) { - TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, block->eval.type_key); + TG_MemberArray data_members = tg_data_members_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, block->eval.type_key); TG_MemberArray filtered_data_members = df_filtered_data_members_from_members_cfg_table(scratch.arena, data_members, &block->cfg_table); for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max && idx < filtered_data_members.count; idx += 1) { @@ -7292,13 +7274,13 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop // rjf: apply view rules to eval { - member_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, member_eval); + member_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, member_eval); member_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, macro_map, member_eval, &view_rule_table); } // rjf: build & push row - String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, member_eval, member, &view_rule_table); - String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, member_eval, member, &view_rule_table); + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, member_eval, member, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, member_eval, member, &view_rule_table); DF_EvalVizRow *row = df_eval_viz_row_list_push_new(arena, parse_ctx, &list, block, key, member_eval); if(member->kind == TG_MemberKind_Padding) { @@ -7325,7 +7307,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop case DF_EvalVizBlockKind_EnumMembers: if(block_type_kind == TG_Kind_Enum) { - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, block->eval.type_key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, block->eval.type_key); for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max && idx < type->count; idx += 1) { TG_EnumVal *enum_val = &type->enum_vals[idx]; @@ -7346,13 +7328,13 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop // rjf: apply view rules to eval { - eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval, &view_rule_table); } // rjf: build & push row - String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); - String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); DF_EvalVizRow *row = df_eval_viz_row_list_push_new(arena, parse_ctx, &list, block, key, eval); row->expr = push_str8_copy(arena, enum_val->name); row->display_value = str8_list_join(arena, &display_strings, 0); @@ -7369,9 +7351,9 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop // case DF_EvalVizBlockKind_Elements: { - TG_Key direct_type_key = tg_unwrapped_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, block->eval.type_key); + TG_Key direct_type_key = tg_unwrapped_direct_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, block->eval.type_key); TG_Kind direct_type_kind = tg_kind_from_key(direct_type_key); - U64 direct_type_key_byte_size = tg_byte_size_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, direct_type_key); + U64 direct_type_key_byte_size = tg_byte_size_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, direct_type_key); for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) { // rjf: get keys for this row @@ -7393,13 +7375,13 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop // rjf: apply view rules to eval { - elem_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, elem_eval); + elem_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, elem_eval); elem_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, macro_map, elem_eval, &view_rule_table); } // rjf: build row - String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, elem_eval, 0, &view_rule_table); - String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, elem_eval, 0, &view_rule_table); + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, elem_eval, 0, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, elem_eval, 0, &view_rule_table); DF_EvalVizRow *row = df_eval_viz_row_list_push_new(arena, parse_ctx, &list, block, key, elem_eval); row->expr = push_str8f(arena, "[%I64u]", idx); row->display_value = str8_list_join(arena, &display_strings, 0); @@ -7420,7 +7402,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop // case DF_EvalVizBlockKind_Links: { - DF_EvalLinkBaseChunkList link_base_chunks = df_eval_link_base_chunk_list_from_eval(scratch.arena, parse_ctx->type_graph, parse_ctx->rdbg, block->link_member_type_key, block->link_member_off, ctrl_ctx, block->eval, 512); + DF_EvalLinkBaseChunkList link_base_chunks = df_eval_link_base_chunk_list_from_eval(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, block->link_member_type_key, block->link_member_off, ctrl_ctx, block->eval, 512); DF_EvalLinkBaseArray link_bases = df_eval_link_base_array_from_chunk_list(scratch.arena, &link_base_chunks); for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) { @@ -7444,13 +7426,13 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop df_cfg_table_push_unparsed_string(scratch.arena, &view_rule_table, view_rule_string, DF_CfgSrc_User); // rjf: apply view rules to eval - link_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, link_eval); + link_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, link_eval); link_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, macro_map, link_eval, &view_rule_table); TG_Kind link_type_kind = tg_kind_from_key(link_eval.type_key); // rjf: build row - String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, link_eval, 0, &view_rule_table); - String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, link_eval, 0, &view_rule_table); + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, link_eval, 0, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, link_eval, 0, &view_rule_table); DF_EvalVizRow *row = df_eval_viz_row_list_push_new(arena, parse_ctx, &list, block, key, link_eval); row->expr = push_str8f(arena, "[%I64u]", idx); row->display_value = str8_list_join(arena, &display_strings, 0); @@ -7489,7 +7471,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) { // rjf: unpack info about this row - String8 name = dbgi_fuzzy_item_string_from_rdbg_target_element_idx(parse_ctx->rdbg, block->dbgi_target, block->backing_search_items.v[idx].idx); + String8 name = dbgi_fuzzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, block->dbgi_target, block->backing_search_items.v[idx].idx); // rjf: get keys for this row DF_ExpandKey parent_key = block->parent_key; @@ -7506,13 +7488,13 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop // rjf: apply view rules to eval { - eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval, &view_rule_table); } // rjf: build row - String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); - String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); + String8List display_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); + String8List edit_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, 0, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, default_radix, font, font_size, 500, 0, eval, 0, &view_rule_table); DF_EvalVizRow *row = df_eval_viz_row_list_push_new(arena, parse_ctx, &list, block, key, eval); row->expr = name; row->display_value = str8_list_join(arena, &display_strings, 0); @@ -7535,7 +7517,10 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop internal void df_set_hover_eval(DF_Window *ws, Vec2F32 pos, DF_CtrlCtx ctrl_ctx, DF_Entity *file, TxtPt pt, U64 vaddr, String8 string) { - if(ws->hover_eval_last_frame_idx+1 < df_frame_index() && ui_key_match(ui_active_key(Side_Min), ui_key_zero()) && ui_key_match(ui_active_key(Side_Max), ui_key_zero())) + if(ws->hover_eval_last_frame_idx+1 < df_frame_index() && + 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(ws->hover_eval_string, string, 0); if(is_new_string) @@ -7658,307 +7643,6 @@ df_push_search_string(Arena *arena) return result; } -//////////////////////////////// -//~ rjf: Background Text Searching Thread - -internal void -df_text_search_match_chunk_list_push(Arena *arena, DF_TextSearchMatchChunkList *list, U64 cap, DF_TextSearchMatch *match) -{ - DF_TextSearchMatchChunkNode *node = list->last; - if(node == 0 || node->count >= node->cap) - { - node = push_array(arena, DF_TextSearchMatchChunkNode, 1); - node->cap = cap; - node->v = push_array_no_zero(arena, DF_TextSearchMatch, node->cap); - SLLQueuePush(list->first, list->last, node); - list->node_count += 1; - } - node->v[node->count] = *match; - node->count += 1; - list->total_count += 1; -} - -internal DF_TextSearchMatchArray -df_text_search_match_array_from_chunk_list(Arena *arena, DF_TextSearchMatchChunkList *chunks) -{ - DF_TextSearchMatchArray array = {0}; - array.count = chunks->total_count; - array.v = push_array_no_zero(arena, DF_TextSearchMatch, array.count); - U64 idx = 0; - for(DF_TextSearchMatchChunkNode *node = chunks->first; node != 0; node = node->next) - { - MemoryCopy(array.v+idx, node->v, node->count * sizeof(DF_TextSearchMatch)); - idx += node->count; - } - return array; -} - -internal U64 -df_text_search_little_hash_from_hash(U128 hash) -{ - // TODO(rjf): [ ] @de2ctrl df_text_search_little_hash_from_hash - U64 little_hash = 0; - MemoryCopy(&little_hash, &hash, sizeof(little_hash)); - return little_hash; -} - -internal void -df_text_search_thread_entry_point(void *p) -{ - TCTX tctx_; - tctx_init_and_equip(&tctx_); -#if 0 - // TODO(rjf): [ ] @de2ctrl text searcher -- wound up in DE_Hash - - //- rjf: types - typedef enum WorkKind - { - WorkKind_Search, - WorkKind_GarbageCollect, - WorkKind_COUNT - } - WorkKind; - typedef struct WorkNode WorkNode; - struct WorkNode - { - WorkNode *next; - WorkKind kind; - U128 hash; - String8 needle; - DF_TextSliceFlags flags; - TxtPt start_pt; - }; - - //- rjf: set up local debug engine map - Arena *local_map_arena = arena_alloc(); - DE_ContentMap local_map = {0}; - DE_PipelineHint hint = zero_struct; - - //- rjf: loop over work - for(;;) - { - //- rjf: begin - Temp scratch = scratch_begin(0, 0); - DE_Session *session = de_session_begin(); - - //- rjf: wait for changes - os_mutex_take(df_gfx_state->tsrch_wakeup_mutex); - os_condition_variable_wait(df_gfx_state->tsrch_wakeup_cv, df_gfx_state->tsrch_wakeup_mutex, os_now_microseconds()+1000000); - os_mutex_drop(df_gfx_state->tsrch_wakeup_mutex); - - //- rjf: gather all searches to complete - WorkNode *first_work_node = 0; - WorkNode *last_work_node = 0; - for(U64 slot_idx = 0; slot_idx < df_gfx_state->tsrch_slot_count; slot_idx += 1) - { - //- rjf: slot idx -> slot * stripe - DF_TextSearchCacheSlot *slot = &df_gfx_state->tsrch_slots[slot_idx]; - U64 stripe_idx = slot_idx%df_gfx_state->tsrch_stripe_count; - OS_Handle stripe_rw_mutex = df_gfx_state->tsrch_stripe_rw_mutexes[stripe_idx]; - - //- rjf: gather nodes in this slot - os_rw_mutex_take_r(stripe_rw_mutex); - { - for(DF_TextSearchCacheNode *n = slot->first; n != 0; n = n->next) - { - B32 not_done = (n->good == 0); - B32 expired = (os_now_microseconds() >= n->last_time_touched_us + 10000000); - if(not_done || expired) - { - WorkNode *work = push_array(scratch.arena, WorkNode, 1); - work->kind = not_done ? WorkKind_Search : WorkKind_GarbageCollect; - work->hash = n->hash; - work->needle = push_str8_copy(scratch.arena, n->needle); - work->flags = n->flags; - work->start_pt = n->start_pt; - SLLQueuePush(first_work_node, last_work_node, work); - } - } - } - os_rw_mutex_drop_r(stripe_rw_mutex); - } - - //- rjf: perform all searches - for(WorkNode *work_node = first_work_node; work_node != 0; work_node = work_node->next) - { - //- rjf: unpack work node - WorkKind kind = work_node->kind; - DE_Hash hash = work_node->hash; - String8 needle = work_node->needle; - DF_TextSliceFlags flags = work_node->flags; - TxtPt start_pt = work_node->start_pt; - - //- rjf: work params -> slot/stripe info - U64 little_hash = df_text_search_little_hash_from_hash(hash); - U64 slot_idx = little_hash%df_gfx_state->tsrch_slot_count; - DF_TextSearchCacheSlot *slot = &df_gfx_state->tsrch_slots[slot_idx]; - U64 stripe_idx = slot_idx%df_gfx_state->tsrch_stripe_count; - OS_Handle stripe_rw_mutex = df_gfx_state->tsrch_stripe_rw_mutexes[stripe_idx]; - - //- rjf: do work - switch(kind) - { - //- rjf: search - default: - case WorkKind_Search: - { - //- rjf: hash -> artifacts - DE_Key hash2data_key = de_key_hash(DE_KeyFunc_DataFromHash, &hash); - DE_Val *hash2data_val = de_shared_chained_lookup(local_map_arena, &local_map, de_shared, &hint, &hash2data_key); - DE_ContentBlock *hash2data_block = de_session_node_access_via_val(session, hash2data_val); - String8 data = hash2data_block->data; - DE_Key hash2txti_key = de_key_hash(DE_KeyFunc_TxtiFromHash, &hash); - DE_Val *hash2txti_val = de_shared_chained_lookup(local_map_arena, &local_map, de_shared, &hint, &hash2txti_key); - DE_ContentBlock *hash2txti_block = de_session_node_access_via_val(session, hash2txti_val); - DE_InfoTxt *txt = hash2txti_block->txt; - - //- rjf: start pt -> search start offset - U64 start_off = 0; - if(1 <= start_pt.line && start_pt.line <= txt->line_count) - { - start_off = txt->line_ranges[start_pt.line-1].min; - if(1 <= start_pt.column && start_pt.column <= dim_1u64(txt->line_ranges[start_pt.line-1])) - { - start_off += (start_pt.column-1); - } - } - - //- rjf: search for all needle occurrences - U8 *byte_first = data.str; - U8 *byte_opl = data.str+data.size; - U8 *byte_start = byte_first + start_off; - U64 num_bytes_traversed = 0; - for(U8 *byte = byte_start; num_bytes_traversed < data.size;) - { - String8 rest_of_data = str8(byte, byte_opl-byte); - String8 next_needle_size = str8_prefix(rest_of_data, needle.size); - B32 found_match = str8_match(next_needle_size, needle, StringMatchFlag_CaseInsensitive); - - // rjf: record match - if(found_match) - { - U64 match_off = (U64)(byte-byte_first); - TxtPt match_pt = de_txt_pt_from_txti_off(txt, match_off); - DF_TextSearchMatch match = {match_pt}; - os_rw_mutex_take_w(stripe_rw_mutex); - { - DF_TextSearchCacheNode *node = 0; - for(DF_TextSearchCacheNode *n = slot->first; n != 0; n = n->next) - { - if(MemoryMatchStruct(&hash, &n->hash) && - str8_match(needle, n->needle, 0) && - flags == n->flags) - { - node = n; - } - } - df_text_search_match_chunk_list_push(node->arena, &node->search_matches, 256, &match); - node->good = 1; - } - os_rw_mutex_drop_w(stripe_rw_mutex); - } - - // rjf: increment - byte += 1; - num_bytes_traversed += 1; - if(byte >= byte_opl) - { - byte = byte_first; - } - } - - }break; - - //- rjf: garbage collect - case WorkKind_GarbageCollect: - { - os_rw_mutex_take_w(stripe_rw_mutex); - { - DF_TextSearchCacheNode *node = 0; - for(DF_TextSearchCacheNode *n = slot->first; n != 0; n = n->next) - { - if(MemoryMatchStruct(&hash, &n->hash) && - str8_match(needle, n->needle, 0) && - flags == n->flags) - { - node = n; - } - } - if(node != 0) - { - DLLRemove(slot->first, slot->last, node); - arena_release(node->arena); - } - } - os_rw_mutex_drop_w(stripe_rw_mutex); - }break; - } - } - - //- rjf: end - de_session_end(session); - scratch_end(scratch); - } -#endif -} - -internal int -df_text_search_match_array_qsort_compare(TxtPt *a, TxtPt *b) -{ - int result = 0; - if(txt_pt_less_than(*a, *b)) - { - result = -1; - } - else if(txt_pt_less_than(*b, *a)) - { - result = +1; - } - return result; -} - -internal void -df_text_search_match_array_sort_in_place(DF_TextSearchMatchArray *array) -{ - qsort(array->v, array->count, sizeof(DF_TextSearchMatch), (int (*)(const void *, const void *))df_text_search_match_array_qsort_compare); -} - -internal DF_TextSearchMatch -df_text_search_match_array_find_nearest__linear_scan(DF_TextSearchMatchArray *array, TxtPt pt, Side side) -{ - ProfBeginFunction(); - DF_TextSearchMatch result = {0}; - if(array->count != 0) - { - S64 best_line_distance = max_S64; - S64 best_column_distance = max_S64; - B32 best_matches_side = 0; - for(U64 idx = 0; idx < array->count; idx += 1) - { - S64 line_distance = abs_s64(array->v[idx].pt.line - pt.line); - S64 column_distance = abs_s64(array->v[idx].pt.column - pt.column); - B32 matches_side = (side == Side_Max ? txt_pt_less_than(pt, array->v[idx].pt) : - side == Side_Min ? txt_pt_less_than(array->v[idx].pt, pt) : - 1); - if(matches_side >= best_matches_side && line_distance == 0 && column_distance < best_column_distance) - { - best_matches_side = matches_side; - best_line_distance = 0; - best_column_distance = column_distance; - result = array->v[idx]; - } - else if(matches_side >= best_matches_side && line_distance < best_line_distance) - { - best_matches_side = matches_side; - best_line_distance = line_distance; - result = array->v[idx]; - } - } - } - ProfEnd(); - return result; -} - //////////////////////////////// //~ rjf: Colors, Fonts, Config @@ -8105,19 +7789,18 @@ df_rgba_from_theme_color(DF_ThemeColor color) } internal DF_ThemeColor -df_theme_color_from_txti_token_kind(TXTI_TokenKind kind) +df_theme_color_from_txt_token_kind(TXT_TokenKind kind) { DF_ThemeColor color = DF_ThemeColor_CodeDefault; switch(kind) { default:break; - case TXTI_TokenKind_Keyword:{color = DF_ThemeColor_CodeKeyword;}break; - case TXTI_TokenKind_Numeric:{color = DF_ThemeColor_CodeNumeric;}break; - case TXTI_TokenKind_String: {color = DF_ThemeColor_CodeString;}break; - case TXTI_TokenKind_Meta: {color = DF_ThemeColor_CodeMeta;}break; - case TXTI_TokenKind_Comment:{color = DF_ThemeColor_CodeComment;}break; - case TXTI_TokenKind_Symbol: {color = DF_ThemeColor_CodeSymbol;}break; - case TXTI_TokenKind_Type: {color = DF_ThemeColor_CodeType;}break; + case TXT_TokenKind_Keyword:{color = DF_ThemeColor_CodeKeyword;}break; + case TXT_TokenKind_Numeric:{color = DF_ThemeColor_CodeNumeric;}break; + case TXT_TokenKind_String: {color = DF_ThemeColor_CodeString;}break; + case TXT_TokenKind_Meta: {color = DF_ThemeColor_CodeMeta;}break; + case TXT_TokenKind_Comment:{color = DF_ThemeColor_CodeComment;}break; + case TXT_TokenKind_Symbol: {color = DF_ThemeColor_CodeSymbol;}break; } return color; } @@ -8438,6 +8121,124 @@ df_cfg_strings_from_gfx(Arena *arena, String8 root_path, DF_CfgSrc source) return strs; } +//////////////////////////////// +//~ rjf: Process Control Info Stringification + +internal String8 +df_string_from_exception_code(U32 code) +{ + String8 string = {0}; + for(EachNonZeroEnumVal(CTRL_ExceptionCodeKind, k)) + { + if(code == ctrl_exception_code_kind_code_table[k]) + { + string = ctrl_exception_code_kind_display_string_table[k]; + break; + } + } + return string; +} + +internal String8 +df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, DF_IconKind *icon_out) +{ + DF_IconKind icon = DF_IconKind_Null; + String8 explanation = {0}; + Temp scratch = scratch_begin(&arena, 1); + DF_Entity *thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); + String8 thread_display_string = df_display_string_from_entity(scratch.arena, thread); + switch(event->kind) + { + default: + { + switch(event->cause) + { + default:{}break; + case CTRL_EventCause_Finished: + { + if(!df_entity_is_nil(thread)) + { + explanation = push_str8f(arena, "%S completed step", thread_display_string); + } + else + { + explanation = str8_lit("Stopped"); + } + }break; + case CTRL_EventCause_UserBreakpoint: + { + if(!df_entity_is_nil(thread)) + { + icon = DF_IconKind_CircleFilled; + explanation = push_str8f(arena, "%S hit a breakpoint", thread_display_string); + } + }break; + case CTRL_EventCause_InterruptedByException: + { + if(!df_entity_is_nil(thread)) + { + icon = DF_IconKind_WarningBig; + switch(event->exception_kind) + { + default: + { + String8 exception_code_string = df_string_from_exception_code(event->exception_code); + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x%s%S", thread_display_string, event->exception_code, exception_code_string.size > 0 ? ": " : "", exception_code_string); + }break; + case CTRL_ExceptionKind_CppThrow: + { + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: C++ exception", thread_display_string, event->exception_code); + }break; + case CTRL_ExceptionKind_MemoryRead: + { + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation reading 0x%I64x", + thread_display_string, + event->exception_code, + event->vaddr_rng.min); + }break; + case CTRL_ExceptionKind_MemoryWrite: + { + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation writing 0x%I64x", + thread_display_string, + event->exception_code, + event->vaddr_rng.min); + }break; + case CTRL_ExceptionKind_MemoryExecute: + { + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation executing 0x%I64x", + thread_display_string, + event->exception_code, + event->vaddr_rng.min); + }break; + } + } + else + { + icon = DF_IconKind_Pause; + explanation = str8_lit("Interrupted"); + } + }break; + case CTRL_EventCause_InterruptedByTrap: + { + icon = DF_IconKind_WarningBig; + explanation = push_str8f(arena, "%S interrupted by trap - 0x%x", thread_display_string, event->exception_code); + }break; + case CTRL_EventCause_InterruptedByHalt: + { + icon = DF_IconKind_Pause; + explanation = str8_lit("Halted"); + }break; + } + }break; + } + scratch_end(scratch); + if(icon_out) + { + *icon_out = icon; + } + return explanation; +} + //////////////////////////////// //~ rjf: UI Widgets: Fancy Buttons @@ -8500,26 +8301,26 @@ df_cmd_binding_button(DF_CmdSpec *spec) UI_Signal sig = ui_signal_from_box(box); { // rjf: hover => visualize clickability - if(sig.hovering) + if(ui_hovering(sig)) { box->flags |= UI_BoxFlag_DrawBorder; box->flags |= UI_BoxFlag_DrawBackground; } // rjf: click => toggle activity - if(!df_gfx_state->bind_change_active && sig.clicked) + if(!df_gfx_state->bind_change_active && ui_clicked(sig)) { df_gfx_state->bind_change_active = 1; df_gfx_state->bind_change_cmd_spec = spec; df_gfx_state->bind_change_binding = binding; } - else if(df_gfx_state->bind_change_active && sig.clicked) + else if(df_gfx_state->bind_change_active && ui_clicked(sig)) { df_gfx_state->bind_change_active = 0; } // rjf: hover w/ conflicts => show conflicts - if(sig.hovering && has_conflicts) UI_Tooltip + if(ui_hovering(sig) && has_conflicts) UI_Tooltip { ui_labelf("This binding conflicts with others:"); for(DF_CmdSpecNode *n = specs_with_binding.first; n != 0; n = n->next) @@ -8604,7 +8405,7 @@ df_cmd_list_menu_buttons(DF_Window *ws, U64 count, DF_CoreCmdKind *cmds, U32 *fa DF_CmdSpec *spec = df_cmd_spec_from_core_cmd_kind(cmds[idx]); ui_set_next_fastpath_codepoint(fastpath_codepoints[idx]); UI_Signal sig = df_cmd_spec_button(spec); - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.cmd_spec = spec; @@ -8705,6 +8506,25 @@ df_entity_tooltips(DF_Entity *entity) } UI_PrefWidth(ui_text_dim(10, 1)) ui_label(display_string); } + { + CTRL_Event stop_event = df_ctrl_last_stop_event(); + DF_Entity *stopper_thread = df_entity_from_ctrl_handle(stop_event.machine_id, stop_event.entity); + if(stopper_thread == entity) + { + ui_spacer(ui_em(1.5f, 1.f)); + DF_IconKind icon_kind = DF_IconKind_Null; + String8 explanation = df_stop_explanation_string_icon_from_ctrl_event(scratch.arena, &stop_event, &icon_kind); + if(explanation.size != 0) + { + UI_PrefWidth(ui_children_sum(1)) UI_Row UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) + { + UI_PrefWidth(ui_em(1.5f, 1.f)) UI_Font(df_font_from_slot(DF_FontSlot_Icons)) ui_label(df_g_icon_kind_text_table[icon_kind]); + UI_PrefWidth(ui_text_dim(10, 1)) ui_label(explanation); + } + } + } + } + ui_spacer(ui_em(1.5f, 1.f)); UI_PrefWidth(ui_children_sum(1)) UI_Row { UI_PrefWidth(ui_em(18.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("TID: "); @@ -8881,7 +8701,7 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam info_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "%S###%p_temp_info", df_g_icon_kind_text_table[DF_IconKind_Info], entity); } UI_Signal info_sig = ui_signal_from_box(info_box); - if(info_sig.hovering) UI_Tooltip + if(ui_hovering(info_sig)) UI_Tooltip { ui_labelf("Specified via command line; not saved in profile."); } @@ -8955,7 +8775,7 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam } // rjf: click => fastpath or dropdown for this entity - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(entity); @@ -8964,7 +8784,7 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam } // rjf: right-click => context menu for this entity - else if(sig.right_clicked) + else if(ui_right_clicked(sig)) { DF_Handle handle = df_handle_from_entity(entity); if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) @@ -8979,7 +8799,7 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam } // rjf: drag+drop - else if(sig.dragging && !contains_2f32(box->rect, ui_mouse())) + else if(ui_dragging(sig) && !contains_2f32(box->rect, ui_mouse())) { DF_DragDropPayload payload = {0}; payload.key = box->key; @@ -9021,7 +8841,7 @@ df_entity_src_loc_button(DF_Window *ws, DF_Entity *entity, TxtPt point) } // rjf: click => find code location - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.file_path = full_path; @@ -9032,7 +8852,7 @@ df_entity_src_loc_button(DF_Window *ws, DF_Entity *entity, TxtPt point) } // rjf: drag+drop - else if(sig.dragging && !contains_2f32(box->rect, ui_mouse())) + else if(ui_dragging(sig) && !contains_2f32(box->rect, ui_mouse())) { DF_DragDropPayload payload = {0}; payload.key = box->key; @@ -9042,7 +8862,7 @@ df_entity_src_loc_button(DF_Window *ws, DF_Entity *entity, TxtPt point) } // rjf: hover => show full path - else if(sig.hovering && !sig.dragging) UI_Tooltip + else if(ui_hovering(sig) && !ui_dragging(sig)) UI_Tooltip { ui_labelf("%S:%I64d:%I64d", full_path, point.line, point.column); } @@ -9224,6 +9044,29 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } } + ////////////////////////////// + //- 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) + { + DF_EntityList threads = params->line_ips[line_idx]; + for(DF_EntityNode *n = threads.first; n != 0; n = n->next) + { + if(n->entity == stopper_thread && (stop_event.cause == CTRL_EventCause_InterruptedByTrap || stop_event.cause == CTRL_EventCause_InterruptedByException)) + { + line_bg_colors[line_idx] = df_rgba_from_theme_color(DF_ThemeColor_FailureBackground); + line_bg_colors[line_idx].w *= 0.25f; + } + } + } + } + ////////////////////////////// //- rjf: build per-line context menus // @@ -9241,28 +9084,28 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ DF_TextLineDasm2SrcInfoList *line_dasm2src_list = ¶ms->line_dasm2src[line_idx]; //- rjf: copy selection - if(!txt_pt_match(*cursor, *mark) && df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Copy)).clicked) + if(!txt_pt_match(*cursor, *mark) && ui_clicked(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Copy)))) { result.copy_range = txt_rng(*cursor, *mark); ui_ctx_menu_close(); } //- rjf: watch selection - if(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpressionAtCursor)).clicked) + if(ui_clicked(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpressionAtCursor)))) { result.toggle_cursor_watch = 1; ui_ctx_menu_close(); } //- rjf: set-next-statement - if(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetNextStatement)).clicked) + if(ui_clicked(df_cmd_spec_button(df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetNextStatement)))) { result.set_next_statement_line_num = line_num; ui_ctx_menu_close(); } //- rjf: run-to-line - if(df_icon_buttonf(DF_IconKind_Play, 0, "Run To Line").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Play, 0, "Run To Line"))) { result.run_to_line_num = line_num; ui_ctx_menu_close(); @@ -9270,9 +9113,9 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ //- rjf: breakpoint placing if((params->line_bps[line_idx].count == 0 && - df_icon_buttonf(DF_IconKind_CircleFilled, 0, "Place Breakpoint").clicked) || + ui_clicked(df_icon_buttonf(DF_IconKind_CircleFilled, 0, "Place Breakpoint"))) || (params->line_bps[line_idx].count != 0 && - df_icon_buttonf(DF_IconKind_CircleFilled, 0, "Remove Breakpoint").clicked)) + ui_clicked(df_icon_buttonf(DF_IconKind_CircleFilled, 0, "Remove Breakpoint")))) { result.clicked_margin_line_num = line_num; ui_ctx_menu_close(); @@ -9280,7 +9123,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ //- rjf: go from src -> disasm if(line_src2dasm_list->first != 0 && - df_icon_buttonf(DF_IconKind_Find, 0, "Go To Disassembly").clicked) + ui_clicked(df_icon_buttonf(DF_IconKind_Find, 0, "Go To Disassembly"))) { result.goto_disasm_line_num = line_num; ui_ctx_menu_close(); @@ -9288,7 +9131,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ //- rjf: go from disasm -> src if(line_dasm2src_list->first != 0 && - df_icon_buttonf(DF_IconKind_Find, 0, "Go To Source").clicked) + ui_clicked(df_icon_buttonf(DF_IconKind_Find, 0, "Go To Source"))) { result.goto_src_line_num = line_num; ui_ctx_menu_close(); @@ -9306,7 +9149,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ ui_set_next_pref_width(ui_px(params->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); - margin_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable, str8_lit("margin_container")); + margin_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable*!!(params->flags & DF_CodeSliceFlag_Clickable), str8_lit("margin_container")); UI_Parent(margin_container_box) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) { U64 line_idx = 0; @@ -9319,7 +9162,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ DF_EntityList 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|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 & DF_CodeSliceFlag_Clickable)|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawActiveEffects, "line_margin_%I64x", line_num); UI_Parent(line_margin_box) { //- rjf: build margin thread ip ui @@ -9372,7 +9215,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ ui_set_next_text_alignment(UI_TextAlign_Center); UI_Key thread_box_key = ui_key_from_stringf(top_container_box->key, "###ip_%p", thread); UI_Box *thread_box = ui_build_box_from_key(UI_BoxFlag_DisableTextTrunc| - UI_BoxFlag_Clickable| + UI_BoxFlag_Clickable*!!(params->flags & DF_CodeSliceFlag_Clickable)| UI_BoxFlag_AnimatePosX| UI_BoxFlag_DrawText, thread_box_key); @@ -9417,13 +9260,13 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } // rjf: hover tooltips - if(thread_sig.hovering) + if(ui_hovering(thread_sig)) { df_entity_tooltips(thread); } // rjf: ip right-click menu - if(thread_sig.right_clicked) + if(ui_right_clicked(thread_sig)) { DF_Handle handle = df_handle_from_entity(thread); if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) @@ -9438,7 +9281,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } // rjf: double click => select - if(thread_sig.double_clicked) + if(ui_double_clicked(thread_sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(thread); @@ -9447,7 +9290,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } // rjf: drag start - if(thread_sig.dragging && !contains_2f32(thread_box->rect, ui_mouse())) + if(ui_dragging(thread_sig) && !contains_2f32(thread_box->rect, ui_mouse())) { DF_DragDropPayload payload = {0}; payload.key = thread_box->key; @@ -9498,7 +9341,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ UI_BoxFlag_DrawHotEffects| UI_BoxFlag_DrawBorder| UI_BoxFlag_AnimatePosX| - UI_BoxFlag_Clickable| + UI_BoxFlag_Clickable*!!(params->flags & DF_CodeSliceFlag_Clickable)| UI_BoxFlag_DisableTextTrunc, "%S##bp_%p", df_g_icon_kind_text_table[DF_IconKind_CircleFilled], @@ -9507,13 +9350,13 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ UI_Signal bp_sig = ui_signal_from_box(bp_box); // rjf: bp hovering - if(bp_sig.hovering) + if(ui_hovering(bp_sig)) { df_entity_tooltips(bp); } // rjf: click => remove breakpoint - if(bp_sig.clicked) + if(ui_clicked(bp_sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(bp); @@ -9522,7 +9365,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } // rjf: drag start - if(bp_sig.dragging && !contains_2f32(bp_box->rect, ui_mouse())) + if(ui_dragging(bp_sig) && !contains_2f32(bp_box->rect, ui_mouse())) { DF_DragDropPayload payload = {0}; payload.entity = df_handle_from_entity(bp); @@ -9530,7 +9373,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } // rjf: bp right-click menu - if(bp_sig.right_clicked) + if(ui_right_clicked(bp_sig)) { DF_Handle handle = df_handle_from_entity(bp); if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) @@ -9565,7 +9408,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ UI_BoxFlag_DrawActiveEffects| UI_BoxFlag_DrawHotEffects| UI_BoxFlag_DrawBorder| - UI_BoxFlag_Clickable| + UI_BoxFlag_Clickable*!!(params->flags & DF_CodeSliceFlag_Clickable)| UI_BoxFlag_AnimatePosX| UI_BoxFlag_DisableTextTrunc, "%S##watch_%p", @@ -9574,13 +9417,13 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ UI_Signal pin_sig = ui_signal_from_box(pin_box); // rjf: watch hovering - if(pin_sig.hovering) + if(ui_hovering(pin_sig)) { df_entity_tooltips(pin); } // rjf: click => remove pin - if(pin_sig.clicked) + if(ui_clicked(pin_sig)) { DF_CmdParams params = df_cmd_params_from_window(ws); params.entity = df_handle_from_entity(pin); @@ -9589,7 +9432,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } // rjf: drag start - if(pin_sig.dragging && !contains_2f32(pin_box->rect, ui_mouse())) + if(ui_dragging(pin_sig) && !contains_2f32(pin_box->rect, ui_mouse())) { DF_DragDropPayload payload = {0}; payload.entity = df_handle_from_entity(pin); @@ -9597,7 +9440,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } // rjf: watch right-click menu - if(pin_sig.right_clicked) + if(ui_right_clicked(pin_sig)) { DF_Handle handle = df_handle_from_entity(pin); if(ui_ctx_menu_is_open(ws->entity_ctx_menu_key) && df_handle_match(ws->entity_ctx_menu_entity, handle)) @@ -9613,7 +9456,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } } UI_Signal line_margin_sig = ui_signal_from_box(line_margin_box); - if(line_margin_sig.clicked) + if(ui_clicked(line_margin_sig)) { result.clicked_margin_line_num = line_num; } @@ -9629,7 +9472,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ { ui_set_next_hover_cursor(ctrlified ? OS_Cursor_HandPoint : OS_Cursor_IBar); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); - text_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable, str8_lit("text_container")); + text_container_box = ui_build_box_from_string(UI_BoxFlag_Clickable*!!(params->flags & DF_CodeSliceFlag_Clickable), str8_lit("text_container")); } ////////////////////////////// @@ -9665,6 +9508,49 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } } + ////////////////////////////// + //- rjf: build exception annotations + // + UI_Focus(UI_FocusKind_Off) + { + 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) + { + DF_EntityList threads = params->line_ips[line_idx]; + for(DF_EntityNode *n = threads.first; n != 0; n = n->next) + { + DF_Entity *thread = n->entity; + if(thread == stopper_thread && + (stop_event.cause == CTRL_EventCause_InterruptedByException || + stop_event.cause == CTRL_EventCause_InterruptedByTrap)) + { + DF_IconKind icon = DF_IconKind_WarningBig; + String8 explanation = df_stop_explanation_string_icon_from_ctrl_event(scratch.arena, &stop_event, &icon); + UI_Parent(line_extras_boxes[line_idx]) UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_px(params->line_height_px, 1.f)) + { + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder, "###exception_info"); + UI_Parent(box) + { + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) + UI_Font(df_font_from_slot(DF_FontSlot_Icons)) + UI_PrefWidth(ui_text_dim(10, 1)) + { + ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); + } + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) + UI_PrefWidth(ui_text_dim(10, 1)) + { + ui_label(explanation); + } + } + } + } + } + } + } + ////////////////////////////// //- rjf: build watch pin annotations // @@ -9688,13 +9574,16 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ if(!tg_key_match(tg_key_zero(), eval.type_key)) { DF_CfgTable cfg_table = {0}; - String8List eval_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, 10, params->font, params->font_size, params->font_size*60.f, 0, eval, 0, &cfg_table); + String8List eval_strings = df_single_line_eval_value_strings_from_eval(scratch.arena, DF_EvalVizStringFlag_ReadOnlyDisplayRules, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, 10, params->font, params->font_size, params->font_size*60.f, 0, eval, 0, &cfg_table); eval_string = str8_list_join(scratch.arena, &eval_strings, 0); } 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|UI_BoxFlag_DrawHotEffects|UI_BoxFlag_DrawBorder, pin_box_key); + UI_Box *pin_box = ui_build_box_from_key(UI_BoxFlag_AnimatePos| + UI_BoxFlag_Clickable*!!(params->flags & DF_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 = df_rgba_from_theme_color(DF_ThemeColor_WeakText); @@ -9709,13 +9598,13 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ UI_Flags(UI_BoxFlag_DisableTextTrunc) { UI_Signal sig = ui_buttonf("%S###pin_nub", df_g_icon_kind_text_table[DF_IconKind_Pin]); - if(sig.dragging && !contains_2f32(sig.box->rect, ui_mouse())) + if(ui_dragging(sig) && !contains_2f32(sig.box->rect, ui_mouse())) { DF_DragDropPayload payload = {0}; payload.entity = df_handle_from_entity(pin); df_drag_begin(&payload); } - if(sig.clicked || sig.right_clicked) + if(ui_clicked(sig) || ui_right_clicked(sig)) { ui_ctx_menu_open(ws->entity_ctx_menu_key, sig.box->key, v2f32(0, sig.box->rect.y1-sig.box->rect.y0)); ws->entity_ctx_menu_entity = df_handle_from_entity(pin); @@ -9778,6 +9667,28 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ result.mouse_pt = mouse_pt; } + ////////////////////////////// + //- rjf: mouse point -> mouse token range, mouse line range + // + TxtRng mouse_token_rng = txt_rng(mouse_pt, mouse_pt); + TxtRng mouse_line_rng = txt_rng(mouse_pt, mouse_pt); + if(contains_1s64(params->line_num_range, mouse_pt.line)) + { + TXT_TokenArray *line_tokens = ¶ms->line_tokens[mouse_pt.line-params->line_num_range.min]; + Rng1U64 line_range = params->line_ranges[mouse_pt.line-params->line_num_range.min]; + U64 mouse_pt_off = (mouse_pt.column-1) + line_range.min; + for(U64 line_token_idx = 0; line_token_idx < line_tokens->count; line_token_idx += 1) + { + TXT_Token *line_token = &line_tokens->v[line_token_idx]; + if(contains_1u64(line_token->range, mouse_pt_off)) + { + mouse_token_rng = txt_rng(txt_pt(mouse_pt.line, 1+line_token->range.min-line_range.min), txt_pt(mouse_pt.line, 1+line_token->range.max-line_range.min)); + break; + } + } + mouse_line_rng = txt_rng(txt_pt(mouse_pt.line, 1), txt_pt(mouse_pt.line, 1+line_range.max)); + } + ////////////////////////////// //- rjf: interact with margin box & text box // @@ -9785,8 +9696,19 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ UI_Signal text_container_sig = ui_signal_from_box(text_container_box); DF_Entity *line_drag_entity = &df_g_nil_entity; { + //- rjf: determine mouse drag range + TxtRng mouse_drag_rng = txt_rng(mouse_pt, mouse_pt); + if(text_container_sig.f & UI_SignalFlag_LeftTripleDragging) + { + mouse_drag_rng = mouse_line_rng; + } + else if(text_container_sig.f & UI_SignalFlag_LeftDoubleDragging) + { + mouse_drag_rng = mouse_token_rng; + } + //- rjf: clicking/dragging over the text container - if(!ctrlified && text_container_sig.dragging) + if(!ctrlified && ui_dragging(text_container_sig)) { if(mouse_pt.line == 0) { @@ -9800,16 +9722,24 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ mouse_pt.line = params->line_num_range.max + 2; } } - if(text_container_sig.pressed) + if(ui_pressed(text_container_sig)) { - *mark = mouse_pt; + *cursor = mouse_drag_rng.max; + *mark = mouse_drag_rng.min; + } + if(txt_pt_less_than(mouse_pt, *mark)) + { + *cursor = mouse_drag_rng.min; + } + else + { + *cursor = mouse_drag_rng.max; } - *cursor = mouse_pt; *preferred_column = cursor->column; } //- rjf: right-click => active context menu for line - if(text_container_sig.right_clicked) + if(ui_right_clicked(text_container_sig)) { S64 line_idx = mouse_pt.line-params->line_num_range.min; if(0 <= line_idx && line_idx < dim_1s64(params->line_num_range)) @@ -9823,7 +9753,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } //- rjf: hovering text container & ctrl+scroll -> change font size - if(text_container_sig.hovering) + if(ui_hovering(text_container_sig)) { for(OS_Event *event = ui_events()->first; event != 0; event = event->next) { @@ -9875,7 +9805,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ ////////////////////////////// //- rjf: mouse -> expression range info // - if(text_container_sig.hovering && contains_1s64(params->line_num_range, mouse_pt.line)) ProfScope("mouse -> expression range") + if(ui_hovering(text_container_sig) && contains_1s64(params->line_num_range, mouse_pt.line)) ProfScope("mouse -> expression range") { TxtRng selected_rng = txt_rng(*cursor, *mark); if(!txt_pt_match(*cursor, *mark) && cursor->line == mark->line && @@ -9893,7 +9823,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ { U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; String8 line_text = params->line_text[line_slice_idx]; - TXTI_TokenArray line_tokens = params->line_tokens[line_slice_idx]; + TXT_TokenArray line_tokens = params->line_tokens[line_slice_idx]; Rng1U64 line_range = params->line_ranges[line_slice_idx]; U64 mouse_pt_off = line_range.min + (mouse_pt.column-1); Rng1U64 expr_off_rng = txti_expr_range_from_line_off_range_string_tokens(mouse_pt_off, line_range, line_text, &line_tokens); @@ -9910,7 +9840,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ ////////////////////////////// //- rjf: mouse -> set global frontend hovered line info // - if(text_container_sig.hovering && contains_1s64(params->line_num_range, mouse_pt.line)) + if(ui_hovering(text_container_sig) && contains_1s64(params->line_num_range, mouse_pt.line)) { U64 line_slice_idx = mouse_pt.line-params->line_num_range.min; if(params->line_src2dasm[line_slice_idx].first != 0 && @@ -10091,9 +10021,15 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ { String8 line_string = params->line_text[line_idx]; Rng1U64 line_range = params->line_ranges[line_idx]; - TXTI_TokenArray *line_tokens = ¶ms->line_tokens[line_idx]; + TXT_TokenArray *line_tokens = ¶ms->line_tokens[line_idx]; ui_set_next_text_padding(-2); 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_background_color(line_bg_color); + ui_set_next_flags(UI_BoxFlag_DrawBackground); + } UI_Box *line_box = ui_build_box_from_key(UI_BoxFlag_DisableTextTrunc|UI_BoxFlag_DrawText|UI_BoxFlag_DisableIDString, line_key); D_Bucket *line_bucket = d_bucket_make(); d_push_bucket(line_bucket); @@ -10116,9 +10052,9 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } else { - TXTI_Token *line_tokens_first = line_tokens->v; - TXTI_Token *line_tokens_opl = line_tokens->v + line_tokens->count; - for(TXTI_Token *token = line_tokens_first; token < line_tokens_opl; token += 1) + 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}; @@ -10138,15 +10074,15 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // rjf: token -> token color Vec4F32 token_color = df_rgba_from_theme_color(DF_ThemeColor_CodeDefault); { - DF_ThemeColor new_color_kind = df_theme_color_from_txti_token_kind(token->kind); + DF_ThemeColor new_color_kind = df_theme_color_from_txt_token_kind(token->kind); F32 mix_t = 1.f; - if(token->kind == TXTI_TokenKind_Identifier) + if(token->kind == TXT_TokenKind_Identifier || token->kind == TXT_TokenKind_Keyword) { B32 mapped_special = 0; for(DF_EntityNode *n = params->relevant_binaries.first; n != 0; n = n->next) { DF_Entity *binary = n->entity; - if(!mapped_special) + if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { U64 voff = df_voff_from_binary_symbol_name(binary, token_string); if(voff != 0) @@ -10156,7 +10092,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ mix_t = selected_thread_module->alive_t; } } - if(!mapped_special) + if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { U64 type_num = df_type_num_from_binary_name(binary, token_string); if(type_num != 0) @@ -10166,7 +10102,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ mix_t = selected_thread_module->alive_t; } } - if(!mapped_special) + if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { U64 local_num = eval_num_from_string(parse_ctx->locals_map, token_string); if(local_num != 0) @@ -10176,6 +10112,26 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ mix_t = selected_thread_module->alive_t; } } + if(!mapped_special) + { + U64 reg_num = eval_num_from_string(parse_ctx->regs_map, token_string); + if(reg_num != 0) + { + mapped_special = 1; + new_color_kind = DF_ThemeColor_CodeRegister; + mix_t = selected_thread_module->alive_t; + } + } + if(!mapped_special) + { + U64 alias_num = eval_num_from_string(parse_ctx->reg_alias_map, token_string); + if(alias_num != 0) + { + mapped_special = 1; + new_color_kind = DF_ThemeColor_CodeRegister; + mix_t = selected_thread_module->alive_t; + } + } break; } } @@ -10396,6 +10352,183 @@ df_code_slicef(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF return sig; } +internal B32 +df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column) +{ + Temp scratch = scratch_begin(0, 0); + B32 change = 0; + UI_NavActionList *nav_actions = ui_nav_actions(); + for(UI_NavActionNode *n = nav_actions->first, *next = 0; n != 0; n = next) + { + next = n->next; + B32 taken = 0; + + String8 line = txt_string_from_info_data_line_num(info, data, cursor->line); + UI_NavTxtOp single_line_op = ui_nav_single_line_txt_op_from_action(scratch.arena, n->v, line, *cursor, *mark); + + //- rjf: invalid single-line op or endpoint units => try multiline + if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint || single_line_op.flags & UI_NavTxtOpFlag_Invalid) + { + U64 line_count = info->lines_count; + String8 prev_line = txt_string_from_info_data_line_num(info, data, cursor->line-1); + String8 next_line = txt_string_from_info_data_line_num(info, data, cursor->line+1); + Vec2S32 delta = n->v.delta; + + //- rjf: wrap lines right + if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x > 0 && cursor->column == line.size+1 && cursor->line+1 <= line_count) + { + cursor->line += 1; + cursor->column = 1; + *preferred_column = 1; + change = 1; + taken = 1; + } + + //- rjf: wrap lines left + if(n->v.delta_unit != UI_NavDeltaUnit_EndPoint && delta.x < 0 && cursor->column == 1 && cursor->line-1 >= 1) + { + cursor->line -= 1; + cursor->column = prev_line.size+1; + *preferred_column = prev_line.size+1; + change = 1; + taken = 1; + } + + //- rjf: movement down (plain) + if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y > 0 && cursor->line+1 <= line_count) + { + cursor->line += 1; + cursor->column = Min(*preferred_column, next_line.size+1); + change = 1; + taken = 1; + } + + //- rjf: movement up (plain) + if(n->v.delta_unit == UI_NavDeltaUnit_Element && delta.y < 0 && cursor->line-1 >= 1) + { + cursor->line -= 1; + cursor->column = Min(*preferred_column, prev_line.size+1); + change = 1; + taken = 1; + } + + //- rjf: movement down (chunk) + if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y > 0 && cursor->line+1 <= line_count) + { + for(S64 line_num = cursor->line+1; line_num <= line_count; line_num += 1) + { + String8 line = txt_string_from_info_data_line_num(info, data, line_num); + U64 line_size = line.size; + if(line_size == 0) + { + cursor->line = line_num; + cursor->column = 1; + break; + } + else if(line_num == line_count) + { + cursor->line = line_num; + cursor->column = line_size+1; + } + } + change = 1; + taken = 1; + } + + //- rjf: movement up (chunk) + if(n->v.delta_unit == UI_NavDeltaUnit_Chunk && delta.y < 0 && cursor->line-1 >= 1) + { + for(S64 line_num = cursor->line-1; line_num > 0; line_num -= 1) + { + String8 line = txt_string_from_info_data_line_num(info, data, line_num); + U64 line_size = line.size; + if(line_size == 0) + { + cursor->line = line_num; + cursor->column = 1; + break; + } + else if(line_num == 1) + { + cursor->line = line_num; + cursor->column = 1; + } + } + change = 1; + taken = 1; + } + + //- rjf: movement down (page) + if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y > 0) + { + cursor->line += line_count_per_page; + cursor->column = 1; + cursor->line = Clamp(1, cursor->line, line_count); + change = 1; + taken = 1; + } + + //- rjf: movement up (page) + if(n->v.delta_unit == UI_NavDeltaUnit_Whole && delta.y < 0) + { + cursor->line -= line_count_per_page; + cursor->column = 1; + cursor->line = Clamp(1, cursor->line, line_count); + change = 1; + taken = 1; + } + + //- rjf: movement to endpoint (+) + if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y > 0 || delta.x > 0)) + { + *cursor = txt_pt(line_count, info->lines_count ? dim_1u64(info->lines_ranges[info->lines_count-1])+1 : 1); + change = 1; + taken = 1; + } + + //- rjf: movement to endpoint (-) + if(n->v.delta_unit == UI_NavDeltaUnit_EndPoint && (delta.y < 0 || delta.x < 0)) + { + *cursor = txt_pt(1, 1); + change = 1; + taken = 1; + } + + //- rjf: stick mark to cursor, when we don't want to keep it in the same spot + if(!(n->v.flags & UI_NavActionFlag_KeepMark)) + { + *mark = *cursor; + } + } + + //- rjf: valid single-line op => do single-line op + else + { + *cursor = single_line_op.cursor; + *mark = single_line_op.mark; + *preferred_column = cursor->column; + change = 1; + taken = 1; + } + + //- rjf: copy + if(n->v.flags & UI_NavActionFlag_Copy) + { + String8 text = txt_string_from_info_data_txt_rng(info, data, txt_rng(*cursor, *mark)); + os_set_clipboard_text(text); + } + + //- rjf: consume + if(taken) + { + ui_nav_eat_action_node(nav_actions, n); + } + } + + scratch_end(scratch); + return change; +} + internal B32 df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column) { @@ -10574,16 +10707,6 @@ df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, return change; } -internal B32 -df_do_dasm_controls(DASM_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column) -{ - Temp scratch = scratch_begin(0, 0); - B32 change = 0; - UI_NavActionList *nav_actions = ui_nav_actions(); - scratch_end(scratch); - return change; -} - //////////////////////////////// //~ rjf: UI Widgets: Fancy Labels @@ -10611,7 +10734,7 @@ df_help_label(String8 string) UI_Parent(box) { UI_PrefWidth(ui_pct(1, 0)) ui_label(string); - if(sig.hovering) UI_PrefWidth(ui_em(2.25f, 1)) + if(ui_hovering(sig)) UI_PrefWidth(ui_em(2.25f, 1)) { result = 1; ui_set_next_font(ui_icon_font()); @@ -10632,12 +10755,12 @@ df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s { Temp scratch = scratch_begin(&arena, 1); D_FancyStringList fancy_strings = {0}; - TXTI_TokenArray tokens = txti_token_array_from_string__cpp(scratch.arena, 0, string); - TXTI_Token *tokens_opl = tokens.v+tokens.count; + 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; - for(TXTI_Token *token = tokens.v; token < tokens_opl; token += 1) + for(TXT_Token *token = tokens.v; token < tokens_opl; token += 1) { - DF_ThemeColor token_color = df_theme_color_from_txti_token_kind(token->kind); + DF_ThemeColor token_color = df_theme_color_from_txt_token_kind(token->kind); Vec4F32 token_color_rgba = df_rgba_from_theme_color(token_color); token_color_rgba.w *= alpha; String8 token_string = str8_substr(string, token->range); @@ -10657,7 +10780,7 @@ df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s }; d_fancy_string_list_push(arena, &fancy_strings, &fancy_string); }break; - case TXTI_TokenKind_Identifier: + case TXT_TokenKind_Identifier: { D_FancyString fancy_string = { @@ -10668,7 +10791,7 @@ df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s }; d_fancy_string_list_push(arena, &fancy_strings, &fancy_string); }break; - case TXTI_TokenKind_Numeric: + case TXT_TokenKind_Numeric: { Vec4F32 token_color_rgba_alt = token_color_rgba; token_color_rgba_alt.x *= 0.7f; @@ -10838,7 +10961,7 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx UI_Focus(UI_FocusKind_Off) { UI_Signal expander_sig = ui_expanderf(*expanded_out, "expander"); - if(expander_sig.pressed) + if(ui_pressed(expander_sig)) { *expanded_out ^= 1; } @@ -10892,13 +11015,16 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx //- rjf: get signal UI_Signal sig = ui_signal_from_box(box); - sig.commit = sig.commit || commit; + if(commit) + { + sig.f |= UI_SignalFlag_Commit; + } //- rjf: do start/end editing interaction B32 focus_started = 0; if(!is_focus_active) { - B32 start_editing_via_sig = (sig.double_clicked || sig.keyboard_clicked); + B32 start_editing_via_sig = (ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed); B32 start_editing_via_typing = 0; if(is_focus_hot) { @@ -10929,10 +11055,10 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx focus_started = 1; } } - else if(is_focus_active && sig.keyboard_clicked) + else if(is_focus_active && sig.f&UI_SignalFlag_KeyboardPressed) { ui_set_auto_focus_active_key(ui_key_zero()); - sig.commit = 1; + sig.f |= UI_SignalFlag_Commit; } //- rjf: take navigation actions for editing @@ -11077,15 +11203,15 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, FuzzyMatchRangeList *matches, Tx } //- rjf: click+drag - if(is_focus_active && sig.dragging) + if(is_focus_active && ui_dragging(sig)) { - if(sig.pressed) + if(ui_pressed(sig)) { *mark = mouse_pt; } *cursor = mouse_pt; } - if(!is_focus_active && is_focus_active_disabled && sig.pressed) + if(!is_focus_active && is_focus_active_disabled && ui_pressed(sig)) { *cursor = *mark = mouse_pt; } diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index c55cf7d2..0809b846 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -47,71 +47,6 @@ struct DF_StringBindingPair DF_Binding binding; }; -//////////////////////////////// -//~ rjf: Text Searching Types - -typedef struct DF_TextSearchMatch DF_TextSearchMatch; -struct DF_TextSearchMatch -{ - TxtPt pt; -}; - -typedef struct DF_TextSearchMatchChunkNode DF_TextSearchMatchChunkNode; -struct DF_TextSearchMatchChunkNode -{ - DF_TextSearchMatchChunkNode *next; - DF_TextSearchMatch *v; - U64 count; - U64 cap; -}; - -typedef struct DF_TextSearchMatchChunkList DF_TextSearchMatchChunkList; -struct DF_TextSearchMatchChunkList -{ - DF_TextSearchMatchChunkNode *first; - DF_TextSearchMatchChunkNode *last; - U64 node_count; - U64 total_count; -}; - -typedef struct DF_TextSearchMatchArray DF_TextSearchMatchArray; -struct DF_TextSearchMatchArray -{ - DF_TextSearchMatch *v; - U64 count; -}; - -typedef struct DF_TextSearchCacheNode DF_TextSearchCacheNode; -struct DF_TextSearchCacheNode -{ - // rjf: links - DF_TextSearchCacheNode *next; - DF_TextSearchCacheNode *prev; - - // rjf: allocation - Arena *arena; - - // rjf: search parameters - U128 hash; - String8 needle; - DF_TextSliceFlags flags; - TxtPt start_pt; - - // rjf: search results - B32 good; - DF_TextSearchMatchChunkList search_matches; - - // rjf: last time touched - U64 last_time_touched_us; -}; - -typedef struct DF_TextSearchCacheSlot DF_TextSearchCacheSlot; -struct DF_TextSearchCacheSlot -{ - DF_TextSearchCacheNode *first; - DF_TextSearchCacheNode *last; -}; - //////////////////////////////// //~ rjf: Key Map Types @@ -178,7 +113,7 @@ struct DF_ViewSpecInfo DF_ViewSpecFlags flags; String8 name; String8 display_string; - DF_NameKind name_kind; + enum DF_NameKind name_kind; DF_IconKind icon_kind; DF_ViewSetupFunctionType *setup_hook; DF_ViewStringFromStateFunctionType *string_from_state_hook; @@ -346,6 +281,7 @@ enum DF_GfxViewRuleSpecInfoFlag_LineStringize = (1<<1), DF_GfxViewRuleSpecInfoFlag_RowUI = (1<<2), DF_GfxViewRuleSpecInfoFlag_BlockUI = (1<<3), + DF_GfxViewRuleSpecInfoFlag_WholeUI = (1<<4), }; #define DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_SIG(name) void name(void) @@ -364,10 +300,15 @@ enum #define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name) df_gfx_view_rule_block_ui__##name #define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name)) +#define DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_SIG(name) void name(struct DF_Window *ws, struct DF_Panel *panel, struct DF_View *view, Rng2F32 rect, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg) +#define DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_NAME(name) df_gfx_view_rule_whole_ui__##name +#define DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_NAME(name)) + typedef DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_SIG(DF_GfxViewRuleVizRowProdHookFunctionType); typedef DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_SIG(DF_GfxViewRuleLineStringizeHookFunctionType); typedef DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(DF_GfxViewRuleRowUIFunctionType); typedef DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(DF_GfxViewRuleBlockUIFunctionType); +typedef DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_SIG(DF_GfxViewRuleWholeUIFunctionType); typedef struct DF_GfxViewRuleSpecInfo DF_GfxViewRuleSpecInfo; struct DF_GfxViewRuleSpecInfo @@ -378,6 +319,7 @@ struct DF_GfxViewRuleSpecInfo DF_GfxViewRuleLineStringizeHookFunctionType *line_stringize; DF_GfxViewRuleRowUIFunctionType *row_ui; DF_GfxViewRuleBlockUIFunctionType *block_ui; + DF_GfxViewRuleWholeUIFunctionType *whole_ui; }; typedef struct DF_GfxViewRuleSpecInfoArray DF_GfxViewRuleSpecInfoArray; @@ -441,8 +383,9 @@ enum typedef U32 DF_CodeSliceFlags; enum { - DF_CodeSliceFlag_Margin = (1<<0), - DF_CodeSliceFlag_LineNums = (1<<1), + DF_CodeSliceFlag_Clickable = (1<<0), + DF_CodeSliceFlag_Margin = (1<<1), + DF_CodeSliceFlag_LineNums = (1<<2), }; typedef struct DF_CodeSliceParams DF_CodeSliceParams; @@ -453,7 +396,7 @@ struct DF_CodeSliceParams Rng1S64 line_num_range; String8 *line_text; Rng1U64 *line_ranges; - TXTI_TokenArray *line_tokens; + TXT_TokenArray *line_tokens; DF_EntityList *line_bps; DF_EntityList *line_ips; DF_EntityList *line_pins; @@ -961,7 +904,7 @@ internal void df_window_update_and_render(Arena *arena, OS_EventList *events, DF //~ rjf: Eval Viz internal String8 df_eval_escaped_from_raw_string(Arena *arena, String8 raw); -internal String8List df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table); +internal String8List df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table); internal DF_EvalVizWindowedRowList df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks); //////////////////////////////// @@ -985,17 +928,6 @@ internal void df_set_autocomp_lister_query(DF_Window *ws, UI_Key root_key, DF_Ct internal void df_set_search_string(String8 string); internal String8 df_push_search_string(Arena *arena); -//////////////////////////////// -//~ rjf: Text Searching - -internal void df_text_search_match_chunk_list_push(Arena *arena, DF_TextSearchMatchChunkList *list, U64 cap, DF_TextSearchMatch *match); -internal DF_TextSearchMatchArray df_text_search_match_array_from_chunk_list(Arena *arena, DF_TextSearchMatchChunkList *chunks); -internal U64 df_text_search_little_hash_from_hash(U128 hash); -internal void df_text_search_thread_entry_point(void *p); -internal int df_text_search_match_array_qsort_compare(TxtPt *a, TxtPt *b); -internal void df_text_search_match_array_sort_in_place(DF_TextSearchMatchArray *array); -internal DF_TextSearchMatch df_text_search_match_array_find_nearest__linear_scan(DF_TextSearchMatchArray *array, TxtPt pt, Side side); - //////////////////////////////// //~ rjf: Colors, Fonts, Config @@ -1010,7 +942,7 @@ internal DF_CmdSpecList df_cmd_spec_list_from_event_flags(Arena *arena, OS_Event //- rjf: colors internal Vec4F32 df_rgba_from_theme_color(DF_ThemeColor color); -internal DF_ThemeColor df_theme_color_from_txti_token_kind(TXTI_TokenKind kind); +internal DF_ThemeColor df_theme_color_from_txt_token_kind(TXT_TokenKind kind); //- rjf: fonts/sizes internal F_Tag df_font_from_slot(DF_FontSlot slot); @@ -1019,6 +951,12 @@ internal F32 df_font_size_from_slot(DF_Window *ws, DF_FontSlot slot); //- rjf: config serialization internal String8List df_cfg_strings_from_gfx(Arena *arena, String8 root_path, DF_CfgSrc source); +//////////////////////////////// +//~ rjf: Process Control Info Stringification + +internal String8 df_string_from_exception_code(U32 code); +internal String8 df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, DF_IconKind *icon_out); + //////////////////////////////// //~ rjf: UI Widgets: Fancy Buttons @@ -1040,8 +978,8 @@ internal UI_BOX_CUSTOM_DRAW(df_bp_box_draw_extensions); internal DF_CodeSliceSignal df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, String8 string); internal DF_CodeSliceSignal df_code_slicef(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *preferred_column, char *fmt, ...); +internal B32 df_do_txt_controls(TXT_TextInfo *info, String8 data, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); internal B32 df_do_txti_controls(TXTI_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); -internal B32 df_do_dasm_controls(DASM_Handle handle, U64 line_count_per_page, TxtPt *cursor, TxtPt *mark, S64 *preferred_column); //////////////////////////////// //~ rjf: UI Widgets: Fancy Labels diff --git a/src/df/gfx/df_gfx.mdesk b/src/df/gfx/df_gfx.mdesk index 26233177..4fbcbf72 100644 --- a/src/df/gfx/df_gfx.mdesk +++ b/src/df/gfx/df_gfx.mdesk @@ -177,6 +177,14 @@ DF_BindingVersionRemapTable: //////////////////////////////// //~ rjf: Gfx Layer View Kinds +@table(name) +DF_NameKindTable: +{ + {Null} + {EntityName} + {EntityKindName} +} + @table(name, name_lower, display_string, name_kind, icon, parameterized_by_entity, can_serialize, can_serialize_entity_path, can_filter, filter_is_code, typing_automatically_filters, inc_in_docs, docs_desc) DF_GfxViewTable: { @@ -196,6 +204,7 @@ DF_GfxViewTable: { PendingEntity "pending_entity" "Pending Entity" EntityName FileOutline 1 0 0 0 0 0 0 "" } { Code "code" "Code" EntityName FileOutline 1 1 1 0 0 0 0 "" } { Disassembly "disassembly" "Disassembly" Null Glasses 0 1 0 0 0 0 1 "Displays disassembled instructions in a textual form from the selected thread's containing process virtual address space." } + { EvalViewer "eval_viewer" "Evaluation Viewer" Null Binoculars 0 1 0 0 0 0 0 "." } { Watch "watch" "Watch" Null Binoculars 0 1 0 1 1 1 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" Null Binoculars 0 1 0 1 1 1 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" Null Binoculars 0 1 0 1 1 1 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." } @@ -231,23 +240,23 @@ DF_CmdParamSlot2ViewSpecMap: // // NOTE(rjf): see @view_rule_info -@table(string vr ls ru bu) +@table(string vr ls ru bu wu) DF_GfxViewRuleTable: { - {"array" - - - -} - {"list" x - - -} - {"dec" - x - -} - {"bin" - x - -} - {"oct" - x - -} - {"hex" - x - -} - {"only" x x - -} - {"omit" x x - -} - {"no_addr" - x - -} - {"rgba" - - x x} - {"text" - - - x} - {"disasm" - - - x} - {"bitmap" - - x x} - {"geo" - - x x} + {"array" - - - - - } + {"list" x - - - - } + {"dec" - x - - - } + {"bin" - x - - - } + {"oct" - x - - - } + {"hex" - x - - - } + {"only" x x - - - } + {"omit" x x - - - } + {"no_addr" - x - - - } + {"rgba" - - x x - } + {"text" - - - x - } + {"disasm" - - - x - } + {"bitmap" - - x x x } + {"geo" - - x x - } } //////////////////////////////// @@ -265,6 +274,7 @@ DF_ThemeTable: {CodeFunction "Code (Function)" code_function } {CodeType "Code (Type)" code_type } {CodeLocal "Code (Local)" code_local } + {CodeRegister "Code (Register)" code_register } {CodeKeyword "Code (Keyword)" code_keyword } {CodeSymbol "Code (Symbol)" code_symbol } {CodeNumeric "Code (Numeric)" code_numeric } @@ -349,6 +359,7 @@ DF_ThemePresetColorTable: (code_function 0x7fcc99ff 0x2a7a45ff 0xdcdcaaff 0x74531fff 0x1c7dd1ff 0xc39d36ff 0xcc5735ff 0x7fcc99ff 0x49b2ffff ) (code_type 0x66b2e5ff 0x2c688fff 0x4ec9b0ff 0x2b91afff 0x1c7dd1ff 0x66b2e5ff 0xd8a51dff 0x66b2e5ff 0x49b2ffff ) (code_local 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff 0xfe9548ff ) + (code_register 0xd45d90ff 0xd45d90ff 0xd45d90ff 0xd45d90ff 0xd45d90ff 0xd45d90ff 0xd45d90ff 0xd45d90ff 0xd45d90ff ) (code_keyword 0xf7bf5eff 0xa47729ff 0x569cd6ff 0x0000ffff 0x63980fff 0xc39d36ff 0xac7b0bff 0xd08f20ff 0xff0000ff ) (code_symbol 0x994c32ff 0x6c2d18ff 0xb4b4b4ff 0x000000ff 0x839496ff 0x2e5256ff 0x994c32ff 0x994c32ff 0xffffffff ) (code_numeric 0x4ce54cff 0x2c7d2cff 0xb5cea8ff 0x000000ff 0xcb4b20ff 0x657b83ff 0x6b8e23ff 0x50ff30ff 0x2cff50ff ) @@ -400,149 +411,131 @@ DF_ThemePresetColorTable: //- rjf: enums -@table_gen_enum -DF_GfxViewKind: +@enum DF_NameKind: { - @expand(DF_GfxViewTable a) - `DF_GfxViewKind_$(a.name),` - `DF_GfxViewKind_COUNT`; + @expand(DF_NameKindTable, a) `$(a.name)`, + COUNT, } -@table_gen_enum -DF_ThemeColor: +@enum DF_GfxViewKind: { - @expand(DF_ThemeTable, a) - `DF_ThemeColor_$(a.name),`; - `DF_ThemeColor_COUNT`; + @expand(DF_GfxViewTable a) `$(a.name)`, + COUNT, } -@table_gen_enum -DF_ThemePreset: +@enum DF_ThemeColor: { - @expand(DF_ThemePresetTable a) - `DF_ThemePreset_$(a.name),`; - `DF_ThemePreset_COUNT`; + @expand(DF_ThemeTable a) `$(a.name)`, + COUNT, +} + +@enum DF_ThemePreset: +{ + @expand(DF_ThemePresetTable a) `$(a.name)`, + COUNT, } //- rjf: theme preset color tables -@table_gen_data(type: String8, fallback: `{0}`) -df_g_theme_preset_display_string_table: +@data(String8) df_g_theme_preset_display_string_table: { - @expand(DF_ThemePresetTable a) `str8_lit_comp("$(a.display_string)"),`; + @expand(DF_ThemePresetTable a) `str8_lit_comp("$(a.display_string)")`, } -@table_gen_data(type: String8, fallback: `{0}`) -df_g_theme_preset_code_string_table: +@data(String8) df_g_theme_preset_code_string_table: { - @expand(DF_ThemePresetTable a) `str8_lit_comp("$(a.name_lower)"),`; + @expand(DF_ThemePresetTable a) `str8_lit_comp("$(a.name_lower)")`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__default_dark: +@data(Vec4F32) df_g_theme_preset_colors__default_dark: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_dark)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_dark))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__default_light: +@data(Vec4F32) df_g_theme_preset_colors__default_light: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_light)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.default_light))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__vs_dark: +@data(Vec4F32) df_g_theme_preset_colors__vs_dark: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_dark)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_dark))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__vs_light: +@data(Vec4F32) df_g_theme_preset_colors__vs_light: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_light)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.vs_light))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__solarized_dark: +@data(Vec4F32) df_g_theme_preset_colors__solarized_dark: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_dark)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_dark))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__solarized_light: +@data(Vec4F32) df_g_theme_preset_colors__solarized_light: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_light)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.solarized_light))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__handmade_hero: +@data(Vec4F32) df_g_theme_preset_colors__handmade_hero: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.handmade_hero)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.handmade_hero))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__four_coder: +@data(Vec4F32) df_g_theme_preset_colors__four_coder: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.four_coder)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.four_coder))`, } -@table_gen_data(type: Vec4F32, fallback: `{1, 0, 1, 1}`) -df_g_theme_preset_colors__far_manager: +@data(Vec4F32) df_g_theme_preset_colors__far_manager: { - @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.far_manager)),`; + @expand(DF_ThemePresetColorTable a) `rgba_from_u32_lit_comp($(a.far_manager))`; } -@table_gen_data(type: `Vec4F32 *`, fallback: `0`) -df_g_theme_preset_colors_table: +@data(`Vec4F32*`) df_g_theme_preset_colors_table: { - @expand(DF_ThemePresetTable a) `df_g_theme_preset_colors__$(a.name_lower),`; + @expand(DF_ThemePresetTable a) `df_g_theme_preset_colors__$(a.name_lower)`, } //- rjf: cmd param slot -> view spec tables -@table_gen_data(type: DF_CmdParamSlot, fallback:`DF_CmdParamSlot_Null`) -df_g_cmd_param_slot_2_view_spec_src_map: +@data(DF_CmdParamSlot) df_g_cmd_param_slot_2_view_spec_src_map: { - @expand(DF_CmdParamSlot2ViewSpecMap a) `DF_CmdParamSlot_$(a.slot),` + @expand(DF_CmdParamSlot2ViewSpecMap a) `DF_CmdParamSlot_$(a.slot)` } -@table_gen_data(type: String8, fallback:`{0}`) -df_g_cmd_param_slot_2_view_spec_dst_map: +@data(String8) df_g_cmd_param_slot_2_view_spec_dst_map: { - @expand(DF_CmdParamSlot2ViewSpecMap a) `str8_lit_comp("$(a.view_spec)"),` + @expand(DF_CmdParamSlot2ViewSpecMap a) `str8_lit_comp("$(a.view_spec)")` } -@table_gen_data(type: String8, fallback:`{0}`) -df_g_cmd_param_slot_2_view_spec_cmd_map: +@data(String8) df_g_cmd_param_slot_2_view_spec_cmd_map: { - @expand(DF_CmdParamSlot2ViewSpecMap a) `str8_lit_comp("$(a.opt_cmd_spec)"),` + @expand(DF_CmdParamSlot2ViewSpecMap a) `str8_lit_comp("$(a.opt_cmd_spec)")` } //- rjf: default bindings table -@table_gen_data(type: DF_StringBindingPair, fallback: `{0}`) -df_g_default_binding_table: +@data(DF_StringBindingPair) df_g_default_binding_table: { - @expand(DF_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_EventFlag_Ctrl`) $(a.shift != 0 -> `|OS_EventFlag_Shift`) $(a.alt != 0 -> `|OS_EventFlag_Alt`)}},```; + @expand(DF_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_EventFlag_Ctrl`) $(a.shift != 0 -> `|OS_EventFlag_Shift`) $(a.alt != 0 -> `|OS_EventFlag_Alt`)}}```; } //- rjf: binding version remap tables -@table_gen_data(type: String8, fallback: `{0}`) -df_g_binding_version_remap_old_name_table: +@data(String8) df_g_binding_version_remap_old_name_table: { - @expand(DF_BindingVersionRemapTable a) `str8_lit_comp("$(a.old_name)"),` + @expand(DF_BindingVersionRemapTable a) `str8_lit_comp("$(a.old_name)")` } -@table_gen_data(type: String8, fallback: `{0}`) -df_g_binding_version_remap_new_name_table: +@data(String8) df_g_binding_version_remap_new_name_table: { - @expand(DF_BindingVersionRemapTable a) `str8_lit_comp("$(a.new_name)"),` + @expand(DF_BindingVersionRemapTable a) `str8_lit_comp("$(a.new_name)")` } //- rjf: view hook forward declares -@table_gen +@gen { @expand(DF_GfxViewTable a) `DF_VIEW_SETUP_FUNCTION_DEF($(a.name));`; @expand(DF_GfxViewTable a) `DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF($(a.name));`; @@ -552,7 +545,7 @@ df_g_binding_version_remap_new_name_table: //- rjf: gfx view rule function forward declares -@table_gen +@gen { ``; @expand(DF_GfxViewRuleTable a) @@ -563,37 +556,35 @@ df_g_binding_version_remap_new_name_table: `$(a.ru == "x" -> "DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(" .. a.name_lower .. ");")`; @expand(DF_GfxViewRuleTable a) `$(a.bu == "x" -> "DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(" .. a.name_lower .. ");")`; + @expand(DF_GfxViewRuleTable a) + `$(a.wu == "x" -> "DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_DEF(" .. a.name_lower .. ");")`; } //- rjf: gfx view rule tables -@table_gen_data(type: DF_GfxViewRuleSpecInfo, fallback: `{0}`) @c_file -df_g_gfx_view_rule_spec_info_table: +@data(DF_GfxViewRuleSpecInfo) @c_file df_g_gfx_view_rule_spec_info_table: { @expand(DF_GfxViewRuleTable a) - ```{ str8_lit_comp("$(a.string)"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*$(a.vr == "x"))|(DF_GfxViewRuleSpecInfoFlag_LineStringize*$(a.ls == "x"))|(DF_GfxViewRuleSpecInfoFlag_RowUI*$(a.ru == "x"))|(DF_GfxViewRuleSpecInfoFlag_BlockUI*$(a.bu == "x")), $(a.vr == "x" -> "DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vr != "x" -> 0), $(a.ls == "x" -> "DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME("..a.name_lower..")") $(a.ls != "x" -> 0), $(a.ru == "x" -> "DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME("..a.name_lower..")") $(a.ru != "x" -> 0), $(a.bu == "x" -> "DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME("..a.name_lower..")") $(a.bu != "x" -> 0), },```; + ```{ str8_lit_comp("$(a.string)"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*$(a.vr == "x"))|(DF_GfxViewRuleSpecInfoFlag_LineStringize*$(a.ls == "x"))|(DF_GfxViewRuleSpecInfoFlag_RowUI*$(a.ru == "x"))|(DF_GfxViewRuleSpecInfoFlag_BlockUI*$(a.bu == "x")), $(a.vr == "x" -> "DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME("..a.name_lower..")") $(a.vr != "x" -> 0), $(a.ls == "x" -> "DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME("..a.name_lower..")") $(a.ls != "x" -> 0), $(a.ru == "x" -> "DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME("..a.name_lower..")") $(a.ru != "x" -> 0), $(a.bu == "x" -> "DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME("..a.name_lower..")") $(a.bu != "x" -> 0), $(a.wu == "x" -> "DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_NAME("..a.name_lower..")") $(a.wu != "x" -> 0) }```; } //- rjf: default view spec info table -@table_gen_data(type: DF_ViewSpecInfo, fallback: `{0}`) -df_g_gfx_view_kind_spec_info_table: +@data(DF_ViewSpecInfo) df_g_gfx_view_kind_spec_info_table: { - @expand(DF_GfxViewTable a) ```{(0|$(a.parameterized_by_entity)*DF_ViewSpecFlag_ParameterizedByEntity|$(a.can_serialize)*DF_ViewSpecFlag_CanSerialize|$(a.can_serialize_entity_path)*DF_ViewSpecFlag_CanSerializeEntityPath|$(a.can_filter)*DF_ViewSpecFlag_CanFilter|$(a.filter_is_code)*DF_ViewSpecFlag_FilterIsCode|$(a.typing_automatically_filters)*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("$(a.name_lower)"), str8_lit_comp("$(a.display_string)"), DF_NameKind_$(a.name_kind), DF_IconKind_$(a.icon), DF_VIEW_SETUP_FUNCTION_NAME($(a.name)), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME($(a.name)), DF_VIEW_CMD_FUNCTION_NAME($(a.name)), DF_VIEW_UI_FUNCTION_NAME($(a.name))},```; + @expand(DF_GfxViewTable a) ```{(0|$(a.parameterized_by_entity)*DF_ViewSpecFlag_ParameterizedByEntity|$(a.can_serialize)*DF_ViewSpecFlag_CanSerialize|$(a.can_serialize_entity_path)*DF_ViewSpecFlag_CanSerializeEntityPath|$(a.can_filter)*DF_ViewSpecFlag_CanFilter|$(a.filter_is_code)*DF_ViewSpecFlag_FilterIsCode|$(a.typing_automatically_filters)*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("$(a.name_lower)"), str8_lit_comp("$(a.display_string)"), DF_NameKind_$(a.name_kind), DF_IconKind_$(a.icon), DF_VIEW_SETUP_FUNCTION_NAME($(a.name)), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME($(a.name)), DF_VIEW_CMD_FUNCTION_NAME($(a.name)), DF_VIEW_UI_FUNCTION_NAME($(a.name))}```; } //- rjf: theme color tables -@table_gen_data(type: String8, fallback: `str8_lit_comp("")`) -df_g_theme_color_display_string_table: +@data(String8) df_g_theme_color_display_string_table: { - @expand(DF_ThemeTable a) `str8_lit_comp("$(a.display_name)"),`; + @expand(DF_ThemeTable a) `str8_lit_comp("$(a.display_name)")` } -@table_gen_data(type: String8, fallback: `str8_lit_comp("")`) -df_g_theme_color_cfg_string_table: +@data(String8) df_g_theme_color_cfg_string_table: { - @expand(DF_ThemeTable a) `str8_lit_comp("$(a.name_lower)"),`; + @expand(DF_ThemeTable a) `str8_lit_comp("$(a.name_lower)")` } //////////////////////////////// diff --git a/src/df/gfx/df_view_rule_hooks.c b/src/df/gfx/df_view_rule_hooks.c index 985cd4b8..4d7bb5b4 100644 --- a/src/df/gfx/df_view_rule_hooks.c +++ b/src/df/gfx/df_view_rule_hooks.c @@ -5,7 +5,7 @@ //~ rjf: Helpers internal Vec4F32 -df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_Entity *process) +df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_Entity *process) { Vec4F32 rgba = {0}; Temp scratch = scratch_begin(0, 0); @@ -27,14 +27,14 @@ df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed case TG_Kind_Array: if(eval.mode == EVAL_EvalMode_Addr) { - U64 array_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 array_total_size = tg_byte_size_from_graph_rdi_key(graph, raddbg, type_key); U64 array_total_size_capped = ClampTop(array_total_size, 64); Rng1U64 array_memory_vaddr_rng = r1u64(eval.offset, eval.offset + array_total_size_capped); CTRL_ProcessMemorySlice array_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, array_memory_vaddr_rng, 0); String8 array_memory = array_slice.data; - TG_Key element_type_key = tg_unwrapped_direct_from_graph_raddbg_key(graph, raddbg, type_key); + TG_Key element_type_key = tg_unwrapped_direct_from_graph_rdi_key(graph, raddbg, type_key); TG_Kind element_type_kind = tg_kind_from_key(element_type_key); - U64 element_type_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, element_type_key); + U64 element_type_size = tg_byte_size_from_graph_rdi_key(graph, raddbg, element_type_key); for(U64 element_idx = 0; element_idx < 4; element_idx += 1) { U64 offset = element_idx*element_type_size; @@ -64,12 +64,12 @@ df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed case TG_Kind_Union: if(eval.mode == EVAL_EvalMode_Addr) { - U64 struct_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 struct_total_size = tg_byte_size_from_graph_rdi_key(graph, raddbg, type_key); U64 struct_total_size_capped = ClampTop(struct_total_size, 64); Rng1U64 struct_memory_vaddr_rng = r1u64(eval.offset, eval.offset + struct_total_size_capped); CTRL_ProcessMemorySlice struct_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, struct_memory_vaddr_rng, 0); String8 struct_memory = struct_slice.data; - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, raddbg, type_key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, raddbg, type_key); for(U64 element_idx = 0, member_idx = 0; element_idx < 4 && member_idx < type->count; member_idx += 1) @@ -102,7 +102,7 @@ df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed } internal void -df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba) +df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba) { TG_Key type_key = eval.type_key; TG_Kind type_kind = tg_kind_from_key(type_key); @@ -126,13 +126,13 @@ df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RADDBG_Parse case TG_Kind_Array: if(eval.mode == EVAL_EvalMode_Addr) { - U64 array_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 array_total_size = tg_byte_size_from_graph_rdi_key(graph, raddbg, type_key); U64 array_total_size_capped = ClampTop(array_total_size, 64); Rng1U64 array_memory_vaddr_rng = r1u64(eval.offset, eval.offset + array_total_size_capped); String8 array_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, array_memory_vaddr_rng); - TG_Key element_type_key = tg_unwrapped_direct_from_graph_raddbg_key(graph, raddbg, type_key); + TG_Key element_type_key = tg_unwrapped_direct_from_graph_rdi_key(graph, raddbg, type_key); TG_Kind element_type_kind = tg_kind_from_key(element_type_key); - U64 element_type_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, element_type_key); + U64 element_type_size = tg_byte_size_from_graph_rdi_key(graph, raddbg, element_type_key); for(U64 element_idx = 0; element_idx < 4; element_idx += 1) { U64 offset = element_idx*element_type_size; @@ -162,11 +162,11 @@ df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RADDBG_Parse case TG_Kind_Union: if(eval.mode == EVAL_EvalMode_Addr) { - U64 struct_total_size = tg_byte_size_from_graph_raddbg_key(graph, raddbg, type_key); + U64 struct_total_size = tg_byte_size_from_graph_rdi_key(graph, raddbg, type_key); U64 struct_total_size_capped = ClampTop(struct_total_size, 64); Rng1U64 struct_memory_vaddr_rng = r1u64(eval.offset, eval.offset + struct_total_size_capped); String8 struct_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, struct_memory_vaddr_rng); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, raddbg, type_key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, raddbg, type_key); for(U64 element_idx = 0, member_idx = 0; element_idx < 4 && member_idx < type->count; member_idx += 1) @@ -223,10 +223,10 @@ df_view_rule_hooks__bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx String8 height_expr = str8_list_join(scratch.arena, &height_expr_strs, 0); String8 fmt_string = fmt_cfg->first->string; DF_Eval width_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, width_expr); - DF_Eval width_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, width_eval); + DF_Eval width_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, width_eval); info.width = width_eval_value.imm_u64; DF_Eval height_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, height_expr); - DF_Eval height_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, height_eval); + DF_Eval height_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, height_eval); info.height = height_eval_value.imm_u64; if(fmt_string.size != 0) { @@ -276,9 +276,9 @@ df_view_rule_hooks__geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ct DF_Eval count_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, count_expr); DF_Eval vertices_base_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, vertices_base_expr); DF_Eval vertices_size_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, vertices_size_expr); - DF_Eval count_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, count_eval); - DF_Eval vertices_base_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, vertices_base_eval); - DF_Eval vertices_size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, vertices_size_eval); + DF_Eval count_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, count_eval); + DF_Eval vertices_base_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, vertices_base_eval); + DF_Eval vertices_size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, vertices_size_eval); U64 vertices_base_vaddr = vertices_base_val_eval.imm_u64 ? vertices_base_val_eval.imm_u64 : vertices_base_val_eval.offset; result.index_count = count_val_eval.imm_u64; result.vertices_vaddr_range = r1u64(vertices_base_vaddr, vertices_base_vaddr+vertices_size_val_eval.imm_u64); @@ -306,7 +306,7 @@ df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ct lang_string = lang_cfg->first->string; String8 size_expr = str8_list_join(scratch.arena, &size_expr_strs, &join); DF_Eval size_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, size_expr); - DF_Eval size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, size_eval); + DF_Eval size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, size_eval); result.lang = txt_lang_kind_from_extension(lang_string); result.size_cap = size_val_eval.imm_u64; } @@ -314,6 +314,36 @@ df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ct return result; } +internal DF_DisasmTopologyInfo +df_view_rule_hooks__disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +{ + Temp scratch = scratch_begin(0, 0); + DF_DisasmTopologyInfo result = zero_struct; + { + StringJoin join = {0}; + join.sep = str8_lit(" "); + DF_CfgNode *size_cfg = df_cfg_node_child_from_string(cfg, str8_lit("size"), 0); + DF_CfgNode *arch_cfg = df_cfg_node_child_from_string(cfg, str8_lit("arch"), 0); + String8List size_expr_strs = {0}; + String8 arch_string = {0}; + for(DF_CfgNode *child = size_cfg->first; child != &df_g_nil_cfg_node; child = child->next) + { + str8_list_push(scratch.arena, &size_expr_strs, child->string); + } + arch_string = arch_cfg->first->string; + String8 size_expr = str8_list_join(scratch.arena, &size_expr_strs, &join); + DF_Eval size_eval = df_eval_from_string(scratch.arena, scope, ctrl_ctx, parse_ctx, macro_map, size_expr); + DF_Eval size_val_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, size_eval); + if(str8_match(arch_string, str8_lit("x64"), StringMatchFlag_CaseInsensitive)) + { + result.arch = Architecture_x64; + } + result.size_cap = size_val_eval.imm_u64; + } + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: "array" @@ -337,13 +367,13 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array) } String8 array_size_expr = str8_list_join(scratch.arena, &array_size_expr_strs, 0); DF_Eval array_size_eval = df_eval_from_string(arena, dbgi_scope, ctrl_ctx, parse_ctx, macro_map, array_size_expr); - DF_Eval array_size_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, array_size_eval); + DF_Eval array_size_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, array_size_eval); eval_error_list_concat_in_place(&eval.errors, &array_size_eval.errors); array_size = array_size_eval_value.imm_u64; } // rjf: apply array size to type - TG_Key pointee = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, type_key); + TG_Key pointee = tg_ptee_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, type_key); TG_Key array_type = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Array, pointee, array_size); eval.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, array_type, 0); } @@ -353,17 +383,8 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array) } //////////////////////////////// -//~ bill: utility procedures +//~ bill: "slice" -internal void dbg_printf(char const *fmt, ...) -{ - va_list argp; - va_start(argp, fmt); - char buf[4096] = {}; - vsnprintf_s(buf, 4095, fmt, argp); - va_end(argp); - OutputDebugStringA(buf); -} internal TG_Member *tg_member_from_name(TG_MemberArray array, String8 name, StringMatchFlags flags) { @@ -378,17 +399,13 @@ internal TG_Member *tg_member_from_name(TG_MemberArray array, String8 name, Stri return NULL; } -//////////////////////////////// -//~ bill: "slice" - - internal U64 df_evaluate_integer_from_eval(EVAL_ParseCtx *parse_ctx, DF_CtrlCtx *ctrl_ctx, DF_Eval eval, TG_Member *member) { DF_Eval res = zero_struct; res.mode = EVAL_EvalMode_Addr; res.offset = eval.offset + member->off; res.type_key = member->type_key; - res = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, res); + res = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, res); if (res.mode == EVAL_EvalMode_Value) { return res.imm_u64; @@ -403,29 +420,28 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(slice) if (type_kind == TG_Kind_Struct) { - Temp scratch = scratch_begin(&arena, 1); DF_CfgNode *struct_node = val->last; if (struct_node != &df_g_nil_cfg_node) { + Temp scratch = scratch_begin(&arena, 1); - TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(arena, parse_ctx->type_graph, parse_ctx->rdbg, type_key); + TG_MemberArray data_members = tg_data_members_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, type_key); TG_Member *member_ptr = NULL; TG_Member *member_len = NULL; - member_ptr = member_ptr ? member_ptr : tg_member_from_name(data_members, str8_lit("data"), StringMatchFlag_CaseInsensitive); - member_ptr = member_ptr ? member_ptr : tg_member_from_name(data_members, str8_lit("str"), StringMatchFlag_CaseInsensitive); - member_ptr = member_ptr ? member_ptr : tg_member_from_name(data_members, str8_lit("ptr"), StringMatchFlag_CaseInsensitive); - - member_len = member_len ? member_len : tg_member_from_name(data_members, str8_lit("len"), StringMatchFlag_CaseInsensitive); - member_len = member_len ? member_len : tg_member_from_name(data_members, str8_lit("size"), StringMatchFlag_CaseInsensitive); - member_len = member_len ? member_len : tg_member_from_name(data_members, str8_lit("count"), StringMatchFlag_CaseInsensitive); + member_ptr = member_ptr ? member_ptr : tg_member_from_name(data_members, str8_lit("data"), StringMatchFlag_CaseInsensitive); + member_ptr = member_ptr ? member_ptr : tg_member_from_name(data_members, str8_lit("str"), StringMatchFlag_CaseInsensitive); + member_ptr = member_ptr ? member_ptr : tg_member_from_name(data_members, str8_lit("ptr"), StringMatchFlag_CaseInsensitive); + member_len = member_len ? member_len : tg_member_from_name(data_members, str8_lit("len"), StringMatchFlag_CaseInsensitive); + member_len = member_len ? member_len : tg_member_from_name(data_members, str8_lit("length"), StringMatchFlag_CaseInsensitive); + member_len = member_len ? member_len : tg_member_from_name(data_members, str8_lit("count"), StringMatchFlag_CaseInsensitive); + member_len = member_len ? member_len : tg_member_from_name(data_members, str8_lit("size"), StringMatchFlag_CaseInsensitive); if (member_ptr && member_len) { - // NOTE(bill): this assumes little-endian format U64 slice_len = df_evaluate_integer_from_eval(parse_ctx, ctrl_ctx, eval, member_len); - TG_Key pointee = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, member_ptr->type_key); + TG_Key pointee = tg_ptee_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, member_ptr->type_key); TG_Key array_type = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Array, pointee, slice_len); // TODO(bill): How do you make this render with the original name, if possible? @@ -436,15 +452,119 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(slice) eval = new_eval; } + + scratch_end(scratch); } - scratch_end(scratch); } return eval; } + //////////////////////////////// //~ bill: "odin_map" + +typedef struct DF_OdinMapCellInfo DF_OdinMapCellInfo; +struct DF_OdinMapCellInfo { + U64 size_of_type; + U64 size_of_cell; + U64 elements_per_cell; +}; + +internal DF_OdinMapCellInfo df_odin_map_cell_info(Arena *arena, EVAL_ParseCtx *parse_ctx, TG_Key type, TG_Key cell_type) +{ + DF_OdinMapCellInfo info = zero_struct; + info.size_of_type = tg_byte_size_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, type); + info.size_of_cell = tg_byte_size_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, cell_type); + + if (info.size_of_type != info.size_of_cell) { + Temp scratch = scratch_begin(&arena, 1); + + TG_Kind kind = tg_kind_from_key(cell_type); + Assert(kind == TG_Kind_Struct); + + TG_MemberArray data_members = tg_data_members_from_graph_rdi_key(scratch.arena, parse_ctx->type_graph, parse_ctx->rdi, cell_type); + Assert(data_members.count >= 1); + TG_Key array_type = data_members.v[0].type_key; + U64 size_of_array = tg_byte_size_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, array_type); + if (size_of_array > 0 && info.size_of_type > 0) { + info.elements_per_cell = size_of_array / info.size_of_type; + } + + scratch_end(scratch); + + } + if (info.elements_per_cell == 0) { + info.elements_per_cell = 1; + } + + return info; +} + + +internal U64 df_odin_map_cell_index(U64 base, DF_OdinMapCellInfo const *info, U64 index) +{ + U64 elements_per_cell = info->elements_per_cell; + U64 size_of_cell = info->size_of_cell; + U64 size_of_type = info->size_of_type; + U64 cell_index = 0; + U64 data_index = 0; + switch (elements_per_cell) { + case 1: + return base + (index * size_of_cell); + case 2: + cell_index = index >> 1; + data_index = index & 1; + break; + case 4: + cell_index = index >> 2; + data_index = index & 3; + break; + case 8: + cell_index = index >> 3; + data_index = index & 7; + break; + case 16: + cell_index = index >> 4; + data_index = index & 15; + break; + case 32: + cell_index = index >> 5; + data_index = index & 31; + break; + default: + cell_index = index / elements_per_cell; + data_index = index % elements_per_cell; + break; + } + return base + (cell_index * size_of_cell) + (data_index * size_of_type); +} + +// internal void dbg_printf(char const *fmt, ...) { +// va_list argp; +// va_start(argp, fmt); +// char buf[4096] = {}; +// vsnprintf_s(buf, 4095, fmt, argp); +// va_end(argp); +// OutputDebugStringA(buf); +// } + + +internal U64 df_evaluate_hash_from_offset(EVAL_ParseCtx *parse_ctx, DF_CtrlCtx *ctrl_ctx, U64 offset, TG_Key hash_type) +{ + DF_Eval res = zero_struct; + res.mode = EVAL_EvalMode_Addr; + res.offset = offset; + res.type_key = hash_type; + res = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, res); + if (res.mode == EVAL_EvalMode_Value) + { + return res.imm_u64; + } + return 0; +} + + DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(odin_map) { TG_Key type_key = eval.type_key; @@ -455,63 +575,102 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(odin_map) DF_CfgNode *struct_node = val->last; if (struct_node != &df_g_nil_cfg_node) { - TG_MemberArray data_members = tg_data_members_from_graph_raddbg_key(arena, parse_ctx->type_graph, parse_ctx->rdbg, type_key); - TG_Member *member_data = tg_member_from_name(data_members, str8_lit("data"), 0); - TG_Member *member_len = tg_member_from_name(data_members, str8_lit("len"), 0); - TG_Member *member_metadata = tg_member_from_name(data_members, str8_lit("__metadata"), 0); + TG_MemberArray data_members = tg_data_members_from_graph_rdi_key(arena, parse_ctx->type_graph, parse_ctx->rdi, type_key); - if (member_data && member_len && member_metadata) + TG_Member *member_data = tg_member_from_name(data_members, str8_lit("data"), 0); + TG_Member *member_len = tg_member_from_name(data_members, str8_lit("len"), 0); + + if (member_data && member_len) { - TG_Key metadata = member_metadata->type_key; - metadata = tg_direct_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, metadata); - metadata = tg_ptee_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, metadata); - Assert(tg_kind_from_key(metadata) == TG_Kind_Struct); + TG_Key metadata = member_data->type_key; + metadata = tg_ptee_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, metadata); + if (tg_kind_from_key(metadata) != TG_Kind_Struct) + { + return eval; + } - TG_MemberArray md_members = tg_data_members_from_graph_raddbg_key(arena, parse_ctx->type_graph, parse_ctx->rdbg, metadata); + TG_MemberArray md_members = tg_data_members_from_graph_rdi_key(arena, parse_ctx->type_graph, parse_ctx->rdi, metadata); TG_Member *m_key = tg_member_from_name(md_members, str8_lit("key"), 0); TG_Member *m_value = tg_member_from_name(md_members, str8_lit("value"), 0); TG_Member *m_hash = tg_member_from_name(md_members, str8_lit("hash"), 0); TG_Member *m_key_cell = tg_member_from_name(md_members, str8_lit("key_cell"), 0); TG_Member *m_value_cell = tg_member_from_name(md_members, str8_lit("value_cell"), 0); - if (m_key == NULL) { + if (m_key == NULL || + m_value == NULL || + m_hash == NULL || + m_key_cell == NULL || + m_value_cell == NULL) + { return eval; } - Assert(m_key && m_value && m_hash && m_key_cell && m_value_cell); + TG_Key key = m_key->type_key; TG_Key value = m_value->type_key; TG_Key hash = m_hash->type_key; TG_Key key_cell = m_key_cell->type_key; TG_Key value_cell = m_value_cell->type_key; + U64 raw_data = df_evaluate_integer_from_eval(parse_ctx, ctrl_ctx, eval, member_data); + U64 ptr = raw_data & ~(U64)63; + U64 len = df_evaluate_integer_from_eval(parse_ctx, ctrl_ctx, eval, member_len); + U64 cap_log2 = raw_data & 63; + U64 cap = cap_log2 ? ((U64)1)<type_graph, parse_ctx->rdi, hash); + + U64 key_ptr = ptr; + U64 value_ptr = df_odin_map_cell_index(key_ptr, &key_cell_info, cap); + U64 hash_ptr = df_odin_map_cell_index(value_ptr, &value_cell_info, cap); + (void)value_ptr; + (void)hash_ptr; + + U64 TOMBSTONE_MASK = ((U64)1u)<<(size_of_hash*8 - 1); + + for (U64 i = 0; i < cap; i += 1) { - cap = ((U64)1)<type_graph, TG_Kind_Array, key, cap); - - // TODO(bill): How do you make this render with the original name, if possible? + TG_Key key_array_type = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Array, key_cell, cap/key_cell_info.elements_per_cell); DF_Eval new_eval = zero_struct; new_eval.mode = EVAL_EvalMode_Value; - new_eval.imm_u64 = data; - new_eval.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, array_type, 0); + new_eval.imm_u64 = key_ptr; + new_eval.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, key_array_type, 0); eval = new_eval; + } } } + return eval; } - - //////////////////////////////// //~ rjf: "list" @@ -533,13 +692,13 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(bswap) Temp scratch = scratch_begin(&arena, 1); TG_Key type_key = eval.type_key; TG_Kind type_kind = tg_kind_from_key(type_key); - U64 type_size_bytes = tg_byte_size_from_graph_raddbg_key(parse_ctx->type_graph, parse_ctx->rdbg, type_key); + U64 type_size_bytes = tg_byte_size_from_graph_rdi_key(parse_ctx->type_graph, parse_ctx->rdi, type_key); if(TG_Kind_Char8 <= type_kind && type_kind <= TG_Kind_S256 && (type_size_bytes == 2 || type_size_bytes == 4 || type_size_bytes == 8)) { - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); if(value_eval.mode == EVAL_EvalMode_Value) { switch(type_size_bytes) @@ -658,8 +817,8 @@ DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(rgba) DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); //- rjf: grab hsva - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); - Vec4F32 rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdbg, process); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); + Vec4F32 rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdi, process); Vec4F32 hsva = hsva_from_rgba(rgba); //- rjf: build text box @@ -706,7 +865,7 @@ DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(rgba) //- rjf: hover color box -> show components UI_Signal sig = ui_signal_from_box(color_box); - if(sig.hovering) + if(ui_hovering(sig)) { ui_do_color_tooltip_hsva(hsva); } @@ -725,17 +884,17 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) Vec4F32 rgba = {0}; Vec4F32 hsva = {0}; { - if(state->memgen_idx >= ctrl_memgen_idx()) + if(state->memgen_idx >= ctrl_mem_gen()) { hsva = state->hsva; rgba = rgba_from_hsva(hsva); } else { - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); - rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdbg, process); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); + rgba = df_view_rule_hooks__rgba_from_eval(value_eval, parse_ctx->type_graph, parse_ctx->rdi, process); state->hsva = hsva = hsva_from_rgba(rgba); - state->memgen_idx = ctrl_memgen_idx(); + state->memgen_idx = ctrl_mem_gen(); } } Vec4F32 initial_hsva = hsva; @@ -747,12 +906,12 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) UI_PrefWidth(ui_px(dim.y, 1.f)) { UI_Signal sv_sig = ui_sat_val_pickerf(hsva.x, &hsva.y, &hsva.z, "sat_val_picker"); - commit = commit || sv_sig.released; + commit = commit || ui_released(sv_sig); } UI_PrefWidth(ui_em(3.f, 1.f)) { UI_Signal h_sig = ui_hue_pickerf(&hsva.x, hsva.y, hsva.z, "hue_picker"); - commit = commit || h_sig.released; + commit = commit || ui_released(h_sig); } UI_PrefWidth(ui_children_sum(1)) UI_Column UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) { @@ -783,8 +942,8 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) if(commit) { Vec4F32 rgba = rgba_from_hsva(hsva); - df_view_rule_hooks__eval_commit_rgba(eval, parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, rgba); - state->memgen_idx = ctrl_memgen_idx(); + df_view_rule_hooks__eval_commit_rgba(eval, parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, rgba); + state->memgen_idx = ctrl_mem_gen(); } //- rjf: commit possible edited value to state @@ -822,84 +981,89 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text) Temp scratch = scratch_begin(0, 0); HS_Scope *hs_scope = hs_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); + + ////////////////////////////// + //- rjf: get & initialize state + // DF_ViewRuleHooks_TextState *state = df_view_rule_block_user_state(key, DF_ViewRuleHooks_TextState); if(!state->initialized) { state->initialized = 1; state->cursor = state->mark = txt_pt(1, 1); } - if(state->last_open_frame_idx+1 < df_frame_index()) + + ////////////////////////////// + //- rjf: unpack evaluation / view rule params + // + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + DF_TxtTopologyInfo top = df_view_rule_hooks__txt_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr + (top.size_cap ? top.size_cap : 2048)); + + ////////////////////////////// + //- rjf: evaluation info -> text visualization info + // + String8 data = {0}; + TXT_TextInfo info = {0}; + TXT_LineTokensSlice line_tokens_slice = {0}; { - state->loaded_t = 0; + U128 text_hash = {0}; + U128 text_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 1); + info = txt_text_info_from_key_lang(txt_scope, text_key, top.lang, &text_hash); + data = hs_data_from_hash(hs_scope, text_hash); + line_tokens_slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, &info, data, r1s64(1, info.lines_count)); } - state->last_open_frame_idx = df_frame_index(); + + ////////////////////////////// + //- rjf: info -> code slice info + // + DF_CodeSliceParams code_slice_params = {0}; { - //- rjf: unpack params - DF_TxtTopologyInfo top = df_view_rule_hooks__txt_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); - - //- rjf: resolve to address value & range - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); - U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; - Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr + (top.size_cap ? top.size_cap : 2048)); - - //- rjf: unpack thread/process of eval - DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); - DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - - //- rjf: unique identifying info about this address -> unique key - U128 text_key = {0}; + code_slice_params.flags = DF_CodeSliceFlag_LineNums; + code_slice_params.line_num_range = r1s64(1, info.lines_count); + code_slice_params.line_text = push_array(scratch.arena, String8, info.lines_count); + code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, info.lines_count); + code_slice_params.line_tokens = push_array(scratch.arena, TXT_TokenArray, info.lines_count); + code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, info.lines_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, info.lines_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, info.lines_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, info.lines_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, info.lines_count); + for(U64 line_idx = 0; line_idx < info.lines_count; line_idx += 1) { - U64 data[] = - { - (U64)process->ctrl_machine_id, - (U64)process->ctrl_handle.u64[0], - vaddr_range.min, - vaddr_range.max, - }; - text_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); + code_slice_params.line_text[line_idx] = str8_substr(data, info.lines_ranges[line_idx]); + code_slice_params.line_ranges[line_idx] = info.lines_ranges[line_idx]; + code_slice_params.line_tokens[line_idx] = line_tokens_slice.line_tokens[line_idx]; } - - //- rjf: address range -> hash - U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 1, 0); - - //- rjf: hash -> data - String8 data = hs_data_from_hash(hs_scope, hash); - - //- rjf: key * hash -> parsed text info - TXT_TextInfo info = txt_text_info_from_key_hash_lang(txt_scope, text_key, hash, top.lang); - - //- rjf: info -> code slice info - DF_CodeSliceParams code_slice_params = {0}; + code_slice_params.font = df_font_from_slot(DF_FontSlot_Code); + code_slice_params.font_size = ui_top_font_size(); + code_slice_params.line_height_px = ui_top_font_size()*1.5f; + code_slice_params.margin_width_px = 0; + code_slice_params.line_num_width_px = ui_top_font_size()*5.f; + code_slice_params.line_text_max_width_px = ui_top_font_size()*2.f*info.lines_max_size; + } + + ////////////////////////////// + //- rjf: build UI + // + if(info.lines_count != 0) + { + //- rjf: build top-level container + UI_Box *container = &ui_g_nil_box; + UI_PrefWidth(ui_px(dim.x, 1.f)) UI_PrefHeight(ui_px(dim.y, 1.f)) { - code_slice_params.flags = DF_CodeSliceFlag_LineNums; - code_slice_params.line_num_range = r1s64(1, info.lines_count); - code_slice_params.line_text = push_array(scratch.arena, String8, info.lines_count); - code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, info.lines_count); - code_slice_params.line_tokens = push_array(scratch.arena, TXTI_TokenArray, info.lines_count); - code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, info.lines_count); - code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, info.lines_count); - code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, info.lines_count); - code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, info.lines_count); - code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, info.lines_count); - for(U64 line_idx = 0; line_idx < info.lines_count; line_idx += 1) - { - code_slice_params.line_text[line_idx] = str8_substr(data, info.lines_ranges[line_idx]); - code_slice_params.line_ranges[line_idx] = info.lines_ranges[line_idx]; - } - code_slice_params.font = df_font_from_slot(DF_FontSlot_Code); - code_slice_params.font_size = ui_top_font_size(); - code_slice_params.line_height_px = ui_top_font_size()*1.5f; - code_slice_params.margin_width_px = 0; - code_slice_params.line_num_width_px = ui_top_font_size()*5.f; - code_slice_params.line_text_max_width_px = ui_top_font_size()*2.f*info.lines_max_size; + container = ui_build_box_from_stringf(UI_BoxFlag_AllowOverflow|UI_BoxFlag_Clip, "###text_container"); } //- rjf: build code slice - if(info.lines_count != 0) UI_Padding(ui_pct(1, 0)) UI_PrefWidth(ui_px(info.lines_max_size*ui_top_font_size()*1.2f, 1.f)) UI_Column UI_Padding(ui_pct(1, 0)) + UI_WidthFill UI_HeightFill UI_Parent(container) { - DF_CodeSliceSignal sig = df_code_slice(ws, ctrl_ctx, parse_ctx, &code_slice_params, &state->cursor, &state->mark, &state->preferred_column, str8_lit("###code_slice")); + DF_CodeSliceSignal slice_sig = df_code_slice(ws, ctrl_ctx, parse_ctx, &code_slice_params, &state->cursor, &state->mark, &state->preferred_column, str8_lit("###slice")); } } + txt_scope_close(txt_scope); hs_scope_close(hs_scope); scratch_end(scratch); @@ -908,6 +1072,17 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text) //////////////////////////////// //~ rjf: "disasm" +typedef struct DF_ViewRuleHooks_DisasmState DF_ViewRuleHooks_DisasmState; +struct DF_ViewRuleHooks_DisasmState +{ + B32 initialized; + TxtPt cursor; + TxtPt mark; + S64 preferred_column; + U64 last_open_frame_idx; + F32 loaded_t; +}; + DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(disasm) { DF_EvalVizBlock *vb = df_eval_viz_block_begin(arena, DF_EvalVizBlockKind_Canvas, key, df_expand_key_make(df_hash_from_expand_key(key), 1), depth); @@ -920,7 +1095,92 @@ DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(disasm) DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm) { - + Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); + DASM_Scope *dasm_scope = dasm_scope_open(); + DF_ViewRuleHooks_DisasmState *state = df_view_rule_block_user_state(key, DF_ViewRuleHooks_DisasmState); + if(!state->initialized) + { + state->initialized = 1; + state->cursor = state->mark = txt_pt(1, 1); + } + if(state->last_open_frame_idx+1 < df_frame_index()) + { + state->loaded_t = 0; + } + state->last_open_frame_idx = df_frame_index(); + { + //- rjf: unpack params + DF_DisasmTopologyInfo top = df_view_rule_hooks__disasm_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + + //- rjf: resolve to address value & range + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); + U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; + Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr + (top.size_cap ? top.size_cap : 2048)); + + //- rjf: unpack thread/process of eval + DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + + //- rjf: unpack key for this region in memory + U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0); + + //- rjf: key -> parsed text info + U128 data_hash = {0}; + DASM_Info dasm_info = dasm_info_from_key_addr_arch_style(dasm_scope, dasm_key, vaddr_range.min, top.arch, 0, DASM_Syntax_Intel, &data_hash); + String8 dasm_text_data = {0}; + TXT_TextInfo dasm_text_info = {0}; + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) + { + U128 dasm_text_hash = hs_hash_from_key(dasm_info.text_key, rewind_idx); + dasm_text_data = hs_data_from_hash(hs_scope, dasm_text_hash); + dasm_text_info = txt_text_info_from_hash_lang(txt_scope, dasm_text_hash, TXT_LangKind_DisasmX64Intel); + if(dasm_text_info.lines_count != 0) + { + break; + } + } + TXT_LineTokensSlice line_tokens_slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, &dasm_text_info, dasm_text_data, r1s64(1, dasm_info.insts.count)); + + //- rjf: info -> code slice info + DF_CodeSliceParams code_slice_params = {0}; + { + code_slice_params.flags = DF_CodeSliceFlag_LineNums; + code_slice_params.line_num_range = r1s64(1, dasm_text_info.lines_count); + code_slice_params.line_text = push_array(scratch.arena, String8, dasm_text_info.lines_count); + code_slice_params.line_ranges = push_array(scratch.arena, Rng1U64, dasm_text_info.lines_count); + code_slice_params.line_tokens = push_array(scratch.arena, TXT_TokenArray, dasm_text_info.lines_count); + code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, dasm_text_info.lines_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, dasm_text_info.lines_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, dasm_text_info.lines_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, dasm_text_info.lines_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, dasm_text_info.lines_count); + for(U64 line_idx = 0; line_idx < dasm_text_info.lines_count; line_idx += 1) + { + code_slice_params.line_text[line_idx] = str8_substr(dasm_text_data, dasm_info.insts.v[line_idx].text_range); + code_slice_params.line_ranges[line_idx] = dasm_info.insts.v[line_idx].text_range; + code_slice_params.line_tokens[line_idx] = line_tokens_slice.line_tokens[line_idx]; + } + code_slice_params.font = df_font_from_slot(DF_FontSlot_Code); + code_slice_params.font_size = ui_top_font_size(); + code_slice_params.line_height_px = ui_top_font_size()*1.5f; + code_slice_params.margin_width_px = 0; + code_slice_params.line_num_width_px = ui_top_font_size()*5.f; + code_slice_params.line_text_max_width_px = ui_top_font_size()*2.f*dasm_text_info.lines_max_size; + } + + //- rjf: build code slice + if(dasm_info.insts.count != 0 && dasm_text_info.lines_count != 0) + UI_Padding(ui_pct(1, 0)) UI_PrefWidth(ui_px(dasm_text_info.lines_max_size*ui_top_font_size()*1.2f, 1.f)) UI_Column UI_Padding(ui_pct(1, 0)) + { + DF_CodeSliceSignal sig = df_code_slice(ws, ctrl_ctx, parse_ctx, &code_slice_params, &state->cursor, &state->mark, &state->preferred_column, str8_lit("###code_slice")); + } + } + dasm_scope_close(dasm_scope); + txt_scope_close(txt_scope); + hs_scope_close(hs_scope); + scratch_end(scratch); } //////////////////////////////// @@ -1004,7 +1264,7 @@ DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(bitmap) DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(bitmap) { - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; DF_BitmapTopologyInfo topology = df_view_rule_hooks__bitmap_topology_info_from_cfg(scope, ctrl_ctx, parse_ctx, macro_map, cfg); U64 expected_size = topology.width*topology.height*r_tex2d_format_bytes_per_pixel_table[topology.fmt]; @@ -1025,7 +1285,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) state->last_open_frame_idx = df_frame_index(); //- rjf: resolve to address value - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; //- rjf: unpack thread/process of eval @@ -1037,34 +1297,22 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) U64 expected_size = topology_info.width*topology_info.height*r_tex2d_format_bytes_per_pixel_table[topology_info.fmt]; Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr+expected_size); - //- rjf: unique identifying info about this address -> unique key - U128 texture_key = {0}; - { - U64 data[] = - { - (U64)process->ctrl_machine_id, - (U64)process->ctrl_handle.u64[0], - vaddr_range.min, - vaddr_range.max, - }; - texture_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); - } - - //- rjf: address range -> hash - U128 hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0, 0); + //- rjf: obtain key for this data range + U128 texture_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vaddr_range, 0); //- rjf: hash & topology -> texture TEX_Topology topology = tex_topology_make(v2s32((S32)topology_info.width, (S32)topology_info.height), topology_info.fmt); - R_Handle texture = tex_texture_from_key_hash_topology(tex_scope, texture_key, hash, topology); + R_Handle texture = tex_texture_from_key_topology(tex_scope, texture_key, topology); //- rjf: build preview F32 rate = 1 - pow_f32(2, (-15.f * df_dt())); if(expected_size != 0) { + F32 img_dim = dim.y - ui_top_font_size()*2.f; UI_Padding(ui_pct(1.f, 0.f)) - UI_PrefWidth(ui_px(dim.y*((F32)topology_info.width/(F32)topology_info.height), 1.f)) + UI_PrefWidth(ui_px(img_dim*((F32)topology_info.width/(F32)topology_info.height), 1.f)) UI_Column UI_Padding(ui_pct(1.f, 0.f)) - UI_PrefHeight(ui_px(dim.y, 1.f)) + UI_PrefHeight(ui_px(img_dim, 1.f)) { ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable|UI_BoxFlag_DrawHotEffects, "image_box"); @@ -1076,7 +1324,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) draw_data->texture = texture; draw_data->src = r2f32(v2f32(0, 0), v2f32((F32)topology_info.width, (F32)topology_info.height)); draw_data->loaded_t = state->loaded_t; - draw_data->hovered = sig.hovering; + draw_data->hovered = ui_hovering(sig); draw_data->mouse_px = mouse_bitmap_px_off; draw_data->ui_per_bmp_px = ui_per_bmp_px; ui_box_equip_custom_draw(box, df_view_rule_hooks__bitmap_box_draw, draw_data); @@ -1093,14 +1341,15 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) df_gfx_request_frame(); } } - if(sig.hovering && r_handle_match(texture, r_handle_zero())) UI_Tooltip + if(ui_hovering(sig) && r_handle_match(texture, r_handle_zero())) UI_Tooltip { ui_labelf("Texture not loaded."); } - if(sig.hovering && !r_handle_match(texture, r_handle_zero())) + if(ui_hovering(sig) && !r_handle_match(texture, r_handle_zero())) { if(dim.y > (F32)topology_info.height) { + U128 hash = hs_hash_from_key(texture_key, 0); String8 data = hs_data_from_hash(hs_scope, hash); U64 bytes_per_pixel = r_tex2d_format_bytes_per_pixel_table[topology.fmt]; U64 mouse_pixel_off = mouse_bitmap_px_off.y*topology_info.width + mouse_bitmap_px_off.x; @@ -1172,6 +1421,11 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) scratch_end(scratch); } +DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_DEF(bitmap) +{ + +} + //////////////////////////////// //~ rjf: "geo" @@ -1247,7 +1501,7 @@ DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(geo) DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(geo) { - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("0x%I64x -> Geometry", base_vaddr); @@ -1272,7 +1526,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo) state->last_open_frame_idx = df_frame_index(); //- rjf: resolve to address value - DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval); + DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; //- rjf: extract extra geo topology info from view rule @@ -1284,39 +1538,13 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo) DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - //- rjf: produce unique keys for index buffer - U128 index_buffer_key = {0}; - { - U64 data[] = - { - (U64)process->ctrl_machine_id, - (U64)process->ctrl_handle.u64[0], - index_buffer_vaddr_range.min, - index_buffer_vaddr_range.max, - }; - index_buffer_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); - } - - //- rjf: produce unique keys for vertex buffer - U128 vertex_buffer_key = {0}; - { - U64 data[] = - { - (U64)process->ctrl_machine_id, - (U64)process->ctrl_handle.u64[0], - vertex_buffer_vaddr_range.min, - vertex_buffer_vaddr_range.max, - }; - vertex_buffer_key = hs_hash_from_data(str8((U8 *)data, sizeof(data))); - } - - //- rjf: address range -> hash - U128 index_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, index_buffer_vaddr_range, 0, 0); - U128 vertex_buffer_hash = ctrl_stored_hash_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vertex_buffer_vaddr_range, 0, 0); + //- rjf: obtain keys for index buffer & vertex buffer memory + U128 index_buffer_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, index_buffer_vaddr_range, 0); + U128 vertex_buffer_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, vertex_buffer_vaddr_range, 0); //- rjf: get gpu buffers - R_Handle index_buffer = geo_buffer_from_key_hash(geo_scope, index_buffer_key, index_buffer_hash); - R_Handle vertex_buffer = geo_buffer_from_key_hash(geo_scope, vertex_buffer_key, vertex_buffer_hash); + R_Handle index_buffer = geo_buffer_from_key(geo_scope, index_buffer_key); + R_Handle vertex_buffer = geo_buffer_from_key(geo_scope, vertex_buffer_key); //- rjf: build preview F32 rate = 1 - pow_f32(2, (-15.f * df_dt())); @@ -1329,9 +1557,9 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo) { UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground|UI_BoxFlag_Clickable, "geo_box"); UI_Signal sig = ui_signal_from_box(box); - if(sig.dragging) + if(ui_dragging(sig)) { - if(sig.pressed) + if(ui_pressed(sig)) { Vec2F32 data = v2f32(state->yaw_target, state->pitch_target); ui_store_drag_struct(&data); diff --git a/src/df/gfx/df_view_rule_hooks.h b/src/df/gfx/df_view_rule_hooks.h index 2d7ea22d..4ac8729e 100644 --- a/src/df/gfx/df_view_rule_hooks.h +++ b/src/df/gfx/df_view_rule_hooks.h @@ -29,13 +29,21 @@ struct DF_TxtTopologyInfo U64 size_cap; }; +typedef struct DF_DisasmTopologyInfo DF_DisasmTopologyInfo; +struct DF_DisasmTopologyInfo +{ + Architecture arch; + U64 size_cap; +}; + //////////////////////////////// //~ rjf: Helpers -internal Vec4F32 df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_Entity *process); -internal void df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RADDBG_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba); +internal Vec4F32 df_view_rule_hooks__rgba_from_eval(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_Entity *process); +internal void df_view_rule_hooks__eval_commit_rgba(DF_Eval eval, TG_Graph *graph, RDI_Parsed *raddbg, DF_CtrlCtx *ctrl_ctx, Vec4F32 rgba); internal DF_BitmapTopologyInfo df_view_rule_hooks__bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); internal DF_GeoTopologyInfo df_view_rule_hooks__geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); internal DF_TxtTopologyInfo df_view_rule_hooks__txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_DisasmTopologyInfo df_view_rule_hooks__disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); #endif //DF_VIEW_RULE_HOOKS_H diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index eb45f21e..d963cc39 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -240,9 +240,9 @@ df_process_info_list_from_query(Arena *arena, String8 query) //- rjf: build list DF_ProcessInfoList list = {0}; { - DEMON_ProcessIter iter = {0}; - demon_proc_iter_begin(&iter); - for(DEMON_ProcessInfo info = {0}; demon_proc_iter_next(scratch.arena, &iter, &info);) + 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) @@ -290,7 +290,7 @@ df_process_info_list_from_query(Arena *arena, String8 query) list.count += 1; } } - demon_proc_iter_end(&iter); + dmn_process_iter_end(&iter); } scratch_end(scratch); @@ -369,176 +369,6 @@ df_entity_lister_item_array_sort_by_strength__in_place(DF_EntityListerItemArray qsort(array.v, array.count, sizeof(DF_EntityListerItem), (int (*)(const void *, const void *))df_qsort_compare_entity_lister__strength); } -//////////////////////////////// -//~ rjf: Disassembly View - -internal TXTI_TokenArray -df_txti_token_array_from_dasm_arch_string(Arena *arena, Architecture arch, String8 string) -{ - Temp scratch = scratch_begin(&arena, 1); - TXTI_TokenChunkList tokens = {0}; - { - TXTI_TokenKind active_token_kind = TXTI_TokenKind_Null; - U64 active_token_start_off = 0; - U64 off = 0; - B32 escaped = 0; - B32 string_is_char = 0; - for(U64 advance = 0; off <= string.size; off += advance) - { - U8 byte = (off+0 < string.size) ? string.str[off+0] : 0; - U8 next_byte = (off+1 < string.size) ? string.str[off+1] : 0; - B32 ender_found = 0; - advance = (active_token_kind != TXTI_TokenKind_Null ? 1 : 0); - if(off == string.size && active_token_kind != TXTI_TokenKind_Null) - { - ender_found = 1; - advance = 1; - } - switch(active_token_kind) - { - default: - case TXTI_TokenKind_Null: - { - if(byte == ' ' || byte == '\t' || byte == '\v' || byte == '\f' || byte == '\r' || byte == '\n') - { - active_token_start_off = off; - active_token_kind = TXTI_TokenKind_Whitespace; - advance = 1; - } - else if(('a' <= byte && byte <= 'z') || ('A' <= byte && byte <= 'Z') || byte == '_') - { - active_token_start_off = off; - active_token_kind = TXTI_TokenKind_Identifier; - advance = 1; - } - else if(byte == '\'') - { - active_token_start_off = off; - active_token_kind = TXTI_TokenKind_String; - advance = 1; - string_is_char = 1; - } - else if(byte == '"') - { - active_token_start_off = off; - active_token_kind = TXTI_TokenKind_String; - advance = 1; - string_is_char = 0; - } - else if(('0' <= byte && byte <= '9') || (byte == '.' && '0' <= next_byte && next_byte <= '9')) - { - active_token_start_off = off; - active_token_kind = TXTI_TokenKind_Numeric; - advance = 1; - } - else if(byte == '~' || byte == '!' || byte == '%' || byte == '^' || - byte == '&' || byte == '*' || byte == '(' || byte == ')' || - byte == '-' || byte == '=' || byte == '+' || byte == '[' || - byte == ']' || byte == '{' || byte == '}' || byte == ';' || - byte == ':' || byte == '?' || byte == '/' || byte == '<' || - byte == '>' || byte == ',' || byte == '.') - { - active_token_start_off = off; - active_token_kind = TXTI_TokenKind_Symbol; - advance = 1; - } - else - { - active_token_start_off = off; - active_token_kind = TXTI_TokenKind_Error; - advance = 1; - } - }break; - case TXTI_TokenKind_Whitespace: - if(byte != ' ' && byte != '\t' && byte != '\v' && byte != '\f') - { - ender_found = 1; - advance = 0; - }break; - case TXTI_TokenKind_Identifier: - if((byte < 'a' || 'z' < byte) && (byte < 'A' || 'Z' < byte) && (byte < '0' || '9' < byte) && byte != '_') - { - ender_found = 1; - advance = 0; - }break; - case TXTI_TokenKind_String: - { - U8 ender_byte = string_is_char ? '\'' : '"'; - if(!escaped && byte == ender_byte) - { - ender_found = 1; - advance = 1; - } - else if(escaped) - { - escaped = 0; - advance = 1; - } - else if(byte == '\\') - { - escaped = 1; - advance = 1; - } - else - { - U8 byte_class = utf8_class[byte>>3]; - if(byte_class > 1) - { - advance = (U64)byte_class; - } - } - }break; - case TXTI_TokenKind_Numeric: - if((byte < 'a' || 'z' < byte) && (byte < 'A' || 'Z' < byte) && (byte < '0' || '9' < byte) && byte != '.') - { - ender_found = 1; - advance = 0; - }break; - case TXTI_TokenKind_Symbol: - if(1) - { - // NOTE(rjf): avoiding maximum munch rule for now - ender_found = 1; - advance = 0; - } - else if(byte != '~' && byte != '!' && byte != '#' && byte != '%' && - byte != '^' && byte != '&' && byte != '*' && byte != '(' && - byte != ')' && byte != '-' && byte != '=' && byte != '+' && - byte != '[' && byte != ']' && byte != '{' && byte != '}' && - byte != ';' && byte != ':' && byte != '?' && byte != '/' && - byte != '<' && byte != '>' && byte != ',' && byte != '.') - { - ender_found = 1; - advance = 0; - }break; - case TXTI_TokenKind_Error: - { - ender_found = 1; - advance = 0; - }break; - } - if(ender_found != 0) - { - TXTI_Token token = {active_token_kind, r1u64(active_token_start_off, off+advance)}; - if(active_token_kind == TXTI_TokenKind_Identifier) - { - String8 token_string = str8_substr(string, token.range); - if(df_info_summary_from_string(arch, token_string).size != 0) - { - token.kind = TXTI_TokenKind_Keyword; - } - } - txti_token_chunk_list_push(arena, &tokens, 1024, &token); - active_token_kind = TXTI_TokenKind_Null; - active_token_start_off = token.range.max; - } - } - } - TXTI_TokenArray result = txti_token_array_from_chunk_list(arena, &tokens); - scratch_end(scratch); - return result; -} - //////////////////////////////// //~ rjf: Eval/Watch Views @@ -610,9 +440,7 @@ df_eval_root_from_expand_key(DF_EvalWatchViewState *ews, DF_EvalView *eval_view, DF_EvalRoot *root = 0; for(DF_EvalRoot *r = ews->first_root; r != 0; r = r->next) { - DF_ExpandKey parent_key = df_expand_key_make(5381, (U64)r); - U64 parent_key_hash = df_hash_from_expand_key(parent_key); - DF_ExpandKey key = df_expand_key_make(parent_key_hash, df_hash_from_string(df_string_from_eval_root(r))); + DF_ExpandKey key = df_expand_key_from_eval_root(r); if(df_expand_key_match(key, expand_key)) { root = r; @@ -629,6 +457,21 @@ df_string_from_eval_root(DF_EvalRoot *root) return string; } +internal DF_ExpandKey +df_parent_expand_key_from_eval_root(DF_EvalRoot *root) +{ + DF_ExpandKey parent_key = df_expand_key_make(5381, (U64)root); + return parent_key; +} + +internal DF_ExpandKey +df_expand_key_from_eval_root(DF_EvalRoot *root) +{ + DF_ExpandKey parent_key = df_parent_expand_key_from_eval_root(root); + DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), (U64)root); + return key; +} + //- rjf: windowed watch tree visualization (both single-line and multi-line) internal DF_EvalVizBlockList @@ -655,7 +498,9 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF FuzzyMatchRangeList matches = fuzzy_match_find(arena, filter, root_expr_string); if(matches.count == matches.needle_part_count) { - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_num(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, (U64)root); + DF_ExpandKey parent_key = df_parent_expand_key_from_eval_root(root); + DF_ExpandKey key = df_expand_key_from_eval_root(root); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -679,7 +524,9 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF FuzzyMatchRangeList matches = fuzzy_match_find(arena, filter, root_expr_string); if(matches.count == matches.needle_part_count) { - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_num(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, num); + DF_ExpandKey parent_key = df_expand_key_make(5381, 0); + DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -689,7 +536,9 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF FuzzyMatchRangeList matches = fuzzy_match_find(arena, filter, root_expr_string); if(matches.count == matches.needle_part_count) { - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_num(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, num); + DF_ExpandKey parent_key = df_expand_key_make(5381, 0); + DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -707,7 +556,9 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF FuzzyMatchRangeList matches = fuzzy_match_find(arena, filter, root_expr_string); if(matches.count == matches.needle_part_count) { - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_num(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, num); + DF_ExpandKey parent_key = df_expand_key_make(5381, 0); + DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -730,7 +581,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF DF_Entity *binary = df_binary_file_from_module(module); String8 exe_path = df_full_path_from_entity(scratch.arena, binary); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, os_now_microseconds()+100); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; //- rjf: calculate top-level keys, expand root-level, grab root expansion node DF_ExpandKey parent_key = df_expand_key_make(5381, 0); @@ -821,7 +672,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF last_vb = df_eval_viz_block_split_and_continue(arena, &blocks, last_vb, sub_expand_item_idxs[sub_expand_idx]); // rjf: grab name for the expanded row - String8 name = dbgi_fuzzy_item_string_from_rdbg_target_element_idx(&dbgi->rdbg, dbgi_target, sub_expand_keys[sub_expand_idx].child_num); + String8 name = dbgi_fuzzy_item_string_from_rdi_target_element_idx(&dbgi->rdi, dbgi_target, sub_expand_keys[sub_expand_idx].child_num); // rjf: recurse for sub-expansion { @@ -1159,7 +1010,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW default:{}break; case EVAL_EvalMode_Addr: { - U64 size = tg_byte_size_from_graph_raddbg_key(parse_ctx.type_graph, parse_ctx.rdbg, row->eval.type_key); + U64 size = tg_byte_size_from_graph_rdi_key(parse_ctx.type_graph, parse_ctx.rdi, row->eval.type_key); size = Min(size, 64); Rng1U64 vaddr_rng = r1u64(row->eval.offset, row->eval.offset+size); CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, vaddr_rng, 0); @@ -1201,18 +1052,25 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW UI_Parent(canvas_box) UI_WidthFill UI_HeightFill { Vec2F32 canvas_dim = v2f32(scroll_list_params.dim_px.x - ui_top_font_size()*1.5f, - (row->skipped_size_in_rows+row->size_in_rows+row->chopped_size_in_rows)*scroll_list_params.row_height_px - scroll_list_params.row_height_px); + (row->skipped_size_in_rows+row->size_in_rows+row->chopped_size_in_rows)*scroll_list_params.row_height_px); row->expand_ui_rule_spec->info.block_ui(ws, row->key, row->eval, scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->expand_ui_rule_node, canvas_dim); } } } UI_Signal sig = ui_signal_from_box(vector); - if(sig.pressed) + if(ui_pressed(sig)) { edit_commit = edit_commit || (!row_selected && ewv->input_editing); next_cursor_tbl = v2s64(DF_EvalWatchViewColumnKind_Expr, (semantic_idx+1)); pressed = 1; } + if(ui_double_clicked(sig)) + { + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.view_spec = df_view_spec_from_gfx_view_kind(DF_GfxViewKind_EvalViewer); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_ViewSpec); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OpenTab)); + } } //- rjf: build normal row @@ -1249,7 +1107,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW row->depth > 0 && !row_expanded) { - U64 next_off = (row->eval.offset + tg_byte_size_from_graph_raddbg_key(parse_ctx.type_graph, parse_ctx.rdbg, row->eval.type_key)); + U64 next_off = (row->eval.offset + tg_byte_size_from_graph_rdi_key(parse_ctx.type_graph, parse_ctx.rdi, row->eval.type_key)); if(next_off%64 != 0 && row->eval.offset/64 < next_off/64) { ui_set_next_fixed_x(0); @@ -1319,13 +1177,13 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW row->expr, "###row_%I64x", row_hash); } - edit_commit = edit_commit || sig.commit; - if(sig.hovering && is_inherited) UI_Tooltip + edit_commit = edit_commit || ui_committed(sig); + if(is_inherited && ui_hovering(sig)) UI_Tooltip { String8List inheritance_chain_type_names = {0}; for(TG_KeyNode *n = row->inherited_type_key_chain.first; n != 0; n = n->next) { - String8 inherited_type_name = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, n->v); + String8 inherited_type_name = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdi, n->v); inherited_type_name = str8_skip_chop_whitespace(inherited_type_name); str8_list_push(scratch.arena, &inheritance_chain_type_names, inherited_type_name); } @@ -1339,13 +1197,13 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1.f, df_rgba_from_theme_color(DF_ThemeColor_CodeType), inheritance_type); } } - if(sig.hovering && DEV_eval_watch_key_tooltips) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Code)) + if(DEV_eval_watch_key_tooltips && ui_hovering(sig)) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Code)) { ui_labelf("Parent Key: %I64x, %I64x", row->parent_key.parent_hash, row->parent_key.child_num); ui_labelf("Hover Key: %I64x, %I64x", row->key.parent_hash, row->key.child_num); ui_labelf("Cursor Key: %I64x, %I64x", ewv->cursor.key.parent_hash, ewv->cursor.key.child_num); } - if(sig.hovering && row->depth == 0 && DEV_eval_compiler_tooltips) UI_Tooltip + if(DEV_eval_compiler_tooltips && row->depth == 0 && ui_hovering(sig)) UI_Tooltip { Temp scratch = scratch_begin(0, 0); String8 string = row->expr; @@ -1378,9 +1236,9 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW if(parse.expr != &eval_expr_nil && errors.count == 0) { ui_labelf("Type:"); - ir_tree_and_type = eval_irtree_and_type_from_expr(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, &eval_string2expr_map_nil, parse.expr, &errors); + ir_tree_and_type = eval_irtree_and_type_from_expr(scratch.arena, parse_ctx.type_graph, parse_ctx.rdi, &eval_string2expr_map_nil, parse.expr, &errors); TG_Key type_key = ir_tree_and_type.type_key; - String8 type_string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, type_key); + String8 type_string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdi, type_key); UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(type_string); } @@ -1394,7 +1252,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW } // rjf: press -> commit if editing & select - if(sig.pressed) + if(ui_pressed(sig)) { edit_commit = edit_commit || (!cell_selected && ewv->input_editing); next_cursor_tbl = v2s64(DF_EvalWatchViewColumnKind_Expr, (semantic_idx+1)); @@ -1408,7 +1266,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW } // rjf: double-click -> start editing - if(sig.double_clicked && !ewv->input_editing && can_edit_expr) + if(ui_double_clicked(sig) && !ewv->input_editing && can_edit_expr) { ui_kill_action(); ewv->input_editing = 1; @@ -1494,18 +1352,18 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW if(value_is_simple) { sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, 0, &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, 0, row->display_value, "%S###val_%I64x", row->display_value, row_hash); - edit_commit = (edit_commit || sig.commit); + edit_commit = (edit_commit || ui_committed(sig)); } } // rjf: bad & hovering -> display - if(row_is_bad && sig.hovering) UI_Tooltip + if(row_is_bad && ui_hovering(sig)) UI_Tooltip { UI_PrefWidth(ui_children_sum(1)) df_error_label(str8_lit("Could not read process memory successfully.")); } // rjf: press -> focus & commit if editing & not selected - if(sig.pressed) + if(ui_pressed(sig)) { pressed = 1; edit_commit = edit_commit || (ewv->input_editing && !cell_selected); @@ -1513,7 +1371,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW } // rjf: double-click -> start editing - if(sig.double_clicked && value_is_simple) + if(ui_double_clicked(sig) && value_is_simple) { ui_kill_action(); ewv->input_editing = 1; @@ -1533,7 +1391,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW UI_FocusActive((cell_selected && ewv->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { TG_Key key = row->eval.type_key; - String8 string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, key); + String8 string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdi, key); string = str8_skip_chop_whitespace(string); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###type_%I64x", row_hash); if(!tg_key_match(key, tg_key_zero())) UI_Parent(box) @@ -1541,7 +1399,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeType), string); } UI_Signal sig = ui_signal_from_box(box); - if(sig.pressed) + if(ui_pressed(sig)) { pressed = 1; edit_commit = edit_commit || (ewv->input_editing && !cell_selected); @@ -1575,11 +1433,11 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW { rule_editing_active = ui_is_focus_active(); sig = df_line_editf(DF_LineEditFlag_CodeContents|DF_LineEditFlag_NoBackground, 0, 0, &ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, 0, view_rule, "###view_rule_%I64x", row_hash); - edit_commit = edit_commit || sig.commit; + edit_commit = edit_commit || ui_committed(sig); } // rjf: press -> commit if not selected, select this cell - if(sig.pressed) + if(ui_pressed(sig)) { pressed = 1; edit_commit = edit_commit || (ewv->input_editing && !cell_selected); @@ -1587,7 +1445,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW } // rjf: double-click -> begin editing - if(sig.double_clicked && !ewv->input_editing) + if(ui_double_clicked(sig) && !ewv->input_editing) { ui_kill_action(); ewv->input_editing = 1; @@ -1624,7 +1482,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW { DF_EvalWatchViewColumnKind commit_column = (DF_EvalWatchViewColumnKind)cursor_tbl.x; cursor_tbl = next_cursor_tbl; - if(edit_commit) + if(commit_row != 0 && edit_commit) { ewv->input_editing = 0; String8 commit_string = str8(ewv->input_buffer, ewv->input_size); @@ -1653,6 +1511,10 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW if(!root && df_expand_key_match(commit_row->key, empty_row_key)) { root = df_eval_root_alloc(view, ewv); + DF_ExpandKey parent_key = df_parent_expand_key_from_eval_root(root); + DF_ExpandKey key = df_expand_key_from_eval_root(root); + df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, parent_key, key, 0); + df_eval_view_set_key_rule(eval_view, key, str8_lit("")); } if(root != 0) { @@ -1666,7 +1528,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW { Temp scratch = scratch_begin(0, 0); DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, commit_string); - B32 success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdbg, &ctrl_ctx, commit_row->eval, write_eval); + B32 success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, commit_row->eval, write_eval); if(success == 0) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); @@ -1807,7 +1669,7 @@ DF_VIEW_UI_FUNCTION_DEF(Empty) UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) - if(df_icon_buttonf(DF_IconKind_Add, 0, "Add Target").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Add, 0, "Add Target"))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_AddTarget); @@ -1832,7 +1694,7 @@ DF_VIEW_UI_FUNCTION_DEF(Empty) UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) { - if(df_icon_buttonf(DF_IconKind_Play, 0, "Launch %S", target_name).clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Play, 0, "Launch %S", target_name))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.entity = df_handle_from_entity(target); @@ -1840,7 +1702,7 @@ DF_VIEW_UI_FUNCTION_DEF(Empty) df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); } ui_spacer(ui_em(1.5f, 1)); - if(df_icon_buttonf(DF_IconKind_Play, 0, "Step Into %S", target_name).clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Play, 0, "Step Into %S", target_name))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.entity = df_handle_from_entity(target); @@ -2057,14 +1919,14 @@ DF_VIEW_UI_FUNCTION_DEF(Commands) //- rjf: interact UI_Signal sig = ui_signal_from_box(box); - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = item->cmd_spec; df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CompleteQuery)); } - if(sig.right_clicked) + if(ui_right_clicked(sig)) { ui_ctx_menu_open(item_ctx_menu_key, ui_key_zero(), sub_2f32(ui_mouse(), v2f32(2, 2))); } @@ -2357,7 +2219,7 @@ DF_VIEW_UI_FUNCTION_DEF(FileSystem) UI_Signal sig = ui_sort_header(sorting, fs->cached_files_sort_side == Side_Min, kinds[idx].string); - if(sig.clicked) + if(ui_clicked(sig)) { if(fs->sort_kind != kinds[idx].kind) { @@ -2429,7 +2291,7 @@ DF_VIEW_UI_FUNCTION_DEF(FileSystem) } // rjf: click => up one directory - if(sig.clicked) + if(ui_clicked(sig)) { String8 new_path = str8_chop_last_slash(str8_chop_last_slash(path_query.path)); if(new_path.size != 0) @@ -2511,7 +2373,7 @@ DF_VIEW_UI_FUNCTION_DEF(FileSystem) } // rjf: click => activate this file - if(file_sig.clicked) + if(ui_clicked(file_sig)) { String8 existing_path = str8_chop_last_slash(path_query.path); String8 new_path = push_str8f(scratch.arena, "%S/%S/", existing_path, file->filename); @@ -2679,7 +2541,7 @@ DF_VIEW_UI_FUNCTION_DEF(SystemProcesses) } // rjf: click => activate this specific process - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.id = info->info.pid; @@ -2829,7 +2691,7 @@ DF_VIEW_UI_FUNCTION_DEF(EntityLister) UI_Box *name_label = ui_build_box_from_stringf(UI_BoxFlag_DrawText, "%S##label_%p", display_string, ent); ui_box_equip_fuzzy_match_ranges(name_label, &item.name_match_ranges); } - if(ui_signal_from_box(box).clicked) + if(ui_clicked(ui_signal_from_box(box))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.entity = df_handle_from_entity(ent); @@ -2893,7 +2755,7 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: query -> raddbg, filtered items U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, os_now_microseconds()+100); - RADDBG_Parsed *rdbg = &dbgi->rdbg; + RDI_Parsed *rdi = &dbgi->rdi; B32 items_stale = 0; DBGI_FuzzySearchItemArray items = dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, query, DBGI_FuzzySearchTarget_Procedures, os_now_microseconds()+100, &items_stale); if(items_stale) @@ -2904,9 +2766,9 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: submit best match when hitting enter w/ no selection if(slv->cursor.y == 0 && items.count != 0 && os_key_press(ui_events(), ui_window(), 0, OS_Key_Return)) { - RADDBG_Procedure *procedure = raddbg_element_from_idx(rdbg, procedures, items.v[0].idx); + RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, items.v[0].idx); U64 name_size = 0; - U8 *name_base = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size); + 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) { @@ -2942,12 +2804,12 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) UI_Focus((slv->cursor.y == idx+1) ? UI_FocusKind_On : UI_FocusKind_Off) { DBGI_FuzzySearchItem *item = &items.v[idx]; - RADDBG_Procedure *procedure = raddbg_element_from_idx(rdbg, procedures, item->idx); + RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx); U64 name_size = 0; - U8 *name_base = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size); + U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); String8 name = str8(name_base, name_size); - RADDBG_TypeNode *type_node = raddbg_element_from_idx(rdbg, type_nodes, procedure->type_idx); - TG_Key type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), procedure->type_idx); + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, procedure->type_idx); + TG_Key type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), procedure->type_idx); ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBackground| @@ -2962,19 +2824,19 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) ui_box_equip_fuzzy_match_ranges(box, &item->match_ranges); if(!tg_key_match(tg_key_zero(), type_key)) { - String8 type_string = tg_string_from_key(scratch.arena, graph, rdbg, type_key); + String8 type_string = tg_string_from_key(scratch.arena, graph, rdi, type_key); df_code_label(0.5f, 0, df_rgba_from_theme_color(DF_ThemeColor_WeakText), type_string); } } UI_Signal sig = ui_signal_from_box(box); - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); p.string = name; df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CompleteQuery)); } - if(sig.hovering) UI_Tooltip + if(ui_hovering(sig)) UI_Tooltip { U64 binary_voff = df_voff_from_binary_symbol_name(binary, name); DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, binary_voff); @@ -3221,18 +3083,18 @@ DF_VIEW_UI_FUNCTION_DEF(Target) UI_FocusActive((value_selected && tv->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &tv->input_cursor, &tv->input_mark, tv->input_buffer, sizeof(tv->input_buffer), &tv->input_size, 0, kv_info[idx].current_text, "###kv_editor_%i", (S32)idx); - edit_commit = edit_commit || sig.commit; + edit_commit = edit_commit || ui_committed(sig); } // rjf: focus panel on press - if(sig.pressed) + if(ui_pressed(sig)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } // rjf: begin editing on double-click - if(!tv->input_editing && sig.double_clicked) + if(!tv->input_editing && ui_double_clicked(sig)) { ui_kill_action(); tv->input_editing = 1; @@ -3243,7 +3105,7 @@ DF_VIEW_UI_FUNCTION_DEF(Target) } // rjf: press on non-selected => commit edit, change selected cell - if(sig.pressed && !value_selected) + if(ui_pressed(sig) && !value_selected) { edit_end = 1; edit_commit = tv->input_editing; @@ -3251,7 +3113,7 @@ DF_VIEW_UI_FUNCTION_DEF(Target) } // rjf: apply commit deltas - if(sig.commit) + if(ui_committed(sig)) { next_cursor.y += 1; } @@ -3268,7 +3130,7 @@ DF_VIEW_UI_FUNCTION_DEF(Target) { UI_FocusHot((row_selected && next_cursor.x == 1) ? UI_FocusKind_On : UI_FocusKind_Off) UI_TextAlignment(UI_TextAlign_Center) - if(ui_buttonf("Browse...").clicked) + if(ui_clicked(ui_buttonf("Browse..."))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(kv_info[idx].fill_with_file ? DF_CoreCmdKind_PickFile : DF_CoreCmdKind_PickFolder); @@ -3402,7 +3264,7 @@ DF_VIEW_UI_FUNCTION_DEF(Targets) UI_Signal add_sig = {0}; UI_FocusHot(cursor.y == 1 ? UI_FocusKind_On : UI_FocusKind_Off) add_sig = df_icon_buttonf(DF_IconKind_Add, 0, "Add New Target"); - if(add_sig.clicked) + if(ui_clicked(add_sig)) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_AddTarget); @@ -3425,13 +3287,13 @@ DF_VIEW_UI_FUNCTION_DEF(Targets) UI_FocusHot((row_selected && cursor.x == 0) ? UI_FocusKind_On : UI_FocusKind_Off) { UI_Signal sig = df_icon_buttonf(target->b32 ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, 0, "###ebl_%p", target); - if(sig.clicked && sig.event_flags == 0) + if(ui_clicked(sig) && sig.event_flags == 0) { DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); p.entity = df_handle_from_entity(target); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SelectTarget)); } - else if(sig.clicked && sig.event_flags == OS_EventFlag_Ctrl) + else if(ui_clicked(sig) && sig.event_flags == OS_EventFlag_Ctrl) { DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); p.entity = df_handle_from_entity(target); @@ -3468,11 +3330,11 @@ DF_VIEW_UI_FUNCTION_DEF(Targets) { sig = df_icon_buttonf(ctrls[ctrl_idx].icon, 0, "###%p_ctrl_%i", target, (int)ctrl_idx); } - if(sig.hovering) UI_Tooltip + if(ui_hovering(sig)) UI_Tooltip { ui_label(ctrls[ctrl_idx].text); } - if(sig.clicked) + if(ui_clicked(sig)) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.entity = df_handle_from_entity(target); @@ -3675,18 +3537,18 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) UI_FocusActive((value_selected && fpms->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &fpms->input_cursor, &fpms->input_mark, fpms->input_buffer, sizeof(fpms->input_buffer), &fpms->input_size, 0, map_src_path, "###src_editor_%p", map); - edit_commit = edit_commit || sig.commit; + edit_commit = edit_commit || ui_committed(sig); } // rjf: focus panel on press - if(sig.pressed) + if(ui_pressed(sig)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } // rjf: begin editing on double-click - if(!fpms->input_editing && sig.double_clicked) + if(!fpms->input_editing && ui_double_clicked(sig)) { fpms->input_editing = 1; fpms->input_size = Min(sizeof(fpms->input_buffer), map_src_path.size); @@ -3696,7 +3558,7 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) } // rjf: press on non-selected => commit edit, change selected cell - if(sig.pressed && !value_selected) + if(ui_pressed(sig) && !value_selected) { edit_end = 1; edit_commit = fpms->input_editing; @@ -3715,7 +3577,7 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) //- rjf: browse button UI_FocusHot((row_selected && fpms->cursor.x == 1) ? UI_FocusKind_On : UI_FocusKind_Off) UI_PrefWidth(ui_text_dim(10, 1)) - if(ui_buttonf("Browse...").clicked) + if(ui_clicked(ui_buttonf("Browse..."))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFileOrFolder); @@ -3749,18 +3611,18 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) UI_FocusActive((value_selected && fpms->input_editing) ? UI_FocusKind_On : UI_FocusKind_Off) { sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &fpms->input_cursor, &fpms->input_mark, fpms->input_buffer, sizeof(fpms->input_buffer), &fpms->input_size, 0, map_dst_path, "###dst_editor_%p", map); - edit_commit = edit_commit || sig.commit; + edit_commit = edit_commit || ui_committed(sig); } // rjf: focus panel on press - if(sig.pressed) + if(ui_pressed(sig)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } // rjf: begin editing on double-click - if(!fpms->input_editing && sig.double_clicked) + if(!fpms->input_editing && ui_double_clicked(sig)) { fpms->input_editing = 1; fpms->input_size = Min(sizeof(fpms->input_buffer), map_dst_path.size); @@ -3770,7 +3632,7 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) } // rjf: press on non-selected => commit edit, change selected cell - if(sig.pressed && !value_selected) + if(ui_pressed(sig) && !value_selected) { edit_end = 1; edit_commit = fpms->input_editing; @@ -3790,7 +3652,7 @@ DF_VIEW_UI_FUNCTION_DEF(FilePathMap) { UI_FocusHot((row_selected && fpms->cursor.x == 3) ? UI_FocusKind_On : UI_FocusKind_Off) UI_PrefWidth(ui_text_dim(10, 1)) - if(ui_buttonf("Browse...").clicked) + if(ui_clicked(ui_buttonf("Browse..."))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFileOrFolder); @@ -3984,11 +3846,11 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) } sig = df_icon_buttonf(frozen ? DF_IconKind_Locked : DF_IconKind_Unlocked, 0, "###lock_%p", entity); } - if(frozen_by_solo_mode && sig.hovering) UI_Tooltip + if(frozen_by_solo_mode && ui_hovering(sig)) UI_Tooltip { ui_label(str8_lit("This thread is frozen during stepping operations because it isn't selected, and Solo Stepping Mode is enabled.")); } - if(sig.clicked) + if(ui_clicked(sig)) { DF_CoreCmdKind cmd_kind = frozen ? DF_CoreCmdKind_ThawEntity : DF_CoreCmdKind_FreezeEntity; DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); @@ -4015,7 +3877,7 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) { UI_PrefWidth(ui_text_dim(10, 1)) UI_TextAlignment(UI_TextAlign_Center) - if(ui_buttonf("Detach").clicked) + if(ui_clicked(ui_buttonf("Detach"))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.entity = df_handle_from_entity(entity); @@ -4027,7 +3889,7 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) } UI_TableCellSized(ui_em(2.25f, 1.f)) UI_FocusHot((row_is_selected && cursor.x == 3) ? UI_FocusKind_On : UI_FocusKind_Off) { - if(df_icon_buttonf(DF_IconKind_Redo, 0, "###retry").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Redo, 0, "###retry"))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); df_handle_list_push(scratch.arena, ¶ms.entity_list, df_handle_from_entity(entity)); @@ -4040,7 +3902,7 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureText)) UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBorder)) - if(df_icon_buttonf(DF_IconKind_X, 0, "###kill").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_X, 0, "###kill"))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); df_handle_list_push(scratch.arena, ¶ms.entity_list, df_handle_from_entity(entity)); @@ -4195,13 +4057,13 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%S###selection_%i", selected_string, (int)frame_idx); UI_Signal sig = ui_signal_from_box(box); - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(0, (S64)frame_idx+1); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } - if(sig.double_clicked || sig.keyboard_clicked) + if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.index = frame_idx; @@ -4217,7 +4079,7 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) { UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "(No Module)###moduleless_frame_%I64x", frame_idx); UI_Signal sig = ui_signal_from_box(box); - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(1, (S64)frame_idx+1); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); @@ -4246,13 +4108,13 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) } UI_Box *box = ui_build_box_from_string(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, symbol); UI_Signal sig = ui_signal_from_box(box); - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(2, (S64)frame_idx+1); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } - if(sig.double_clicked || sig.keyboard_clicked) + if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.index = frame_idx; @@ -4267,13 +4129,13 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) { UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "0x%I64x", rip_vaddr); UI_Signal sig = ui_signal_from_box(box); - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(3, (S64)frame_idx+1); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } - if(sig.double_clicked || sig.keyboard_clicked) + if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.index = frame_idx; @@ -4507,7 +4369,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { UI_Box *range_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "[0x%I64x, 0x%I64x)###vaddr_range_%p", entity->vaddr_rng.min, entity->vaddr_rng.max, entity); UI_Signal sig = ui_signal_from_box(range_box); - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(1, (S64)idx+1); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); @@ -4542,11 +4404,11 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { UI_TextColor(!dbgi_is_valid ? df_rgba_from_theme_color(DF_ThemeColor_FailureBackground) : ui_top_text_color()) sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &mv->txt_cursor, &mv->txt_mark, mv->txt_buffer, sizeof(mv->txt_buffer), &mv->txt_size, 0, dbgi->dbg_path, "###dbg_path_%p", entity); - edit_commit = (edit_commit || sig.commit); + edit_commit = (edit_commit || ui_committed(sig)); } // rjf: press -> focus - if(sig.pressed) + if(ui_pressed(sig)) { edit_commit = (mv->txt_editing && !txt_is_selected); next_cursor = v2s64(2, (S64)idx+1); @@ -4555,7 +4417,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) } // rjf: double-click -> begin editing - if(sig.double_clicked && !mv->txt_editing) + if(ui_double_clicked(sig) && !mv->txt_editing) { ui_kill_action(); mv->txt_editing = 1; @@ -4574,7 +4436,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) // rjf: build browse button UI_FocusHot(brw_is_selected ? UI_FocusKind_On : UI_FocusKind_Off) UI_PrefWidth(ui_text_dim(10, 1)) { - if(ui_buttonf("Browse...").clicked || (brw_is_selected && edit_begin)) + if(ui_clicked(ui_buttonf("Browse...")) || (brw_is_selected && edit_begin)) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); @@ -4775,7 +4637,7 @@ DF_VIEW_UI_FUNCTION_DEF(PendingEntity) UI_CornerRadius(ui_top_font_size()/3) UI_PrefWidth(ui_text_dim(10, 1)) UI_Focus(UI_FocusKind_On) - if(ui_buttonf("Find alternative...").clicked) + if(ui_clicked(ui_buttonf("Find alternative..."))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); @@ -4825,7 +4687,7 @@ DF_VIEW_SETUP_FUNCTION_DEF(Code) // rjf: default to loading df_view_equip_loading_info(view, 1, 0, 0); - view->loading_t_target = 1.f; + view->loading_t = view->loading_t_target = 1.f; } DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Code) @@ -4933,46 +4795,85 @@ DF_VIEW_CMD_FUNCTION_DEF(Code) case DF_CoreCmdKind_GoToNameAtCursor: { Temp scratch = scratch_begin(0, 0); - TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); - TxtRng expr_range = txt_rng(tv->cursor, tv->mark); - if(txt_pt_match(tv->cursor, tv->mark)) + TXT_Scope *txt_scope = txt_scope_open(); + HS_Scope *hs_scope = hs_scope_open(); { - expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + // rjf: unpack entity info + String8 path = df_full_path_from_entity(scratch.arena, entity); + U128 key = fs_key_from_path(path); + TXT_LangKind lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(path)); + U128 hash = {0}; + TXT_TextInfo text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + String8 data = hs_data_from_hash(hs_scope, hash); + + // rjf: determine expression range + Rng1U64 expr_range = {0}; + { + TxtRng selection_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(selection_range.min, selection_range.max)) + { + expr_range = txt_expr_off_range_from_info_data_pt(&text_info, data, tv->cursor); + } + else + { + expr_range = r1u64(txt_off_from_info_pt(&text_info, selection_range.min), txt_off_from_info_pt(&text_info, selection_range.max)); + } + } + + // rjf: expression range -> text + String8 expr_text = str8_substr(data, expr_range); + + // rjf: go to name + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.entity = df_handle_from_entity(entity); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); } - String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); - - // rjf: go to name - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.entity = df_handle_from_entity(entity); - params.string = expr_text; - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); - + hs_scope_close(hs_scope); + txt_scope_close(txt_scope); scratch_end(scratch); }break; case DF_CoreCmdKind_ToggleWatchExpressionAtCursor: { Temp scratch = scratch_begin(0, 0); - TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); - TxtRng expr_range = txt_rng(tv->cursor, tv->mark); - if(txt_pt_match(tv->cursor, tv->mark)) + TXT_Scope *txt_scope = txt_scope_open(); + HS_Scope *hs_scope = hs_scope_open(); { - expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + // rjf: unpack entity info + String8 path = df_full_path_from_entity(scratch.arena, entity); + U128 key = fs_key_from_path(path); + TXT_LangKind lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(path)); + U128 hash = {0}; + TXT_TextInfo text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + String8 data = hs_data_from_hash(hs_scope, hash); + + // rjf: determine expression range + Rng1U64 expr_range = {0}; + { + TxtRng selection_range = txt_rng(tv->cursor, tv->mark); + if(txt_pt_match(selection_range.min, selection_range.max)) + { + expr_range = txt_expr_off_range_from_info_data_pt(&text_info, data, tv->cursor); + } + else + { + expr_range = r1u64(txt_off_from_info_pt(&text_info, selection_range.min), txt_off_from_info_pt(&text_info, selection_range.max)); + } + } + + // rjf: expression range -> text + String8 expr_text = str8_substr(data, expr_range); + + // rjf: toggle watch expr + DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); + params.string = expr_text; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); + scratch_end(scratch); } - String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); - - // rjf: toggle watch expr - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.string = expr_text; - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); - - // rjf: flash marker for grabbed expr - DF_Entity *flash_marker = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); - df_entity_equip_death_timer(flash_marker, 0.5f); - df_entity_equip_txt_pt(flash_marker, expr_range.min); - df_entity_equip_txt_pt_alt(flash_marker, expr_range.max); - df_entity_equip_color_rgba(flash_marker, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); + hs_scope_close(hs_scope); + txt_scope_close(txt_scope); scratch_end(scratch); }break; case DF_CoreCmdKind_PickFile: @@ -4999,7 +4900,9 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + HS_Scope *hs_scope = hs_scope_open(); + DBGI_Scope *dbgi_scope = dbgi_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); ////////////////////////////// @@ -5025,23 +4928,26 @@ DF_VIEW_UI_FUNCTION_DEF(Code) U64 unwind_count = ctrl_ctx.unwind_count; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, process, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, process, rip_vaddr); ////////////////////////////// - //- rjf: unpack entity info + //- rjf: unpack file/text entity info // B32 entity_is_missing = !!(entity->flags & DF_EntityFlag_IsMissing && !(entity->flags & DF_EntityFlag_Output)); - TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); - TXTI_BufferInfo txti_buffer_info = txti_buffer_info_from_handle(scratch.arena, txti_handle); - B32 txti_buffer_is_ready = ((txti_buffer_info.timestamp != 0 || entity->flags & DF_EntityFlag_Output) && - (txti_buffer_info.bytes_processed == txti_buffer_info.bytes_to_process || txti_buffer_info.buffer_apply_gen != 0)); + String8 path = df_full_path_from_entity(scratch.arena, entity); + U128 key = fs_key_from_path(path); + TXT_LangKind lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(path)); + U128 hash = {0}; + TXT_TextInfo text_info = txt_text_info_from_key_lang(txt_scope, key, lang_kind, &hash); + String8 data = hs_data_from_hash(hs_scope, hash); + B32 text_info_is_ready = (text_info.lines_count != 0); ////////////////////////////// //- rjf: buffer is pending -> equip view with loading information // - if(!entity_is_missing && !txti_buffer_is_ready) + if(!entity_is_missing && !text_info_is_ready) { - df_view_equip_loading_info(view, 1, txti_buffer_info.bytes_processed, txti_buffer_info.bytes_to_process); + df_view_equip_loading_info(view, 1, text_info.bytes_processed, text_info.bytes_to_process); } ////////////////////////////// @@ -5053,12 +4959,12 @@ DF_VIEW_UI_FUNCTION_DEF(Code) view->scroll_pos.y.idx + 1 + num_possible_visible_lines); U64 visible_line_count = 0; { - visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)txti_buffer_info.total_line_count); - visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)txti_buffer_info.total_line_count); + visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)text_info.lines_count); + visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)text_info.lines_count); visible_line_num_range.min = Max(1, visible_line_num_range.min); visible_line_num_range.max = Max(1, visible_line_num_range.max); - target_visible_line_num_range.min = Clamp(1, target_visible_line_num_range.min, (S64)txti_buffer_info.total_line_count); - target_visible_line_num_range.max = Clamp(1, target_visible_line_num_range.max, (S64)txti_buffer_info.total_line_count); + target_visible_line_num_range.min = Clamp(1, target_visible_line_num_range.min, (S64)text_info.lines_count); + target_visible_line_num_range.max = Clamp(1, target_visible_line_num_range.max, (S64)text_info.lines_count); target_visible_line_num_range.min = Max(1, target_visible_line_num_range.min); target_visible_line_num_range.max = Max(1, target_visible_line_num_range.max); visible_line_count = (U64)dim_1s64(visible_line_num_range)+1; @@ -5070,11 +4976,11 @@ DF_VIEW_UI_FUNCTION_DEF(Code) S64 line_size_x = 0; Rng1S64 scroll_idx_rng[Axis2_COUNT] = {0}; { - line_size_x = (txti_buffer_info.max_line_size*big_glyph_advance*3)/2; + line_size_x = (text_info.lines_max_size*big_glyph_advance*3)/2; line_size_x = ClampBot(line_size_x, (S64)big_glyph_advance*120); line_size_x = ClampBot(line_size_x, (S64)code_area_dim.x); scroll_idx_rng[Axis2_X] = r1s64(0, line_size_x-(S64)code_area_dim.x); - scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)txti_buffer_info.total_line_count-1); + scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)text_info.lines_count-1); } ////////////////////////////// @@ -5082,7 +4988,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) // F32 margin_width_px = big_glyph_advance*3.5f; F32 line_num_width_px = big_glyph_advance * (log10(visible_line_num_range.max) + 3); - TXTI_Slice slice = txti_slice_from_handle_line_range(scratch.arena, txti_handle, visible_line_num_range); + TXT_LineTokensSlice slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, &text_info, data, visible_line_num_range); ////////////////////////////// //- rjf: get active search query @@ -5105,19 +5011,19 @@ DF_VIEW_UI_FUNCTION_DEF(Code) //- rjf: prepare code slice info bundle, for the viewable region of text // DF_CodeSliceParams code_slice_params = {0}; - if(txti_buffer_is_ready) + if(text_info_is_ready) { // rjf: fill basics - code_slice_params.flags = DF_CodeSliceFlag_Margin|DF_CodeSliceFlag_LineNums; + code_slice_params.flags = DF_CodeSliceFlag_Margin|DF_CodeSliceFlag_LineNums|DF_CodeSliceFlag_Clickable; code_slice_params.line_num_range = visible_line_num_range; - code_slice_params.line_text = slice.line_text; - code_slice_params.line_ranges = slice.line_ranges; - code_slice_params.line_tokens = slice.line_tokens; - code_slice_params.line_bps = push_array(scratch.arena, DF_EntityList, slice.line_count); - code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, slice.line_count); - code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, slice.line_count); - code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, slice.line_count); - code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, slice.line_count); + 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, DF_EntityList, visible_line_count); + code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, visible_line_count); + code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, visible_line_count); + code_slice_params.line_dasm2src = push_array(scratch.arena, DF_TextLineDasm2SrcInfoList, visible_line_count); + code_slice_params.line_src2dasm = push_array(scratch.arena, DF_TextLineSrc2DasmInfoList, visible_line_count); code_slice_params.font = code_font; code_slice_params.font_size = code_font_size; code_slice_params.line_height_px = code_line_height; @@ -5127,6 +5033,18 @@ DF_VIEW_UI_FUNCTION_DEF(Code) code_slice_params.line_text_max_width_px = (F32)line_size_x; code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, entity, DF_EntityKind_FlashMarker); + // rjf: fill text info + { + S64 line_num = visible_line_num_range.min; + U64 line_idx = visible_line_num_range.min-1; + for(U64 visible_line_idx = 0; visible_line_idx < visible_line_count; visible_line_idx += 1, line_idx += 1, line_num += 1) + { + code_slice_params.line_text[visible_line_idx] = str8_substr(data, text_info.lines_ranges[line_idx]); + code_slice_params.line_ranges[visible_line_idx] = text_info.lines_ranges[line_idx]; + code_slice_params.line_tokens[visible_line_idx] = slice.line_tokens[visible_line_idx]; + } + } + // rjf: find visible breakpoints ProfScope("find visible breakpoints") { @@ -5217,7 +5135,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) UI_CornerRadius(ui_top_font_size()/3) UI_PrefWidth(ui_text_dim(10, 1)) UI_Focus(UI_FocusKind_On) - if(ui_buttonf("Find alternative...").clicked) + if(ui_clicked(ui_buttonf("Find alternative..."))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); @@ -5233,7 +5151,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) //- rjf: build container // UI_Box *container_box = &ui_g_nil_box; - if(txti_buffer_is_ready) + if(text_info_is_ready) { ui_set_next_pref_width(ui_px(code_area_dim.x, 1)); ui_set_next_pref_height(ui_px(code_area_dim.y, 1)); @@ -5254,21 +5172,10 @@ DF_VIEW_UI_FUNCTION_DEF(Code) tv->center_cursor = 1; } - ////////////////////////////// - //- rjf: search query -> matches - // - DF_TextSearchMatchArray search_query_matches = {0}; -#if 0 - { - search_query_matches = df_text_search_match_array_from_entity_needle(scratch.arena, entity, search_query, entity_line_string_flags, tv->cursor); - df_text_search_match_array_sort_in_place(&search_query_matches); - } -#endif - ////////////////////////////// //- rjf: do searching operations // - if(txti_buffer_is_ready) + if(text_info_is_ready) { //- rjf: find text (forward) if(tv->find_text_fwd.size != 0) @@ -5277,14 +5184,14 @@ DF_VIEW_UI_FUNCTION_DEF(Code) B32 found = 0; B32 first = 1; S64 line_num_start = tv->cursor.line; - S64 line_num_last = (S64)txti_buffer_info.total_line_count; + S64 line_num_last = (S64)text_info.lines_count; for(S64 line_num = line_num_start;; first = 0) { // rjf: pop scratch temp_end(scratch); // rjf: gather line info - String8 line_string = txti_string_from_handle_line_num(scratch.arena, txti_handle, line_num); + String8 line_string = str8_substr(data, text_info.lines_ranges[line_num-1]); U64 search_start = 0; if(tv->cursor.line == line_num && first) { @@ -5333,14 +5240,14 @@ DF_VIEW_UI_FUNCTION_DEF(Code) B32 found = 0; B32 first = 1; S64 line_num_start = tv->cursor.line; - S64 line_num_last = (S64)txti_buffer_info.total_line_count; + S64 line_num_last = (S64)text_info.lines_count; for(S64 line_num = line_num_start;; first = 0) { // rjf: pop scratch temp_end(scratch); // rjf: gather line info - String8 line_string = txti_string_from_handle_line_num(scratch.arena, txti_handle, line_num); + String8 line_string = str8_substr(data, text_info.lines_ranges[line_num-1]); if(tv->cursor.line == line_num && first) { line_string = str8_prefix(line_string, tv->cursor.column-1); @@ -5398,13 +5305,13 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ////////////////////////////// //- rjf: do goto line // - if(txti_buffer_is_ready) if(tv->goto_line_num != 0) + if(text_info_is_ready) if(tv->goto_line_num != 0) { S64 line_num = tv->goto_line_num; tv->goto_line_num = 0; - line_num = Clamp(1, line_num, txti_buffer_info.total_line_count); + line_num = Clamp(1, line_num, text_info.lines_count); tv->cursor = tv->mark = txt_pt(line_num, 1); - tv->center_cursor = !tv->contain_cursor || (line_num < target_visible_line_num_range.min+8 || target_visible_line_num_range.max-8 < line_num); + tv->center_cursor = !tv->contain_cursor || (line_num < target_visible_line_num_range.min+4 || target_visible_line_num_range.max-4 < line_num); } ////////////////////////////// @@ -5413,16 +5320,16 @@ DF_VIEW_UI_FUNCTION_DEF(Code) B32 snap[Axis2_COUNT] = {0}; UI_Focus(UI_FocusKind_On) { - if(txti_buffer_is_ready && visible_line_num_range.max >= visible_line_num_range.min && ui_is_focus_active()) + if(ui_is_focus_active() && text_info_is_ready && visible_line_num_range.max >= visible_line_num_range.min) { - snap[Axis2_X] = snap[Axis2_Y] = df_do_txti_controls(txti_handle, ClampBot(num_possible_visible_lines, 10) - 10, &tv->cursor, &tv->mark, &tv->preferred_column); + snap[Axis2_X] = snap[Axis2_Y] = df_do_txt_controls(&text_info, data, ClampBot(num_possible_visible_lines, 10) - 10, &tv->cursor, &tv->mark, &tv->preferred_column); } } ////////////////////////////// //- rjf: build container contents // - if(txti_buffer_is_ready) UI_Parent(container_box) + if(text_info_is_ready) UI_Parent(container_box) { //- rjf: build fractional space container_box->view_off.x = container_box->view_off_target.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; @@ -5436,13 +5343,13 @@ DF_VIEW_UI_FUNCTION_DEF(Code) } //- rjf: hover eval - if(!sig.base.dragging && sig.mouse_expr_rng.min.line != 0 && sig.base.event_flags == 0) + if(!ui_dragging(sig.base) && sig.mouse_expr_rng.min.line != 0 && sig.base.event_flags == 0) { TxtRng expr_rng = sig.mouse_expr_rng; - String8 expr = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_rng); + String8 expr = txt_string_from_info_data_txt_rng(&text_info, data, expr_rng); if(expr.size != 0) { - DF_Eval eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); if(eval.mode != EVAL_EvalMode_NULL) { df_set_hover_eval(ws, sig.mouse_expr_baseline_pos, ctrl_ctx, entity, sig.mouse_pt, 0, expr); @@ -5451,25 +5358,25 @@ DF_VIEW_UI_FUNCTION_DEF(Code) } //- rjf: press code slice? -> focus panel - if(sig.base.pressed) + if(ui_pressed(sig.base)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } //- rjf: dragging? -> contain cursor - if(sig.base.dragging && sig.base.event_flags == 0) + if(ui_dragging(sig.base) && sig.base.event_flags == 0) { tv->contain_cursor = 1; } //- rjf: ctrl+pressed? -> go to name - if(sig.base.pressed && sig.base.event_flags & OS_EventFlag_Ctrl) + if(ui_pressed(sig.base) && sig.base.event_flags & OS_EventFlag_Ctrl) { ui_kill_action(); DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.entity = df_handle_from_entity(entity); - params.string = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, txti_expr_range_from_handle_pt(txti_handle, sig.mouse_pt)); + params.string = txt_string_from_info_data_txt_rng(&text_info, data, sig.mouse_expr_rng); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); } @@ -5535,15 +5442,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) //- rjf: copy text if(!txt_pt_match(sig.copy_range.min, sig.copy_range.max)) { - Temp temp = temp_begin(scratch.arena); - DF_Entity *flash_range = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); - df_entity_equip_death_timer(flash_range, 0.5f); - df_entity_equip_color_rgba(flash_range, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); - df_entity_equip_txt_pt(flash_range, sig.copy_range.min); - df_entity_equip_txt_pt_alt(flash_range, sig.copy_range.max); - String8 text = txti_string_from_handle_txt_rng(temp.arena, txti_handle, sig.copy_range); + String8 text = txt_string_from_info_data_txt_rng(&text_info, data, sig.copy_range); os_set_clipboard_text(text); - temp_end(temp); } //- rjf: toggle cursor watch @@ -5605,25 +5505,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ////////////////////////////// //- rjf: apply post-build view snapping rules // - if(txti_buffer_is_ready) + if(text_info_is_ready) { - // rjf: center first match - TxtPt next_match = df_text_search_match_array_find_nearest__linear_scan(&search_query_matches, tv->cursor, search_query_side).pt; - if(search_query.size != 0 && next_match.line != 0) - { - // TODO(rjf): [ ] @de2ctrl -#if 0 - DF_TextSlice match_line_slice = df_text_slice_from_entity(scratch.arena, entity, r1s64(next_match.line, next_match.line), entity_line_string_flags); - String8 match_line = match_line_slice.visible_range_text; - F32 match_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(match_line, next_match.column-1)).x; - container_box->view_off_target.x = match_advance - code_area_dim.x/2; - container_box->view_off_target.y = next_match.line*code_line_height - code_area_dim.y/2 + code_line_height*1.5f; - container_box->view_off_target.x = ClampBot(container_box->view_off_target.x, 0); - container_box->view_off_target.y = ClampBot(container_box->view_off_target.y, 0); - tv->drifted_for_search = 1; -#endif - } - // rjf: contain => snap if(tv->contain_cursor) { @@ -5636,7 +5519,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) if(tv->center_cursor) { tv->center_cursor = 0; - String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + String8 cursor_line = str8_substr(data, text_info.lines_ranges[tv->cursor.line-1]); F32 cursor_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x; // rjf: scroll x @@ -5659,7 +5542,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) // rjf: snap in X if(snap[Axis2_X]) { - String8 cursor_line = txti_string_from_handle_line_num(scratch.arena, txti_handle, tv->cursor.line); + String8 cursor_line = str8_substr(data, text_info.lines_ranges[tv->cursor.line-1]); S64 cursor_off = (S64)(f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(cursor_line, tv->cursor.column-1)).x + margin_width_px + line_num_width_px); Rng1S64 visible_pixel_range = { @@ -5687,7 +5570,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) S64 min_delta = Min(0, cursor_visibility_range.min-(target_visible_line_num_range.min)); S64 max_delta = Max(0, cursor_visibility_range.max-(target_visible_line_num_range.min+num_possible_visible_lines)); S64 new_idx = view->scroll_pos.y.idx+min_delta+max_delta; - new_idx = Clamp(0, new_idx, (S64)txti_buffer_info.total_line_count-1); + new_idx = Clamp(0, new_idx, (S64)text_info.lines_count-1); ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); } } @@ -5695,7 +5578,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ////////////////////////////// //- rjf: build horizontal scroll bar // - if(txti_buffer_is_ready) + if(text_info_is_ready) { ui_set_next_fixed_x(0); ui_set_next_fixed_y(code_area_dim.y); @@ -5713,7 +5596,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ////////////////////////////// //- rjf: build vertical scroll bar // - if(txti_buffer_is_ready) + if(text_info_is_ready) { ui_set_next_fixed_x(code_area_dim.x); ui_set_next_fixed_y(0); @@ -5731,7 +5614,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ////////////////////////////// //- rjf: top-level container interaction (scrolling) // - if(txti_buffer_is_ready) + if(text_info_is_ready) { UI_Signal sig = ui_signal_from_box(container_box); if(sig.scroll.x != 0) @@ -5763,7 +5646,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) String8 full_path = df_full_path_from_entity(scratch.arena, entity); TXTI_Handle handle = txti_handle_from_path(full_path); TXTI_BufferInfo info = txti_buffer_info_from_handle(scratch.arena, handle); - DBGI_Parse *parse = df_dbgi_parse_from_binary_file(scope, binary); + DBGI_Parse *parse = df_dbgi_parse_from_binary_file(dbgi_scope, binary); if(parse->exe_props.modified < info.timestamp) { file_is_out_of_date = 1; @@ -5776,7 +5659,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ////////////////////////////// //- rjf: build bottom info bar // - if(txti_buffer_is_ready) + if(text_info_is_ready) { ui_set_next_fixed_x(0); ui_set_next_fixed_y(code_area_dim.y + scroll_bar_dim); @@ -5801,7 +5684,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_Clickable, "%S###file_ood_warning", df_g_icon_kind_text_table[DF_IconKind_WarningBig]); } UI_Signal sig = ui_signal_from_box(box); - if(sig.hovering) UI_Tooltip + if(ui_hovering(sig)) UI_Tooltip { UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) { @@ -5819,14 +5702,16 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ui_spacer(ui_pct(1, 0)); ui_labelf("(read only)"); ui_labelf("%s", - info.line_end_kind == TXTI_LineEndKind_LF ? "lf" : - info.line_end_kind == TXTI_LineEndKind_CRLF ? "crlf" : + info.line_end_kind == TXT_LineEndKind_LF ? "lf" : + info.line_end_kind == TXT_LineEndKind_CRLF ? "crlf" : "bin"); } } } - dbgi_scope_close(scope); + txt_scope_close(txt_scope); + dbgi_scope_close(dbgi_scope); + hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); } @@ -5844,6 +5729,7 @@ DF_VIEW_SETUP_FUNCTION_DEF(Disassembly) dv->mark = txt_pt(1, 1); dv->preferred_column = 1; dv->find_text_arena = df_view_push_arena_ext(view); + dv->style_flags = DASM_StyleFlag_Addresses; } } @@ -5855,8 +5741,28 @@ DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Disassembly) DF_VIEW_CMD_FUNCTION_DEF(Disassembly) { Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); + DASM_Scope *dasm_scope = dasm_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); DF_DisasmViewState *dv = df_view_user_state(view, DF_DisasmViewState); + + ////////////////////////////// + //- rjf: unpack disassembly info + // DF_Entity *process = df_entity_from_handle(dv->process); + Architecture arch = df_architecture_from_entity(process); + U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); + Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); + U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); + U128 dasm_data_hash = {0}; + DASM_Info dasm_info = dasm_info_from_key_addr_arch_style(dasm_scope, dasm_key, dasm_vaddr_range.min, arch, dv->style_flags, DASM_Syntax_Intel, &dasm_data_hash); + U128 dasm_text_hash = {0}; + TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(txt_scope, dasm_info.text_key, txt_lang_kind_from_architecture(arch), &dasm_text_hash); + String8 dasm_text_data = hs_data_from_hash(hs_scope, dasm_text_hash); + + ////////////////////////////// + //- rjf: process commands + // for(DF_CmdNode *n = cmds->first; n != 0; n = n->next) { DF_Cmd *cmd = &n->cmd; @@ -5918,13 +5824,10 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) }break; case DF_CoreCmdKind_ToggleBreakpointAtCursor: { - DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); - DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); - DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); - if(insts.count != 0) + if(1 <= dv->cursor.line && dv->cursor.line <= dasm_info.insts.count) { - U64 off = dasm_inst_array_off_from_idx(&insts, dv->cursor.line-1); - U64 vaddr = dasm_info.vaddr_range.min+off; + U64 off = dasm_inst_array_code_off_from_idx(&dasm_info.insts, dv->cursor.line-1); + U64 vaddr = dasm_vaddr_range.min+off; DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.vaddr = vaddr; df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); @@ -5934,30 +5837,25 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) }break; case DF_CoreCmdKind_ToggleWatchPinAtCursor: { - DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); - DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); - DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); - if(insts.count != 0) + if(1 <= dv->cursor.line && dv->cursor.line <= dasm_info.insts.count) { - U64 off = dasm_inst_array_off_from_idx(&insts, dv->cursor.line-1); - U64 vaddr = dasm_info.vaddr_range.min+off; + U64 off = dasm_inst_array_code_off_from_idx(&dasm_info.insts, dv->cursor.line-1); + U64 vaddr = dasm_vaddr_range.min+off; DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); p.vaddr = vaddr; p.string = params.string; df_cmd_params_mark_slot(&p, DF_CmdParamSlot_VirtualAddr); df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchPin)); + dv->contain_cursor = 1; } }break; case DF_CoreCmdKind_RunToCursor: { - DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); - DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); - DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); - if(insts.count != 0) + if(1 <= dv->cursor.line && dv->cursor.line <= dasm_info.insts.count) { - U64 off = dasm_inst_array_off_from_idx(&insts, dv->cursor.line-1); - U64 vaddr = dasm_info.vaddr_range.min+off; + U64 off = dasm_inst_array_code_off_from_idx(&dasm_info.insts, dv->cursor.line-1); + U64 vaddr = dasm_vaddr_range.min+off; DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.vaddr = vaddr; df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); @@ -5966,15 +5864,12 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) }break; case DF_CoreCmdKind_SetNextStatement: { - DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); - DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); - DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); - DF_Entity *thread = df_entity_from_handle(params.entity); S64 line_num = (cmd->params.text_point.line == 0 ? dv->cursor.line : cmd->params.text_point.line); - if(insts.count != 0) + DF_Entity *thread = df_entity_from_handle(params.entity); + if(1 <= line_num && line_num <= dasm_info.insts.count) { - U64 off = dasm_inst_array_off_from_idx(&insts, line_num-1); - U64 vaddr = dasm_info.vaddr_range.min+off; + U64 off = dasm_inst_array_code_off_from_idx(&dasm_info.insts, line_num-1); + U64 vaddr = dasm_vaddr_range.min+off; DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.vaddr = vaddr; params.entity = df_handle_from_entity(thread); @@ -5983,59 +5878,70 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetThreadIP)); } }break; + case DF_CoreCmdKind_ToggleCodeBytesVisibility: + { + dv->style_flags ^= DASM_StyleFlag_CodeBytes; + }break; + case DF_CoreCmdKind_ToggleAddressVisibility: + { + dv->style_flags ^= DASM_StyleFlag_Addresses; + }break; case DF_CoreCmdKind_GoToNameAtCursor: { - // TODO(rjf) -#if 0 - Temp scratch = scratch_begin(0, 0); - TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); - TxtRng expr_range = txt_rng(tv->cursor, tv->mark); - if(txt_pt_match(tv->cursor, tv->mark)) + // rjf: determine expression range + Rng1U64 expr_range = {0}; { - expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + TxtRng selection_range = txt_rng(dv->cursor, dv->mark); + if(txt_pt_match(selection_range.min, selection_range.max)) + { + expr_range = txt_expr_off_range_from_info_data_pt(&dasm_text_info, dasm_text_data, dv->cursor); + } + else + { + expr_range = r1u64(txt_off_from_info_pt(&dasm_text_info, selection_range.min), txt_off_from_info_pt(&dasm_text_info, selection_range.max)); + } } - String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); + + // rjf: expression range -> text + String8 expr_text = str8_substr(dasm_text_data, expr_range); // rjf: go to name DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.entity = df_handle_from_entity(entity); params.string = expr_text; df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_GoToName)); - - scratch_end(scratch); -#endif }break; case DF_CoreCmdKind_ToggleWatchExpressionAtCursor: { - // TODO(rjf) -#if 0 - Temp scratch = scratch_begin(0, 0); - TXTI_Handle txti_handle = df_txti_handle_from_entity(entity); - TxtRng expr_range = txt_rng(tv->cursor, tv->mark); - if(txt_pt_match(tv->cursor, tv->mark)) + // rjf: determine expression range + Rng1U64 expr_range = {0}; { - expr_range = txti_expr_range_from_handle_pt(txti_handle, tv->cursor); + TxtRng selection_range = txt_rng(dv->cursor, dv->mark); + if(txt_pt_match(selection_range.min, selection_range.max)) + { + expr_range = txt_expr_off_range_from_info_data_pt(&dasm_text_info, dasm_text_data, dv->cursor); + } + else + { + expr_range = r1u64(txt_off_from_info_pt(&dasm_text_info, selection_range.min), txt_off_from_info_pt(&dasm_text_info, selection_range.max)); + } } - String8 expr_text = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_range); + + // rjf: expression range -> text + String8 expr_text = str8_substr(dasm_text_data, expr_range); // rjf: toggle watch expr DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.string = expr_text; df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_ToggleWatchExpression)); - - // rjf: flash marker for grabbed expr - DF_Entity *flash_marker = df_entity_alloc(entity, DF_EntityKind_FlashMarker); - df_entity_equip_death_timer(flash_marker, 0.5f); - df_entity_equip_txt_pt(flash_marker, expr_range.min); - df_entity_equip_txt_pt_alt(flash_marker, expr_range.max); - df_entity_equip_color_rgba(flash_marker, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); - scratch_end(scratch); -#endif }break; } } + + hs_scope_close(hs_scope); + dasm_scope_close(dasm_scope); + txt_scope_close(txt_scope); scratch_end(scratch); } @@ -6043,22 +5949,16 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + HS_Scope *hs_scope = hs_scope_open(); + DASM_Scope *dasm_scope = dasm_scope_open(); + TXT_Scope *txt_scope = txt_scope_open(); + DBGI_Scope *dbgi_scope = dbgi_scope_open(); DF_DisasmViewState *dv = df_view_user_state(view, DF_DisasmViewState); ////////////////////////////// //- rjf: extract invariants // DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); - - ////////////////////////////// - //- rjf: unpack ctrl ctx & make parse ctx - // - DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); - U64 unwind_count = ctrl_ctx.unwind_count; - U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(selected_thread, unwind_count); - DF_Entity *selected_thread_process = df_entity_ancestor_from_kind(selected_thread, DF_EntityKind_Process); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, selected_thread_process, rip_vaddr); F_Tag code_font = df_font_from_slot(DF_FontSlot_Code); F32 code_font_size = df_font_size_from_slot(ws, DF_FontSlot_Code); F_Metrics code_font_metrics = f_metrics_from_tag_size(code_font, code_font_size); @@ -6069,37 +5969,54 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) F32 scroll_bar_dim = floor_f32(ui_top_font_size()*1.5f); Vec2F32 code_area_dim = v2f32(panel_box_dim.x - scroll_bar_dim, panel_box_dim.y - scroll_bar_dim - bottom_bar_dim.y); S64 num_possible_visible_lines = (S64)(code_area_dim.y/code_line_height)+1; - B32 is_focused = ui_is_focus_active(); + + ////////////////////////////// + //- rjf: unpack ctrl ctx & make parse ctx + // + DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); + DF_Entity *selected_process = df_entity_ancestor_from_kind(selected_thread, DF_EntityKind_Process); + U64 unwind_count = ctrl_ctx.unwind_count; + U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(selected_thread, unwind_count); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, selected_process, rip_vaddr); ////////////////////////////// //- rjf: no disasm process open? -> snap to selected thread // if(df_entity_is_nil(df_entity_from_handle(dv->process))) { - dv->process = df_handle_from_entity(selected_thread_process); + dv->process = df_handle_from_entity(selected_process); dv->base_vaddr = rip_vaddr; dv->goto_vaddr = rip_vaddr; } ////////////////////////////// - //- rjf: unpack entity info + //- rjf: unpack disassembly info // DF_Entity *process = df_entity_from_handle(dv->process); - DASM_Handle dasm_handle = df_dasm_handle_from_process_vaddr(process, dv->base_vaddr); - DASM_BinaryInfo dasm_info = dasm_binary_info_from_handle(scratch.arena, dasm_handle); - Rng1U64 disasm_vaddr_rng = dasm_info.vaddr_range; - DF_Entity *module = df_module_from_process_vaddr(process, disasm_vaddr_rng.min); + Architecture arch = df_architecture_from_entity(process); + U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); + Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); + U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); + U128 dasm_data_hash = {0}; + DASM_Info dasm_info = dasm_info_from_key_addr_arch_style(dasm_scope, dasm_key, dasm_vaddr_range.min, arch, dv->style_flags, DASM_Syntax_Intel, &dasm_data_hash); + U128 dasm_text_hash = {0}; + TXT_TextInfo dasm_text_info = txt_text_info_from_key_lang(txt_scope, dasm_info.text_key, txt_lang_kind_from_architecture(arch), &dasm_text_hash); + String8 dasm_text_data = hs_data_from_hash(hs_scope, dasm_text_hash); + B32 has_disasm = (dasm_info.insts.count != 0 && dasm_text_info.lines_count != 0); + B32 is_loading = (!has_disasm && !df_entity_is_nil(process) && dim_1u64(dasm_vaddr_range) != 0); + + ////////////////////////////// + //- rjf: unpack module info for this region + // + DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); DF_Entity *binary = df_binary_file_from_module(module); - DASM_InstArray insts = dasm_inst_array_from_handle(scratch.arena, dasm_handle, os_now_microseconds()+100); - B32 has_disasm = (insts.count != 0); - B32 is_loading = (!has_disasm && !df_entity_is_nil(process) && dim_1u64(disasm_vaddr_rng) != 0 && !df_ctrl_targets_running()); ////////////////////////////// //- rjf: is loading -> equip view with loading information // if(is_loading) { - df_view_equip_loading_info(view, is_loading, dasm_info.bytes_processed, dasm_info.bytes_to_process); + df_view_equip_loading_info(view, is_loading, 0, 0); } ////////////////////////////// @@ -6109,8 +6026,8 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) view->scroll_pos.y.idx + (S64)(view->scroll_pos.y.off) + 1 + num_possible_visible_lines); U64 visible_line_count = 0; { - visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)insts.count); - visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)insts.count); + visible_line_num_range.min = Clamp(1, visible_line_num_range.min, (S64)dasm_info.insts.count); + visible_line_num_range.max = Clamp(1, visible_line_num_range.max, (S64)dasm_info.insts.count); visible_line_count = (U64)dim_1s64(visible_line_num_range)+1; } @@ -6119,6 +6036,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) // F32 margin_width_px = big_glyph_advance*3.5f; F32 line_num_width_px = big_glyph_advance * (log10(visible_line_num_range.max) + 3); + TXT_LineTokensSlice slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, &dasm_text_info, dasm_text_data, visible_line_num_range); ////////////////////////////// //- rjf: calculate scroll bounds @@ -6130,7 +6048,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) line_size_x = ClampBot(line_size_x, (S64)big_glyph_advance*120); line_size_x = ClampBot(line_size_x, (S64)code_area_dim.x); scroll_idx_rng[Axis2_X] = r1s64(0, line_size_x-(S64)code_area_dim.x); - scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)insts.count-1); + scroll_idx_rng[Axis2_Y] = r1s64(0, (S64)dasm_info.insts.count-1); } ////////////////////////////// @@ -6154,13 +6072,14 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: prepare code slice info bundle, for the viewable region of text // DF_CodeSliceParams code_slice_params = {0}; + if(has_disasm) { // rjf: fill basics - code_slice_params.flags = DF_CodeSliceFlag_Margin|DF_CodeSliceFlag_LineNums; + code_slice_params.flags = DF_CodeSliceFlag_Margin|DF_CodeSliceFlag_LineNums|DF_CodeSliceFlag_Clickable; code_slice_params.line_num_range = visible_line_num_range; 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, TXTI_TokenArray, 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, DF_EntityList, visible_line_count); code_slice_params.line_ips = push_array(scratch.arena, DF_EntityList, visible_line_count); code_slice_params.line_pins = push_array(scratch.arena, DF_EntityList, visible_line_count); @@ -6176,40 +6095,20 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) code_slice_params.flash_ranges = df_push_entity_child_list_with_kind(scratch.arena, process, DF_EntityKind_FlashMarker); df_entity_list_push(scratch.arena, &code_slice_params.relevant_binaries, binary); - // rjf: fill line text - for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) + // rjf: fill text info { - U64 idx = line_num-visible_line_num_range.min; - DASM_Inst *inst = &insts.v[visible_line_num_range.min+idx-1]; - String8 symbol_name = {0}; - if(inst->addr != 0) + S64 line_num = visible_line_num_range.min; + U64 line_idx = visible_line_num_range.min-1; + for(U64 visible_line_idx = 0; visible_line_idx < visible_line_count; visible_line_idx += 1, line_idx += 1, line_num += 1) { - symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, df_voff_from_vaddr(module, inst->addr)); + code_slice_params.line_text[visible_line_idx] = str8_substr(dasm_text_data, dasm_text_info.lines_ranges[line_idx]); + code_slice_params.line_ranges[visible_line_idx] = dasm_text_info.lines_ranges[line_idx]; + code_slice_params.line_tokens[visible_line_idx] = slice.line_tokens[visible_line_idx]; } - code_slice_params.line_text[idx] = push_str8f(scratch.arena, "0x%016I64x %S%s%S%s", - disasm_vaddr_rng.min + inst->off, - inst->string, - symbol_name.size ? " (" : "", - symbol_name, - symbol_name.size ? ")" : ""); - } - - // rjf: fill line ranges - for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) - { - U64 idx = line_num-visible_line_num_range.min; - code_slice_params.line_ranges[idx] = r1u64(0, code_slice_params.line_text[idx].size); - } - - // rjf: fill line tokens - for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) - { - U64 idx = line_num-visible_line_num_range.min; - TXTI_TokenArray tokens = df_txti_token_array_from_dasm_arch_string(scratch.arena, df_architecture_from_entity(process), code_slice_params.line_text[idx]); - code_slice_params.line_tokens[idx] = tokens; } // rjf: find live threads mapping to this disassembly + ProfScope("find live threads mapping to this disassembly") { DF_Entity *selected_thread = df_entity_from_handle(ctrl_ctx.thread); DF_EntityList threads = df_query_cached_entity_list_with_kind(DF_EntityKind_Thread); @@ -6218,10 +6117,10 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_Entity *thread = thread_n->entity; U64 unwind_count = (thread == selected_thread) ? ctrl_ctx.unwind_count : 0; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); - if(contains_1u64(disasm_vaddr_rng, rip_vaddr)) + if(df_entity_ancestor_from_kind(thread, DF_EntityKind_Process) == process && contains_1u64(dasm_vaddr_range, rip_vaddr)) { - U64 rip_off = rip_vaddr - disasm_vaddr_rng.min; - S64 line_num = dasm_inst_array_idx_from_off__linear_scan(&insts, rip_off)+1; + U64 rip_off = rip_vaddr - dasm_vaddr_range.min; + S64 line_num = dasm_inst_array_idx_from_code_off__linear_scan(&dasm_info.insts, rip_off)+1; if(contains_1s64(visible_line_num_range, line_num)) { U64 slice_line_idx = (line_num-visible_line_num_range.min); @@ -6232,15 +6131,16 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) } // rjf: find breakpoints mapping to this disassembly + ProfScope("find breakpoints mapping to this disassembly") { DF_EntityList bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); for(DF_EntityNode *n = bps.first; n != 0; n = n->next) { DF_Entity *bp = n->entity; - if(bp->flags & DF_EntityFlag_HasVAddr && contains_1u64(disasm_vaddr_rng, bp->vaddr)) + if(bp->flags & DF_EntityFlag_HasVAddr && contains_1u64(dasm_vaddr_range, bp->vaddr)) { - U64 off = bp->vaddr-disasm_vaddr_rng.min; - U64 idx = dasm_inst_array_idx_from_off__linear_scan(&insts, off); + U64 off = bp->vaddr-dasm_vaddr_range.min; + U64 idx = dasm_inst_array_idx_from_code_off__linear_scan(&dasm_info.insts, off); S64 line_num = (S64)(idx+1); if(contains_1s64(visible_line_num_range, line_num)) { @@ -6252,15 +6152,16 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) } // rjf: find watch pins mapping to this disassembly + ProfScope("find watch pins mapping to this disassembly") { DF_EntityList pins = df_query_cached_entity_list_with_kind(DF_EntityKind_WatchPin); for(DF_EntityNode *n = pins.first; n != 0; n = n->next) { DF_Entity *pin = n->entity; - if(pin->flags & DF_EntityFlag_HasVAddr && contains_1u64(disasm_vaddr_rng, pin->vaddr)) + if(pin->flags & DF_EntityFlag_HasVAddr && contains_1u64(dasm_vaddr_range, pin->vaddr)) { - U64 off = pin->vaddr-disasm_vaddr_rng.min; - U64 idx = dasm_inst_array_idx_from_off__linear_scan(&insts, off); + U64 off = pin->vaddr-dasm_vaddr_range.min; + U64 idx = dasm_inst_array_idx_from_code_off__linear_scan(&dasm_info.insts, off); S64 line_num = (S64)(idx+1); if(contains_1s64(visible_line_num_range, line_num)) { @@ -6273,11 +6174,11 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) // rjf: fill dasm -> src info { - DF_Entity *module = df_module_from_process_vaddr(process, disasm_vaddr_rng.min); + DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); DF_Entity *binary = df_binary_file_from_module(module); for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) { - U64 vaddr = disasm_vaddr_rng.min + dasm_inst_array_off_from_idx(&insts, line_num-1); + U64 vaddr = dasm_vaddr_range.min + dasm_inst_array_code_off_from_idx(&dasm_info.insts, line_num-1); U64 voff = df_voff_from_vaddr(module, vaddr); U64 slice_idx = line_num-visible_line_num_range.min; DF_TextLineDasm2SrcInfoNode *dasm2src_n = push_array(scratch.arena, DF_TextLineDasm2SrcInfoNode, 1); @@ -6292,9 +6193,12 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: do keyboard interaction // B32 snap[Axis2_COUNT] = {0}; - if(!is_loading && is_focused && visible_line_num_range.max > visible_line_num_range.min) + UI_Focus(UI_FocusKind_On) { - snap[Axis2_X] = snap[Axis2_Y] = df_do_dasm_controls(dasm_handle, ClampBot(visible_line_count, 10) - 10, &dv->cursor, &dv->mark, &dv->preferred_column); + if(ui_is_focus_active() && !is_loading && visible_line_num_range.max >= visible_line_num_range.min) + { + snap[Axis2_X] = snap[Axis2_Y] = df_do_txt_controls(&dasm_text_info, dasm_text_data, ClampBot(visible_line_count, 10) - 10, &dv->cursor, &dv->mark, &dv->preferred_column); + } } ////////////////////////////// @@ -6304,7 +6208,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { U64 vaddr = dv->goto_vaddr; dv->goto_vaddr = 0; - U64 line_idx = dasm_inst_array_idx_from_off__linear_scan(&insts, vaddr-disasm_vaddr_rng.min); + U64 line_idx = dasm_inst_array_idx_from_code_off__linear_scan(&dasm_info.insts, vaddr-dasm_vaddr_range.min); S64 line_num = (S64)(line_idx+1); dv->cursor = dv->mark = txt_pt(line_num, 1); dv->center_cursor = !dv->contain_cursor || (line_num < visible_line_num_range.min+8 || visible_line_num_range.max-8 < line_num); @@ -6338,37 +6242,37 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: build code slice DF_CodeSliceSignal sig = {0}; - UI_Focus(is_focused ? UI_FocusKind_On : UI_FocusKind_Off) + UI_Focus(UI_FocusKind_On) { sig = df_code_slicef(ws, &ctrl_ctx, &parse_ctx, &code_slice_params, &dv->cursor, &dv->mark, &dv->preferred_column, "dasm_slice_%p", view); } //- rjf: hover eval - if(!sig.base.dragging && sig.mouse_expr_rng.min.line != 0 && contains_1s64(visible_line_num_range, sig.mouse_expr_rng.min.line) && sig.mouse_expr_rng.max.line == sig.mouse_expr_rng.min.line && sig.base.event_flags == 0) + if(!ui_dragging(sig.base) && sig.mouse_expr_rng.min.line != 0 && contains_1s64(visible_line_num_range, sig.mouse_expr_rng.min.line) && sig.mouse_expr_rng.max.line == sig.mouse_expr_rng.min.line && sig.base.event_flags == 0) { U64 line_idx = sig.mouse_expr_rng.min.line-visible_line_num_range.min; String8 expr = str8_substr(code_slice_params.line_text[line_idx], r1u64(sig.mouse_expr_rng.min.column-1, sig.mouse_expr_rng.max.column-1)); if(expr.size != 0) { - DF_Eval eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); if(eval.mode != EVAL_EvalMode_NULL) { - U64 off = dasm_inst_array_off_from_idx(&insts, sig.mouse_expr_rng.min.line-1); - U64 vaddr = disasm_vaddr_rng.min+off; + U64 off = dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.mouse_expr_rng.min.line-1); + U64 vaddr = dasm_vaddr_range.min+off; df_set_hover_eval(ws, sig.mouse_expr_baseline_pos, ctrl_ctx, process, sig.mouse_pt, vaddr, expr); } } } //- rjf: press code slice? -> focus panel - if(sig.base.pressed) + if(ui_pressed(sig.base)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } //- rjf: dragging? -> contain cursor - if(sig.base.dragging && sig.base.event_flags == 0) + if(ui_dragging(sig.base) && sig.base.event_flags == 0) { dv->contain_cursor = 1; } @@ -6377,7 +6281,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) if(sig.clicked_margin_line_num != 0) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.clicked_margin_line_num-1); + params.vaddr = dasm_vaddr_range.min+dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.clicked_margin_line_num-1); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_AddressBreakpoint)); } @@ -6385,7 +6289,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: dropped entity onto line? -> do drop if(sig.dropped_entity_line_num != 0 && !df_entity_is_nil(sig.dropped_entity)) { - U64 drop_vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.dropped_entity_line_num-1); + U64 drop_vaddr = dasm_vaddr_range.min+dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.dropped_entity_line_num-1); DF_Entity *dropped_entity = sig.dropped_entity; switch(dropped_entity->kind) { @@ -6415,18 +6319,10 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: copy text if(!txt_pt_match(sig.copy_range.min, sig.copy_range.max)) { - // TODO(rjf) -#if 0 Temp temp = temp_begin(scratch.arena); - DF_Entity *flash_range = df_entity_alloc(entity, DF_EntityKind_FlashMarker); - df_entity_equip_death_timer(flash_range, 0.5f); - df_entity_equip_color_rgba(flash_range, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); - df_entity_equip_txt_pt(flash_range, sig.copy_range.min); - df_entity_equip_txt_pt_alt(flash_range, sig.copy_range.max); - String8 text = txti_string_from_handle_txt_rng(temp.arena, txti_handle, sig.copy_range); + String8 text = txt_string_from_info_data_txt_rng(&dasm_text_info, dasm_text_data, sig.copy_range); os_set_clipboard_text(text); temp_end(temp); -#endif } //- rjf: toggle cursor watch @@ -6448,7 +6344,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) if(sig.run_to_line_num != 0 && contains_1s64(visible_line_num_range, sig.run_to_line_num)) { DF_CmdParams params = df_cmd_params_from_window(ws); - params.vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.run_to_line_num-1); + params.vaddr = dasm_vaddr_range.min+dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.run_to_line_num-1); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunToAddress)); } @@ -6456,7 +6352,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: go to source if(sig.goto_src_line_num != 0 && contains_1s64(visible_line_num_range, sig.goto_src_line_num)) { - U64 vaddr = disasm_vaddr_rng.min+dasm_inst_array_off_from_idx(&insts, sig.goto_src_line_num-1); + U64 vaddr = dasm_vaddr_range.min+dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.goto_src_line_num-1); DF_Entity *module = df_module_from_process_vaddr(process, vaddr); DF_Entity *binary = df_binary_file_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); @@ -6538,12 +6434,12 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) if(snap[Axis2_Y]) { Rng1S64 cursor_visibility_range = r1s64(dv->cursor.line-4, dv->cursor.line+4); - cursor_visibility_range.min = Clamp(0, cursor_visibility_range.min, (S64)insts.count); - cursor_visibility_range.max = Clamp(0, cursor_visibility_range.max, (S64)insts.count); + cursor_visibility_range.min = Clamp(0, cursor_visibility_range.min, (S64)dasm_info.insts.count); + cursor_visibility_range.max = Clamp(0, cursor_visibility_range.max, (S64)dasm_info.insts.count); S64 min_delta = Min(0, cursor_visibility_range.min-visible_line_num_range.min); S64 max_delta = Max(0, cursor_visibility_range.max-visible_line_num_range.max); S64 new_idx = view->scroll_pos.y.idx+min_delta+max_delta; - new_idx = Clamp(0, new_idx, (S64)insts.count-1); + new_idx = Clamp(0, new_idx, (S64)dasm_info.insts.count-1); ui_scroll_pt_target_idx(&view->scroll_pos.y, new_idx); } } @@ -6623,8 +6519,8 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_Font(code_font) { - DF_Entity *module = df_module_from_process_vaddr(process, disasm_vaddr_rng.min); - U64 cursor_vaddr = (1 <= dv->cursor.line && dv->cursor.line <= insts.count) ? (disasm_vaddr_rng.min+insts.v[dv->cursor.line-1].off) : 0; + DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); + U64 cursor_vaddr = (1 <= dv->cursor.line && dv->cursor.line <= dasm_info.insts.count) ? (dasm_vaddr_range.min+dasm_info.insts.v[dv->cursor.line-1].code_off) : 0; ui_labelf("%S", path_normalized_from_string(scratch.arena, module->name)); ui_spacer(ui_em(1.5f, 1)); ui_labelf("Address: 0x%I64x, Row: %I64d, Col: %I64d", cursor_vaddr, dv->cursor.line, dv->cursor.column); @@ -6634,11 +6530,24 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) } } - dbgi_scope_close(scope); + dbgi_scope_close(dbgi_scope); + txt_scope_close(txt_scope); + dasm_scope_close(dasm_scope); + hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); } +//////////////////////////////// +//~ rjf: EvalViewer @view_hook_impl + +DF_VIEW_SETUP_FUNCTION_DEF(EvalViewer) {} +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(EvalViewer) { return str8_lit(""); } +DF_VIEW_CMD_FUNCTION_DEF(EvalViewer) {} +DF_VIEW_UI_FUNCTION_DEF(EvalViewer) +{ +} + //////////////////////////////// //~ rjf: Watch @view_hook_impl @@ -6650,6 +6559,7 @@ DF_VIEW_SETUP_FUNCTION_DEF(Watch) // rjf: add roots for watches { + Temp scratch = scratch_begin(0, 0); DF_EvalViewKey eval_view_key = df_eval_view_key_from_eval_watch_view(ewv); DF_EvalView *eval_view = df_eval_view_from_key(eval_view_key); for(DF_CfgNode *expr = cfg_root->first; expr != &df_g_nil_cfg_node; expr = expr->next) @@ -6657,17 +6567,17 @@ DF_VIEW_SETUP_FUNCTION_DEF(Watch) if(expr->flags & DF_CfgNodeFlag_StringLiteral) { DF_EvalRoot *root = df_eval_root_alloc(view, ewv); - DF_ExpandKey parent_key = df_expand_key_make(5381, (U64)root); - U64 parent_key_hash = df_hash_from_expand_key(parent_key); - df_eval_root_equip_string(root, expr->string); + DF_ExpandKey key = df_expand_key_from_eval_root(root); + String8 expr_raw = df_cfg_raw_from_escaped_string(scratch.arena, expr->string); + df_eval_root_equip_string(root, expr_raw); if(expr->first != &df_g_nil_cfg_node) { - DF_ExpandKey root_key = df_expand_key_make(parent_key_hash, df_hash_from_string(expr->string)); - String8 view_rule = expr->first->string; - df_eval_view_set_key_rule(eval_view, root_key, view_rule); + String8 view_rule_raw = df_cfg_raw_from_escaped_string(scratch.arena, expr->first->string); + df_eval_view_set_key_rule(eval_view, key, view_rule_raw); } } } + scratch_end(scratch); } ProfEnd(); @@ -6683,15 +6593,15 @@ DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Watch) { for(DF_EvalRoot *root = ewv->first_root; root != 0; root = root->next) { - DF_ExpandKey parent_key = df_expand_key_make(5381, (U64)root); - U64 parent_key_hash = df_hash_from_expand_key(parent_key); + DF_ExpandKey key = df_expand_key_from_eval_root(root); String8 string = df_string_from_eval_root(root); - str8_list_pushf(arena, &strs, "\"%S\"", string); - DF_ExpandKey root_key = df_expand_key_make(parent_key_hash, df_hash_from_string(string)); - String8 view_rule = df_eval_view_rule_from_key(eval_view, root_key); - if(view_rule.size != 0) + String8 string_escaped = df_cfg_escaped_from_raw_string(scratch.arena, string); + str8_list_pushf(arena, &strs, "\"%S\"", string_escaped); + String8 view_rule = df_eval_view_rule_from_key(eval_view, key); + String8 view_rule_escaped = df_cfg_escaped_from_raw_string(scratch.arena, view_rule); + if(view_rule_escaped.size != 0) { - str8_list_pushf(arena, &strs, ":{\"%S\"}", view_rule); + str8_list_pushf(arena, &strs, ":{\"%S\"}", view_rule_escaped); } if(root->next != 0) { @@ -6827,7 +6737,7 @@ DF_VIEW_SETUP_FUNCTION_DEF(Output) // rjf: default to loading df_view_equip_loading_info(view, 1, 0, 0); - view->loading_t_target = 1.f; + view->loading_t = view->loading_t_target = 1.f; } DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Output) @@ -7010,7 +6920,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output) if(txti_buffer_is_ready) { // rjf: fill basics - code_slice_params.flags = DF_CodeSliceFlag_LineNums; + code_slice_params.flags = DF_CodeSliceFlag_LineNums|DF_CodeSliceFlag_Clickable; code_slice_params.line_num_range = visible_line_num_range; code_slice_params.line_text = slice.line_text; code_slice_params.line_ranges = slice.line_ranges; @@ -7056,17 +6966,6 @@ DF_VIEW_UI_FUNCTION_DEF(Output) tv->center_cursor = 1; } - ////////////////////////////// - //- rjf: search query -> matches - // - DF_TextSearchMatchArray search_query_matches = {0}; -#if 0 - { - search_query_matches = df_text_search_match_array_from_entity_needle(scratch.arena, entity, search_query, entity_line_string_flags, tv->cursor); - df_text_search_match_array_sort_in_place(&search_query_matches); - } -#endif - ////////////////////////////// //- rjf: do searching operations // @@ -7206,7 +7105,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output) tv->goto_line_num = 0; line_num = Clamp(1, line_num, txti_buffer_info.total_line_count); tv->cursor = tv->mark = txt_pt(line_num, 1); - tv->center_cursor = !tv->contain_cursor || (line_num < target_visible_line_num_range.min+8 || target_visible_line_num_range.max-8 < line_num); + tv->center_cursor = !tv->contain_cursor || (line_num < target_visible_line_num_range.min+4 || target_visible_line_num_range.max-4 < line_num); } ////////////////////////////// @@ -7238,7 +7137,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output) } //- rjf: hover eval - if(!sig.base.dragging && sig.mouse_expr_rng.min.line != 0) + if(!ui_dragging(sig.base) && sig.mouse_expr_rng.min.line != 0) { TxtRng expr_rng = sig.mouse_expr_rng; String8 expr = txti_string_from_handle_txt_rng(scratch.arena, txti_handle, expr_rng); @@ -7253,14 +7152,14 @@ DF_VIEW_UI_FUNCTION_DEF(Output) } //- rjf: press code slice? -> focus panel - if(sig.base.pressed) + if(ui_pressed(sig.base)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } //- rjf: dragging? -> contain cursor - if(sig.base.dragging) + if(ui_dragging(sig.base)) { tv->contain_cursor = 1; } @@ -7269,11 +7168,6 @@ DF_VIEW_UI_FUNCTION_DEF(Output) if(!txt_pt_match(sig.copy_range.min, sig.copy_range.max)) { Temp temp = temp_begin(scratch.arena); - DF_Entity *flash_range = df_entity_alloc(0, entity, DF_EntityKind_FlashMarker); - df_entity_equip_death_timer(flash_range, 0.5f); - df_entity_equip_color_rgba(flash_range, df_rgba_from_theme_color(DF_ThemeColor_Highlight0)); - df_entity_equip_txt_pt(flash_range, sig.copy_range.min); - df_entity_equip_txt_pt_alt(flash_range, sig.copy_range.max); String8 text = txti_string_from_handle_txt_rng(temp.arena, txti_handle, sig.copy_range); os_set_clipboard_text(text); temp_end(temp); @@ -7285,23 +7179,6 @@ DF_VIEW_UI_FUNCTION_DEF(Output) // if(txti_buffer_is_ready) { - // rjf: center first match - TxtPt next_match = df_text_search_match_array_find_nearest__linear_scan(&search_query_matches, tv->cursor, search_query_side).pt; - if(search_query.size != 0 && next_match.line != 0) - { - // TODO(rjf): [ ] @de2ctrl -#if 0 - DF_TextSlice match_line_slice = df_text_slice_from_entity(scratch.arena, entity, r1s64(next_match.line, next_match.line), entity_line_string_flags); - String8 match_line = match_line_slice.visible_range_text; - F32 match_advance = f_dim_from_tag_size_string(code_font, code_font_size, str8_prefix(match_line, next_match.column-1)).x; - container_box->view_off_target.x = match_advance - code_area_dim.x/2; - container_box->view_off_target.y = next_match.line*code_line_height - code_area_dim.y/2 + code_line_height*1.5f; - container_box->view_off_target.x = ClampBot(container_box->view_off_target.x, 0); - container_box->view_off_target.y = ClampBot(container_box->view_off_target.y, 0); - tv->drifted_for_search = 1; -#endif - } - // rjf: contain => snap if(tv->contain_cursor) { @@ -7526,8 +7403,9 @@ DF_VIEW_CMD_FUNCTION_DEF(Memory) DF_VIEW_UI_FUNCTION_DEF(Memory) { - Temp scratch = scratch_begin(0, 0); ProfBeginFunction(); + Temp scratch = scratch_begin(0, 0); + HS_Scope *hs_scope = hs_scope_open(); ////////////////////////////// //- rjf: unpack state @@ -7729,7 +7607,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) U8 *visible_memory = 0; { Rng1U64 chunk_aligned_range_bytes = r1u64(AlignDownPow2(viz_range_bytes.min, KB(4)), AlignPow2(viz_range_bytes.max, KB(4))); - U64 current_memgen_idx = ctrl_memgen_idx(); + U64 current_memgen_idx = ctrl_mem_gen(); B32 range_changed = (chunk_aligned_range_bytes.min != mv->last_viewed_memory_cache_range.min || chunk_aligned_range_bytes.max != mv->last_viewed_memory_cache_range.max); B32 mem_changed = (current_memgen_idx != mv->last_viewed_memory_cache_memgen_idx); @@ -7740,8 +7618,8 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) // rjf: try to read new memory for this range U64 bytes_to_read = dim_1u64(chunk_aligned_range_bytes); U8 *buffer = push_array_no_zero(scratch.arena, U8, bytes_to_read); - U64 half1_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min, chunk_aligned_range_bytes.min+bytes_to_read/2), buffer+0); - U64 half2_bytes_read = ctrl_process_read(process->ctrl_machine_id, process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min+bytes_to_read/2, chunk_aligned_range_bytes.max), buffer+bytes_to_read/2); + U64 half1_bytes_read = dmn_process_read(process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min, chunk_aligned_range_bytes.min+bytes_to_read/2), buffer+0); + U64 half2_bytes_read = dmn_process_read(process->ctrl_handle, r1u64(chunk_aligned_range_bytes.min+bytes_to_read/2, chunk_aligned_range_bytes.max), buffer+bytes_to_read/2); // rjf: worked? -> clear cache & store if(half1_bytes_read+half2_bytes_read >= bytes_to_read) @@ -7876,7 +7754,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) DBGI_Scope *scope = dbgi_scope_open(); U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, process, thread_rip_vaddr); - RADDBG_Parsed *rdbg = parse_ctx.rdbg; + RDI_Parsed *rdi = parse_ctx.rdi; for(EVAL_String2NumMapNode *n = parse_ctx.locals_map->first; n != 0; n = n->order_next) { String8 local_name = n->string; @@ -7884,7 +7762,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) if(local_eval.mode == EVAL_EvalMode_Addr) { TG_Kind local_eval_type_kind = tg_kind_from_key(local_eval.type_key); - U64 local_eval_type_size = tg_byte_size_from_graph_raddbg_key(parse_ctx.type_graph, rdbg, local_eval.type_key); + U64 local_eval_type_size = tg_byte_size_from_graph_rdi_key(parse_ctx.type_graph, rdi, local_eval.type_key); Rng1U64 vaddr_rng = r1u64(local_eval.offset, local_eval.offset+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) @@ -7893,7 +7771,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) { annotation->name_string = push_str8_copy(scratch.arena, local_name); annotation->kind_string = str8_lit("Local"); - annotation->type_string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, local_eval.type_key); + annotation->type_string = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdi, local_eval.type_key); annotation->color = color_gen_table[(vaddr_rng.min/8)%ArrayCount(color_gen_table)]; annotation->vaddr_range = vaddr_rng; } @@ -8014,7 +7892,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) UI_Signal sig = ui_signal_from_box(row_container_box); // rjf: calculate hovered byte - if(sig.hovering || sig.dragging) + if(ui_hovering(sig) || ui_dragging(sig)) { Vec2F32 mouse_rel = sub_2f32(ui_mouse(), row_container_box->rect.p0); U64 row_idx = ClampBot(0, mouse_rel.y) / row_height_px; @@ -8041,25 +7919,25 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) } // rjf: press -> focus panel - if(sig.pressed) + if(ui_pressed(sig)) { DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } // rjf: click & drag -> select - if(sig.dragging && mouse_hover_byte_num != 0) + if(ui_dragging(sig) && mouse_hover_byte_num != 0) { mv->contain_cursor = 1; mv->cursor = mouse_hover_byte_num-1; - if(sig.pressed) + if(ui_pressed(sig)) { mv->mark = mv->cursor; } } // rjf: ctrl+scroll -> change font size - if(sig.hovering) + if(ui_hovering(sig)) { for(OS_Event *event = ui_events()->first, *next = 0; event != 0; event = next) { @@ -8314,6 +8192,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) } } + hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); } @@ -8403,7 +8282,7 @@ DF_VIEW_UI_FUNCTION_DEF(Breakpoints) { UI_TableCell UI_FocusHot((row_is_selected && cursor.x == 0) ? UI_FocusKind_On : UI_FocusKind_Off) { - if(df_icon_buttonf(entity->b32 ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, 0, "###ebl_%p", entity).clicked) + if(ui_clicked(df_icon_buttonf(entity->b32 ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, 0, "###ebl_%p", entity))) { df_entity_equip_b32(entity, !entity->b32); } @@ -8441,7 +8320,7 @@ DF_VIEW_UI_FUNCTION_DEF(Breakpoints) } } UI_Signal sig = ui_signal_from_box(box); - if(sig.double_clicked || sig.keyboard_clicked) + if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed) { DF_CmdParams params = df_cmd_params_from_window(ws); params.file_path = df_full_path_from_entity(scratch.arena, file_parent); @@ -8450,7 +8329,7 @@ DF_VIEW_UI_FUNCTION_DEF(Breakpoints) df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); } - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(2, (S64)(idx)); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); @@ -8466,7 +8345,7 @@ DF_VIEW_UI_FUNCTION_DEF(Breakpoints) UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), hit_count_string); } UI_Signal sig = ui_signal_from_box(box); - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(3, (S64)(idx)); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); @@ -8475,7 +8354,7 @@ DF_VIEW_UI_FUNCTION_DEF(Breakpoints) } UI_TableCell UI_FocusHot((row_is_selected && cursor.x == 4) ? UI_FocusKind_On : UI_FocusKind_Off) { - if(df_icon_buttonf(DF_IconKind_Trash, 0, "###del_%p", entity).clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Trash, 0, "###del_%p", entity))) { df_entity_mark_for_deletion(entity); } @@ -8587,7 +8466,7 @@ DF_VIEW_UI_FUNCTION_DEF(WatchPins) } UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, "%S###loc_%p", loc_string, entity); UI_Signal sig = ui_signal_from_box(box); - if(sig.double_clicked || sig.keyboard_clicked) + if(ui_double_clicked(sig) || sig.f&UI_SignalFlag_KeyboardPressed) { DF_CmdParams params = df_cmd_params_from_window(ws); params.file_path = df_full_path_from_entity(scratch.arena, file_parent); @@ -8596,7 +8475,7 @@ DF_VIEW_UI_FUNCTION_DEF(WatchPins) df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_TextPoint); df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); } - if(sig.pressed) + if(ui_pressed(sig)) { next_cursor = v2s64(1, (S64)(idx)); DF_CmdParams p = df_cmd_params_from_panel(ws, panel); @@ -8605,7 +8484,7 @@ DF_VIEW_UI_FUNCTION_DEF(WatchPins) } UI_TableCell UI_FocusHot((row_is_selected && cursor.x == 2) ? UI_FocusKind_On : UI_FocusKind_Off) { - if(df_icon_buttonf(DF_IconKind_Trash, 0, "###del_%p", entity).clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_Trash, 0, "###del_%p", entity))) { df_entity_mark_for_deletion(entity); } @@ -8734,7 +8613,7 @@ DF_VIEW_UI_FUNCTION_DEF(ExceptionFilters) { DF_ExceptionFiltersOption *opt = &opts.v[row]; UI_Signal sig = df_icon_buttonf(opt->is_enabled ? DF_IconKind_CheckFilled : DF_IconKind_CheckHollow, &opt->matches, "%S", opt->name); - if(sig.clicked) + if(ui_clicked(sig)) { if(opt->exception_code_kind != CTRL_ExceptionCodeKind_Null) { @@ -8858,7 +8737,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) ui_set_next_background_color(bg_color); ui_set_next_text_color(tx_color); ui_set_next_border_color(bd_color); - if(ui_buttonf("%S", df_g_theme_preset_display_string_table[preset]).clicked) + if(ui_clicked(ui_buttonf("%S", df_g_theme_preset_display_string_table[preset]))) { MemoryCopy(df_gfx_state->cfg_theme_target.colors, colors, sizeof(df_gfx_state->cfg_theme_target.colors)); } @@ -8940,7 +8819,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("Hex"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + if(ui_committed(sig)) { String8 string = str8(sv->txt_buffer, sv->txt_size); Vec4F32 new_rgba = rgba_from_hex_string_4f32(string); @@ -8953,7 +8832,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("R"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + 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); @@ -8965,7 +8844,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("G"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + 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); @@ -8977,7 +8856,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("B"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + 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); @@ -8990,7 +8869,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("H"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + 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); @@ -9001,7 +8880,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("S"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + 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); @@ -9012,7 +8891,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("V"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + 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); @@ -9024,7 +8903,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) { UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_PrefWidth(ui_em(4.5f, 1.f)) ui_labelf("A"); UI_Signal sig = df_line_editf(DF_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(sig.commit) + 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)); @@ -9049,7 +8928,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) UI_FocusHot((sv->cursor.y == 1 && sv->cursor.x == 0) ? UI_FocusKind_On : UI_FocusKind_Off) { UI_Signal preset_sig = df_icon_buttonf(DF_IconKind_Palette, 0, "Apply Preset"); - if(preset_sig.clicked) + if(ui_clicked(preset_sig)) { ui_ctx_menu_open(preset_ctx_menu_key, preset_sig.box->key, v2f32(0, dim_2f32(preset_sig.box->rect).y)); } @@ -9058,7 +8937,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) // rjf: load-from-file UI_FocusHot((sv->cursor.y == 1 && sv->cursor.x == 1) ? UI_FocusKind_On : UI_FocusKind_Off) { - if(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Load From File").clicked) + if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Load From File"))) { DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); @@ -9121,7 +9000,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) ui_set_next_corner_radius_11(ui_top_font_size()/4.f); UI_Box *color_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable|UI_BoxFlag_DrawBorder|UI_BoxFlag_DrawBackground, "###color_box"); UI_Signal color_sig = ui_signal_from_box(color_box); - if(color_sig.hovering) + if(ui_hovering(color_sig)) { ui_do_color_tooltip_hsva(hsva); } @@ -9129,7 +9008,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) ui_spacer(ui_em(0.3f, 1)); } UI_Signal color_row_sig = ui_signal_from_box(color_row); - if(color_row_sig.clicked || color_row_sig.right_clicked) + if(ui_clicked(color_row_sig) || ui_right_clicked(color_row_sig)) { ui_ctx_menu_open(color_ctx_menu_keys[color], color_row->key, v2f32(0, color_row->rect.y1-color_row->rect.y0)); sv->color_ctx_menu_color = color; @@ -9137,7 +9016,7 @@ DF_VIEW_UI_FUNCTION_DEF(Theme) DF_CmdParams p = df_cmd_params_from_panel(ws, panel); df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FocusPanel)); } - if(color_row_sig.hovering) UI_Tooltip + if(ui_hovering(color_row_sig)) UI_Tooltip { ui_label(df_g_theme_color_display_string_table[color]); } diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h index 0a5933dc..ebccf953 100644 --- a/src/df/gfx/df_views.h +++ b/src/df/gfx/df_views.h @@ -144,7 +144,7 @@ struct DF_EntityListerItemArray typedef struct DF_ProcessInfo DF_ProcessInfo; struct DF_ProcessInfo { - DEMON_ProcessInfo info; + DMN_ProcessInfo info; B32 is_attached; FuzzyMatchRangeList attached_match_ranges; FuzzyMatchRangeList name_match_ranges; @@ -364,6 +364,7 @@ struct DF_DisasmViewState TxtPt mark; S64 preferred_column; B32 drifted_for_search; + DASM_StyleFlags style_flags; // rjf: per-frame command info S64 goto_line_num; @@ -435,11 +436,6 @@ internal DF_EntityListerItemList df_entity_lister_item_list_from_needle(Arena *a internal DF_EntityListerItemArray df_entity_lister_item_array_from_list(Arena *arena, DF_EntityListerItemList list); internal void df_entity_lister_item_array_sort_by_strength__in_place(DF_EntityListerItemArray array); -//////////////////////////////// -//~ rjf: Disassembly View - -internal TXTI_TokenArray df_txti_token_array_from_dasm_arch_string(Arena *arena, Architecture arch, String8 string); - //////////////////////////////// //~ rjf: Eval/Watch Views @@ -453,6 +449,8 @@ internal void df_eval_root_equip_string(DF_EvalRoot *root, String8 str internal DF_EvalRoot * df_eval_root_from_string(DF_EvalWatchViewState *ews, String8 string); internal DF_EvalRoot * df_eval_root_from_expand_key(DF_EvalWatchViewState *ews, DF_EvalView *eval_view, DF_ExpandKey expand_key); internal String8 df_string_from_eval_root(DF_EvalRoot *root); +internal DF_ExpandKey df_parent_expand_key_from_eval_root(DF_EvalRoot *root); +internal DF_ExpandKey df_expand_key_from_eval_root(DF_EvalRoot *root); //- rjf: windowed watch tree visualization internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_EvalWatchViewState *ews); diff --git a/src/df/gfx/generated/df_gfx.meta.c b/src/df/gfx/generated/df_gfx.meta.c index d43cb23e..287fc4c8 100644 --- a/src/df/gfx/generated/df_gfx.meta.c +++ b/src/df/gfx/generated/df_gfx.meta.c @@ -3,21 +3,883 @@ //- GENERATED CODE -DF_GfxViewRuleSpecInfo df_g_gfx_view_rule_spec_info_table[] = +C_LINKAGE_BEGIN +String8 df_g_theme_preset_display_string_table[9] = { -{ str8_lit_comp("array"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, 0, 0, 0, }, -{ str8_lit_comp("list"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(list) , 0, 0, 0, }, -{ str8_lit_comp("dec"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(dec) , 0, 0, }, -{ str8_lit_comp("bin"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(bin) , 0, 0, }, -{ str8_lit_comp("oct"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(oct) , 0, 0, }, -{ str8_lit_comp("hex"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(hex) , 0, 0, }, -{ str8_lit_comp("only"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(only) , DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(only) , 0, 0, }, -{ str8_lit_comp("omit"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(omit) , DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(omit) , 0, 0, }, -{ str8_lit_comp("no_addr"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(no_addr) , 0, 0, }, -{ str8_lit_comp("rgba"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(rgba) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(rgba) , }, -{ str8_lit_comp("text"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, 0, DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(text) , }, -{ str8_lit_comp("disasm"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, 0, DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(disasm) , }, -{ str8_lit_comp("bitmap"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(bitmap) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(bitmap) , }, -{ str8_lit_comp("geo"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(geo) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(geo) , }, +str8_lit_comp("Default (Dark)"), +str8_lit_comp("Default (Light)"), +str8_lit_comp("VS (Dark)"), +str8_lit_comp("VS (Light)"), +str8_lit_comp("Solarized (Dark)"), +str8_lit_comp("Solarized (Light)"), +str8_lit_comp("Handmade Hero"), +str8_lit_comp("4coder"), +str8_lit_comp("Far Manager"), }; +String8 df_g_theme_preset_code_string_table[9] = +{ +str8_lit_comp("default_dark"), +str8_lit_comp("default_light"), +str8_lit_comp("vs_dark"), +str8_lit_comp("vs_light"), +str8_lit_comp("solarized_dark"), +str8_lit_comp("solarized_light"), +str8_lit_comp("handmade_hero"), +str8_lit_comp("four_coder"), +str8_lit_comp("far_manager"), +}; + +Vec4F32 df_g_theme_preset_colors__default_dark[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x3333337f), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x7fcc99ff), +rgba_from_u32_lit_comp(0x66b2e5ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0xf7bf5eff), +rgba_from_u32_lit_comp(0x994c32ff), +rgba_from_u32_lit_comp(0x4ce54cff), +rgba_from_u32_lit_comp(0xe5cc66ff), +rgba_from_u32_lit_comp(0xe54c4cff), +rgba_from_u32_lit_comp(0x7f7f7fff), +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(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +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(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__default_light[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x383838ff), +rgba_from_u32_lit_comp(0xedededfe), +rgba_from_u32_lit_comp(0x0000001d), +rgba_from_u32_lit_comp(0x00000033), +rgba_from_u32_lit_comp(0x282828ff), +rgba_from_u32_lit_comp(0x2a7a45ff), +rgba_from_u32_lit_comp(0x2c688fff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0xa47729ff), +rgba_from_u32_lit_comp(0x6c2d18ff), +rgba_from_u32_lit_comp(0x2c7d2cff), +rgba_from_u32_lit_comp(0xcc5a0fff), +rgba_from_u32_lit_comp(0x8a0c0cff), +rgba_from_u32_lit_comp(0x7f7f7fff), +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(0x535353ff), +rgba_from_u32_lit_comp(0xfefefebc), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xc7a27dff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0xd76489cc), +rgba_from_u32_lit_comp(0x0000007f), +rgba_from_u32_lit_comp(0x7d98b34c), +rgba_from_u32_lit_comp(0x101010ff), +rgba_from_u32_lit_comp(0xb272189b), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x75db61ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xf27961ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xad7c34ff), +rgba_from_u32_lit_comp(0x639b2aff), +rgba_from_u32_lit_comp(0xa94c91ff), +rgba_from_u32_lit_comp(0x305398ff), +rgba_from_u32_lit_comp(0x339574ff), +rgba_from_u32_lit_comp(0xbf7416ff), +rgba_from_u32_lit_comp(0x57238bff), +rgba_from_u32_lit_comp(0x2a7e1cff), +rgba_from_u32_lit_comp(0x236481ff), +rgba_from_u32_lit_comp(0x0000000d), +rgba_from_u32_lit_comp(0x0000003b), +}; + +Vec4F32 df_g_theme_preset_colors__vs_dark[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x1e1e1eff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xd4d4d4ff), +rgba_from_u32_lit_comp(0xdcdcaaff), +rgba_from_u32_lit_comp(0x4ec9b0ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0x569cd6ff), +rgba_from_u32_lit_comp(0xb4b4b4ff), +rgba_from_u32_lit_comp(0xb5cea8ff), +rgba_from_u32_lit_comp(0xd69d85ff), +rgba_from_u32_lit_comp(0x9b9b9bff), +rgba_from_u32_lit_comp(0x6a9955ff), +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(0xf1f1f1ff), +rgba_from_u32_lit_comp(0x1b1b1cff), +rgba_from_u32_lit_comp(0x333337ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0x007accff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +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(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__vs_light[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x1e1e1eff), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0xcccedb1d), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x000000ff), +rgba_from_u32_lit_comp(0x74531fff), +rgba_from_u32_lit_comp(0x2b91afff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0x0000ffff), +rgba_from_u32_lit_comp(0x000000ff), +rgba_from_u32_lit_comp(0x000000ff), +rgba_from_u32_lit_comp(0xc11515ff), +rgba_from_u32_lit_comp(0x808080ff), +rgba_from_u32_lit_comp(0x008000ff), +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(0x535353ff), +rgba_from_u32_lit_comp(0xfefefebc), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0x007accff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0x0000007f), +rgba_from_u32_lit_comp(0x7d98b34c), +rgba_from_u32_lit_comp(0x101010ff), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xad7c34ff), +rgba_from_u32_lit_comp(0x639b2aff), +rgba_from_u32_lit_comp(0xa94c91ff), +rgba_from_u32_lit_comp(0x305398ff), +rgba_from_u32_lit_comp(0x339574ff), +rgba_from_u32_lit_comp(0xbf7416ff), +rgba_from_u32_lit_comp(0x57238bff), +rgba_from_u32_lit_comp(0x2a7e1cff), +rgba_from_u32_lit_comp(0x236481ff), +rgba_from_u32_lit_comp(0x0000000d), +rgba_from_u32_lit_comp(0x0000003b), +}; + +Vec4F32 df_g_theme_preset_colors__solarized_dark[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x002b36ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x839496ff), +rgba_from_u32_lit_comp(0x1c7dd1ff), +rgba_from_u32_lit_comp(0x1c7dd1ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0x63980fff), +rgba_from_u32_lit_comp(0x839496ff), +rgba_from_u32_lit_comp(0xcb4b20ff), +rgba_from_u32_lit_comp(0x2aa198ff), +rgba_from_u32_lit_comp(0xe54c4cff), +rgba_from_u32_lit_comp(0x7f7f7fff), +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(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x002b36ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0x28515eff), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +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(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__solarized_light[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x1e1e1eff), +rgba_from_u32_lit_comp(0xfcf6e2ff), +rgba_from_u32_lit_comp(0xcccedb1d), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x74878cff), +rgba_from_u32_lit_comp(0xc39d36ff), +rgba_from_u32_lit_comp(0x66b2e5ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0xc39d36ff), +rgba_from_u32_lit_comp(0x2e5256ff), +rgba_from_u32_lit_comp(0x657b83ff), +rgba_from_u32_lit_comp(0x5ab4a9ff), +rgba_from_u32_lit_comp(0xe54c4cff), +rgba_from_u32_lit_comp(0xadafb2ff), +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(0x535353ff), +rgba_from_u32_lit_comp(0xfcf6e2ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0x0000007f), +rgba_from_u32_lit_comp(0x7d98b34c), +rgba_from_u32_lit_comp(0x101010ff), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +rgba_from_u32_lit_comp(0xad7c34ff), +rgba_from_u32_lit_comp(0x639b2aff), +rgba_from_u32_lit_comp(0xa94c91ff), +rgba_from_u32_lit_comp(0x305398ff), +rgba_from_u32_lit_comp(0x339574ff), +rgba_from_u32_lit_comp(0xbf7416ff), +rgba_from_u32_lit_comp(0x57238bff), +rgba_from_u32_lit_comp(0x2a7e1cff), +rgba_from_u32_lit_comp(0x236481ff), +rgba_from_u32_lit_comp(0x0000000d), +rgba_from_u32_lit_comp(0x0000003b), +}; + +Vec4F32 df_g_theme_preset_colors__handmade_hero[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0xa08563ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xa08563ff), +rgba_from_u32_lit_comp(0xcc5735ff), +rgba_from_u32_lit_comp(0xd8a51dff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0xac7b0bff), +rgba_from_u32_lit_comp(0x994c32ff), +rgba_from_u32_lit_comp(0x6b8e23ff), +rgba_from_u32_lit_comp(0x6b8e23ff), +rgba_from_u32_lit_comp(0xdab98fff), +rgba_from_u32_lit_comp(0x686868ff), +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(0xa08563ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xa08563af), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +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(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__four_coder[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x90b080ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0x181818a0), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x90b080ff), +rgba_from_u32_lit_comp(0x7fcc99ff), +rgba_from_u32_lit_comp(0x66b2e5ff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0xd08f20ff), +rgba_from_u32_lit_comp(0x994c32ff), +rgba_from_u32_lit_comp(0x50ff30ff), +rgba_from_u32_lit_comp(0x50ff30ff), +rgba_from_u32_lit_comp(0x50ff30ff), +rgba_from_u32_lit_comp(0x2090f0ff), +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(0x90b080ff), +rgba_from_u32_lit_comp(0x0c0c0cff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0x90b080af), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +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(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32 df_g_theme_preset_colors__far_manager[54] = +{ +rgba_from_u32_lit_comp(0xff00ffff), +rgba_from_u32_lit_comp(0x00ffffff), +rgba_from_u32_lit_comp(0x000082ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x00ffffff), +rgba_from_u32_lit_comp(0x49b2ffff), +rgba_from_u32_lit_comp(0x49b2ffff), +rgba_from_u32_lit_comp(0xfe9548ff), +rgba_from_u32_lit_comp(0xd45d90ff), +rgba_from_u32_lit_comp(0xff0000ff), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x2cff50ff), +rgba_from_u32_lit_comp(0xe5cc66ff), +rgba_from_u32_lit_comp(0xffff00ff), +rgba_from_u32_lit_comp(0x7f7f7fff), +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(0x000000ff), +rgba_from_u32_lit_comp(0x008184ff), +rgba_from_u32_lit_comp(0xffffff19), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0x42474c7f), +rgba_from_u32_lit_comp(0xa87a4c99), +rgba_from_u32_lit_comp(0x4293cc99), +rgba_from_u32_lit_comp(0x8e2d4ccc), +rgba_from_u32_lit_comp(0xffffff7f), +rgba_from_u32_lit_comp(0x99ccff4c), +rgba_from_u32_lit_comp(0x66e566e5), +rgba_from_u32_lit_comp(0xb27219ff), +rgba_from_u32_lit_comp(0x327f19ff), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0x32b219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xe5e5e5ff), +rgba_from_u32_lit_comp(0xb23219ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffffff), +rgba_from_u32_lit_comp(0x327fb2ff), +rgba_from_u32_lit_comp(0xffffff33), +rgba_from_u32_lit_comp(0xffffff0c), +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(0x0000003f), +rgba_from_u32_lit_comp(0x0000007f), +}; + +Vec4F32* df_g_theme_preset_colors_table[9] = +{ +df_g_theme_preset_colors__default_dark, +df_g_theme_preset_colors__default_light, +df_g_theme_preset_colors__vs_dark, +df_g_theme_preset_colors__vs_light, +df_g_theme_preset_colors__solarized_dark, +df_g_theme_preset_colors__solarized_light, +df_g_theme_preset_colors__handmade_hero, +df_g_theme_preset_colors__four_coder, +df_g_theme_preset_colors__far_manager, +}; + +DF_CmdParamSlot df_g_cmd_param_slot_2_view_spec_src_map[7] = +{ +DF_CmdParamSlot_Entity, +DF_CmdParamSlot_EntityList, +DF_CmdParamSlot_FilePath, +DF_CmdParamSlot_CmdSpec, +DF_CmdParamSlot_ID, +DF_CmdParamSlot_String, +DF_CmdParamSlot_String, +}; + +String8 df_g_cmd_param_slot_2_view_spec_dst_map[7] = +{ +str8_lit_comp("entity_lister"), +str8_lit_comp("entity_lister"), +str8_lit_comp("file_system"), +str8_lit_comp("commands"), +str8_lit_comp("system_processes"), +str8_lit_comp("symbol_lister"), +str8_lit_comp("symbol_lister"), +}; + +String8 df_g_cmd_param_slot_2_view_spec_cmd_map[7] = +{ +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp("goto_name"), +str8_lit_comp("function_breakpoint"), +}; + +DF_StringBindingPair df_g_default_binding_table[97] = +{ +{str8_lit_comp("kill_all"), {OS_Key_F5, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("step_into_inst"), {OS_Key_F11, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("step_over_inst"), {OS_Key_F10, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("step_out"), {OS_Key_F11, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("halt"), {OS_Key_X, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("halt"), {OS_Key_Pause, 0 }}, +{str8_lit_comp("soft_halt_refresh"), {OS_Key_R, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("run"), {OS_Key_F5, 0 }}, +{str8_lit_comp("restart"), {OS_Key_F5, 0 |OS_EventFlag_Ctrl |OS_EventFlag_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_EventFlag_Ctrl }}, +{str8_lit_comp("set_next_statement"), {OS_Key_F10, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("inc_ui_font_scale"), {OS_Key_Equal, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("dec_ui_font_scale"), {OS_Key_Minus, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("inc_code_font_scale"), {OS_Key_Equal, 0 |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("dec_code_font_scale"), {OS_Key_Minus, 0 |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("window"), {OS_Key_N, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("toggle_fullscreen"), {OS_Key_Return, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("new_panel_right"), {OS_Key_P, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("new_panel_down"), {OS_Key_Minus, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("rotate_panel_columns"), {OS_Key_2, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("next_panel"), {OS_Key_Comma, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("prev_panel"), {OS_Key_Comma, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("focus_panel_right"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("focus_panel_left"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("focus_panel_up"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("focus_panel_down"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("close_panel"), {OS_Key_P, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("next_tab"), {OS_Key_PageDown, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("prev_tab"), {OS_Key_PageUp, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("next_tab"), {OS_Key_Tab, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("prev_tab"), {OS_Key_Tab, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_tab_right"), {OS_Key_PageDown, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_tab_left"), {OS_Key_PageUp, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("close_tab"), {OS_Key_W, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("tab_bar_top"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("tab_bar_bottom"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("open"), {OS_Key_O, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("reload_active"), {OS_Key_R, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("switch"), {OS_Key_I, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("switch_to_partner_file"), {OS_Key_O, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("load_user"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, +{str8_lit_comp("load_profile"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, +{str8_lit_comp("move_left"), {OS_Key_Left, 0 }}, +{str8_lit_comp("move_right"), {OS_Key_Right, 0 }}, +{str8_lit_comp("move_up"), {OS_Key_Up, 0 }}, +{str8_lit_comp("move_down"), {OS_Key_Down, 0 }}, +{str8_lit_comp("move_left_select"), {OS_Key_Left, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_right_select"), {OS_Key_Right, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_select"), {OS_Key_Up, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_select"), {OS_Key_Down, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_left_chunk"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_right_chunk"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_up_chunk"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_down_chunk"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_up_page"), {OS_Key_PageUp, 0 }}, +{str8_lit_comp("move_down_page"), {OS_Key_PageDown, 0 }}, +{str8_lit_comp("move_up_whole"), {OS_Key_Home, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_down_whole"), {OS_Key_End, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("move_left_chunk_select"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_right_chunk_select"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_chunk_select"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_chunk_select"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_page_select"), {OS_Key_PageUp, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_page_select"), {OS_Key_PageDown, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_up_whole_select"), {OS_Key_Home, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_down_whole_select"), {OS_Key_End, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, +{str8_lit_comp("move_home"), {OS_Key_Home, 0 }}, +{str8_lit_comp("move_end"), {OS_Key_End, 0 }}, +{str8_lit_comp("move_home_select"), {OS_Key_Home, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("move_end_select"), {OS_Key_End, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("select_all"), {OS_Key_A, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("delete_single"), {OS_Key_Delete, 0 }}, +{str8_lit_comp("delete_chunk"), {OS_Key_Delete, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("backspace_single"), {OS_Key_Backspace, 0 }}, +{str8_lit_comp("backspace_chunk"), {OS_Key_Backspace, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("copy"), {OS_Key_C, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("cut"), {OS_Key_X, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("paste"), {OS_Key_V, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("insert_text"), {OS_Key_Null, 0 }}, +{str8_lit_comp("goto_line"), {OS_Key_G, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("goto_address"), {OS_Key_G, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("find_text_forward"), {OS_Key_F, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("find_text_backward"), {OS_Key_R, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("find_next"), {OS_Key_F3, 0 }}, +{str8_lit_comp("find_prev"), {OS_Key_F3, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("find_selected_thread"), {OS_Key_F4, 0 }}, +{str8_lit_comp("goto_name"), {OS_Key_J, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("goto_name_at_cursor"), {OS_Key_F12, 0 }}, +{str8_lit_comp("toggle_watch_expr_at_cursor"), {OS_Key_W, 0 |OS_EventFlag_Alt}}, +{str8_lit_comp("toggle_watch_pin_at_cursor"), {OS_Key_F9, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("toggle_breakpoint_cursor"), {OS_Key_F9, 0 }}, +{str8_lit_comp("add_target"), {OS_Key_T, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("attach"), {OS_Key_F6, 0 |OS_EventFlag_Shift }}, +{str8_lit_comp("filter"), {OS_Key_Slash, 0 |OS_EventFlag_Ctrl }}, +{str8_lit_comp("run_command"), {OS_Key_F1, 0 }}, +}; + +String8 df_g_binding_version_remap_old_name_table[3] = +{ +str8_lit_comp("commands"), +str8_lit_comp("load_user"), +str8_lit_comp("load_profile"), +}; + +String8 df_g_binding_version_remap_new_name_table[3] = +{ +str8_lit_comp("run_command"), +str8_lit_comp("open_user"), +str8_lit_comp("open_profile"), +}; + +DF_GfxViewRuleSpecInfo df_g_gfx_view_rule_spec_info_table[14] = +{ +{ str8_lit_comp("array"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, 0, 0, 0, 0 }, +{ str8_lit_comp("list"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(list) , 0, 0, 0, 0 }, +{ str8_lit_comp("dec"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(dec) , 0, 0, 0 }, +{ str8_lit_comp("bin"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(bin) , 0, 0, 0 }, +{ str8_lit_comp("oct"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(oct) , 0, 0, 0 }, +{ str8_lit_comp("hex"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(hex) , 0, 0, 0 }, +{ str8_lit_comp("only"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(only) , DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(only) , 0, 0, 0 }, +{ str8_lit_comp("omit"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*1)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), DF_GFX_VIEW_RULE_VIZ_ROW_PROD_FUNCTION_NAME(omit) , DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(omit) , 0, 0, 0 }, +{ str8_lit_comp("no_addr"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*1)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*0), 0, DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(no_addr) , 0, 0, 0 }, +{ str8_lit_comp("rgba"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(rgba) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(rgba) , 0 }, +{ str8_lit_comp("text"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, 0, DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(text) , 0 }, +{ str8_lit_comp("disasm"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*0)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, 0, DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(disasm) , 0 }, +{ str8_lit_comp("bitmap"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(bitmap) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(bitmap) , DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_NAME(bitmap) }, +{ str8_lit_comp("geo"), (DF_GfxViewRuleSpecInfoFlag_VizRowProd*0)|(DF_GfxViewRuleSpecInfoFlag_LineStringize*0)|(DF_GfxViewRuleSpecInfoFlag_RowUI*1)|(DF_GfxViewRuleSpecInfoFlag_BlockUI*1), 0, 0, DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(geo) , DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(geo) , 0 }, +}; + +DF_ViewSpecInfo df_g_gfx_view_kind_spec_info_table[30] = +{ +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("null"), str8_lit_comp(""), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Null), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Null), DF_VIEW_CMD_FUNCTION_NAME(Null), DF_VIEW_UI_FUNCTION_NAME(Null)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("empty"), str8_lit_comp(""), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Empty), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Empty), DF_VIEW_CMD_FUNCTION_NAME(Empty), DF_VIEW_UI_FUNCTION_NAME(Empty)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("commands"), str8_lit_comp("Commands"), DF_NameKind_Null, DF_IconKind_List, DF_VIEW_SETUP_FUNCTION_NAME(Commands), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Commands), DF_VIEW_CMD_FUNCTION_NAME(Commands), DF_VIEW_UI_FUNCTION_NAME(Commands)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("file_system"), str8_lit_comp("File System"), DF_NameKind_Null, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(FileSystem), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(FileSystem), DF_VIEW_CMD_FUNCTION_NAME(FileSystem), DF_VIEW_UI_FUNCTION_NAME(FileSystem)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("system_processes"), str8_lit_comp("System Processes"), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(SystemProcesses), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(SystemProcesses), DF_VIEW_CMD_FUNCTION_NAME(SystemProcesses), DF_VIEW_UI_FUNCTION_NAME(SystemProcesses)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("entity_lister"), str8_lit_comp("Entity List"), DF_NameKind_EntityKindName, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(EntityLister), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(EntityLister), DF_VIEW_CMD_FUNCTION_NAME(EntityLister), DF_VIEW_UI_FUNCTION_NAME(EntityLister)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("symbol_lister"), str8_lit_comp("Symbols"), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(SymbolLister), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(SymbolLister), DF_VIEW_CMD_FUNCTION_NAME(SymbolLister), DF_VIEW_UI_FUNCTION_NAME(SymbolLister)}, +{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("target"), str8_lit_comp("Target"), DF_NameKind_EntityName, DF_IconKind_Target, DF_VIEW_SETUP_FUNCTION_NAME(Target), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Target), DF_VIEW_CMD_FUNCTION_NAME(Target), DF_VIEW_UI_FUNCTION_NAME(Target)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("targets"), str8_lit_comp("Targets"), DF_NameKind_Null, DF_IconKind_Target, DF_VIEW_SETUP_FUNCTION_NAME(Targets), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Targets), DF_VIEW_CMD_FUNCTION_NAME(Targets), DF_VIEW_UI_FUNCTION_NAME(Targets)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("file_path_map"), str8_lit_comp("File Path Map"), DF_NameKind_Null, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(FilePathMap), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(FilePathMap), DF_VIEW_CMD_FUNCTION_NAME(FilePathMap), DF_VIEW_UI_FUNCTION_NAME(FilePathMap)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("scheduler"), str8_lit_comp("Scheduler"), DF_NameKind_Null, DF_IconKind_Scheduler, DF_VIEW_SETUP_FUNCTION_NAME(Scheduler), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Scheduler), DF_VIEW_CMD_FUNCTION_NAME(Scheduler), DF_VIEW_UI_FUNCTION_NAME(Scheduler)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("call_stack"), str8_lit_comp("Call Stack"), DF_NameKind_Null, DF_IconKind_Thread, DF_VIEW_SETUP_FUNCTION_NAME(CallStack), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(CallStack), DF_VIEW_CMD_FUNCTION_NAME(CallStack), DF_VIEW_UI_FUNCTION_NAME(CallStack)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("modules"), str8_lit_comp("Modules"), DF_NameKind_Null, DF_IconKind_Module, DF_VIEW_SETUP_FUNCTION_NAME(Modules), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Modules), DF_VIEW_CMD_FUNCTION_NAME(Modules), DF_VIEW_UI_FUNCTION_NAME(Modules)}, +{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("pending_entity"), str8_lit_comp("Pending Entity"), DF_NameKind_EntityName, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(PendingEntity), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(PendingEntity), DF_VIEW_CMD_FUNCTION_NAME(PendingEntity), DF_VIEW_UI_FUNCTION_NAME(PendingEntity)}, +{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|1*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("code"), str8_lit_comp("Code"), DF_NameKind_EntityName, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(Code), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Code), DF_VIEW_CMD_FUNCTION_NAME(Code), DF_VIEW_UI_FUNCTION_NAME(Code)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("disassembly"), str8_lit_comp("Disassembly"), DF_NameKind_Null, DF_IconKind_Glasses, DF_VIEW_SETUP_FUNCTION_NAME(Disassembly), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Disassembly), DF_VIEW_CMD_FUNCTION_NAME(Disassembly), DF_VIEW_UI_FUNCTION_NAME(Disassembly)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("eval_viewer"), str8_lit_comp("Evaluation Viewer"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(EvalViewer), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(EvalViewer), DF_VIEW_CMD_FUNCTION_NAME(EvalViewer), DF_VIEW_UI_FUNCTION_NAME(EvalViewer)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("watch"), str8_lit_comp("Watch"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Watch), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Watch), DF_VIEW_CMD_FUNCTION_NAME(Watch), DF_VIEW_UI_FUNCTION_NAME(Watch)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("locals"), str8_lit_comp("Locals"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Locals), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Locals), DF_VIEW_CMD_FUNCTION_NAME(Locals), DF_VIEW_UI_FUNCTION_NAME(Locals)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("registers"), str8_lit_comp("Registers"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Registers), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Registers), DF_VIEW_CMD_FUNCTION_NAME(Registers), DF_VIEW_UI_FUNCTION_NAME(Registers)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("globals"), str8_lit_comp("Globals"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Globals), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Globals), DF_VIEW_CMD_FUNCTION_NAME(Globals), DF_VIEW_UI_FUNCTION_NAME(Globals)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("thread_locals"), str8_lit_comp("Thread Locals"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(ThreadLocals), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(ThreadLocals), DF_VIEW_CMD_FUNCTION_NAME(ThreadLocals), DF_VIEW_UI_FUNCTION_NAME(ThreadLocals)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("types"), str8_lit_comp("Types"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Types), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Types), DF_VIEW_CMD_FUNCTION_NAME(Types), DF_VIEW_UI_FUNCTION_NAME(Types)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("procedures"), str8_lit_comp("Procedures"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Procedures), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Procedures), DF_VIEW_CMD_FUNCTION_NAME(Procedures), DF_VIEW_UI_FUNCTION_NAME(Procedures)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("output"), str8_lit_comp("Output"), DF_NameKind_Null, DF_IconKind_List, DF_VIEW_SETUP_FUNCTION_NAME(Output), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Output), DF_VIEW_CMD_FUNCTION_NAME(Output), DF_VIEW_UI_FUNCTION_NAME(Output)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|1*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("memory"), str8_lit_comp("Memory"), DF_NameKind_Null, DF_IconKind_Grid, DF_VIEW_SETUP_FUNCTION_NAME(Memory), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Memory), DF_VIEW_CMD_FUNCTION_NAME(Memory), DF_VIEW_UI_FUNCTION_NAME(Memory)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoints"), DF_NameKind_Null, DF_IconKind_CircleFilled, DF_VIEW_SETUP_FUNCTION_NAME(Breakpoints), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Breakpoints), DF_VIEW_CMD_FUNCTION_NAME(Breakpoints), DF_VIEW_UI_FUNCTION_NAME(Breakpoints)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pins"), DF_NameKind_Null, DF_IconKind_Pin, DF_VIEW_SETUP_FUNCTION_NAME(WatchPins), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(WatchPins), DF_VIEW_CMD_FUNCTION_NAME(WatchPins), DF_VIEW_UI_FUNCTION_NAME(WatchPins)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("exception_filters"), str8_lit_comp("Exception Filters"), DF_NameKind_Null, DF_IconKind_Gear, DF_VIEW_SETUP_FUNCTION_NAME(ExceptionFilters), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(ExceptionFilters), DF_VIEW_CMD_FUNCTION_NAME(ExceptionFilters), DF_VIEW_UI_FUNCTION_NAME(ExceptionFilters)}, +{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("theme"), str8_lit_comp("Theme"), DF_NameKind_Null, DF_IconKind_Palette, DF_VIEW_SETUP_FUNCTION_NAME(Theme), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Theme), DF_VIEW_CMD_FUNCTION_NAME(Theme), DF_VIEW_UI_FUNCTION_NAME(Theme)}, +}; + +String8 df_g_theme_color_display_string_table[54] = +{ +str8_lit_comp("Null"), +str8_lit_comp("Plain Text"), +str8_lit_comp("Plain Background"), +str8_lit_comp("Plain Border"), +str8_lit_comp("Plain Overlay"), +str8_lit_comp("Code (Default)"), +str8_lit_comp("Code (Function)"), +str8_lit_comp("Code (Type)"), +str8_lit_comp("Code (Local)"), +str8_lit_comp("Code (Register)"), +str8_lit_comp("Code (Keyword)"), +str8_lit_comp("Code (Symbol)"), +str8_lit_comp("Code (Numeric)"), +str8_lit_comp("Code (String)"), +str8_lit_comp("Code (Meta)"), +str8_lit_comp("Code (Comment)"), +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 Text"), +str8_lit_comp("Alt Background"), +str8_lit_comp("Alt Border"), +str8_lit_comp("Alt Overlay"), +str8_lit_comp("Inactive Tab"), +str8_lit_comp("Active Tab"), +str8_lit_comp("Entity Background"), +str8_lit_comp("Query Bar"), +str8_lit_comp("Weak Text"), +str8_lit_comp("Text Selection"), +str8_lit_comp("Cursor"), +str8_lit_comp("Highlight (0)"), +str8_lit_comp("Highlight (1)"), +str8_lit_comp("Success Text"), +str8_lit_comp("Success Background"), +str8_lit_comp("Success Border"), +str8_lit_comp("Failure Text"), +str8_lit_comp("Failure Background"), +str8_lit_comp("Failure Border"), +str8_lit_comp("Action Text"), +str8_lit_comp("Action Background"), +str8_lit_comp("Action Border"), +str8_lit_comp("Drop Site Overlay"), +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("Inactive Panel Overlay"), +str8_lit_comp("Drop Shadow"), +}; + +String8 df_g_theme_color_cfg_string_table[54] = +{ +str8_lit_comp("null"), +str8_lit_comp("plain_text"), +str8_lit_comp("plain_background"), +str8_lit_comp("plain_border"), +str8_lit_comp("plain_overlay"), +str8_lit_comp("code_default"), +str8_lit_comp("code_function"), +str8_lit_comp("code_type"), +str8_lit_comp("code_local"), +str8_lit_comp("code_register"), +str8_lit_comp("code_keyword"), +str8_lit_comp("code_symbol"), +str8_lit_comp("code_numeric"), +str8_lit_comp("code_string"), +str8_lit_comp("code_meta"), +str8_lit_comp("code_comment"), +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_text"), +str8_lit_comp("alt_background"), +str8_lit_comp("alt_border"), +str8_lit_comp("alt_overlay"), +str8_lit_comp("tab_inactive"), +str8_lit_comp("tab_active"), +str8_lit_comp("entity_background"), +str8_lit_comp("query_bar"), +str8_lit_comp("weak_text"), +str8_lit_comp("text_selection"), +str8_lit_comp("cursor"), +str8_lit_comp("highlight_0"), +str8_lit_comp("highlight_1"), +str8_lit_comp("success_text"), +str8_lit_comp("success_background"), +str8_lit_comp("success_border"), +str8_lit_comp("failure_text"), +str8_lit_comp("failure_background"), +str8_lit_comp("failure_border"), +str8_lit_comp("action_text"), +str8_lit_comp("action_background"), +str8_lit_comp("action_border"), +str8_lit_comp("drop_site_overlay"), +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("inactive_panel_overlay"), +str8_lit_comp("drop_shadow"), +}; + +C_LINKAGE_END + diff --git a/src/df/gfx/generated/df_gfx.meta.h b/src/df/gfx/generated/df_gfx.meta.h index b1cceb74..f9efdf56 100644 --- a/src/df/gfx/generated/df_gfx.meta.h +++ b/src/df/gfx/generated/df_gfx.meta.h @@ -6,6 +6,14 @@ #ifndef DF_GFX_META_H #define DF_GFX_META_H +typedef enum DF_NameKind +{ +DF_NameKind_Null, +DF_NameKind_EntityName, +DF_NameKind_EntityKindName, +DF_NameKind_COUNT, +} DF_NameKind; + typedef enum DF_GfxViewKind { DF_GfxViewKind_Null, @@ -24,6 +32,7 @@ DF_GfxViewKind_Modules, DF_GfxViewKind_PendingEntity, DF_GfxViewKind_Code, DF_GfxViewKind_Disassembly, +DF_GfxViewKind_EvalViewer, DF_GfxViewKind_Watch, DF_GfxViewKind_Locals, DF_GfxViewKind_Registers, @@ -37,7 +46,7 @@ DF_GfxViewKind_Breakpoints, DF_GfxViewKind_WatchPins, DF_GfxViewKind_ExceptionFilters, DF_GfxViewKind_Theme, -DF_GfxViewKind_COUNT +DF_GfxViewKind_COUNT, } DF_GfxViewKind; typedef enum DF_ThemeColor @@ -51,6 +60,7 @@ DF_ThemeColor_CodeDefault, DF_ThemeColor_CodeFunction, DF_ThemeColor_CodeType, DF_ThemeColor_CodeLocal, +DF_ThemeColor_CodeRegister, DF_ThemeColor_CodeKeyword, DF_ThemeColor_CodeSymbol, DF_ThemeColor_CodeNumeric, @@ -95,7 +105,7 @@ DF_ThemeColor_Thread7, DF_ThemeColor_ThreadUnwound, DF_ThemeColor_InactivePanelOverlay, DF_ThemeColor_DropShadow, -DF_ThemeColor_COUNT +DF_ThemeColor_COUNT, } DF_ThemeColor; typedef enum DF_ThemePreset @@ -109,7 +119,7 @@ DF_ThemePreset_SolarizedLight, DF_ThemePreset_HandmadeHero, DF_ThemePreset_FourCoder, DF_ThemePreset_FarManager, -DF_ThemePreset_COUNT +DF_ThemePreset_COUNT, } DF_ThemePreset; DF_VIEW_SETUP_FUNCTION_DEF(Null); @@ -128,6 +138,7 @@ DF_VIEW_SETUP_FUNCTION_DEF(Modules); DF_VIEW_SETUP_FUNCTION_DEF(PendingEntity); DF_VIEW_SETUP_FUNCTION_DEF(Code); DF_VIEW_SETUP_FUNCTION_DEF(Disassembly); +DF_VIEW_SETUP_FUNCTION_DEF(EvalViewer); DF_VIEW_SETUP_FUNCTION_DEF(Watch); DF_VIEW_SETUP_FUNCTION_DEF(Locals); DF_VIEW_SETUP_FUNCTION_DEF(Registers); @@ -157,6 +168,7 @@ DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Modules); DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(PendingEntity); DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Code); DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Disassembly); +DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(EvalViewer); DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Watch); DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Locals); DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(Registers); @@ -186,6 +198,7 @@ DF_VIEW_CMD_FUNCTION_DEF(Modules); DF_VIEW_CMD_FUNCTION_DEF(PendingEntity); DF_VIEW_CMD_FUNCTION_DEF(Code); DF_VIEW_CMD_FUNCTION_DEF(Disassembly); +DF_VIEW_CMD_FUNCTION_DEF(EvalViewer); DF_VIEW_CMD_FUNCTION_DEF(Watch); DF_VIEW_CMD_FUNCTION_DEF(Locals); DF_VIEW_CMD_FUNCTION_DEF(Registers); @@ -215,6 +228,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules); DF_VIEW_UI_FUNCTION_DEF(PendingEntity); DF_VIEW_UI_FUNCTION_DEF(Code); DF_VIEW_UI_FUNCTION_DEF(Disassembly); +DF_VIEW_UI_FUNCTION_DEF(EvalViewer); DF_VIEW_UI_FUNCTION_DEF(Watch); DF_VIEW_UI_FUNCTION_DEF(Locals); DF_VIEW_UI_FUNCTION_DEF(Registers); @@ -247,853 +261,29 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text); DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm); DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap); DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo); -String8 df_g_theme_preset_display_string_table[] = -{ -str8_lit_comp("Default (Dark)"), -str8_lit_comp("Default (Light)"), -str8_lit_comp("VS (Dark)"), -str8_lit_comp("VS (Light)"), -str8_lit_comp("Solarized (Dark)"), -str8_lit_comp("Solarized (Light)"), -str8_lit_comp("Handmade Hero"), -str8_lit_comp("4coder"), -str8_lit_comp("Far Manager"), -}; - -String8 df_g_theme_preset_code_string_table[] = -{ -str8_lit_comp("default_dark"), -str8_lit_comp("default_light"), -str8_lit_comp("vs_dark"), -str8_lit_comp("vs_light"), -str8_lit_comp("solarized_dark"), -str8_lit_comp("solarized_light"), -str8_lit_comp("handmade_hero"), -str8_lit_comp("four_coder"), -str8_lit_comp("far_manager"), -}; - -Vec4F32 df_g_theme_preset_colors__default_dark[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x3333337f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x7fcc99ff), -rgba_from_u32_lit_comp(0x66b2e5ff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0xf7bf5eff), -rgba_from_u32_lit_comp(0x994c32ff), -rgba_from_u32_lit_comp(0x4ce54cff), -rgba_from_u32_lit_comp(0xe5cc66ff), -rgba_from_u32_lit_comp(0xe54c4cff), -rgba_from_u32_lit_comp(0x7f7f7fff), -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(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0xa87a4c99), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0xffffff7f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0x66e566e5), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -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(0x0000003f), -rgba_from_u32_lit_comp(0x0000007f), -}; - -Vec4F32 df_g_theme_preset_colors__default_light[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x383838ff), -rgba_from_u32_lit_comp(0xedededfe), -rgba_from_u32_lit_comp(0x0000001d), -rgba_from_u32_lit_comp(0x00000033), -rgba_from_u32_lit_comp(0x282828ff), -rgba_from_u32_lit_comp(0x2a7a45ff), -rgba_from_u32_lit_comp(0x2c688fff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0xa47729ff), -rgba_from_u32_lit_comp(0x6c2d18ff), -rgba_from_u32_lit_comp(0x2c7d2cff), -rgba_from_u32_lit_comp(0xcc5a0fff), -rgba_from_u32_lit_comp(0x8a0c0cff), -rgba_from_u32_lit_comp(0x7f7f7fff), -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(0x535353ff), -rgba_from_u32_lit_comp(0xfefefebc), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0xc7a27dff), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0xd76489cc), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x7d98b34c), -rgba_from_u32_lit_comp(0x101010ff), -rgba_from_u32_lit_comp(0xb272189b), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x75db61ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xf27961ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0xad7c34ff), -rgba_from_u32_lit_comp(0x639b2aff), -rgba_from_u32_lit_comp(0xa94c91ff), -rgba_from_u32_lit_comp(0x305398ff), -rgba_from_u32_lit_comp(0x339574ff), -rgba_from_u32_lit_comp(0xbf7416ff), -rgba_from_u32_lit_comp(0x57238bff), -rgba_from_u32_lit_comp(0x2a7e1cff), -rgba_from_u32_lit_comp(0x236481ff), -rgba_from_u32_lit_comp(0x0000000d), -rgba_from_u32_lit_comp(0x0000003b), -}; - -Vec4F32 df_g_theme_preset_colors__vs_dark[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x1e1e1eff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xd4d4d4ff), -rgba_from_u32_lit_comp(0xdcdcaaff), -rgba_from_u32_lit_comp(0x4ec9b0ff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0x569cd6ff), -rgba_from_u32_lit_comp(0xb4b4b4ff), -rgba_from_u32_lit_comp(0xb5cea8ff), -rgba_from_u32_lit_comp(0xd69d85ff), -rgba_from_u32_lit_comp(0x9b9b9bff), -rgba_from_u32_lit_comp(0x6a9955ff), -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(0xf1f1f1ff), -rgba_from_u32_lit_comp(0x1b1b1cff), -rgba_from_u32_lit_comp(0x333337ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0x007accff), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0xffffff7f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0x66e566e5), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -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(0x0000003f), -rgba_from_u32_lit_comp(0x0000007f), -}; - -Vec4F32 df_g_theme_preset_colors__vs_light[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x1e1e1eff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0xcccedb1d), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0x74531fff), -rgba_from_u32_lit_comp(0x2b91afff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0x0000ffff), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0x000000ff), -rgba_from_u32_lit_comp(0xc11515ff), -rgba_from_u32_lit_comp(0x808080ff), -rgba_from_u32_lit_comp(0x008000ff), -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(0x535353ff), -rgba_from_u32_lit_comp(0xfefefebc), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0x007accff), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x7d98b34c), -rgba_from_u32_lit_comp(0x101010ff), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0xad7c34ff), -rgba_from_u32_lit_comp(0x639b2aff), -rgba_from_u32_lit_comp(0xa94c91ff), -rgba_from_u32_lit_comp(0x305398ff), -rgba_from_u32_lit_comp(0x339574ff), -rgba_from_u32_lit_comp(0xbf7416ff), -rgba_from_u32_lit_comp(0x57238bff), -rgba_from_u32_lit_comp(0x2a7e1cff), -rgba_from_u32_lit_comp(0x236481ff), -rgba_from_u32_lit_comp(0x0000000d), -rgba_from_u32_lit_comp(0x0000003b), -}; - -Vec4F32 df_g_theme_preset_colors__solarized_dark[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x002b36ff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x839496ff), -rgba_from_u32_lit_comp(0x1c7dd1ff), -rgba_from_u32_lit_comp(0x1c7dd1ff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0x63980fff), -rgba_from_u32_lit_comp(0x839496ff), -rgba_from_u32_lit_comp(0xcb4b20ff), -rgba_from_u32_lit_comp(0x2aa198ff), -rgba_from_u32_lit_comp(0xe54c4cff), -rgba_from_u32_lit_comp(0x7f7f7fff), -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(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x002b36ff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0x28515eff), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0xffffff7f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0x66e566e5), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -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(0x0000003f), -rgba_from_u32_lit_comp(0x0000007f), -}; - -Vec4F32 df_g_theme_preset_colors__solarized_light[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x1e1e1eff), -rgba_from_u32_lit_comp(0xfcf6e2ff), -rgba_from_u32_lit_comp(0xcccedb1d), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x74878cff), -rgba_from_u32_lit_comp(0xc39d36ff), -rgba_from_u32_lit_comp(0x66b2e5ff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0xc39d36ff), -rgba_from_u32_lit_comp(0x2e5256ff), -rgba_from_u32_lit_comp(0x657b83ff), -rgba_from_u32_lit_comp(0x5ab4a9ff), -rgba_from_u32_lit_comp(0xe54c4cff), -rgba_from_u32_lit_comp(0xadafb2ff), -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(0x535353ff), -rgba_from_u32_lit_comp(0xfcf6e2ff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0xa87a4c99), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0x0000007f), -rgba_from_u32_lit_comp(0x7d98b34c), -rgba_from_u32_lit_comp(0x101010ff), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -rgba_from_u32_lit_comp(0xad7c34ff), -rgba_from_u32_lit_comp(0x639b2aff), -rgba_from_u32_lit_comp(0xa94c91ff), -rgba_from_u32_lit_comp(0x305398ff), -rgba_from_u32_lit_comp(0x339574ff), -rgba_from_u32_lit_comp(0xbf7416ff), -rgba_from_u32_lit_comp(0x57238bff), -rgba_from_u32_lit_comp(0x2a7e1cff), -rgba_from_u32_lit_comp(0x236481ff), -rgba_from_u32_lit_comp(0x0000000d), -rgba_from_u32_lit_comp(0x0000003b), -}; - -Vec4F32 df_g_theme_preset_colors__handmade_hero[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0xa08563ff), -rgba_from_u32_lit_comp(0x0c0c0cff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xa08563ff), -rgba_from_u32_lit_comp(0xcc5735ff), -rgba_from_u32_lit_comp(0xd8a51dff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0xac7b0bff), -rgba_from_u32_lit_comp(0x994c32ff), -rgba_from_u32_lit_comp(0x6b8e23ff), -rgba_from_u32_lit_comp(0x6b8e23ff), -rgba_from_u32_lit_comp(0xdab98fff), -rgba_from_u32_lit_comp(0x686868ff), -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(0xa08563ff), -rgba_from_u32_lit_comp(0x0c0c0cff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0xa87a4c99), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0xa08563af), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0x66e566e5), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -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(0x0000003f), -rgba_from_u32_lit_comp(0x0000007f), -}; - -Vec4F32 df_g_theme_preset_colors__four_coder[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x90b080ff), -rgba_from_u32_lit_comp(0x0c0c0cff), -rgba_from_u32_lit_comp(0x181818a0), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x90b080ff), -rgba_from_u32_lit_comp(0x7fcc99ff), -rgba_from_u32_lit_comp(0x66b2e5ff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0xd08f20ff), -rgba_from_u32_lit_comp(0x994c32ff), -rgba_from_u32_lit_comp(0x50ff30ff), -rgba_from_u32_lit_comp(0x50ff30ff), -rgba_from_u32_lit_comp(0x50ff30ff), -rgba_from_u32_lit_comp(0x2090f0ff), -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(0x90b080ff), -rgba_from_u32_lit_comp(0x0c0c0cff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0xa87a4c99), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0x90b080af), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0x66e566e5), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -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(0x0000003f), -rgba_from_u32_lit_comp(0x0000007f), -}; - -Vec4F32 df_g_theme_preset_colors__far_manager[] = -{ -rgba_from_u32_lit_comp(0xff00ffff), -rgba_from_u32_lit_comp(0x00ffffff), -rgba_from_u32_lit_comp(0x000082ff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x00ffffff), -rgba_from_u32_lit_comp(0x49b2ffff), -rgba_from_u32_lit_comp(0x49b2ffff), -rgba_from_u32_lit_comp(0xfe9548ff), -rgba_from_u32_lit_comp(0xff0000ff), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x2cff50ff), -rgba_from_u32_lit_comp(0xe5cc66ff), -rgba_from_u32_lit_comp(0xffff00ff), -rgba_from_u32_lit_comp(0x7f7f7fff), -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(0x000000ff), -rgba_from_u32_lit_comp(0x008184ff), -rgba_from_u32_lit_comp(0xffffff19), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0x42474c7f), -rgba_from_u32_lit_comp(0xa87a4c99), -rgba_from_u32_lit_comp(0x4293cc99), -rgba_from_u32_lit_comp(0x8e2d4ccc), -rgba_from_u32_lit_comp(0xffffff7f), -rgba_from_u32_lit_comp(0x99ccff4c), -rgba_from_u32_lit_comp(0x66e566e5), -rgba_from_u32_lit_comp(0xb27219ff), -rgba_from_u32_lit_comp(0x327f19ff), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0x32b219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xe5e5e5ff), -rgba_from_u32_lit_comp(0xb23219ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffffff), -rgba_from_u32_lit_comp(0x327fb2ff), -rgba_from_u32_lit_comp(0xffffff33), -rgba_from_u32_lit_comp(0xffffff0c), -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(0x0000003f), -rgba_from_u32_lit_comp(0x0000007f), -}; - -Vec4F32 * df_g_theme_preset_colors_table[] = -{ -df_g_theme_preset_colors__default_dark, -df_g_theme_preset_colors__default_light, -df_g_theme_preset_colors__vs_dark, -df_g_theme_preset_colors__vs_light, -df_g_theme_preset_colors__solarized_dark, -df_g_theme_preset_colors__solarized_light, -df_g_theme_preset_colors__handmade_hero, -df_g_theme_preset_colors__four_coder, -df_g_theme_preset_colors__far_manager, -}; - -DF_CmdParamSlot df_g_cmd_param_slot_2_view_spec_src_map[] = -{ -DF_CmdParamSlot_Entity, -DF_CmdParamSlot_EntityList, -DF_CmdParamSlot_FilePath, -DF_CmdParamSlot_CmdSpec, -DF_CmdParamSlot_ID, -DF_CmdParamSlot_String, -DF_CmdParamSlot_String, -}; - -String8 df_g_cmd_param_slot_2_view_spec_dst_map[] = -{ -str8_lit_comp("entity_lister"), -str8_lit_comp("entity_lister"), -str8_lit_comp("file_system"), -str8_lit_comp("commands"), -str8_lit_comp("system_processes"), -str8_lit_comp("symbol_lister"), -str8_lit_comp("symbol_lister"), -}; - -String8 df_g_cmd_param_slot_2_view_spec_cmd_map[] = -{ -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp("goto_name"), -str8_lit_comp("function_breakpoint"), -}; - -DF_StringBindingPair df_g_default_binding_table[] = -{ -{str8_lit_comp("kill_all"), {OS_Key_F5, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("step_into_inst"), {OS_Key_F11, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("step_over_inst"), {OS_Key_F10, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("step_out"), {OS_Key_F11, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("halt"), {OS_Key_X, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("halt"), {OS_Key_Pause, 0 }}, -{str8_lit_comp("soft_halt_refresh"), {OS_Key_R, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("run"), {OS_Key_F5, 0 }}, -{str8_lit_comp("restart"), {OS_Key_F5, 0 |OS_EventFlag_Ctrl |OS_EventFlag_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_EventFlag_Ctrl }}, -{str8_lit_comp("set_next_statement"), {OS_Key_F10, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("inc_ui_font_scale"), {OS_Key_Equal, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("dec_ui_font_scale"), {OS_Key_Minus, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("inc_code_font_scale"), {OS_Key_Equal, 0 |OS_EventFlag_Shift |OS_EventFlag_Alt}}, -{str8_lit_comp("dec_code_font_scale"), {OS_Key_Minus, 0 |OS_EventFlag_Shift |OS_EventFlag_Alt}}, -{str8_lit_comp("window"), {OS_Key_N, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("toggle_fullscreen"), {OS_Key_Return, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("new_panel_right"), {OS_Key_P, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("new_panel_down"), {OS_Key_Minus, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("rotate_panel_columns"), {OS_Key_2, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("next_panel"), {OS_Key_Comma, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("prev_panel"), {OS_Key_Comma, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("focus_panel_right"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, -{str8_lit_comp("focus_panel_left"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, -{str8_lit_comp("focus_panel_up"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, -{str8_lit_comp("focus_panel_down"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, -{str8_lit_comp("close_panel"), {OS_Key_P, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("next_tab"), {OS_Key_PageDown, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("prev_tab"), {OS_Key_PageUp, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("next_tab"), {OS_Key_Tab, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("prev_tab"), {OS_Key_Tab, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_tab_right"), {OS_Key_PageDown, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_tab_left"), {OS_Key_PageUp, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("close_tab"), {OS_Key_W, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("tab_bar_top"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, -{str8_lit_comp("tab_bar_bottom"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, -{str8_lit_comp("open"), {OS_Key_O, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("reload_active"), {OS_Key_R, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("switch"), {OS_Key_I, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("switch_to_partner_file"), {OS_Key_O, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("load_user"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift |OS_EventFlag_Alt}}, -{str8_lit_comp("load_profile"), {OS_Key_O, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Alt}}, -{str8_lit_comp("move_left"), {OS_Key_Left, 0 }}, -{str8_lit_comp("move_right"), {OS_Key_Right, 0 }}, -{str8_lit_comp("move_up"), {OS_Key_Up, 0 }}, -{str8_lit_comp("move_down"), {OS_Key_Down, 0 }}, -{str8_lit_comp("move_left_select"), {OS_Key_Left, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("move_right_select"), {OS_Key_Right, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("move_up_select"), {OS_Key_Up, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("move_down_select"), {OS_Key_Down, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("move_left_chunk"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("move_right_chunk"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("move_up_chunk"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("move_down_chunk"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("move_up_page"), {OS_Key_PageUp, 0 }}, -{str8_lit_comp("move_down_page"), {OS_Key_PageDown, 0 }}, -{str8_lit_comp("move_up_whole"), {OS_Key_Home, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("move_down_whole"), {OS_Key_End, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("move_left_chunk_select"), {OS_Key_Left, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_right_chunk_select"), {OS_Key_Right, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_up_chunk_select"), {OS_Key_Up, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_down_chunk_select"), {OS_Key_Down, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_up_page_select"), {OS_Key_PageUp, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("move_down_page_select"), {OS_Key_PageDown, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("move_up_whole_select"), {OS_Key_Home, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_down_whole_select"), {OS_Key_End, 0 |OS_EventFlag_Ctrl |OS_EventFlag_Shift }}, -{str8_lit_comp("move_home"), {OS_Key_Home, 0 }}, -{str8_lit_comp("move_end"), {OS_Key_End, 0 }}, -{str8_lit_comp("move_home_select"), {OS_Key_Home, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("move_end_select"), {OS_Key_End, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("select_all"), {OS_Key_A, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("delete_single"), {OS_Key_Delete, 0 }}, -{str8_lit_comp("delete_chunk"), {OS_Key_Delete, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("backspace_single"), {OS_Key_Backspace, 0 }}, -{str8_lit_comp("backspace_chunk"), {OS_Key_Backspace, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("copy"), {OS_Key_C, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("cut"), {OS_Key_X, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("paste"), {OS_Key_V, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("insert_text"), {OS_Key_Null, 0 }}, -{str8_lit_comp("goto_line"), {OS_Key_G, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("goto_address"), {OS_Key_G, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("find_text_forward"), {OS_Key_F, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("find_text_backward"), {OS_Key_R, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("find_next"), {OS_Key_F3, 0 }}, -{str8_lit_comp("find_prev"), {OS_Key_F3, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("find_selected_thread"), {OS_Key_F4, 0 }}, -{str8_lit_comp("goto_name"), {OS_Key_J, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("goto_name_at_cursor"), {OS_Key_F12, 0 }}, -{str8_lit_comp("toggle_watch_expr_at_cursor"), {OS_Key_W, 0 |OS_EventFlag_Alt}}, -{str8_lit_comp("toggle_watch_pin_at_cursor"), {OS_Key_F9, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("toggle_breakpoint_cursor"), {OS_Key_F9, 0 }}, -{str8_lit_comp("add_target"), {OS_Key_T, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("attach"), {OS_Key_F6, 0 |OS_EventFlag_Shift }}, -{str8_lit_comp("filter"), {OS_Key_Slash, 0 |OS_EventFlag_Ctrl }}, -{str8_lit_comp("run_command"), {OS_Key_F1, 0 }}, -}; - -String8 df_g_binding_version_remap_old_name_table[] = -{ -str8_lit_comp("commands"), -str8_lit_comp("load_user"), -str8_lit_comp("load_profile"), -}; - -String8 df_g_binding_version_remap_new_name_table[] = -{ -str8_lit_comp("run_command"), -str8_lit_comp("open_user"), -str8_lit_comp("open_profile"), -}; - -DF_ViewSpecInfo df_g_gfx_view_kind_spec_info_table[] = -{ -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("null"), str8_lit_comp(""), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Null), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Null), DF_VIEW_CMD_FUNCTION_NAME(Null), DF_VIEW_UI_FUNCTION_NAME(Null)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("empty"), str8_lit_comp(""), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(Empty), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Empty), DF_VIEW_CMD_FUNCTION_NAME(Empty), DF_VIEW_UI_FUNCTION_NAME(Empty)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("commands"), str8_lit_comp("Commands"), DF_NameKind_Null, DF_IconKind_List, DF_VIEW_SETUP_FUNCTION_NAME(Commands), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Commands), DF_VIEW_CMD_FUNCTION_NAME(Commands), DF_VIEW_UI_FUNCTION_NAME(Commands)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("file_system"), str8_lit_comp("File System"), DF_NameKind_Null, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(FileSystem), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(FileSystem), DF_VIEW_CMD_FUNCTION_NAME(FileSystem), DF_VIEW_UI_FUNCTION_NAME(FileSystem)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("system_processes"), str8_lit_comp("System Processes"), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(SystemProcesses), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(SystemProcesses), DF_VIEW_CMD_FUNCTION_NAME(SystemProcesses), DF_VIEW_UI_FUNCTION_NAME(SystemProcesses)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("entity_lister"), str8_lit_comp("Entity List"), DF_NameKind_EntityKindName, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(EntityLister), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(EntityLister), DF_VIEW_CMD_FUNCTION_NAME(EntityLister), DF_VIEW_UI_FUNCTION_NAME(EntityLister)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("symbol_lister"), str8_lit_comp("Symbols"), DF_NameKind_Null, DF_IconKind_Null, DF_VIEW_SETUP_FUNCTION_NAME(SymbolLister), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(SymbolLister), DF_VIEW_CMD_FUNCTION_NAME(SymbolLister), DF_VIEW_UI_FUNCTION_NAME(SymbolLister)}, -{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("target"), str8_lit_comp("Target"), DF_NameKind_EntityName, DF_IconKind_Target, DF_VIEW_SETUP_FUNCTION_NAME(Target), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Target), DF_VIEW_CMD_FUNCTION_NAME(Target), DF_VIEW_UI_FUNCTION_NAME(Target)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("targets"), str8_lit_comp("Targets"), DF_NameKind_Null, DF_IconKind_Target, DF_VIEW_SETUP_FUNCTION_NAME(Targets), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Targets), DF_VIEW_CMD_FUNCTION_NAME(Targets), DF_VIEW_UI_FUNCTION_NAME(Targets)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("file_path_map"), str8_lit_comp("File Path Map"), DF_NameKind_Null, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(FilePathMap), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(FilePathMap), DF_VIEW_CMD_FUNCTION_NAME(FilePathMap), DF_VIEW_UI_FUNCTION_NAME(FilePathMap)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("scheduler"), str8_lit_comp("Scheduler"), DF_NameKind_Null, DF_IconKind_Scheduler, DF_VIEW_SETUP_FUNCTION_NAME(Scheduler), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Scheduler), DF_VIEW_CMD_FUNCTION_NAME(Scheduler), DF_VIEW_UI_FUNCTION_NAME(Scheduler)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("call_stack"), str8_lit_comp("Call Stack"), DF_NameKind_Null, DF_IconKind_Thread, DF_VIEW_SETUP_FUNCTION_NAME(CallStack), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(CallStack), DF_VIEW_CMD_FUNCTION_NAME(CallStack), DF_VIEW_UI_FUNCTION_NAME(CallStack)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("modules"), str8_lit_comp("Modules"), DF_NameKind_Null, DF_IconKind_Module, DF_VIEW_SETUP_FUNCTION_NAME(Modules), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Modules), DF_VIEW_CMD_FUNCTION_NAME(Modules), DF_VIEW_UI_FUNCTION_NAME(Modules)}, -{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|0*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("pending_entity"), str8_lit_comp("Pending Entity"), DF_NameKind_EntityName, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(PendingEntity), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(PendingEntity), DF_VIEW_CMD_FUNCTION_NAME(PendingEntity), DF_VIEW_UI_FUNCTION_NAME(PendingEntity)}, -{(0|1*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|1*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("code"), str8_lit_comp("Code"), DF_NameKind_EntityName, DF_IconKind_FileOutline, DF_VIEW_SETUP_FUNCTION_NAME(Code), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Code), DF_VIEW_CMD_FUNCTION_NAME(Code), DF_VIEW_UI_FUNCTION_NAME(Code)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("disassembly"), str8_lit_comp("Disassembly"), DF_NameKind_Null, DF_IconKind_Glasses, DF_VIEW_SETUP_FUNCTION_NAME(Disassembly), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Disassembly), DF_VIEW_CMD_FUNCTION_NAME(Disassembly), DF_VIEW_UI_FUNCTION_NAME(Disassembly)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("watch"), str8_lit_comp("Watch"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Watch), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Watch), DF_VIEW_CMD_FUNCTION_NAME(Watch), DF_VIEW_UI_FUNCTION_NAME(Watch)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("locals"), str8_lit_comp("Locals"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Locals), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Locals), DF_VIEW_CMD_FUNCTION_NAME(Locals), DF_VIEW_UI_FUNCTION_NAME(Locals)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("registers"), str8_lit_comp("Registers"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Registers), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Registers), DF_VIEW_CMD_FUNCTION_NAME(Registers), DF_VIEW_UI_FUNCTION_NAME(Registers)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("globals"), str8_lit_comp("Globals"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Globals), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Globals), DF_VIEW_CMD_FUNCTION_NAME(Globals), DF_VIEW_UI_FUNCTION_NAME(Globals)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("thread_locals"), str8_lit_comp("Thread Locals"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(ThreadLocals), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(ThreadLocals), DF_VIEW_CMD_FUNCTION_NAME(ThreadLocals), DF_VIEW_UI_FUNCTION_NAME(ThreadLocals)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("types"), str8_lit_comp("Types"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Types), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Types), DF_VIEW_CMD_FUNCTION_NAME(Types), DF_VIEW_UI_FUNCTION_NAME(Types)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("procedures"), str8_lit_comp("Procedures"), DF_NameKind_Null, DF_IconKind_Binoculars, DF_VIEW_SETUP_FUNCTION_NAME(Procedures), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Procedures), DF_VIEW_CMD_FUNCTION_NAME(Procedures), DF_VIEW_UI_FUNCTION_NAME(Procedures)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("output"), str8_lit_comp("Output"), DF_NameKind_Null, DF_IconKind_List, DF_VIEW_SETUP_FUNCTION_NAME(Output), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Output), DF_VIEW_CMD_FUNCTION_NAME(Output), DF_VIEW_UI_FUNCTION_NAME(Output)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|1*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("memory"), str8_lit_comp("Memory"), DF_NameKind_Null, DF_IconKind_Grid, DF_VIEW_SETUP_FUNCTION_NAME(Memory), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Memory), DF_VIEW_CMD_FUNCTION_NAME(Memory), DF_VIEW_UI_FUNCTION_NAME(Memory)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("breakpoints"), str8_lit_comp("Breakpoints"), DF_NameKind_Null, DF_IconKind_CircleFilled, DF_VIEW_SETUP_FUNCTION_NAME(Breakpoints), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Breakpoints), DF_VIEW_CMD_FUNCTION_NAME(Breakpoints), DF_VIEW_UI_FUNCTION_NAME(Breakpoints)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|1*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("watch_pins"), str8_lit_comp("Watch Pins"), DF_NameKind_Null, DF_IconKind_Pin, DF_VIEW_SETUP_FUNCTION_NAME(WatchPins), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(WatchPins), DF_VIEW_CMD_FUNCTION_NAME(WatchPins), DF_VIEW_UI_FUNCTION_NAME(WatchPins)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|1*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|1*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("exception_filters"), str8_lit_comp("Exception Filters"), DF_NameKind_Null, DF_IconKind_Gear, DF_VIEW_SETUP_FUNCTION_NAME(ExceptionFilters), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(ExceptionFilters), DF_VIEW_CMD_FUNCTION_NAME(ExceptionFilters), DF_VIEW_UI_FUNCTION_NAME(ExceptionFilters)}, -{(0|0*DF_ViewSpecFlag_ParameterizedByEntity|1*DF_ViewSpecFlag_CanSerialize|0*DF_ViewSpecFlag_CanSerializeEntityPath|0*DF_ViewSpecFlag_CanFilter|0*DF_ViewSpecFlag_FilterIsCode|0*DF_ViewSpecFlag_TypingAutomaticallyFilters), str8_lit_comp("theme"), str8_lit_comp("Theme"), DF_NameKind_Null, DF_IconKind_Palette, DF_VIEW_SETUP_FUNCTION_NAME(Theme), DF_VIEW_STRING_FROM_STATE_FUNCTION_NAME(Theme), DF_VIEW_CMD_FUNCTION_NAME(Theme), DF_VIEW_UI_FUNCTION_NAME(Theme)}, -}; - -String8 df_g_theme_color_display_string_table[] = -{ -str8_lit_comp("Null"), -str8_lit_comp("Plain Text"), -str8_lit_comp("Plain Background"), -str8_lit_comp("Plain Border"), -str8_lit_comp("Plain Overlay"), -str8_lit_comp("Code (Default)"), -str8_lit_comp("Code (Function)"), -str8_lit_comp("Code (Type)"), -str8_lit_comp("Code (Local)"), -str8_lit_comp("Code (Keyword)"), -str8_lit_comp("Code (Symbol)"), -str8_lit_comp("Code (Numeric)"), -str8_lit_comp("Code (String)"), -str8_lit_comp("Code (Meta)"), -str8_lit_comp("Code (Comment)"), -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 Text"), -str8_lit_comp("Alt Background"), -str8_lit_comp("Alt Border"), -str8_lit_comp("Alt Overlay"), -str8_lit_comp("Inactive Tab"), -str8_lit_comp("Active Tab"), -str8_lit_comp("Entity Background"), -str8_lit_comp("Query Bar"), -str8_lit_comp("Weak Text"), -str8_lit_comp("Text Selection"), -str8_lit_comp("Cursor"), -str8_lit_comp("Highlight (0)"), -str8_lit_comp("Highlight (1)"), -str8_lit_comp("Success Text"), -str8_lit_comp("Success Background"), -str8_lit_comp("Success Border"), -str8_lit_comp("Failure Text"), -str8_lit_comp("Failure Background"), -str8_lit_comp("Failure Border"), -str8_lit_comp("Action Text"), -str8_lit_comp("Action Background"), -str8_lit_comp("Action Border"), -str8_lit_comp("Drop Site Overlay"), -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("Inactive Panel Overlay"), -str8_lit_comp("Drop Shadow"), -}; - -String8 df_g_theme_color_cfg_string_table[] = -{ -str8_lit_comp("null"), -str8_lit_comp("plain_text"), -str8_lit_comp("plain_background"), -str8_lit_comp("plain_border"), -str8_lit_comp("plain_overlay"), -str8_lit_comp("code_default"), -str8_lit_comp("code_function"), -str8_lit_comp("code_type"), -str8_lit_comp("code_local"), -str8_lit_comp("code_keyword"), -str8_lit_comp("code_symbol"), -str8_lit_comp("code_numeric"), -str8_lit_comp("code_string"), -str8_lit_comp("code_meta"), -str8_lit_comp("code_comment"), -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_text"), -str8_lit_comp("alt_background"), -str8_lit_comp("alt_border"), -str8_lit_comp("alt_overlay"), -str8_lit_comp("tab_inactive"), -str8_lit_comp("tab_active"), -str8_lit_comp("entity_background"), -str8_lit_comp("query_bar"), -str8_lit_comp("weak_text"), -str8_lit_comp("text_selection"), -str8_lit_comp("cursor"), -str8_lit_comp("highlight_0"), -str8_lit_comp("highlight_1"), -str8_lit_comp("success_text"), -str8_lit_comp("success_background"), -str8_lit_comp("success_border"), -str8_lit_comp("failure_text"), -str8_lit_comp("failure_background"), -str8_lit_comp("failure_border"), -str8_lit_comp("action_text"), -str8_lit_comp("action_background"), -str8_lit_comp("action_border"), -str8_lit_comp("drop_site_overlay"), -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("inactive_panel_overlay"), -str8_lit_comp("drop_shadow"), -}; - +DF_GFX_VIEW_RULE_WHOLE_UI_FUNCTION_DEF(bitmap); +C_LINKAGE_BEGIN +extern String8 df_g_theme_preset_display_string_table[9]; +extern String8 df_g_theme_preset_code_string_table[9]; +extern Vec4F32 df_g_theme_preset_colors__default_dark[54]; +extern Vec4F32 df_g_theme_preset_colors__default_light[54]; +extern Vec4F32 df_g_theme_preset_colors__vs_dark[54]; +extern Vec4F32 df_g_theme_preset_colors__vs_light[54]; +extern Vec4F32 df_g_theme_preset_colors__solarized_dark[54]; +extern Vec4F32 df_g_theme_preset_colors__solarized_light[54]; +extern Vec4F32 df_g_theme_preset_colors__handmade_hero[54]; +extern Vec4F32 df_g_theme_preset_colors__four_coder[54]; +extern Vec4F32 df_g_theme_preset_colors__far_manager[54]; +extern Vec4F32* df_g_theme_preset_colors_table[9]; +extern DF_CmdParamSlot df_g_cmd_param_slot_2_view_spec_src_map[7]; +extern String8 df_g_cmd_param_slot_2_view_spec_dst_map[7]; +extern String8 df_g_cmd_param_slot_2_view_spec_cmd_map[7]; +extern DF_StringBindingPair df_g_default_binding_table[97]; +extern String8 df_g_binding_version_remap_old_name_table[3]; +extern String8 df_g_binding_version_remap_new_name_table[3]; +extern DF_ViewSpecInfo df_g_gfx_view_kind_spec_info_table[30]; +extern String8 df_g_theme_color_display_string_table[54]; +extern String8 df_g_theme_color_cfg_string_table[54]; read_only global U8 df_g_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, @@ -5674,5 +4864,6 @@ read_only global U8 df_g_default_code_font_bytes__data[] = }; read_only global String8 df_g_default_code_font_bytes = {df_g_default_code_font_bytes__data, sizeof(df_g_default_code_font_bytes__data)}; +C_LINKAGE_END #endif // DF_GFX_META_H diff --git a/src/draw/draw.mdesk b/src/draw/draw.mdesk index bba9861e..cc4be4f2 100644 --- a/src/draw/draw.mdesk +++ b/src/draw/draw.mdesk @@ -10,31 +10,31 @@ D_StackTable: {Transparency transparency F32 `0` } } -@table_gen +@gen { @expand(D_StackTable a) `typedef struct D_$(a.name)Node D_$(a.name)Node; struct D_$(a.name)Node {D_$(a.name)Node *next; $(a.type) v;};`; } -@table_gen +@gen { `#define D_BucketStackDecls struct{\\`; @expand(D_StackTable a) `D_$(a.name)Node *top_$(a.name_lower);\\`; `}`; } -@table_gen +@gen { @expand(D_StackTable a) `read_only global D_$(a.name)Node d_nil_$(a.name_lower) = {0, $(a.default_init)};`; } -@table_gen +@gen { `#define D_BucketStackInits(b) do{\\`; @expand(D_StackTable a) `(b)->top_$(a.name_lower) = &d_nil_$(a.name_lower);\\`; `}while(0)`; } -@table_gen +@gen { `#if 0`; @expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v);`; @@ -43,14 +43,14 @@ D_StackTable: `#endif`; } -@table_gen @c_file +@gen @c_file { @expand(D_StackTable a) `internal $(a.type) $(=>35) d_push_$(a.name_lower)($(a.type) v) {D_StackPushImpl($(a.name), $(a.name_lower), $(a.type), v);}`; @expand(D_StackTable a) `internal $(a.type) $(=>35) d_pop_$(a.name_lower)(void) {D_StackPopImpl($(a.name), $(a.name_lower), $(a.type));}`; @expand(D_StackTable a) `internal $(a.type) $(=>35) d_top_$(a.name_lower)(void) {D_StackTopImpl($(a.name), $(a.name_lower), $(a.type));}`; } -@table_gen +@gen { `#if 0`; @expand(D_StackTable a) `#define D_$(a.name)Scope(v) $(=>35) DeferLoop(d_push_$(a.name_lower)(v), d_pop_$(a.name_lower)())`; diff --git a/src/draw/generated/draw.meta.c b/src/draw/generated/draw.meta.c index 50ed1be1..eee3e601 100644 --- a/src/draw/generated/draw.meta.c +++ b/src/draw/generated/draw.meta.c @@ -15,3 +15,6 @@ internal R_Tex2DSampleKind d_top_tex2d_sample_kind(void) {D_StackTopImp internal Mat3x3F32 d_top_xform2d(void) {D_StackTopImpl(XForm2D, xform2d, Mat3x3F32);} internal Rng2F32 d_top_clip(void) {D_StackTopImpl(Clip, clip, Rng2F32);} internal F32 d_top_transparency(void) {D_StackTopImpl(Transparency, transparency, F32);} +C_LINKAGE_BEGIN +C_LINKAGE_END + diff --git a/src/draw/generated/draw.meta.h b/src/draw/generated/draw.meta.h index 0cf4f6d9..e465899d 100644 --- a/src/draw/generated/draw.meta.h +++ b/src/draw/generated/draw.meta.h @@ -46,5 +46,7 @@ internal F32 d_top_transparency(void); #define D_ClipScope(v) DeferLoop(d_push_clip(v), d_pop_clip()) #define D_TransparencyScope(v) DeferLoop(d_push_transparency(v), d_pop_transparency()) #endif +C_LINKAGE_BEGIN +C_LINKAGE_END #endif // DRAW_META_H diff --git a/src/eval/eval.mdesk b/src/eval/eval.mdesk index 8e26553a..56c26b51 100644 --- a/src/eval/eval.mdesk +++ b/src/eval/eval.mdesk @@ -6,6 +6,8 @@ // op_string - string for quick display of the operator EVAL_ExprKindTable: { + { Nil 0 "" } + { ArrayIndex 2 "[]" } { MemberAccess 2 "." } { Deref 1 "*" } @@ -54,31 +56,51 @@ EVAL_ExprKindTable: { LeafIdent 0 "leaf_ident" } } -@table_gen +@table(name display_string) +EVAL_ResultCodeTable: { - `typedef U32 EVAL_ExprKind;`; - `enum`; - `{`; - @expand(EVAL_ExprKindTable a) `EVAL_ExprKind_$(a.name),`; - `EVAL_ExprKind_COUNT`; - `};`; - ``; + { Good "" } + { DivideByZero "Cannot divide by zero." } + { BadOp "Invalid operation." } + { BadOpTypes "Invalid operation types." } + { BadMemRead "Failed memory read." } + { BadRegRead "Failed register read." } + { BadFrameBase "Invalid frame base address." } + { BadModuleBase "Invalid module base address." } + { BadTLSBase "Invalid thread-local storage base address." } + { InsufficientStackSpace "Insufficient evaluation machine stack space." } + { MalformedBytecode "Malformed bytecode." } } -@table_gen_data(type:U8, fallback:0) -eval_expr_kind_child_counts: +@enum(U32) EVAL_ExprKind: { - @expand(EVAL_ExprKindTable a) `$(a.num_children),`; + @expand(EVAL_ExprKindTable a) `$(a.name)`, + COUNT, } -@table_gen_data(type:String8, fallback:`{0}`) +@enum EVAL_ResultCode: +{ + @expand(EVAL_ResultCodeTable a) `$(a.name)`, + COUNT, +} + +@data(U8) eval_expr_kind_child_counts: +{ + @expand(EVAL_ExprKindTable a) `$(a.num_children)` +} + +@data(String8) eval_expr_kind_strings: { - @expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.name)"),`; + @expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.name)")` } -@table_gen_data(type:String8, fallback:`{0}`) -eval_expr_op_strings: +@data(String8) eval_result_code_display_strings: { - @expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.op_string)"),`; + @expand(EVAL_ResultCodeTable a) `str8_lit_comp("$(a.display_string)")` +} + +@data(String8) eval_expr_op_strings: +{ + @expand(EVAL_ExprKindTable a) `str8_lit_comp("$(a.op_string)")` } diff --git a/src/eval/eval_compiler.c b/src/eval/eval_compiler.c index e303f29d..792d1cb9 100644 --- a/src/eval/eval_compiler.c +++ b/src/eval/eval_compiler.c @@ -23,8 +23,8 @@ eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list){ default: { // compute bytecode advance - U8 ctrlbits = raddbg_eval_opcode_ctrlbits[opcode]; - U64 extra_byte_count = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); + U8 ctrlbits = rdi_eval_opcode_ctrlbits[opcode]; + U64 extra_byte_count = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); U8 *next_ptr = ptr + 1 + extra_byte_count; Assert(next_ptr <= opl); @@ -62,9 +62,9 @@ eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list){ } internal void -eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RADDBG_EvalOp opcode, U64 p){ - U8 ctrlbits = raddbg_eval_opcode_ctrlbits[opcode]; - U32 p_size = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); +eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RDI_EvalOp opcode, U64 p){ + U8 ctrlbits = rdi_eval_opcode_ctrlbits[opcode]; + U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); EVAL_Op *node = push_array_no_zero(arena, EVAL_Op, 1); node->opcode = opcode; @@ -78,35 +78,35 @@ eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RADDBG_EvalOp opcode, U64 p internal void eval_oplist_push_uconst(Arena *arena, EVAL_OpList *list, U64 x){ if (x <= 0xFF){ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU8, x); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU8, x); } else if (x <= 0xFFFF){ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU16, x); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU16, x); } else if (x <= 0xFFFFFFFF){ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU32, x); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU32, x); } else{ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU64, x); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU64, x); } } internal void eval_oplist_push_sconst(Arena *arena, EVAL_OpList *list, S64 x){ if (-0x80 <= x && x <= 0x7F){ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU8, (U64)x); - eval_oplist_push_op(arena, list, RADDBG_EvalOp_TruncSigned, 8); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU8, (U64)x); + eval_oplist_push_op(arena, list, RDI_EvalOp_TruncSigned, 8); } else if (-0x8000 <= x && x <= 0x7FFF){ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU16, (U64)x); - eval_oplist_push_op(arena, list, RADDBG_EvalOp_TruncSigned, 16); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU16, (U64)x); + eval_oplist_push_op(arena, list, RDI_EvalOp_TruncSigned, 16); } else if (-0x80000000ll <= x && x <= 0x7FFFFFFFll){ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU32, (U64)x); - eval_oplist_push_op(arena, list, RADDBG_EvalOp_TruncSigned, 32); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU32, (U64)x); + eval_oplist_push_op(arena, list, RDI_EvalOp_TruncSigned, 32); } else{ - eval_oplist_push_op(arena, list, RADDBG_EvalOp_ConstU64, (U64)x); + eval_oplist_push_op(arena, list, RDI_EvalOp_ConstU64, (U64)x); } } @@ -138,31 +138,31 @@ eval_oplist_concat_in_place(EVAL_OpList *left_dst, EVAL_OpList *right_destroyed) //////////////////////////////// //~ allen: EVAL Expression Info Functions -internal RADDBG_EvalOp +internal RDI_EvalOp eval_opcode_from_expr_kind(EVAL_ExprKind kind){ - RADDBG_EvalOp result = RADDBG_EvalOp_Stop; + RDI_EvalOp result = RDI_EvalOp_Stop; switch (kind){ - case EVAL_ExprKind_Neg: result = RADDBG_EvalOp_Neg; break; - case EVAL_ExprKind_LogNot: result = RADDBG_EvalOp_LogNot; break; - case EVAL_ExprKind_BitNot: result = RADDBG_EvalOp_BitNot; break; - case EVAL_ExprKind_Mul: result = RADDBG_EvalOp_Mul; break; - case EVAL_ExprKind_Div: result = RADDBG_EvalOp_Div; break; - case EVAL_ExprKind_Mod: result = RADDBG_EvalOp_Mod; break; - case EVAL_ExprKind_Add: result = RADDBG_EvalOp_Add; break; - case EVAL_ExprKind_Sub: result = RADDBG_EvalOp_Sub; break; - case EVAL_ExprKind_LShift: result = RADDBG_EvalOp_LShift; break; - case EVAL_ExprKind_RShift: result = RADDBG_EvalOp_RShift; break; - case EVAL_ExprKind_Less: result = RADDBG_EvalOp_Less; break; - case EVAL_ExprKind_LsEq: result = RADDBG_EvalOp_LsEq; break; - case EVAL_ExprKind_Grtr: result = RADDBG_EvalOp_Grtr; break; - case EVAL_ExprKind_GrEq: result = RADDBG_EvalOp_GrEq; break; - case EVAL_ExprKind_EqEq: result = RADDBG_EvalOp_EqEq; break; - case EVAL_ExprKind_NtEq: result = RADDBG_EvalOp_NtEq; break; - case EVAL_ExprKind_BitAnd: result = RADDBG_EvalOp_BitAnd; break; - case EVAL_ExprKind_BitXor: result = RADDBG_EvalOp_BitXor; break; - case EVAL_ExprKind_BitOr: result = RADDBG_EvalOp_BitOr; break; - case EVAL_ExprKind_LogAnd: result = RADDBG_EvalOp_LogAnd; break; - case EVAL_ExprKind_LogOr: result = RADDBG_EvalOp_LogOr; break; + case EVAL_ExprKind_Neg: result = RDI_EvalOp_Neg; break; + case EVAL_ExprKind_LogNot: result = RDI_EvalOp_LogNot; break; + case EVAL_ExprKind_BitNot: result = RDI_EvalOp_BitNot; break; + case EVAL_ExprKind_Mul: result = RDI_EvalOp_Mul; break; + case EVAL_ExprKind_Div: result = RDI_EvalOp_Div; break; + case EVAL_ExprKind_Mod: result = RDI_EvalOp_Mod; break; + case EVAL_ExprKind_Add: result = RDI_EvalOp_Add; break; + case EVAL_ExprKind_Sub: result = RDI_EvalOp_Sub; break; + case EVAL_ExprKind_LShift: result = RDI_EvalOp_LShift; break; + case EVAL_ExprKind_RShift: result = RDI_EvalOp_RShift; break; + case EVAL_ExprKind_Less: result = RDI_EvalOp_Less; break; + case EVAL_ExprKind_LsEq: result = RDI_EvalOp_LsEq; break; + case EVAL_ExprKind_Grtr: result = RDI_EvalOp_Grtr; break; + case EVAL_ExprKind_GrEq: result = RDI_EvalOp_GrEq; break; + case EVAL_ExprKind_EqEq: result = RDI_EvalOp_EqEq; break; + case EVAL_ExprKind_NtEq: result = RDI_EvalOp_NtEq; break; + case EVAL_ExprKind_BitAnd: result = RDI_EvalOp_BitAnd; break; + case EVAL_ExprKind_BitXor: result = RDI_EvalOp_BitXor; break; + case EVAL_ExprKind_BitOr: result = RDI_EvalOp_BitOr; break; + case EVAL_ExprKind_LogAnd: result = RDI_EvalOp_LogAnd; break; + case EVAL_ExprKind_LogOr: result = RDI_EvalOp_LogOr; break; } return(result); } @@ -286,9 +286,9 @@ eval_expr_leaf_type(Arena *arena, void *location, TG_Key type_key){ //////////////////////////////// //~ allen: EVAL Type Information Transformers -internal RADDBG_EvalTypeGroup +internal RDI_EvalTypeGroup eval_type_group_from_kind(TG_Kind kind){ - RADDBG_EvalTypeGroup result = 0; + RDI_EvalTypeGroup result = 0; switch (kind){ default:{}break; @@ -303,7 +303,7 @@ eval_type_group_from_kind(TG_Kind kind){ case TG_Kind_IncompleteStruct: case TG_Kind_IncompleteClass: case TG_Kind_IncompleteUnion: case TG_Kind_IncompleteEnum: case TG_Kind_Bitfield: case TG_Kind_Variadic: - result = RADDBG_EvalTypeGroup_Other; break; + result = RDI_EvalTypeGroup_Other; break; case TG_Kind_Handle: case TG_Kind_UChar8: case TG_Kind_UChar16: case TG_Kind_UChar32: @@ -312,26 +312,26 @@ eval_type_group_from_kind(TG_Kind kind){ case TG_Kind_U512: case TG_Kind_Ptr: case TG_Kind_LRef: case TG_Kind_RRef: case TG_Kind_Function: case TG_Kind_Method: case TG_Kind_MemberPtr: - result = RADDBG_EvalTypeGroup_U; break; + result = RDI_EvalTypeGroup_U; break; case TG_Kind_Char8: case TG_Kind_Char16: case TG_Kind_Char32: case TG_Kind_S8: case TG_Kind_S16: case TG_Kind_S32: case TG_Kind_S64: case TG_Kind_S128: case TG_Kind_S256: case TG_Kind_S512: case TG_Kind_Bool: - result = RADDBG_EvalTypeGroup_S; break; + result = RDI_EvalTypeGroup_S; break; case TG_Kind_F32: - result = RADDBG_EvalTypeGroup_F32; break; + result = RDI_EvalTypeGroup_F32; break; case TG_Kind_F64: - result = RADDBG_EvalTypeGroup_F64; break; + result = RDI_EvalTypeGroup_F64; break; } return(result); } internal TG_Key -eval_type_unwrap_enum(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +eval_type_unwrap_enum(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { TG_Key result = key; for(B32 good = 1; good;) @@ -339,7 +339,7 @@ eval_type_unwrap_enum(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) TG_Kind kind = tg_kind_from_key(key); if(kind == TG_Kind_Enum) { - result = tg_direct_from_graph_raddbg_key(graph, rdbg, result); + result = tg_direct_from_graph_rdi_key(graph, rdi, result); } else { @@ -350,7 +350,7 @@ eval_type_unwrap_enum(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) } internal TG_Key -eval_type_promote(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key){ +eval_type_promote(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key){ TG_Key result = key; TG_Kind kind = tg_kind_from_key(key); if(kind == TG_Kind_Bool || @@ -365,17 +365,17 @@ eval_type_promote(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key){ } internal TG_Key -eval_type_coerce(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ +eval_type_coerce(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r){ Assert(eval_kind_is_basic_or_enum(tg_kind_from_key(l)) && eval_kind_is_basic_or_enum(tg_kind_from_key(r))); // replace enums with corresponding ints - TG_Key lt = eval_type_unwrap_enum(graph, rdbg, l); - TG_Key rt = eval_type_unwrap_enum(graph, rdbg, r); + TG_Key lt = eval_type_unwrap_enum(graph, rdi, l); + TG_Key rt = eval_type_unwrap_enum(graph, rdi, r); // first promote each - TG_Key lp = eval_type_promote(graph, rdbg, lt); - TG_Key rp = eval_type_promote(graph, rdbg, rt); + TG_Key lp = eval_type_promote(graph, rdi, lt); + TG_Key rp = eval_type_promote(graph, rdi, rt); TG_Kind lk = tg_kind_from_key(lp); TG_Kind rk = tg_kind_from_key(rp); @@ -384,12 +384,12 @@ eval_type_coerce(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ } internal B32 -eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ +eval_type_match(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r){ B32 result = 0; // unwrap - TG_Key lu = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, l); - TG_Key ru = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, r); + TG_Key lu = tg_unwrapped_from_graph_rdi_key(graph, rdi, l); + TG_Key ru = tg_unwrapped_from_graph_rdi_key(graph, rdi, r); if (tg_key_match(lu, ru)){ result = 1; @@ -408,21 +408,21 @@ eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ case TG_Kind_LRef: case TG_Kind_RRef: { - TG_Key lud = tg_direct_from_graph_raddbg_key(graph, rdbg, lu); - TG_Key rud = tg_direct_from_graph_raddbg_key(graph, rdbg, ru); - if (eval_type_match(graph, rdbg, lud, rud)){ + TG_Key lud = tg_direct_from_graph_rdi_key(graph, rdi, lu); + TG_Key rud = tg_direct_from_graph_rdi_key(graph, rdi, ru); + if (eval_type_match(graph, rdi, lud, rud)){ result = 1; } }break; case TG_Kind_MemberPtr: { - TG_Key lud = tg_direct_from_graph_raddbg_key(graph, rdbg, lu); - TG_Key rud = tg_direct_from_graph_raddbg_key(graph, rdbg, ru); - TG_Key luo = tg_owner_from_graph_raddbg_key(graph, rdbg, lu); - TG_Key ruo = tg_owner_from_graph_raddbg_key(graph, rdbg, ru); - if (eval_type_match(graph, rdbg, lud, rud) && - eval_type_match(graph, rdbg, luo, ruo)){ + TG_Key lud = tg_direct_from_graph_rdi_key(graph, rdi, lu); + TG_Key rud = tg_direct_from_graph_rdi_key(graph, rdi, ru); + TG_Key luo = tg_owner_from_graph_rdi_key(graph, rdi, lu); + TG_Key ruo = tg_owner_from_graph_rdi_key(graph, rdi, ru); + if (eval_type_match(graph, rdi, lud, rud) && + eval_type_match(graph, rdi, luo, ruo)){ result = 1; } }break; @@ -430,9 +430,9 @@ eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ case TG_Kind_Array: { Temp scratch = scratch_begin(0, 0); - TG_Type *lt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, l); - TG_Type *rt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, r); - if(lt->count == rt->count && eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key)) + TG_Type *lt = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, l); + TG_Type *rt = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, r); + if(lt->count == rt->count && eval_type_match(graph, rdi, lt->direct_type_key, rt->direct_type_key)) { result = 1; } @@ -442,9 +442,9 @@ eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ case TG_Kind_Function: { Temp scratch = scratch_begin(0, 0); - TG_Type *lt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, l); - TG_Type *rt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, r); - if (lt->count == rt->count && eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key)) + TG_Type *lt = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, l); + TG_Type *rt = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, r); + if (lt->count == rt->count && eval_type_match(graph, rdi, lt->direct_type_key, rt->direct_type_key)) { B32 params_match = 1; TG_Key *lp = lt->param_type_keys; @@ -452,7 +452,7 @@ eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ U64 count = lt->count; for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) { - if(!eval_type_match(graph, rdbg, *lp, *rp)) + if(!eval_type_match(graph, rdi, *lp, *rp)) { params_match = 0; break; @@ -466,11 +466,11 @@ eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ case TG_Kind_Method: { Temp scratch = scratch_begin(0, 0); - TG_Type *lt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, l); - TG_Type *rt = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, r); + TG_Type *lt = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, l); + TG_Type *rt = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, r); if (lt->count == rt->count && - eval_type_match(graph, rdbg, lt->direct_type_key, rt->direct_type_key) && - eval_type_match(graph, rdbg, lt->owner_type_key, rt->owner_type_key)) + eval_type_match(graph, rdi, lt->direct_type_key, rt->direct_type_key) && + eval_type_match(graph, rdi, lt->owner_type_key, rt->owner_type_key)) { B32 params_match = 1; TG_Key *lp = lt->param_type_keys; @@ -478,7 +478,7 @@ eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r){ U64 count = lt->count; for(U64 i = 0; i < count; i += 1, lp += 1, rp += 1) { - if(!eval_type_match(graph, rdbg, *lp, *rp)) + if(!eval_type_match(graph, rdi, *lp, *rp)) { params_match = 0; break; @@ -522,15 +522,15 @@ eval_kind_is_basic_or_enum(TG_Kind kind){ internal EVAL_IRTree* eval_irtree_const_u(Arena *arena, U64 v){ // choose encoding op - RADDBG_EvalOp op = RADDBG_EvalOp_ConstU64; + RDI_EvalOp op = RDI_EvalOp_ConstU64; if (v < 0x100){ - op = RADDBG_EvalOp_ConstU8; + op = RDI_EvalOp_ConstU8; } else if (v < 0x10000){ - op = RADDBG_EvalOp_ConstU16; + op = RDI_EvalOp_ConstU16; } else if (v < 0x100000000){ - op = RADDBG_EvalOp_ConstU32; + op = RDI_EvalOp_ConstU32; } // make the tree node @@ -541,8 +541,8 @@ eval_irtree_const_u(Arena *arena, U64 v){ } internal EVAL_IRTree* -eval_irtree_unary_op(Arena *arena, RADDBG_EvalOp op, - RADDBG_EvalTypeGroup group, EVAL_IRTree *c){ +eval_irtree_unary_op(Arena *arena, RDI_EvalOp op, + RDI_EvalTypeGroup group, EVAL_IRTree *c){ EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); result->op = op; result->p = group; @@ -551,7 +551,7 @@ eval_irtree_unary_op(Arena *arena, RADDBG_EvalOp op, } internal EVAL_IRTree* -eval_irtree_binary_op(Arena *arena, RADDBG_EvalOp op, RADDBG_EvalTypeGroup group, +eval_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, EVAL_IRTree *l, EVAL_IRTree *r){ EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); result->op = op; @@ -562,15 +562,15 @@ eval_irtree_binary_op(Arena *arena, RADDBG_EvalOp op, RADDBG_EvalTypeGroup group } internal EVAL_IRTree* -eval_irtree_binary_op_u(Arena *arena, RADDBG_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r){ - EVAL_IRTree *result = eval_irtree_binary_op(arena, op, RADDBG_EvalTypeGroup_U, l, r); +eval_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r){ + EVAL_IRTree *result = eval_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, l, r); return(result); } internal EVAL_IRTree* eval_irtree_conditional(Arena *arena, EVAL_IRTree *c, EVAL_IRTree *l, EVAL_IRTree *r){ EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); - result->op = RADDBG_EvalOp_Cond; + result->op = RDI_EvalOp_Cond; result->children[0] = c; result->children[1] = l; result->children[2] = r; @@ -589,13 +589,13 @@ eval_irtree_bytecode_no_copy(Arena *arena, String8 bytecode){ //~ allen: EVAL IR-Tree High Level Helpers internal EVAL_IRTree* -eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key){ - U64 byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); +eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key){ + U64 byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); EVAL_IRTree *result = &eval_irtree_nil; if (0 < byte_size && byte_size <= 8){ // build the read node EVAL_IRTree *read_node = push_array(arena, EVAL_IRTree, 1); - read_node->op = RADDBG_EvalOp_MemRead; + read_node->op = RDI_EvalOp_MemRead; read_node->p = byte_size; read_node->children[0] = c; @@ -605,7 +605,7 @@ eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EV TG_Kind kind = tg_kind_from_key(type_key); if (bit_size < 64 && eval_kind_is_signed(kind)){ with_trunc = push_array(arena, EVAL_IRTree, 1); - with_trunc->op = RADDBG_EvalOp_TruncSigned; + with_trunc->op = RDI_EvalOp_TruncSigned; with_trunc->p = bit_size; with_trunc->children[0] = read_node; } @@ -620,23 +620,23 @@ eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EV } internal EVAL_IRTree* -eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RADDBG_EvalTypeGroup out, RADDBG_EvalTypeGroup in){ +eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RDI_EvalTypeGroup out, RDI_EvalTypeGroup in){ EVAL_IRTree *result = push_array(arena, EVAL_IRTree, 1); - result->op = RADDBG_EvalOp_Convert; + result->op = RDI_EvalOp_Convert; result->p = in | (out << 8); result->children[0] = c; return(result); } internal EVAL_IRTree* -eval_irtree_trunc(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key){ +eval_irtree_trunc(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key){ EVAL_IRTree *result = c; - U64 byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + U64 byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); if (byte_size < 64){ - RADDBG_EvalOp op = RADDBG_EvalOp_Trunc; + RDI_EvalOp op = RDI_EvalOp_Trunc; TG_Kind kind = tg_kind_from_key(type_key); if (eval_kind_is_signed(kind)){ - op = RADDBG_EvalOp_TruncSigned; + op = RDI_EvalOp_TruncSigned; } U64 bit_size = byte_size << 3; result = push_array(arena, EVAL_IRTree, 1); @@ -648,39 +648,39 @@ eval_irtree_trunc(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTre } internal EVAL_IRTree* -eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key out, TG_Key in){ +eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key out, TG_Key in){ EVAL_IRTree *result = c; TG_Kind in_kind = tg_kind_from_key(in); TG_Kind out_kind = tg_kind_from_key(out); U8 in_group = eval_type_group_from_kind(in_kind); U8 out_group = eval_type_group_from_kind(out_kind); - U32 conversion_rule = raddbg_eval_conversion_rule(in_group, out_group); - if(conversion_rule == RADDBG_EvalConversionKind_Legal) + U32 conversion_rule = rdi_eval_conversion_rule(in_group, out_group); + if(conversion_rule == RDI_EvalConversionKind_Legal) { result = eval_irtree_convert_lo(arena, result, out_group, in_group); } - U64 in_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, in); - U64 out_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, out); + U64 in_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, in); + U64 out_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, out); if(out_byte_size < in_byte_size && eval_kind_is_integer(out_kind)) { - result = eval_irtree_trunc(arena, graph, rdbg, result, out); + result = eval_irtree_trunc(arena, graph, rdi, result, out); } return(result); } internal EVAL_IRTree* -eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_EvalMode from_mode, +eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_EvalMode from_mode, EVAL_IRTree *tree, TG_Key type_key){ EVAL_IRTree *result = tree; switch (from_mode){ default:{}break; case EVAL_EvalMode_Addr: { - result = eval_irtree_mem_read_type(arena, graph, rdbg, tree, type_key); + result = eval_irtree_mem_read_type(arena, graph, rdi, tree, type_key); }break; case EVAL_EvalMode_Reg: { - result = eval_irtree_unary_op(arena, RADDBG_EvalOp_RegReadDyn, RADDBG_EvalTypeGroup_U, tree); + result = eval_irtree_unary_op(arena, RDI_EvalOp_RegReadDyn, RDI_EvalTypeGroup_U, tree); }break; } return(result); @@ -715,7 +715,7 @@ eval_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, EVAL_String2ExprMap } internal TG_Key -eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_Expr *expr, EVAL_ErrorList *eout){ +eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_Expr *expr, EVAL_ErrorList *eout){ TG_Key result = zero_struct; EVAL_ExprKind kind = expr->kind; @@ -732,14 +732,14 @@ eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVA case EVAL_ExprKind_Ptr: { - TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdbg, expr->children[0], eout); + TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdi, expr->children[0], eout); result = tg_cons_type_make(graph, TG_Kind_Ptr, direct_type_key, 0); }break; case EVAL_ExprKind_Array: { EVAL_Expr *child_expr = expr->child_and_constant.child; - TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdbg, child_expr, eout); + TG_Key direct_type_key = eval_type_from_type_expr(arena, graph, rdi, child_expr, eout); result = tg_cons_type_make(graph, TG_Kind_Array, direct_type_key, expr->child_and_constant.u64); }break; @@ -758,7 +758,7 @@ eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVA } internal EVAL_IRTreeAndType -eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_String2ExprMap *leaf_ident_expr_map, EVAL_Expr *expr, EVAL_ErrorList *eout) +eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_String2ExprMap *leaf_ident_expr_map, EVAL_Expr *expr, EVAL_ErrorList *eout) { ProfBeginFunction(); EVAL_IRTreeAndType result = {0}; @@ -777,12 +777,12 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb EVAL_Expr *exprl = expr->children[0]; EVAL_Expr *exprr = expr->children[1]; - EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout); - EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout); + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprl, eout); + EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprr, eout); if (l.tree->op != 0 && r.tree->op != 0){ - TG_Key l_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, l.type_key); - TG_Key r_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, r.type_key); + TG_Key l_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, l.type_key); + TG_Key r_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, r.type_key); TG_Kind l_restype_kind = tg_kind_from_key(l_restype); TG_Kind r_restype_kind = tg_kind_from_key(r_restype); @@ -795,8 +795,8 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Cannot index with this type."); } else{ - direct_type = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, l_restype); - direct_type_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct_type); + direct_type = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, l_restype); + direct_type_size = tg_byte_size_from_graph_rdi_key(graph, rdi, direct_type); if (l_restype_kind == TG_Kind_Ptr){ if (direct_type_size == 0){ eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, exprr->location, "Cannot index into pointers of zero-sized types."); @@ -829,20 +829,20 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb // generate ir tree if (can_generate){ // how to compute the index - EVAL_IRTree *index_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); + EVAL_IRTree *index_tree = eval_irtree_resolve_to_value(arena, graph, rdi, r.mode, r.tree, r_restype); if (direct_type_size > 1){ EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size); - index_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Mul, index_tree, const_tree); + index_tree = eval_irtree_binary_op_u(arena, RDI_EvalOp_Mul, index_tree, const_tree); } // how to compute the base address EVAL_IRTree *base_tree = l.tree; if (l_resolve){ - base_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, base_tree, l_restype); + base_tree = eval_irtree_resolve_to_value(arena, graph, rdi, l.mode, base_tree, l_restype); } // how to compute the final address - EVAL_IRTree *new_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Add, index_tree, base_tree); + EVAL_IRTree *new_tree = eval_irtree_binary_op_u(arena, RDI_EvalOp_Add, index_tree, base_tree); // fill result result.tree = new_tree; @@ -857,17 +857,17 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb EVAL_Expr *exprl = expr->children[0]; EVAL_Expr *exprr = expr->children[1]; - EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout); + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprl, eout); if (l.tree->op != 0 && !tg_key_match(tg_key_zero(), l.type_key)){ - TG_Key l_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, l.type_key); + TG_Key l_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, l.type_key); TG_Kind l_restype_kind = tg_kind_from_key(l_restype); // determine which type to use TG_Key check_type_key = l_restype; TG_Kind check_type_kind = l_restype_kind; if (l_restype_kind == TG_Kind_Ptr || l_restype_kind == TG_Kind_LRef || l_restype_kind == TG_Kind_RRef){ - check_type_key = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, l_restype); + check_type_key = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, l_restype); check_type_kind = tg_kind_from_key(check_type_key); } @@ -921,7 +921,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb if (l_good && r_good){ Temp scratch = scratch_begin(&arena, 1); - TG_MemberArray check_type_members = tg_data_members_from_graph_raddbg_key(scratch.arena, graph, rdbg, check_type_key); + TG_MemberArray check_type_members = tg_data_members_from_graph_rdi_key(scratch.arena, graph, rdi, check_type_key); // lookup member String8 member_name = exprr->name; @@ -953,11 +953,11 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb if (can_generate){ EVAL_IRTree *new_tree = l.tree; if (l_resolve){ - new_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, new_tree, l_restype); + new_tree = eval_irtree_resolve_to_value(arena, graph, rdi, l.mode, new_tree, l_restype); } if (r_off != 0){ EVAL_IRTree *const_tree = eval_irtree_const_u(arena, r_off); - new_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Add, new_tree, const_tree); + new_tree = eval_irtree_binary_op_u(arena, RDI_EvalOp_Add, new_tree, const_tree); } // fill result @@ -975,13 +975,13 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb { EVAL_Expr *exprc = expr->children[0]; - EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout); + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprc, eout); if (c.tree->op != 0){ - TG_Key c_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, c.type_key); + TG_Key c_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, c.type_key); TG_Kind c_restype_kind = tg_kind_from_key(c_restype); - TG_Key c_restype_direct = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, c_restype); - U64 c_restype_direct_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, c_restype_direct); + TG_Key c_restype_direct = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, c_restype); + U64 c_restype_direct_size = tg_byte_size_from_graph_rdi_key(graph, rdi, c_restype_direct); // analyze situation B32 can_generate = 0; @@ -1018,7 +1018,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb if (can_generate){ EVAL_IRTree *new_tree = c.tree; if (c_resolve){ - new_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); + new_tree = eval_irtree_resolve_to_value(arena, graph, rdi, c.mode, c.tree, c_restype); } // fill result @@ -1032,10 +1032,10 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb case EVAL_ExprKind_Address: { EVAL_Expr *exprc = expr->children[0]; - EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout); + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprc, eout); if(c.tree->op != 0 && !tg_key_match(c.type_key, tg_key_zero())) { - TG_Key c_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, c.type_key); + TG_Key c_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, c.type_key); TG_Kind c_restype_kind = tg_kind_from_key(c_restype); // analyze situation @@ -1064,36 +1064,36 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb EVAL_Expr *exprl = expr->children[0]; EVAL_Expr *exprr = expr->children[1]; - TG_Key cast_type_key = eval_type_from_type_expr(arena, graph, rdbg, exprl, eout); + TG_Key cast_type_key = eval_type_from_type_expr(arena, graph, rdi, exprl, eout); TG_Kind cast_type_kind = tg_kind_from_key(cast_type_key); - EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout); + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprr, eout); if(cast_type_kind != TG_Kind_Null && c.tree->op != 0) { - TG_Key c_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, c.type_key); + TG_Key c_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, c.type_key); TG_Kind c_restype_kind = tg_kind_from_key(c_restype); - U64 c_restype_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, c_restype); - U64 cast_type_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, cast_type_key); + U64 c_restype_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, c_restype); + U64 cast_type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, cast_type_key); // analyze situation U8 in_group = eval_type_group_from_kind(c_restype_kind); U8 out_group = eval_type_group_from_kind(cast_type_kind); - RADDBG_EvalConversionKind conversion_rule = raddbg_eval_conversion_rule(in_group, out_group); + RDI_EvalConversionKind conversion_rule = rdi_eval_conversion_rule(in_group, out_group); // generate tree switch(conversion_rule) { - case RADDBG_EvalConversionKind_Noop: - case RADDBG_EvalConversionKind_Legal: + case RDI_EvalConversionKind_Noop: + case RDI_EvalConversionKind_Legal: { - EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); + EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdi, c.mode, c.tree, c_restype); EVAL_IRTree *new_tree = in_tree; - if (conversion_rule == RADDBG_EvalConversionKind_Legal){ + if (conversion_rule == RDI_EvalConversionKind_Legal){ new_tree = eval_irtree_convert_lo(arena, in_tree, out_group, in_group); } if (cast_type_byte_size < c_restype_byte_size && eval_kind_is_integer(cast_type_kind)){ - new_tree = eval_irtree_trunc(arena, graph, rdbg, in_tree, cast_type_key); + new_tree = eval_irtree_trunc(arena, graph, rdi, in_tree, cast_type_key); } result.tree = new_tree; @@ -1104,8 +1104,8 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb default: { String8 text = str8_lit("(internal) unknown conversion rule"); - if (conversion_rule < RADDBG_EvalConversionKind_COUNT){ - text.str = raddbg_eval_conversion_message(conversion_rule, &text.size); + if (conversion_rule < RDI_EvalConversionKind_COUNT){ + text.str = rdi_eval_conversion_message(conversion_rule, &text.size); } eval_error(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, text); }break; @@ -1126,13 +1126,13 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb case EVAL_ExprKind_Array: case EVAL_ExprKind_Func: { - type_key = eval_type_from_type_expr(arena, graph, rdbg, exprc, eout); + type_key = eval_type_from_type_expr(arena, graph, rdi, exprc, eout); }break; // size of value expression default: { - EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout); + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprc, eout); type_key = c.type_key; }break; } @@ -1141,7 +1141,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb TG_Kind type_kind = tg_kind_from_key(type_key); if (type_kind != TG_Kind_Null){ can_generate = 1; - size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, type_key); + size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); } // generate ir tree @@ -1160,17 +1160,17 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb { EVAL_Expr *exprc = expr->children[0]; - EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout); + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprc, eout); if (c.tree->op != 0){ - TG_Key c_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, c.type_key); - TG_Key p_type = eval_type_promote(graph, rdbg, c_restype); + TG_Key c_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, c.type_key); + TG_Key p_type = eval_type_promote(graph, rdi, c_restype); TG_Kind c_restype_kind = tg_kind_from_key(c_restype); // analyze situation B32 can_generate = 0; - RADDBG_EvalOp op = eval_opcode_from_expr_kind(kind); + RDI_EvalOp op = eval_opcode_from_expr_kind(kind); U8 c_group = eval_type_group_from_kind(c_restype_kind); - if (!raddbg_eval_opcode_type_compatible(op, c_group)){ + if (!rdi_eval_opcode_type_compatible(op, c_group)){ eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Cannot use this operator on this type."); } else{ @@ -1179,8 +1179,8 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb // generate ir tree if (can_generate){ - EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); - in_tree = eval_irtree_convert_hi(arena, graph, rdbg, in_tree, p_type, c_restype); + EVAL_IRTree *in_tree = eval_irtree_resolve_to_value(arena, graph, rdi, c.mode, c.tree, c_restype); + in_tree = eval_irtree_convert_hi(arena, graph, rdi, in_tree, p_type, c_restype); EVAL_IRTree *new_tree = eval_irtree_unary_op(arena, op, c_group, in_tree); @@ -1214,12 +1214,12 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb EVAL_Expr *exprl = expr->children[0]; EVAL_Expr *exprr = expr->children[1]; - EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout); - EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout); + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprl, eout); + EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprr, eout); if (l.tree->op != 0 && r.tree->op != 0){ - TG_Key l_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, l.type_key); - TG_Key r_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, r.type_key); + TG_Key l_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, l.type_key); + TG_Key r_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, r.type_key); TG_Kind l_restype_kind = tg_kind_from_key(l_restype); TG_Kind r_restype_kind = tg_kind_from_key(r_restype); @@ -1235,7 +1235,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb r_restype_kind = tg_kind_from_key(r_restype); } - RADDBG_EvalOp op = eval_opcode_from_expr_kind(kind); + RDI_EvalOp op = eval_opcode_from_expr_kind(kind); //- pointer decay B32 l_is_pointer = (l_restype_kind == TG_Kind_Ptr); @@ -1267,10 +1267,10 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb arith_path = EVAL_ArithPath_PtrAdd; } if (l_is_pointer_like && r_is_pointer_like){ - TG_Key l_restype_direct = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, l_restype); - TG_Key r_restype_direct = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, r_restype); - U64 l_restype_direct_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, l_restype_direct); - U64 r_restype_direct_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, r_restype_direct); + TG_Key l_restype_direct = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, l_restype); + TG_Key r_restype_direct = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, r_restype); + U64 l_restype_direct_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, l_restype_direct); + U64 r_restype_direct_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, r_restype_direct); if (l_restype_direct_byte_size == r_restype_direct_byte_size){ arith_path = EVAL_ArithPath_PtrSub; } @@ -1289,9 +1289,9 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb TG_Key cv_type_key = zero_struct; if (both_basic){ - cv_type_key = eval_type_coerce(graph, rdbg, l_restype, r_restype); + cv_type_key = eval_type_coerce(graph, rdi, l_restype, r_restype); } - else if (is_comparison && eval_type_match(graph, rdbg, l_restype, r_restype)){ + else if (is_comparison && eval_type_match(graph, rdi, l_restype, r_restype)){ cv_type_key = l_restype; } @@ -1299,7 +1299,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb U8 cv_group = eval_type_group_from_kind(cv_type_kind); B32 can_generate = 0; - if (raddbg_eval_opcode_type_compatible(op, cv_group)){ + if (rdi_eval_opcode_type_compatible(op, cv_group)){ can_generate = 1; } else{ @@ -1313,11 +1313,11 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb final_type_key = tg_key_basic(TG_Kind_Bool); } - EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype); - l_tree = eval_irtree_convert_hi(arena, graph, rdbg, l_tree, cv_type_key, l_restype); + EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdi, l.mode, l.tree, l_restype); + l_tree = eval_irtree_convert_hi(arena, graph, rdi, l_tree, cv_type_key, l_restype); - EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); - r_tree = eval_irtree_convert_hi(arena, graph, rdbg, r_tree, cv_type_key, r_restype); + EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdi, r.mode, r.tree, r_restype); + r_tree = eval_irtree_convert_hi(arena, graph, rdi, r_tree, cv_type_key, r_restype); EVAL_IRTree *new_tree = eval_irtree_binary_op(arena, op, cv_group, l_tree, r_tree); @@ -1339,19 +1339,19 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb ptr_is_decay = r_is_decay; } - TG_Key direct = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, ptr->type_key); - U64 direct_type_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct); + TG_Key direct = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, ptr->type_key); + U64 direct_type_size = tg_byte_size_from_graph_rdi_key(graph, rdi, direct); // generate ir tree EVAL_IRTree *ptr_tree = ptr->tree; if (!ptr_is_decay){ - ptr_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, ptr->mode, ptr_tree, ptr->type_key); + ptr_tree = eval_irtree_resolve_to_value(arena, graph, rdi, ptr->mode, ptr_tree, ptr->type_key); } - EVAL_IRTree *integer_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, integer->mode, integer->tree, integer->type_key); + EVAL_IRTree *integer_tree = eval_irtree_resolve_to_value(arena, graph, rdi, integer->mode, integer->tree, integer->type_key); if (direct_type_size > 1){ EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size); - integer_tree = eval_irtree_binary_op_u(arena, RADDBG_EvalOp_Mul, integer_tree, const_tree); + integer_tree = eval_irtree_binary_op_u(arena, RDI_EvalOp_Mul, integer_tree, const_tree); } TG_Key ptr_type = ptr->type_key; @@ -1359,7 +1359,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb ptr_type = tg_cons_type_make(graph, TG_Kind_Ptr, direct, 0); } - EVAL_IRTree *new_tree = eval_irtree_binary_op(arena, op, RADDBG_EvalTypeGroup_U, ptr_tree, integer_tree); + EVAL_IRTree *new_tree = eval_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, ptr_tree, integer_tree); result.tree = new_tree; result.type_key = ptr_type; @@ -1368,26 +1368,26 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb case EVAL_ArithPath_PtrSub: { - TG_Key direct = tg_unwrapped_direct_from_graph_raddbg_key(graph, rdbg, l_restype); - U64 direct_type_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, direct); + TG_Key direct = tg_unwrapped_direct_from_graph_rdi_key(graph, rdi, l_restype); + U64 direct_type_size = tg_byte_size_from_graph_rdi_key(graph, rdi, direct); // generate ir tree EVAL_IRTree *l_tree = l.tree; if (!l_is_decay){ - l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype); + l_tree = eval_irtree_resolve_to_value(arena, graph, rdi, l.mode, l.tree, l_restype); } EVAL_IRTree *r_tree = r.tree; if (!r_is_decay){ - r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); + r_tree = eval_irtree_resolve_to_value(arena, graph, rdi, r.mode, r.tree, r_restype); } - EVAL_IRTree *op_tree = eval_irtree_binary_op(arena, op, RADDBG_EvalTypeGroup_U, l_tree, r_tree); + EVAL_IRTree *op_tree = eval_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, l_tree, r_tree); EVAL_IRTree *new_tree = op_tree; if (direct_type_size > 1){ EVAL_IRTree *const_tree = eval_irtree_const_u(arena, direct_type_size); - new_tree = eval_irtree_binary_op(arena, RADDBG_EvalOp_Div, RADDBG_EvalTypeGroup_U, new_tree, const_tree); + new_tree = eval_irtree_binary_op(arena, RDI_EvalOp_Div, RDI_EvalTypeGroup_U, new_tree, const_tree); } result.tree = new_tree; @@ -1404,15 +1404,15 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb EVAL_Expr *exprl = expr->children[1]; EVAL_Expr *exprr = expr->children[2]; - EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprc, eout); - EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprl, eout); - EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, exprr, eout); + EVAL_IRTreeAndType c = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprc, eout); + EVAL_IRTreeAndType l = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprl, eout); + EVAL_IRTreeAndType r = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, exprr, eout); if (l.tree->op != 0 && r.tree->op != 0 && c.tree->op != 0){ - TG_Key c_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, c.type_key); - TG_Key l_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, l.type_key); - TG_Key r_restype = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, r.type_key); + TG_Key c_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, c.type_key); + TG_Key l_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, l.type_key); + TG_Key r_restype = tg_unwrapped_from_graph_rdi_key(graph, rdi, r.type_key); TG_Kind c_restype_kind = tg_kind_from_key(c_restype); TG_Kind l_restype_kind = tg_kind_from_key(l_restype); TG_Kind r_restype_kind = tg_kind_from_key(r_restype); @@ -1427,10 +1427,10 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb if (eval_kind_is_basic_or_enum(l_restype_kind) && eval_kind_is_basic_or_enum(r_restype_kind)){ can_generate = 1; - final_type = eval_type_coerce(graph, rdbg, l_restype, r_restype); + final_type = eval_type_coerce(graph, rdi, l_restype, r_restype); } else{ - if (eval_type_match(graph, rdbg, l_restype, r_restype)){ + if (eval_type_match(graph, rdi, l_restype, r_restype)){ if (l_restype_kind == TG_Kind_Ptr){ can_generate = 1; final_type = l_restype; @@ -1447,13 +1447,13 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb // generate ir tree if (can_generate){ - EVAL_IRTree *c_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, c.mode, c.tree, c_restype); + EVAL_IRTree *c_tree = eval_irtree_resolve_to_value(arena, graph, rdi, c.mode, c.tree, c_restype); - EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, l.mode, l.tree, l_restype); - l_tree = eval_irtree_convert_hi(arena, graph, rdbg, l_tree, final_type, l_restype); + EVAL_IRTree *l_tree = eval_irtree_resolve_to_value(arena, graph, rdi, l.mode, l.tree, l_restype); + l_tree = eval_irtree_convert_hi(arena, graph, rdi, l_tree, final_type, l_restype); - EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdbg, r.mode, r.tree, r_restype); - r_tree = eval_irtree_convert_hi(arena, graph, rdbg, r_tree, final_type, r_restype); + EVAL_IRTree *r_tree = eval_irtree_resolve_to_value(arena, graph, rdi, r.mode, r.tree, r_restype); + r_tree = eval_irtree_convert_hi(arena, graph, rdi, r_tree, final_type, r_restype); EVAL_IRTree *new_tree = eval_irtree_conditional(arena, c_tree, l_tree, r_tree); @@ -1540,7 +1540,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb { eval_errorf(arena, eout, EVAL_ErrorKind_MalformedInput, expr->location, "Left side of assignment must be an identifier."); } - result = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, expr->children[1], eout); + result = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, expr->children[1], eout); }break; case EVAL_ExprKind_LeafIdent: { @@ -1553,7 +1553,7 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb else { eval_string2expr_map_inc_poison(leaf_ident_expr_map, name); - result = eval_irtree_and_type_from_expr(arena, graph, rdbg, leaf_ident_expr_map, leaf_ident_expr, eout); + result = eval_irtree_and_type_from_expr(arena, graph, rdi, leaf_ident_expr_map, leaf_ident_expr, eout); eval_string2expr_map_dec_poison(leaf_ident_expr_map, name); } }break; @@ -1568,8 +1568,8 @@ eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out){ ProfBeginFunction(); U32 op = tree->op; switch (op){ - case RADDBG_EvalOp_Stop: - case RADDBG_EvalOp_Skip: + case RDI_EvalOp_Stop: + case RDI_EvalOp_Skip: { // TODO: error - invalid ir-tree op }break; @@ -1579,7 +1579,7 @@ eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out){ eval_oplist_push_bytecode(arena, out, tree->bytecode); }break; - case RADDBG_EvalOp_Cond: + case RDI_EvalOp_Cond: { // split out each of the children EVAL_OpList prt_cond = {0}; @@ -1598,11 +1598,11 @@ eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out){ // 4. // modify prt_right in place to create step 2 - eval_oplist_push_op(arena, &prt_right, RADDBG_EvalOp_Skip, prt_left.encoded_size); + eval_oplist_push_op(arena, &prt_right, RDI_EvalOp_Skip, prt_left.encoded_size); // merge 1 into out eval_oplist_concat_in_place(out, &prt_cond); - eval_oplist_push_op(arena, out, RADDBG_EvalOp_Cond, prt_right.encoded_size); + eval_oplist_push_op(arena, out, RDI_EvalOp_Cond, prt_right.encoded_size); // merge 2 into out eval_oplist_concat_in_place(out, &prt_right); @@ -1613,20 +1613,20 @@ eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out){ default: { - if (op >= RADDBG_EvalOp_COUNT){ + if (op >= RDI_EvalOp_COUNT){ // TODO: error - invalid ir-tree op } else{ // handle all children - U8 ctrlbits = raddbg_eval_opcode_ctrlbits[op]; - U64 child_count = RADDBG_POPN_FROM_CTRLBITS(ctrlbits); + U8 ctrlbits = rdi_eval_opcode_ctrlbits[op]; + U64 child_count = RDI_POPN_FROM_CTRLBITS(ctrlbits); EVAL_IRTree**child = tree->children; for (U64 i = 0; i < child_count; i += 1, child += 1){ eval_oplist_from_irtree(arena, *child, out); } // emit op to compute this node - eval_oplist_push_op(arena, out, (RADDBG_EvalOp)tree->op, tree->p); + eval_oplist_push_op(arena, out, (RDI_EvalOp)tree->op, tree->p); } }break; } diff --git a/src/eval/eval_compiler.h b/src/eval/eval_compiler.h index ab2ec297..4f44ee55 100644 --- a/src/eval/eval_compiler.h +++ b/src/eval/eval_compiler.h @@ -9,7 +9,7 @@ internal String8 eval_bytecode_from_oplist(Arena *arena, EVAL_OpList *list); -internal void eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RADDBG_EvalOp op, U64 p); +internal void eval_oplist_push_op(Arena *arena, EVAL_OpList *list, RDI_EvalOp op, U64 p); internal void eval_oplist_push_uconst(Arena *arena, EVAL_OpList *list, U64 x); internal void eval_oplist_push_sconst(Arena *arena, EVAL_OpList *list, S64 x); @@ -20,8 +20,8 @@ internal void eval_oplist_concat_in_place(EVAL_OpList *left_dst, EVAL_OpList *ri //////////////////////////////// //~ allen: EVAL Expression Info Functions -internal RADDBG_EvalOp eval_opcode_from_expr_kind(EVAL_ExprKind kind); -internal B32 eval_expr_kind_is_comparison(EVAL_ExprKind kind); +internal RDI_EvalOp eval_opcode_from_expr_kind(EVAL_ExprKind kind); +internal B32 eval_expr_kind_is_comparison(EVAL_ExprKind kind); //////////////////////////////// //~ allen: EVAL Expression Constructors @@ -40,13 +40,13 @@ internal EVAL_Expr* eval_expr_leaf_type(Arena *arena, void *location, TG_Key typ //////////////////////////////// //~ allen: EVAL Type Information Transformers -internal RADDBG_EvalTypeGroup eval_type_group_from_kind(TG_Kind kind); +internal RDI_EvalTypeGroup eval_type_group_from_kind(TG_Kind kind); -internal TG_Key eval_type_unwrap_enum(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_Key eval_type_promote(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_Key eval_type_coerce(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r); +internal TG_Key eval_type_unwrap_enum(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_Key eval_type_promote(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_Key eval_type_coerce(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r); -internal B32 eval_type_match(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key l, TG_Key r); +internal B32 eval_type_match(TG_Graph *graph, RDI_Parsed *rdi, TG_Key l, TG_Key r); internal B32 eval_kind_is_integer(TG_Kind kind); internal B32 eval_kind_is_signed(TG_Kind kind); @@ -56,27 +56,27 @@ internal B32 eval_kind_is_basic_or_enum(TG_Kind kind); //~ allen: EVAL IR-Tree Constructors internal EVAL_IRTree* eval_irtree_const_u(Arena *arena, U64 v); -internal EVAL_IRTree* eval_irtree_unary_op(Arena *arena, RADDBG_EvalOp op, RADDBG_EvalTypeGroup group, EVAL_IRTree *c); -internal EVAL_IRTree* eval_irtree_binary_op(Arena *arena, RADDBG_EvalOp op, RADDBG_EvalTypeGroup group, EVAL_IRTree *l, EVAL_IRTree *r); -internal EVAL_IRTree* eval_irtree_binary_op_u(Arena *arena, RADDBG_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r); +internal EVAL_IRTree* eval_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, EVAL_IRTree *c); +internal EVAL_IRTree* eval_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, EVAL_IRTree *l, EVAL_IRTree *r); +internal EVAL_IRTree* eval_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, EVAL_IRTree *l, EVAL_IRTree *r); internal EVAL_IRTree* eval_irtree_conditional(Arena *arena, EVAL_IRTree *c, EVAL_IRTree *l, EVAL_IRTree *r); internal EVAL_IRTree* eval_irtree_bytecode_no_copy(Arena *arena, String8 bytecode); //////////////////////////////// //~ allen: EVAL IR-Tree High Level Helpers -internal EVAL_IRTree* eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key); -internal EVAL_IRTree* eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RADDBG_EvalTypeGroup out, RADDBG_EvalTypeGroup in); -internal EVAL_IRTree* eval_irtree_trunc(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key type_key); -internal EVAL_IRTree* eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_IRTree *c, TG_Key out, TG_Key in); -internal EVAL_IRTree* eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_EvalMode from_mode, EVAL_IRTree *tree, TG_Key type_key); +internal EVAL_IRTree* eval_irtree_mem_read_type(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key); +internal EVAL_IRTree* eval_irtree_convert_lo(Arena *arena, EVAL_IRTree *c, RDI_EvalTypeGroup out, RDI_EvalTypeGroup in); +internal EVAL_IRTree* eval_irtree_trunc(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key type_key); +internal EVAL_IRTree* eval_irtree_convert_hi(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_IRTree *c, TG_Key out, TG_Key in); +internal EVAL_IRTree* eval_irtree_resolve_to_value(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_EvalMode from_mode, EVAL_IRTree *tree, TG_Key type_key); //////////////////////////////// //~ allen: EVAL Compiler Phases internal void eval_push_leaf_ident_exprs_from_expr__in_place(Arena *arena, EVAL_String2ExprMap *map, EVAL_Expr *expr, EVAL_ErrorList *eout); -internal TG_Key eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_Expr *expr, EVAL_ErrorList *eout); -internal EVAL_IRTreeAndType eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, EVAL_String2ExprMap *leaf_ident_expr_map, EVAL_Expr *expr, EVAL_ErrorList *eout); +internal TG_Key eval_type_from_type_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_Expr *expr, EVAL_ErrorList *eout); +internal EVAL_IRTreeAndType eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, EVAL_String2ExprMap *leaf_ident_expr_map, EVAL_Expr *expr, EVAL_ErrorList *eout); internal void eval_oplist_from_irtree(Arena *arena, EVAL_IRTree *tree, EVAL_OpList *out); #endif //EVAL_COMPILER_H diff --git a/src/eval/eval_core.c b/src/eval/eval_core.c index 6c26e6e3..791579bf 100644 --- a/src/eval/eval_core.c +++ b/src/eval/eval_core.c @@ -1,6 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/eval.meta.c" + //////////////////////////////// //~ rjf: Basic Functions diff --git a/src/eval/eval_core.h b/src/eval/eval_core.h index 7a1d47cf..662dc26e 100644 --- a/src/eval/eval_core.h +++ b/src/eval/eval_core.h @@ -13,6 +13,7 @@ typedef enum EVAL_ErrorKind EVAL_ErrorKind_MalformedInput, EVAL_ErrorKind_MissingInfo, EVAL_ErrorKind_ResolutionFailure, + EVAL_ErrorKind_InterpretationError, EVAL_ErrorKind_COUNT } EVAL_ErrorKind; @@ -40,7 +41,7 @@ struct EVAL_ErrorList enum { - EVAL_IRExtKind_Bytecode = RADDBG_EvalOp_COUNT, + EVAL_IRExtKind_Bytecode = RDI_EvalOp_COUNT, EVAL_IRExtKind_COUNT }; @@ -48,7 +49,7 @@ typedef struct EVAL_Op EVAL_Op; struct EVAL_Op { EVAL_Op *next; - RADDBG_EvalOp opcode; + RDI_EvalOp opcode; union { U64 p; @@ -114,7 +115,7 @@ struct EVAL_Expr typedef struct EVAL_IRTree EVAL_IRTree; struct EVAL_IRTree{ - RADDBG_EvalOp op; + RDI_EvalOp op; EVAL_IRTree *children[3]; union{ U64 p; @@ -212,7 +213,7 @@ internal U64 eval_num_from_string(EVAL_String2NumMap *map, String8 string); //- rjf: string -> expr internal EVAL_String2ExprMap eval_string2expr_map_make(Arena *arena, U64 slot_count); -internal void eval_string2expr_map_insert(Arena *arena, EVAL_String2NumMap *map, String8 string, EVAL_Expr *expr); +internal void eval_string2expr_map_insert(Arena *arena, EVAL_String2ExprMap *map, String8 string, EVAL_Expr *expr); internal void eval_string2expr_map_inc_poison(EVAL_String2ExprMap *map, String8 string); internal void eval_string2expr_map_dec_poison(EVAL_String2ExprMap *map, String8 string); internal EVAL_Expr *eval_expr_from_string(EVAL_String2ExprMap *map, String8 string); diff --git a/src/eval/eval_machine.c b/src/eval/eval_machine.c index 6afd7e12..0a44e9f9 100644 --- a/src/eval/eval_machine.c +++ b/src/eval/eval_machine.c @@ -5,7 +5,8 @@ //~ allen: Eval Machine Functions internal EVAL_Result -eval_interpret(EVAL_Machine *machine, String8 bytecode){ +eval_interpret(EVAL_Machine *machine, String8 bytecode) +{ ProfBeginFunction(); EVAL_Result result = {0}; @@ -21,21 +22,21 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ for (;ptr < opl;){ // consume opcode - RADDBG_EvalOp op = (RADDBG_EvalOp)*ptr; - if (op >= RADDBG_EvalOp_COUNT){ - result.bad_eval = 1; + RDI_EvalOp op = (RDI_EvalOp)*ptr; + if (op >= RDI_EvalOp_COUNT){ + result.code = EVAL_ResultCode_BadOp; goto done; } - U8 ctrlbits = raddbg_eval_opcode_ctrlbits[op]; + U8 ctrlbits = rdi_eval_opcode_ctrlbits[op]; ptr += 1; // decode U64 imm = 0; { - U32 decode_size = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); + U32 decode_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); U8 *next_ptr = ptr + decode_size; if (next_ptr > opl){ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOp; goto done; } // TODO(allen): to improve this: @@ -53,9 +54,9 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ // pop EVAL_Slot *svals = 0; { - U32 pop_count = RADDBG_POPN_FROM_CTRLBITS(ctrlbits); + U32 pop_count = RDI_POPN_FROM_CTRLBITS(ctrlbits); if (pop_count > stack_count){ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOp; goto done; } if (pop_count <= stack_count){ @@ -67,29 +68,29 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ // interpret EVAL_Slot nval = {0}; switch (op){ - case RADDBG_EvalOp_Stop: + case RDI_EvalOp_Stop: { goto done; }break; - case RADDBG_EvalOp_Noop: + case RDI_EvalOp_Noop: { // do nothing }break; - case RADDBG_EvalOp_Cond: + case RDI_EvalOp_Cond: { if (svals[0].u64){ ptr += imm; } }break; - case RADDBG_EvalOp_Skip: + case RDI_EvalOp_Skip: { ptr += imm; }break; - case RADDBG_EvalOp_MemRead: + case RDI_EvalOp_MemRead: { U64 addr = svals[0].u64; U64 size = imm; @@ -99,17 +100,17 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ good_read = 1; } if (!good_read){ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadMemRead; goto done; } }break; - case RADDBG_EvalOp_RegRead: + case RDI_EvalOp_RegRead: { - U8 raddbg_reg_code = (imm&0x0000FF)>>0; - U8 byte_size = (imm&0x00FF00)>>8; - U8 byte_off = (imm&0xFF0000)>>16; - REGS_RegCode base_reg_code = regs_reg_code_from_arch_raddbg_code(machine->arch, raddbg_reg_code); + U8 rdi_reg_code = (imm&0x0000FF)>>0; + U8 byte_size = (imm&0x00FF00)>>8; + U8 byte_off = (imm&0xFF0000)>>16; + REGS_RegCode base_reg_code = regs_reg_code_from_arch_rdi_code(machine->arch, rdi_reg_code); REGS_Rng rng = regs_reg_code_rng_table_from_architecture(machine->arch)[base_reg_code]; U64 off = (U64)rng.byte_off + byte_off; U64 size = (U64)byte_size; @@ -117,12 +118,12 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ MemoryCopy(&nval, (U8*)machine->reg_data + off, size); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadRegRead; goto done; } }break; - case RADDBG_EvalOp_RegReadDyn: + case RDI_EvalOp_RegReadDyn: { U64 off = svals[0].u64; U64 size = bit_size_from_arch(machine->arch)/8; @@ -130,61 +131,61 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ MemoryCopy(&nval, (U8*)machine->reg_data + off, size); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadRegRead; goto done; } }break; - case RADDBG_EvalOp_FrameOff: + case RDI_EvalOp_FrameOff: { if (machine->frame_base != 0){ nval.u64 = *machine->frame_base + imm; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadFrameBase; goto done; } }break; - case RADDBG_EvalOp_ModuleOff: + case RDI_EvalOp_ModuleOff: { if (machine->module_base != 0){ nval.u64 = *machine->module_base + imm; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadModuleBase; goto done; } }break; - case RADDBG_EvalOp_TLSOff: + case RDI_EvalOp_TLSOff: { if (machine->tls_base != 0){ nval.u64 = *machine->tls_base + imm; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadTLSBase; goto done; } }break; - case RADDBG_EvalOp_ConstU8: - case RADDBG_EvalOp_ConstU16: - case RADDBG_EvalOp_ConstU32: - case RADDBG_EvalOp_ConstU64: + case RDI_EvalOp_ConstU8: + case RDI_EvalOp_ConstU16: + case RDI_EvalOp_ConstU32: + case RDI_EvalOp_ConstU64: { nval.u64 = imm; }break; - case RADDBG_EvalOp_Abs: + case RDI_EvalOp_Abs: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.f32 = svals[0].f32; if (svals[0].f32 < 0){ nval.f32 = -svals[0].f32; } } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.f64 = svals[0].f64; if (svals[0].f64 < 0){ nval.f64 = -svals[0].f64; @@ -198,12 +199,12 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_Neg: + case RDI_EvalOp_Neg: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.f32 = -svals[0].f32; } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.f64 = -svals[0].f64; } else{ @@ -211,12 +212,12 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_Add: + case RDI_EvalOp_Add: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.f32 = svals[0].f32 + svals[1].f32; } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.f64 = svals[0].f64 + svals[1].f64; } else{ @@ -224,12 +225,12 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_Sub: + case RDI_EvalOp_Sub: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.f32 = svals[0].f32 - svals[1].f32; } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.f64 = svals[0].f64 - svals[1].f64; } else{ @@ -237,12 +238,12 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_Mul: + case RDI_EvalOp_Mul: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.f32 = svals[0].f32*svals[1].f32; } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.f64 = svals[0].f64*svals[1].f64; } else{ @@ -250,245 +251,260 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_Div: + case RDI_EvalOp_Div: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ if (svals[1].f32 != 0.f){ nval.f32 = svals[0].f32/svals[1].f32; } + else + { + result.code = EVAL_ResultCode_DivideByZero; + goto done; + } } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ if (svals[1].f64 != 0.){ nval.f64 = svals[0].f64/svals[1].f64; } + else + { + result.code = EVAL_ResultCode_DivideByZero; + goto done; + } } - else if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + else if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ if (svals[1].u64 != 0){ nval.u64 = svals[0].u64/svals[1].u64; } + else + { + result.code = EVAL_ResultCode_DivideByZero; + goto done; + } } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_Mod: + case RDI_EvalOp_Mod: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ if (svals[1].u64 != 0){ nval.u64 = svals[0].u64%svals[1].u64; } } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_LShift: + case RDI_EvalOp_LShift: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = svals[0].u64 << svals[1].u64; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_RShift: + case RDI_EvalOp_RShift: { - if (imm == RADDBG_EvalTypeGroup_U){ + if (imm == RDI_EvalTypeGroup_U){ nval.u64 = svals[0].u64 >> svals[1].u64; } - else if (imm == RADDBG_EvalTypeGroup_S){ + else if (imm == RDI_EvalTypeGroup_S){ nval.u64 = svals[0].s64 >> svals[1].u64; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_BitAnd: + case RDI_EvalOp_BitAnd: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = svals[0].u64&svals[1].u64; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_BitOr: + case RDI_EvalOp_BitOr: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = svals[0].u64|svals[1].u64; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_BitXor: + case RDI_EvalOp_BitXor: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = svals[0].u64^svals[1].u64; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_BitNot: + case RDI_EvalOp_BitNot: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = ~svals[0].u64; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_LogAnd: + case RDI_EvalOp_LogAnd: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = (svals[0].u64 && svals[1].u64); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_LogOr: + case RDI_EvalOp_LogOr: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = (svals[0].u64 || svals[1].u64); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_LogNot: + case RDI_EvalOp_LogNot: { - if (imm == RADDBG_EvalTypeGroup_U || - imm == RADDBG_EvalTypeGroup_S){ + if (imm == RDI_EvalTypeGroup_U || + imm == RDI_EvalTypeGroup_S){ nval.u64 = (!svals[0].u64); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_EqEq: + case RDI_EvalOp_EqEq: { nval.u64 = (svals[0].u64 == svals[1].u64); }break; - case RADDBG_EvalOp_NtEq: + case RDI_EvalOp_NtEq: { nval.u64 = (svals[0].u64 != svals[1].u64); }break; - case RADDBG_EvalOp_LsEq: + case RDI_EvalOp_LsEq: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.u64 = (svals[0].f32 <= svals[1].f32); } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.u64 = (svals[0].f64 <= svals[1].f64); } - else if (imm == RADDBG_EvalTypeGroup_U){ + else if (imm == RDI_EvalTypeGroup_U){ nval.u64 = (svals[0].u64 <= svals[1].u64); } - else if (imm == RADDBG_EvalTypeGroup_S){ + else if (imm == RDI_EvalTypeGroup_S){ nval.u64 = (svals[0].s64 <= svals[1].s64); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_GrEq: + case RDI_EvalOp_GrEq: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.u64 = (svals[0].f32 >= svals[1].f32); } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.u64 = (svals[0].f64 >= svals[1].f64); } - else if (imm == RADDBG_EvalTypeGroup_U){ + else if (imm == RDI_EvalTypeGroup_U){ nval.u64 = (svals[0].u64 >= svals[1].u64); } - else if (imm == RADDBG_EvalTypeGroup_S){ + else if (imm == RDI_EvalTypeGroup_S){ nval.u64 = (svals[0].s64 >= svals[1].s64); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_Less: + case RDI_EvalOp_Less: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.u64 = (svals[0].f32 < svals[1].f32); } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.u64 = (svals[0].f64 < svals[1].f64); } - else if (imm == RADDBG_EvalTypeGroup_U){ + else if (imm == RDI_EvalTypeGroup_U){ nval.u64 = (svals[0].u64 < svals[1].u64); } - else if (imm == RADDBG_EvalTypeGroup_S){ + else if (imm == RDI_EvalTypeGroup_S){ nval.u64 = (svals[0].s64 < svals[1].s64); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_Grtr: + case RDI_EvalOp_Grtr: { - if (imm == RADDBG_EvalTypeGroup_F32){ + if (imm == RDI_EvalTypeGroup_F32){ nval.u64 = (svals[0].f32 > svals[1].f32); } - else if (imm == RADDBG_EvalTypeGroup_F64){ + else if (imm == RDI_EvalTypeGroup_F64){ nval.u64 = (svals[0].f64 > svals[1].f64); } - else if (imm == RADDBG_EvalTypeGroup_U){ + else if (imm == RDI_EvalTypeGroup_U){ nval.u64 = (svals[0].u64 > svals[1].u64); } - else if (imm == RADDBG_EvalTypeGroup_S){ + else if (imm == RDI_EvalTypeGroup_S){ nval.u64 = (svals[0].s64 > svals[1].s64); } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOpTypes; goto done; } }break; - case RADDBG_EvalOp_Trunc: + case RDI_EvalOp_Trunc: { if (0 < imm){ U64 mask = 0; @@ -499,7 +515,7 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_TruncSigned: + case RDI_EvalOp_TruncSigned: { if (0 < imm){ U64 mask = 0; @@ -514,52 +530,52 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_Convert: + case RDI_EvalOp_Convert: { U32 in = imm&0xFF; U32 out = (imm >> 8)&0xFF; if (in != out){ - switch (in + out*RADDBG_EvalTypeGroup_COUNT){ - case RADDBG_EvalTypeGroup_F32 + RADDBG_EvalTypeGroup_U*RADDBG_EvalTypeGroup_COUNT: + switch (in + out*RDI_EvalTypeGroup_COUNT){ + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f32; }break; - case RADDBG_EvalTypeGroup_F64 + RADDBG_EvalTypeGroup_U*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_U*RDI_EvalTypeGroup_COUNT: { nval.u64 = (U64)svals[0].f64; }break; - case RADDBG_EvalTypeGroup_F32 + RADDBG_EvalTypeGroup_S*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f32; }break; - case RADDBG_EvalTypeGroup_F64 + RADDBG_EvalTypeGroup_S*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_S*RDI_EvalTypeGroup_COUNT: { nval.s64 = (S64)svals[0].f64; }break; - case RADDBG_EvalTypeGroup_U + RADDBG_EvalTypeGroup_F32*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].u64; }break; - case RADDBG_EvalTypeGroup_S + RADDBG_EvalTypeGroup_F32*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].s64; }break; - case RADDBG_EvalTypeGroup_F64 + RADDBG_EvalTypeGroup_F32*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_F64 + RDI_EvalTypeGroup_F32*RDI_EvalTypeGroup_COUNT: { nval.f32 = (F32)svals[0].f64; }break; - case RADDBG_EvalTypeGroup_U + RADDBG_EvalTypeGroup_F64*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_U + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].u64; }break; - case RADDBG_EvalTypeGroup_S + RADDBG_EvalTypeGroup_F64*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_S + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].s64; }break; - case RADDBG_EvalTypeGroup_F32 + RADDBG_EvalTypeGroup_F64*RADDBG_EvalTypeGroup_COUNT: + case RDI_EvalTypeGroup_F32 + RDI_EvalTypeGroup_F64*RDI_EvalTypeGroup_COUNT: { nval.f64 = (F64)svals[0].f32; }break; @@ -567,23 +583,23 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } }break; - case RADDBG_EvalOp_Pick: + case RDI_EvalOp_Pick: { if (stack_count > imm){ nval = stack[stack_count - imm - 1]; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOp; goto done; } }break; - case RADDBG_EvalOp_Pop: + case RDI_EvalOp_Pop: { // do nothing - the pop is handled by the control bits }break; - case RADDBG_EvalOp_Insert: + case RDI_EvalOp_Insert: { if (stack_count > imm){ if (imm > 0){ @@ -595,7 +611,7 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ } } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_BadOp; goto done; } }break; @@ -603,14 +619,14 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ // push { - U64 push_count = RADDBG_PUSHN_FROM_CTRLBITS(ctrlbits); + U64 push_count = RDI_PUSHN_FROM_CTRLBITS(ctrlbits); if (push_count == 1){ if (stack_count < stack_cap){ stack[stack_count] = nval; stack_count += 1; } else{ - result.bad_eval = 1; + result.code = EVAL_ResultCode_InsufficientStackSpace; goto done; } } @@ -622,8 +638,8 @@ eval_interpret(EVAL_Machine *machine, String8 bytecode){ if (stack_count == 1){ result.value = stack[0]; } - else{ - result.bad_eval = 1; + else if(result.code == EVAL_ResultCode_Good){ + result.code = EVAL_ResultCode_MalformedBytecode; } scratch_end(scratch); diff --git a/src/eval/eval_machine.h b/src/eval/eval_machine.h index b520629e..12b77b2f 100644 --- a/src/eval/eval_machine.h +++ b/src/eval/eval_machine.h @@ -10,7 +10,8 @@ typedef B32 EVAL_MemoryRead(void *u, void *out, U64 addr, U64 size); typedef struct EVAL_Machine EVAL_Machine; -struct EVAL_Machine{ +struct EVAL_Machine +{ void *u; Architecture arch; EVAL_MemoryRead *memory_read; @@ -22,7 +23,8 @@ struct EVAL_Machine{ }; typedef union EVAL_Slot EVAL_Slot; -union EVAL_Slot{ +union EVAL_Slot +{ U64 u256[4]; U64 u128[2]; U64 u64; @@ -32,9 +34,10 @@ union EVAL_Slot{ }; typedef struct EVAL_Result EVAL_Result; -struct EVAL_Result{ +struct EVAL_Result +{ EVAL_Slot value; - B32 bad_eval; + EVAL_ResultCode code; }; //////////////////////////////// diff --git a/src/eval/eval_parser.c b/src/eval/eval_parser.c index 1d134bb7..71bf8a1b 100644 --- a/src/eval/eval_parser.c +++ b/src/eval/eval_parser.c @@ -57,7 +57,7 @@ global read_only S64 eval_g_max_precedence = 15; //~ rjf: Map Building Fast Paths internal EVAL_String2NumMap * -eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff) +eval_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) { Temp scratch = scratch_begin(&arena, 1); @@ -66,17 +66,17 @@ eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 vof struct Task { Task *next; - RADDBG_Scope *scope; + RDI_Scope *scope; }; Task *first_task = 0; Task *last_task = 0; //- rjf: voff -> tightest scope - RADDBG_Scope *tightest_scope = 0; - if(rdbg->scope_vmap != 0 && rdbg->scopes != 0) + RDI_Scope *tightest_scope = 0; + if(rdi->scope_vmap != 0 && rdi->scopes != 0) { - U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff); - RADDBG_Scope *scope = &rdbg->scopes[scope_idx]; + U64 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, voff); + RDI_Scope *scope = &rdi->scopes[scope_idx]; Task *task = push_array(scratch.arena, Task, 1); task->scope = scope; SLLQueuePush(first_task, last_task, task); @@ -84,10 +84,10 @@ eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 vof } //- rjf: voff-1 -> scope - if(voff > 0 && rdbg->scope_vmap != 0 && rdbg->scopes != 0) + if(voff > 0 && rdi->scope_vmap != 0 && rdi->scopes != 0) { - U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff-1); - RADDBG_Scope *scope = &rdbg->scopes[scope_idx]; + U64 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, voff-1); + RDI_Scope *scope = &rdi->scopes[scope_idx]; if(scope != tightest_scope) { Task *task = push_array(scratch.arena, Task, 1); @@ -99,9 +99,9 @@ eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 vof //- rjf: tightest scope -> walk up the tree & build tasks for each parent scope if(tightest_scope != 0) { - for(RADDBG_Scope *scope = &rdbg->scopes[tightest_scope->parent_scope_idx]; - scope != 0 && scope != &rdbg->scopes[0]; - scope = &rdbg->scopes[scope->parent_scope_idx]) + for(RDI_Scope *scope = &rdi->scopes[tightest_scope->parent_scope_idx]; + scope != 0 && scope != &rdi->scopes[0]; + scope = &rdi->scopes[scope->parent_scope_idx]) { Task *task = push_array(scratch.arena, Task, 1); task->scope = scope; @@ -116,15 +116,15 @@ eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 vof //- rjf: accumulate locals for all tasks for(Task *task = first_task; task != 0; task = task->next) { - RADDBG_Scope *scope = task->scope; + 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) { - RADDBG_Local *local_var = &rdbg->locals[local_idx]; + RDI_Local *local_var = &rdi->locals[local_idx]; U64 local_name_size = 0; - U8 *local_name_str = raddbg_string_from_idx(rdbg, local_var->name_string_idx, &local_name_size); + 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)); eval_string2num_map_insert(arena, map, name, (U64)local_idx+1); } @@ -136,35 +136,35 @@ eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 vof } internal EVAL_String2NumMap * -eval_push_member_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff) +eval_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff) { //- rjf: voff -> tightest scope - RADDBG_Scope *tightest_scope = 0; - if(rdbg->scope_vmap != 0 && rdbg->scopes != 0) + RDI_Scope *tightest_scope = 0; + if(rdi->scope_vmap != 0 && rdi->scopes != 0) { - U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff); - tightest_scope = &rdbg->scopes[scope_idx]; + U64 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, voff); + tightest_scope = &rdi->scopes[scope_idx]; } //- rjf: tightest scope -> procedure - RADDBG_Procedure *procedure = 0; - if(tightest_scope != 0 && rdbg->procedures != 0) + RDI_Procedure *procedure = 0; + if(tightest_scope != 0 && rdi->procedures != 0) { U32 proc_idx = tightest_scope->proc_idx; - if(0 < proc_idx && proc_idx < rdbg->procedures_count) + if(0 < proc_idx && proc_idx < rdi->procedures_count) { - procedure = &rdbg->procedures[proc_idx]; + procedure = &rdi->procedures[proc_idx]; } } //- rjf: procedure -> udt - RADDBG_UDT *udt = 0; - if(procedure != 0 && rdbg->udts != 0 && procedure->link_flags & RADDBG_LinkFlag_TypeScoped) + RDI_UDT *udt = 0; + if(procedure != 0 && rdi->udts != 0 && procedure->link_flags & RDI_LinkFlag_TypeScoped) { U32 udt_idx = procedure->container_idx; - if(0 < udt_idx && udt_idx < rdbg->udts_count) + if(0 < udt_idx && udt_idx < rdi->udts_count) { - udt = &rdbg->udts[udt_idx]; + udt = &rdi->udts[udt_idx]; } } @@ -173,22 +173,22 @@ eval_push_member_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 vof *map = eval_string2num_map_make(arena, 64); //- rjf: udt -> fill member map - if(udt != 0 && !(udt->flags & RADDBG_UserDefinedTypeFlag_EnumMembers) && rdbg->members != 0) + if(udt != 0 && !(udt->flags & RDI_UserDefinedTypeFlag_EnumMembers) && rdi->members != 0) { U64 data_member_num = 1; for(U32 member_idx = udt->member_first; member_idx < udt->member_first+udt->member_count; member_idx += 1) { - if(member_idx < 1 || rdbg->members_count <= member_idx) + if(member_idx < 1 || rdi->members_count <= member_idx) { break; } - RADDBG_Member *m = &rdbg->members[member_idx]; - if(m->kind == RADDBG_MemberKind_DataField) + RDI_Member *m = &rdi->members[member_idx]; + if(m->kind == RDI_MemberKind_DataField) { String8 name = {0}; - name.str = raddbg_string_from_idx(rdbg, m->name_string_idx, &name.size); + name.str = rdi_string_from_idx(rdi, m->name_string_idx, &name.size); eval_string2num_map_insert(arena, map, name, data_member_num); data_member_num += 1; } @@ -464,25 +464,25 @@ eval_token_array_make_first_opl(EVAL_Token *first, EVAL_Token *opl) //~ rjf: Parser Functions internal TG_Key -eval_leaf_type_from_name(RADDBG_Parsed *rdbg, String8 name) +eval_leaf_type_from_name(RDI_Parsed *rdi, String8 name) { TG_Key key = zero_struct; B32 found = 0; - if(rdbg->type_nodes != 0) + if(rdi->type_nodes != 0) { - RADDBG_NameMap *name_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Types); - RADDBG_ParsedNameMap parsed_name_map = {0}; - raddbg_name_map_parse(rdbg, name_map, &parsed_name_map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &parsed_name_map, name.str, name.size); + RDI_NameMap *name_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Types); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_name_map_parse(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 = raddbg_matches_from_map_node(rdbg, node, &match_count); + U32 *matches = rdi_matches_from_map_node(rdi, node, &match_count); if(match_count != 0) { - RADDBG_TypeNode *type_node = raddbg_element_from_idx(rdbg, type_nodes, matches[0]); - found = type_node->kind != RADDBG_TypeKind_NULL; - key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)matches[0]); + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, matches[0]); + found = type_node->kind != RDI_TypeKind_NULL; + key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), (U64)matches[0]); } } } @@ -569,7 +569,7 @@ eval_parse_type_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, if(token.kind == EVAL_TokenKind_Identifier) { String8 token_string = str8_substr(text, token.range); - TG_Key type_key = eval_leaf_type_from_name(ctx->rdbg, token_string); + TG_Key type_key = eval_leaf_type_from_name(ctx->rdi, token_string); if(!tg_key_match(tg_key_zero(), type_key)) { token_it += 1; @@ -680,7 +680,7 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 String8 some_type_identifier_maybe_string = str8_substr(text, some_type_identifier_maybe.range); if(some_type_identifier_maybe.kind == EVAL_TokenKind_Identifier) { - TG_Key type_key = eval_leaf_type_from_name(ctx->rdbg, some_type_identifier_maybe_string); + TG_Key type_key = eval_leaf_type_from_name(ctx->rdi, some_type_identifier_maybe_string); if(!tg_key_match(type_key, tg_key_zero()) || str8_match(some_type_identifier_maybe_string, str8_lit("unsigned"), 0)) { // rjf: move past open paren @@ -775,6 +775,38 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 } } + //- rjf: descent to assembly-style dereference sub-expression + else if(token.kind == EVAL_TokenKind_Symbol && str8_match(token_string, str8_lit("["), 0)) + { + // rjf: skip [ + it += 1; + + // rjf: parse [] contents + EVAL_TokenArray nested_parse_tokens = eval_token_array_make_first_opl(it, it_opl); + EVAL_ParseResult nested_parse = eval_parse_expr_from_text_tokens__prec(arena, ctx, text, &nested_parse_tokens, eval_g_max_precedence); + eval_error_list_concat_in_place(&result.errors, &nested_parse.errors); + atom = nested_parse.expr; + it = nested_parse.last_token; + + // rjf: build cast-to-U64*, and dereference operators + atom = eval_expr(arena, EVAL_ExprKind_Cast, token_string.str, eval_expr_leaf_type(arena, token_string.str, tg_cons_type_make(ctx->type_graph, TG_Kind_Ptr, tg_key_basic(TG_Kind_U64), 0)), atom, 0); + atom = eval_expr(arena, EVAL_ExprKind_Deref, token_string.str, atom, 0, 0); + + // rjf: expect ] + EVAL_Token close_paren_maybe = eval_token_at_it(it, tokens); + String8 close_paren_maybe_string = str8_substr(text, close_paren_maybe.range); + if(close_paren_maybe.kind != EVAL_TokenKind_Symbol || !str8_match(close_paren_maybe_string, str8_lit("]"), 0)) + { + eval_errorf(arena, &result.errors, EVAL_ErrorKind_MalformedInput, token_string.str, "Missing ]."); + } + + // rjf: consume ) + else + { + it += 1; + } + } + //- rjf: leaf (identifier, literal) else if(token.kind != EVAL_TokenKind_Symbol) { @@ -787,9 +819,9 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 B32 mapped_identifier = 0; B32 identifier_type_is_possibly_dynamically_overridden = 0; B32 identifier_looks_like_type_expr = 0; - RADDBG_LocationKind loc_kind = RADDBG_LocationKind_NULL; - RADDBG_LocationRegister loc_reg = {0}; - RADDBG_LocationRegisterPlusU16 loc_reg_u16 = {0}; + RDI_LocationKind loc_kind = RDI_LocationKind_NULL; + RDI_LocationRegister loc_reg = {0}; + RDI_LocationRegisterPlusU16 loc_reg_u16 = {0}; String8 loc_bytecode = {0}; REGS_RegCode reg_code = 0; REGS_AliasCode alias_code = 0; @@ -798,14 +830,14 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 //- rjf: form namespaceified fallback versions of this lookup string String8List namespaceified_token_strings = {0}; - if(ctx->rdbg->procedures != 0 && ctx->rdbg->scopes != 0 && ctx->rdbg->scope_vmap != 0) + if(ctx->rdi->procedures != 0 && ctx->rdi->scopes != 0 && ctx->rdi->scope_vmap != 0) { - U64 scope_idx = raddbg_vmap_idx_from_voff(ctx->rdbg->scope_vmap, ctx->rdbg->scope_vmap_count, ctx->ip_voff); - RADDBG_Scope *scope = &ctx->rdbg->scopes[scope_idx]; + U64 scope_idx = rdi_vmap_idx_from_voff(ctx->rdi->scope_vmap, ctx->rdi->scope_vmap_count, ctx->ip_voff); + RDI_Scope *scope = &ctx->rdi->scopes[scope_idx]; U64 proc_idx = scope->proc_idx; - RADDBG_Procedure *procedure = &ctx->rdbg->procedures[proc_idx]; + RDI_Procedure *procedure = &ctx->rdi->procedures[proc_idx]; U64 name_size = 0; - U8 *name_ptr = raddbg_string_from_idx(ctx->rdbg, procedure->name_string_idx, &name_size); + U8 *name_ptr = rdi_string_from_idx(ctx->rdi, procedure->name_string_idx, &name_size); String8 containing_procedure_name = str8(name_ptr, name_size); U64 last_past_scope_resolution_pos = 0; for(;;) @@ -843,48 +875,48 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 { mapped_identifier = 1; identifier_type_is_possibly_dynamically_overridden = 1; - RADDBG_Local *local_var = raddbg_element_from_idx(ctx->rdbg, locals, local_num-1); - RADDBG_TypeNode *type_node = raddbg_element_from_idx(ctx->rdbg, type_nodes, local_var->type_idx); - type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)local_var->type_idx); + RDI_Local *local_var = rdi_element_from_idx(ctx->rdi, locals, local_num-1); + RDI_TypeNode *type_node = rdi_element_from_idx(ctx->rdi, type_nodes, local_var->type_idx); + type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), (U64)local_var->type_idx); // rjf: grab location info for(U32 loc_block_idx = local_var->location_first; loc_block_idx < local_var->location_opl; loc_block_idx += 1) { - RADDBG_LocationBlock *block = &ctx->rdbg->location_blocks[loc_block_idx]; + RDI_LocationBlock *block = &ctx->rdi->location_blocks[loc_block_idx]; if(block->scope_off_first <= ctx->ip_voff && ctx->ip_voff < block->scope_off_opl) { - loc_kind = *((RADDBG_LocationKind *)(ctx->rdbg->location_data + block->location_data_off)); + loc_kind = *((RDI_LocationKind *)(ctx->rdi->location_data + block->location_data_off)); switch(loc_kind) { default:{mapped_identifier = 0;}break; - case RADDBG_LocationKind_AddrBytecodeStream: - case RADDBG_LocationKind_ValBytecodeStream: + case RDI_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: { - U8 *bytecode_base = ctx->rdbg->location_data + block->location_data_off + sizeof(RADDBG_LocationKind); + U8 *bytecode_base = ctx->rdi->location_data + block->location_data_off + sizeof(RDI_LocationKind); U64 bytecode_size = 0; - for(U64 idx = 0; idx < ctx->rdbg->location_data_size; idx += 1) + for(U64 idx = 0; idx < ctx->rdi->location_data_size; idx += 1) { U8 op = bytecode_base[idx]; if(op == 0) { break; } - U8 ctrlbits = raddbg_eval_opcode_ctrlbits[op]; - U32 p_size = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); + U8 ctrlbits = rdi_eval_opcode_ctrlbits[op]; + U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); bytecode_size += 1+p_size; } loc_bytecode = str8(bytecode_base, bytecode_size); }break; - case RADDBG_LocationKind_AddrRegisterPlusU16: - case RADDBG_LocationKind_AddrAddrRegisterPlusU16: + case RDI_LocationKind_AddrRegisterPlusU16: + case RDI_LocationKind_AddrAddrRegisterPlusU16: { - MemoryCopy(&loc_reg_u16, (ctx->rdbg->location_data + block->location_data_off), sizeof(loc_reg_u16)); + MemoryCopy(&loc_reg_u16, (ctx->rdi->location_data + block->location_data_off), sizeof(loc_reg_u16)); }break; - case RADDBG_LocationKind_ValRegister: + case RDI_LocationKind_ValRegister: { - MemoryCopy(&loc_reg, (ctx->rdbg->location_data + block->location_data_off), sizeof(loc_reg)); + MemoryCopy(&loc_reg, (ctx->rdi->location_data + block->location_data_off), sizeof(loc_reg)); }break; } } @@ -919,21 +951,21 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 //- rjf: try global variables if(mapped_identifier == 0) { - RADDBG_NameMap *name_map = raddbg_name_map_from_kind(ctx->rdbg, RADDBG_NameMapKind_GlobalVariables); - if(name_map != 0 && ctx->rdbg->global_variables != 0) + RDI_NameMap *name_map = rdi_name_map_from_kind(ctx->rdi, RDI_NameMapKind_GlobalVariables); + if(name_map != 0 && ctx->rdi->global_variables != 0) { - RADDBG_ParsedNameMap parsed_name_map = {0}; - raddbg_name_map_parse(ctx->rdbg, name_map, &parsed_name_map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, token_string.str, token_string.size); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_name_map_parse(ctx->rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(ctx->rdi, &parsed_name_map, token_string.str, token_string.size); U32 matches_count = 0; - U32 *matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + U32 *matches = rdi_matches_from_map_node(ctx->rdi, node, &matches_count); for(String8Node *n = namespaceified_token_strings.first; n != 0 && matches_count == 0; n = n->next) { - node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, n->string.str, n->string.size); + node = rdi_name_map_lookup(ctx->rdi, &parsed_name_map, n->string.str, n->string.size); matches_count = 0; - matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + matches = rdi_matches_from_map_node(ctx->rdi, node, &matches_count); } if(matches_count != 0) { @@ -942,16 +974,16 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 // 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]; - RADDBG_GlobalVariable *global_var = &ctx->rdbg->global_variables[match_idx]; + RDI_GlobalVariable *global_var = &ctx->rdi->global_variables[match_idx]; EVAL_OpList oplist = {0}; - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ModuleOff, global_var->voff); - loc_kind = RADDBG_LocationKind_AddrBytecodeStream; + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_ModuleOff, global_var->voff); + loc_kind = RDI_LocationKind_AddrBytecodeStream; loc_bytecode = eval_bytecode_from_oplist(arena, &oplist); U32 type_idx = global_var->type_idx; - if(type_idx < ctx->rdbg->type_nodes_count) + if(type_idx < ctx->rdi->type_nodes_count) { - RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; - type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_idx); + RDI_TypeNode *type_node = &ctx->rdi->type_nodes[type_idx]; + type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), (U64)type_idx); } mapped_identifier = 1; } @@ -961,35 +993,35 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 //- rjf: try thread variables if(mapped_identifier == 0) { - RADDBG_NameMap *name_map = raddbg_name_map_from_kind(ctx->rdbg, RADDBG_NameMapKind_ThreadVariables); - if(name_map != 0 && ctx->rdbg->global_variables != 0) + RDI_NameMap *name_map = rdi_name_map_from_kind(ctx->rdi, RDI_NameMapKind_ThreadVariables); + if(name_map != 0 && ctx->rdi->global_variables != 0) { - RADDBG_ParsedNameMap parsed_name_map = {0}; - raddbg_name_map_parse(ctx->rdbg, name_map, &parsed_name_map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, token_string.str, token_string.size); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_name_map_parse(ctx->rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(ctx->rdi, &parsed_name_map, token_string.str, token_string.size); U32 matches_count = 0; - U32 *matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + U32 *matches = rdi_matches_from_map_node(ctx->rdi, node, &matches_count); for(String8Node *n = namespaceified_token_strings.first; n != 0 && matches_count == 0; n = n->next) { - node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, n->string.str, n->string.size); + node = rdi_name_map_lookup(ctx->rdi, &parsed_name_map, n->string.str, n->string.size); matches_count = 0; - matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + matches = rdi_matches_from_map_node(ctx->rdi, node, &matches_count); } if(matches_count != 0) { U32 match_idx = matches[0]; - RADDBG_ThreadVariable *thread_var = &ctx->rdbg->thread_variables[match_idx]; + RDI_ThreadVariable *thread_var = &ctx->rdi->thread_variables[match_idx]; EVAL_OpList oplist = {0}; - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_TLSOff, thread_var->tls_off); - loc_kind = RADDBG_LocationKind_AddrBytecodeStream; + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, thread_var->tls_off); + loc_kind = RDI_LocationKind_AddrBytecodeStream; loc_bytecode = eval_bytecode_from_oplist(arena, &oplist); U32 type_idx = thread_var->type_idx; - if(type_idx < ctx->rdbg->type_nodes_count) + if(type_idx < ctx->rdi->type_nodes_count) { - RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; - type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_idx); + RDI_TypeNode *type_node = &ctx->rdi->type_nodes[type_idx]; + type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), (U64)type_idx); } mapped_identifier = 1; } @@ -999,37 +1031,37 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 //- rjf: try procedures if(mapped_identifier == 0) { - RADDBG_NameMap *name_map = raddbg_name_map_from_kind(ctx->rdbg, RADDBG_NameMapKind_Procedures); - if(name_map != 0 && ctx->rdbg->procedures != 0 && ctx->rdbg->scopes != 0 && ctx->rdbg->scope_voffs) + RDI_NameMap *name_map = rdi_name_map_from_kind(ctx->rdi, RDI_NameMapKind_Procedures); + if(name_map != 0 && ctx->rdi->procedures != 0 && ctx->rdi->scopes != 0 && ctx->rdi->scope_voffs) { - RADDBG_ParsedNameMap parsed_name_map = {0}; - raddbg_name_map_parse(ctx->rdbg, name_map, &parsed_name_map); - RADDBG_NameMapNode *node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, token_string.str, token_string.size); + RDI_ParsedNameMap parsed_name_map = {0}; + rdi_name_map_parse(ctx->rdi, name_map, &parsed_name_map); + RDI_NameMapNode *node = rdi_name_map_lookup(ctx->rdi, &parsed_name_map, token_string.str, token_string.size); U32 matches_count = 0; - U32 *matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + U32 *matches = rdi_matches_from_map_node(ctx->rdi, node, &matches_count); for(String8Node *n = namespaceified_token_strings.first; n != 0 && matches_count == 0; n = n->next) { - node = raddbg_name_map_lookup(ctx->rdbg, &parsed_name_map, n->string.str, n->string.size); + node = rdi_name_map_lookup(ctx->rdi, &parsed_name_map, n->string.str, n->string.size); matches_count = 0; - matches = raddbg_matches_from_map_node(ctx->rdbg, node, &matches_count); + matches = rdi_matches_from_map_node(ctx->rdi, node, &matches_count); } if(matches_count != 0) { U32 match_idx = matches[0]; - RADDBG_Procedure *procedure = &ctx->rdbg->procedures[match_idx]; - RADDBG_Scope *scope = &ctx->rdbg->scopes[procedure->root_scope_idx]; - U64 voff = ctx->rdbg->scope_voffs[scope->voff_range_first]; + RDI_Procedure *procedure = &ctx->rdi->procedures[match_idx]; + RDI_Scope *scope = &ctx->rdi->scopes[procedure->root_scope_idx]; + U64 voff = ctx->rdi->scope_voffs[scope->voff_range_first]; EVAL_OpList oplist = {0}; - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ModuleOff, voff); - loc_kind = RADDBG_LocationKind_ValBytecodeStream; + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_ModuleOff, voff); + loc_kind = RDI_LocationKind_ValBytecodeStream; loc_bytecode = eval_bytecode_from_oplist(arena, &oplist); U32 type_idx = procedure->type_idx; - if(type_idx < ctx->rdbg->type_nodes_count) + if(type_idx < ctx->rdi->type_nodes_count) { - RADDBG_TypeNode *type_node = &ctx->rdbg->type_nodes[type_idx]; - type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type_node->kind), (U64)type_idx); + RDI_TypeNode *type_node = &ctx->rdi->type_nodes[type_idx]; + type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), (U64)type_idx); } mapped_identifier = 1; } @@ -1039,7 +1071,7 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 //- rjf: try types if(mapped_identifier == 0) { - type_key = eval_leaf_type_from_name(ctx->rdbg, token_string); + type_key = eval_leaf_type_from_name(ctx->rdi, token_string); if(!tg_key_match(tg_key_zero(), type_key)) { mapped_identifier = 1; @@ -1086,44 +1118,44 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 eval_errorf(arena, &result.errors, EVAL_ErrorKind_MissingInfo, token_string.str, "Missing location information for \"%S\".", token_string); } }break; - case RADDBG_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_AddrBytecodeStream: { atom = eval_expr_leaf_bytecode(arena, token_string.str, type_key, loc_bytecode, EVAL_EvalMode_Addr); }break; - case RADDBG_LocationKind_ValBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: { atom = eval_expr_leaf_bytecode(arena, token_string.str, type_key, loc_bytecode, EVAL_EvalMode_Value); }break; - case RADDBG_LocationKind_AddrRegisterPlusU16: + case RDI_LocationKind_AddrRegisterPlusU16: { EVAL_OpList oplist = {0}; U64 byte_size = bit_size_from_arch(ctx->arch)/8; - U64 regread_param = RADDBG_EncodeRegReadParam(loc_reg_u16.register_code, byte_size, 0); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_RegRead, regread_param); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ConstU16, loc_reg_u16.offset); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_Add, 0); + U64 regread_param = RDI_EncodeRegReadParam(loc_reg_u16.register_code, byte_size, 0); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, regread_param); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, loc_reg_u16.offset); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, 0); atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Addr); }break; - case RADDBG_LocationKind_AddrAddrRegisterPlusU16: + case RDI_LocationKind_AddrAddrRegisterPlusU16: { EVAL_OpList oplist = {0}; U64 byte_size = bit_size_from_arch(ctx->arch)/8; - U64 regread_param = RADDBG_EncodeRegReadParam(loc_reg_u16.register_code, byte_size, 0); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_RegRead, regread_param); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_ConstU16, loc_reg_u16.offset); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_Add, 0); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_MemRead, bit_size_from_arch(ctx->arch)/8); + U64 regread_param = RDI_EncodeRegReadParam(loc_reg_u16.register_code, byte_size, 0); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, regread_param); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU16, loc_reg_u16.offset); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_Add, 0); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_MemRead, bit_size_from_arch(ctx->arch)/8); atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Addr); }break; - case RADDBG_LocationKind_ValRegister: + case RDI_LocationKind_ValRegister: { - REGS_RegCode regs_reg_code = regs_reg_code_from_arch_raddbg_code(ctx->arch, loc_reg.register_code); + REGS_RegCode regs_reg_code = regs_reg_code_from_arch_rdi_code(ctx->arch, loc_reg.register_code); REGS_Rng reg_rng = regs_reg_code_rng_table_from_architecture(ctx->arch)[regs_reg_code]; EVAL_OpList oplist = {0}; U64 byte_size = (U64)reg_rng.byte_size; U64 byte_pos = 0; - U64 regread_param = RADDBG_EncodeRegReadParam(loc_reg.register_code, byte_size, byte_pos); - eval_oplist_push_op(arena, &oplist, RADDBG_EvalOp_RegRead, regread_param); + U64 regread_param = RDI_EncodeRegReadParam(loc_reg.register_code, byte_size, byte_pos); + eval_oplist_push_op(arena, &oplist, RDI_EvalOp_RegRead, regread_param); atom = eval_expr_leaf_op_list(arena, token_string.str, type_key, &oplist, EVAL_EvalMode_Value); }break; } diff --git a/src/eval/eval_parser.h b/src/eval/eval_parser.h index b711da0b..d58ab206 100644 --- a/src/eval/eval_parser.h +++ b/src/eval/eval_parser.h @@ -67,7 +67,7 @@ struct EVAL_ParseCtx { Architecture arch; U64 ip_voff; - RADDBG_Parsed *rdbg; + RDI_Parsed *rdi; TG_Graph *type_graph; EVAL_String2NumMap *regs_map; EVAL_String2NumMap *reg_alias_map; @@ -85,8 +85,8 @@ global read_only EVAL_ParseResult eval_parse_result_nil = {0, &eval_expr_nil}; //////////////////////////////// //~ rjf: Debug-Info-Driven Map Building Fast Paths -internal EVAL_String2NumMap *eval_push_locals_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff); -internal EVAL_String2NumMap *eval_push_member_map_from_raddbg_voff(Arena *arena, RADDBG_Parsed *rdbg, U64 voff); +internal EVAL_String2NumMap *eval_push_locals_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); +internal EVAL_String2NumMap *eval_push_member_map_from_rdi_voff(Arena *arena, RDI_Parsed *rdi, U64 voff); //////////////////////////////// //~ rjf: Tokenization Functions @@ -101,7 +101,7 @@ internal EVAL_TokenArray eval_token_array_make_first_opl(EVAL_Token *first, EVAL //////////////////////////////// //~ rjf: Parser Functions -internal TG_Key eval_leaf_type_from_name(RADDBG_Parsed *rdbg, String8 name); +internal TG_Key eval_leaf_type_from_name(RDI_Parsed *rdi, String8 name); internal EVAL_ParseResult eval_parse_type_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens); internal EVAL_ParseResult eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens, S64 max_precedence); internal EVAL_ParseResult eval_parse_expr_from_text_tokens(Arena *arena, EVAL_ParseCtx *ctx, String8 text, EVAL_TokenArray *tokens); diff --git a/src/eval/generated/eval.meta.c b/src/eval/generated/eval.meta.c index b9d27fe6..c6566590 100644 --- a/src/eval/generated/eval.meta.c +++ b/src/eval/generated/eval.meta.c @@ -3,3 +3,153 @@ //- GENERATED CODE +C_LINKAGE_BEGIN +U8 eval_expr_kind_child_counts[40] = +{ +0, +2, +2, +1, +1, +2, +1, +1, +1, +1, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +2, +3, +0, +0, +0, +0, +0, +0, +1, +2, +1, +2, +0, +}; + +String8 eval_expr_kind_strings[40] = +{ +str8_lit_comp("Nil"), +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("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("LeafU64"), +str8_lit_comp("LeafF64"), +str8_lit_comp("LeafF32"), +str8_lit_comp("TypeIdent"), +str8_lit_comp("Ptr"), +str8_lit_comp("Array"), +str8_lit_comp("Func"), +str8_lit_comp("Define"), +str8_lit_comp("LeafIdent"), +}; + +String8 eval_result_code_display_strings[11] = +{ +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."), +}; + +String8 eval_expr_op_strings[40] = +{ +str8_lit_comp(""), +str8_lit_comp("[]"), +str8_lit_comp("."), +str8_lit_comp("*"), +str8_lit_comp("&"), +str8_lit_comp("cast"), +str8_lit_comp("sizeof"), +str8_lit_comp("-"), +str8_lit_comp("!"), +str8_lit_comp("~"), +str8_lit_comp("*"), +str8_lit_comp("/"), +str8_lit_comp("%"), +str8_lit_comp("+"), +str8_lit_comp("-"), +str8_lit_comp("<<"), +str8_lit_comp(">>"), +str8_lit_comp("<"), +str8_lit_comp("<="), +str8_lit_comp(">"), +str8_lit_comp(">="), +str8_lit_comp("=="), +str8_lit_comp("!="), +str8_lit_comp("&"), +str8_lit_comp("^"), +str8_lit_comp("|"), +str8_lit_comp("&&"), +str8_lit_comp("||"), +str8_lit_comp("? "), +str8_lit_comp("bytecode"), +str8_lit_comp("member"), +str8_lit_comp("U64"), +str8_lit_comp("F64"), +str8_lit_comp("F32"), +str8_lit_comp("type_ident"), +str8_lit_comp("ptr"), +str8_lit_comp("array"), +str8_lit_comp("function"), +str8_lit_comp("="), +str8_lit_comp("leaf_ident"), +}; + +C_LINKAGE_END + diff --git a/src/eval/generated/eval.meta.h b/src/eval/generated/eval.meta.h index 418412c8..4c90936c 100644 --- a/src/eval/generated/eval.meta.h +++ b/src/eval/generated/eval.meta.h @@ -7,8 +7,9 @@ #define EVAL_META_H typedef U32 EVAL_ExprKind; -enum +typedef enum EVAL_ExprKindEnum { +EVAL_ExprKind_Nil, EVAL_ExprKind_ArrayIndex, EVAL_ExprKind_MemberAccess, EVAL_ExprKind_Deref, @@ -48,137 +49,30 @@ EVAL_ExprKind_Array, EVAL_ExprKind_Func, EVAL_ExprKind_Define, EVAL_ExprKind_LeafIdent, -EVAL_ExprKind_COUNT -}; +EVAL_ExprKind_COUNT, +} EVAL_ExprKindEnum; -U8 eval_expr_kind_child_counts[] = +typedef enum EVAL_ResultCode { -2, -2, -1, -1, -2, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -0, -0, -0, -0, -0, -0, -1, -2, -1, -2, -0, -}; - -String8 eval_expr_kind_strings[] = -{ -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("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("LeafU64"), -str8_lit_comp("LeafF64"), -str8_lit_comp("LeafF32"), -str8_lit_comp("TypeIdent"), -str8_lit_comp("Ptr"), -str8_lit_comp("Array"), -str8_lit_comp("Func"), -str8_lit_comp("Define"), -str8_lit_comp("LeafIdent"), -}; - -String8 eval_expr_op_strings[] = -{ -str8_lit_comp("[]"), -str8_lit_comp("."), -str8_lit_comp("*"), -str8_lit_comp("&"), -str8_lit_comp("cast"), -str8_lit_comp("sizeof"), -str8_lit_comp("-"), -str8_lit_comp("!"), -str8_lit_comp("~"), -str8_lit_comp("*"), -str8_lit_comp("/"), -str8_lit_comp("%"), -str8_lit_comp("+"), -str8_lit_comp("-"), -str8_lit_comp("<<"), -str8_lit_comp(">>"), -str8_lit_comp("<"), -str8_lit_comp("<="), -str8_lit_comp(">"), -str8_lit_comp(">="), -str8_lit_comp("=="), -str8_lit_comp("!="), -str8_lit_comp("&"), -str8_lit_comp("^"), -str8_lit_comp("|"), -str8_lit_comp("&&"), -str8_lit_comp("||"), -str8_lit_comp("? "), -str8_lit_comp("bytecode"), -str8_lit_comp("member"), -str8_lit_comp("U64"), -str8_lit_comp("F64"), -str8_lit_comp("F32"), -str8_lit_comp("type_ident"), -str8_lit_comp("ptr"), -str8_lit_comp("array"), -str8_lit_comp("function"), -str8_lit_comp("="), -str8_lit_comp("leaf_ident"), -}; +EVAL_ResultCode_Good, +EVAL_ResultCode_DivideByZero, +EVAL_ResultCode_BadOp, +EVAL_ResultCode_BadOpTypes, +EVAL_ResultCode_BadMemRead, +EVAL_ResultCode_BadRegRead, +EVAL_ResultCode_BadFrameBase, +EVAL_ResultCode_BadModuleBase, +EVAL_ResultCode_BadTLSBase, +EVAL_ResultCode_InsufficientStackSpace, +EVAL_ResultCode_MalformedBytecode, +EVAL_ResultCode_COUNT, +} EVAL_ResultCode; +C_LINKAGE_BEGIN +extern U8 eval_expr_kind_child_counts[40]; +extern String8 eval_expr_kind_strings[40]; +extern String8 eval_result_code_display_strings[11]; +extern String8 eval_expr_op_strings[40]; +C_LINKAGE_END #endif // EVAL_META_H diff --git a/src/file_stream/file_stream.c b/src/file_stream/file_stream.c index 2bf6fe57..e1b411e5 100644 --- a/src/file_stream/file_stream.c +++ b/src/file_stream/file_stream.c @@ -11,7 +11,7 @@ fs_init(void) fs_shared = push_array(arena, FS_Shared, 1); fs_shared->arena = arena; fs_shared->slots_count = 1024; - fs_shared->stripes_count = 64; + fs_shared->stripes_count = os_logical_core_count(); fs_shared->slots = push_array(arena, FS_Slot, fs_shared->slots_count); fs_shared->stripes = push_array(arena, FS_Stripe, fs_shared->stripes_count); for(U64 idx = 0; idx < fs_shared->stripes_count; idx += 1) @@ -30,61 +30,78 @@ fs_init(void) { fs_shared->streamers[idx] = os_launch_thread(fs_streamer_thread__entry_point, (void *)idx, 0); } + fs_shared->detector_thread = os_launch_thread(fs_detector_thread__entry_point, 0, 0); } //////////////////////////////// //~ rjf: Cache Interaction internal U128 -fs_hash_from_path(String8 path, U64 rewind_count, U64 endt_us) +fs_hash_from_path(String8 path, U64 endt_us) { Temp scratch = scratch_begin(0, 0); + U128 result = {0}; path = path_normalized_from_string(scratch.arena, path); U128 path_key = hs_hash_from_data(path); - U128 result = hs_hash_from_key(path_key, rewind_count); - if(u128_match(result, u128_zero())) + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) { - U64 slot_idx = path_key.u64[0]%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) for(;;) + result = hs_hash_from_key(path_key, rewind_idx); + if(!u128_match(result, u128_zero())) { - FS_Node *node = 0; - for(FS_Node *n = slot->first; n != 0; n = n->next) + break; + } + else if(u128_match(result, u128_zero()) && rewind_idx == 0) + { + U64 slot_idx = path_key.u64[0]%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) for(;;) { - if(str8_match(path, n->path, 0)) + FS_Node *node = 0; + for(FS_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(path, n->path, 0)) + { + node = n; + break; + } + } + if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) + { + node = push_array(stripe->arena, FS_Node, 1); + SLLQueuePush(slot->first, slot->last, node); + node->path = push_str8_copy(stripe->arena, path); + } + if(!ins_atomic_u32_eval_cond_assign(&node->is_working, 1, 0) && + !fs_u2s_enqueue_path(path, endt_us)) + { + ins_atomic_u32_eval_assign(&node->is_working, 0); + } + result = hs_hash_from_key(path_key, 0); + if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us) + { + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + else { - node = n; break; } } - if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) - { - node = push_array(stripe->arena, FS_Node, 1); - SLLQueuePush(slot->first, slot->last, node); - node->path = push_str8_copy(stripe->arena, path); - } - if(os_now_microseconds() >= ins_atomic_u64_eval(&node->last_time_requested_us)+1000000 && - fs_u2s_enqueue_path(path, endt_us)) - { - ins_atomic_u64_eval_assign(&node->last_time_requested_us, os_now_microseconds()); - } - result = hs_hash_from_key(path_key, rewind_count); - if(u128_match(result, u128_zero()) && os_now_microseconds() <= endt_us) - { - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - else - { - break; - } } } scratch_end(scratch); return result; } +internal U128 +fs_key_from_path(String8 path) +{ + U128 key = hs_hash_from_data(path); + fs_hash_from_path(path, 0); + return key; +} + //////////////////////////////// //~ rjf: Streamer Threads @@ -140,53 +157,114 @@ fs_u2s_dequeue_path(Arena *arena) internal void fs_streamer_thread__entry_point(void *p) { - TCTX tctx_; - tctx_init_and_equip(&tctx_); - ThreadName("[fs] streamer #%I64u", (U64)p); + ThreadNameF("[fs] streamer #%I64u", (U64)p); for(;;) { Temp scratch = scratch_begin(0, 0); + + //- rjf: unpack path String8 path = fs_u2s_dequeue_path(scratch.arena); + U128 key = hs_hash_from_data(path); + U64 slot_idx = key.u64[0]%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]; + + //- rjf: load + ProfBegin("load \"%.*s\"", str8_varg(path)); FileProperties pre_props = os_properties_from_file_path(path); OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, path); U64 data_arena_size = pre_props.size+ARENA_HEADER_SIZE; data_arena_size += KB(4)-1; data_arena_size -= data_arena_size%KB(4); + ProfBegin("allocate"); Arena *data_arena = arena_alloc__sized(data_arena_size, data_arena_size); + ProfEnd(); + ProfBegin("read"); String8 data = os_string_from_file_range(data_arena, file, r1u64(0, pre_props.size)); + ProfEnd(); os_file_close(file); FileProperties post_props = os_properties_from_file_path(path); + + //- rjf: abort if modification timestamps differ - we did not successfully read the file if(pre_props.modified != post_props.modified) { - arena_release(data_arena); - MemoryZeroStruct(&data); + ProfScope("abort") + { + arena_release(data_arena); + MemoryZeroStruct(&data); + data_arena = 0; + } } + + //- rjf: submit else { - U128 key = hs_hash_from_data(path); - hs_submit_data(key, &data_arena, data); - U64 slot_idx = key.u64[0]%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_MutexScopeW(stripe->rw_mutex) + ProfScope("submit") { - FS_Node *node = 0; - for(FS_Node *n = slot->first; n != 0; n = n->next) + hs_submit_data(key, &data_arena, data); + } + } + + //- rjf: commit info to cache + ProfScope("commit to cache") OS_MutexScopeW(stripe->rw_mutex) + { + FS_Node *node = 0; + for(FS_Node *n = slot->first; n != 0; n = n->next) + { + if(str8_match(n->path, path, 0)) { - if(str8_match(n->path, path, 0)) - { - node = n; - break; - } + node = n; + break; } - if(node != 0) + } + if(node != 0) + { + if(post_props.modified == pre_props.modified) { node->timestamp = post_props.modified; } + ins_atomic_u32_eval_assign(&node->is_working, 0); } - os_condition_variable_broadcast(stripe->cv); } + os_condition_variable_broadcast(stripe->cv); + + ProfEnd(); scratch_end(scratch); } } + +//////////////////////////////// +//~ rjf: Change Detector Thread + +internal void +fs_detector_thread__entry_point(void *p) +{ + ThreadNameF("[fs] detector"); + for(;;) + { + U64 slots_per_stripe = fs_shared->slots_count/fs_shared->stripes_count; + for(U64 stripe_idx = 0; stripe_idx < fs_shared->stripes_count; stripe_idx += 1) + { + FS_Stripe *stripe = &fs_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1) + { + U64 slot_idx = stripe_idx*slots_per_stripe + slot_in_stripe_idx; + FS_Slot *slot = &fs_shared->slots[slot_idx]; + 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(!ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0) && + !fs_u2s_enqueue_path(n->path, os_now_microseconds()+100000)) + { + ins_atomic_u32_eval_assign(&n->is_working, 0); + } + } + } + } + } + os_sleep_milliseconds(100); + } +} diff --git a/src/file_stream/file_stream.h b/src/file_stream/file_stream.h index 4d54a379..078b3547 100644 --- a/src/file_stream/file_stream.h +++ b/src/file_stream/file_stream.h @@ -13,7 +13,7 @@ struct FS_Node FS_Node *next; String8 path; U64 timestamp; - U64 last_time_requested_us; + B32 is_working; }; typedef struct FS_Slot FS_Slot; @@ -56,6 +56,9 @@ struct FS_Shared // rjf: streamer threads U64 streamer_count; OS_Handle *streamers; + + // rjf: change detector threads + OS_Handle detector_thread; }; //////////////////////////////// @@ -71,7 +74,8 @@ internal void fs_init(void); //////////////////////////////// //~ rjf: Cache Interaction -internal U128 fs_hash_from_path(String8 path, U64 rewind_count, U64 endt_us); +internal U128 fs_hash_from_path(String8 path, U64 endt_us); +internal U128 fs_key_from_path(String8 path); //////////////////////////////// //~ rjf: Streamer Threads @@ -81,4 +85,9 @@ internal String8 fs_u2s_dequeue_path(Arena *arena); internal void fs_streamer_thread__entry_point(void *p); +//////////////////////////////// +//~ rjf: Change Detector Thread + +internal void fs_detector_thread__entry_point(void *p); + #endif // FILE_STREAM_H diff --git a/src/font_cache/font_cache.c b/src/font_cache/font_cache.c index 36f5fa62..ced8a853 100644 --- a/src/font_cache/font_cache.c +++ b/src/font_cache/font_cache.c @@ -10,7 +10,9 @@ #include "third_party/blake2/blake2b.c" #endif -#define TAB_STRING " " +#ifndef F_TAB_STRING +#define F_TAB_STRING " " +#endif internal F_Hash f_hash_from_string(String8 string) @@ -619,7 +621,7 @@ f_push_run_from_string(Arena *arena, F_Tag tag, F32 size, F_RunFlags flags, Stri B32 is_tab = (piece_substring.size == 1 && piece_substring.str[0] == '\t'); if(is_tab) { - piece_substring = str8_lit(TAB_STRING); + piece_substring = str8_lit(F_TAB_STRING); } //- rjf: piece substring -> raster cache info diff --git a/src/font_provider/dwrite/font_provider_dwrite_main.cpp b/src/font_provider/dwrite/font_provider_dwrite_main.cpp index e145de25..4ebbb9b2 100644 --- a/src/font_provider/dwrite/font_provider_dwrite_main.cpp +++ b/src/font_provider/dwrite/font_provider_dwrite_main.cpp @@ -1,4 +1,4 @@ -#define SUPPLEMENT_UNIT 1 +#define BUILD_SUPPLEMENTARY_UNIT 1 #include "base/base_inc.h" #include "os/os_inc.h" diff --git a/src/geo_cache/geo_cache.c b/src/geo_cache/geo_cache.c index 09bdbbe4..cec24960 100644 --- a/src/geo_cache/geo_cache.c +++ b/src/geo_cache/geo_cache.c @@ -11,7 +11,7 @@ geo_init(void) geo_shared = push_array(arena, GEO_Shared, 1); geo_shared->arena = arena; geo_shared->slots_count = 1024; - geo_shared->stripes_count = 64; + geo_shared->stripes_count = Min(geo_shared->slots_count, os_logical_core_count()); geo_shared->slots = push_array(arena, GEO_Slot, geo_shared->slots_count); geo_shared->stripes = push_array(arena, GEO_Stripe, geo_shared->stripes_count); geo_shared->stripes_free_nodes = push_array(arena, GEO_Node *, geo_shared->stripes_count); @@ -21,16 +21,6 @@ geo_init(void) geo_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); geo_shared->stripes[idx].cv = os_condition_variable_alloc(); } - geo_shared->fallback_slots_count = 1024; - geo_shared->fallback_stripes_count = 64; - geo_shared->fallback_slots = push_array(arena, GEO_KeyFallbackSlot, geo_shared->fallback_slots_count); - geo_shared->fallback_stripes = push_array(arena, GEO_Stripe, geo_shared->fallback_stripes_count); - for(U64 idx = 0; idx < geo_shared->fallback_stripes_count; idx += 1) - { - geo_shared->fallback_stripes[idx].arena = arena_alloc(); - geo_shared->fallback_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - geo_shared->fallback_stripes[idx].cv = os_condition_variable_alloc(); - } geo_shared->u2x_ring_size = KB(64); geo_shared->u2x_ring_base = push_array_no_zero(arena, U8, geo_shared->u2x_ring_size); geo_shared->u2x_ring_cv = os_condition_variable_alloc(); @@ -144,7 +134,7 @@ geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node *node) //~ rjf: Cache Lookups internal R_Handle -geo_buffer_from_key_hash(GEO_Scope *scope, U128 key, U128 hash) +geo_buffer_from_hash(GEO_Scope *scope, U128 hash) { R_Handle handle = {0}; if(!u128_match(hash, u128_zero())) @@ -201,42 +191,23 @@ geo_buffer_from_key_hash(GEO_Scope *scope, U128 key, U128 hash) } if(node_is_new) { - geo_u2x_enqueue_req(key, hash, max_U64); + geo_u2x_enqueue_req(hash, max_U64); } - if(r_handle_match(handle, r_handle_zero())) + } + return handle; +} + +internal R_Handle +geo_buffer_from_key(GEO_Scope *scope, U128 key) +{ + R_Handle handle = {0}; + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) + { + U128 hash = hs_hash_from_key(key, rewind_idx); + handle = geo_buffer_from_hash(scope, hash); + if(!r_handle_match(handle, r_handle_zero())) { - U128 fallback_hash = {0}; - U64 fallback_slot_idx = key.u64[1]%geo_shared->fallback_slots_count; - U64 fallback_stripe_idx = fallback_slot_idx%geo_shared->fallback_stripes_count; - GEO_KeyFallbackSlot *fallback_slot = &geo_shared->fallback_slots[fallback_slot_idx]; - GEO_Stripe *fallback_stripe = &geo_shared->fallback_stripes[fallback_stripe_idx]; - OS_MutexScopeR(fallback_stripe->rw_mutex) for(GEO_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) - { - if(u128_match(key, n->key)) - { - fallback_hash = n->hash; - break; - } - } - if(!u128_match(fallback_hash, u128_zero())) - { - U64 retry_slot_idx = fallback_hash.u64[1]%geo_shared->slots_count; - U64 retry_stripe_idx = retry_slot_idx%geo_shared->stripes_count; - GEO_Slot *retry_slot = &geo_shared->slots[retry_slot_idx]; - GEO_Stripe *retry_stripe = &geo_shared->stripes[retry_stripe_idx]; - OS_MutexScopeR(retry_stripe->rw_mutex) - { - for(GEO_Node *n = retry_slot->first; n != 0; n = n->next) - { - if(u128_match(fallback_hash, n->hash)) - { - handle = n->buffer; - geo_scope_touch_node__stripe_r_guarded(scope, n); - break; - } - } - } - } + break; } } return handle; @@ -246,17 +217,16 @@ geo_buffer_from_key_hash(GEO_Scope *scope, U128 key, U128 hash) //~ rjf: Transfer Threads internal B32 -geo_u2x_enqueue_req(U128 key, U128 hash, U64 endt_us) +geo_u2x_enqueue_req(U128 hash, U64 endt_us) { B32 good = 0; OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; U64 available_size = geo_shared->u2x_ring_size-unconsumed_size; - if(available_size >= sizeof(key)+sizeof(hash)) + if(available_size >= sizeof(hash)) { good = 1; - geo_shared->u2x_ring_write_pos += ring_write_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_write_pos, &key); geo_shared->u2x_ring_write_pos += ring_write_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_write_pos, &hash); break; } @@ -274,14 +244,13 @@ geo_u2x_enqueue_req(U128 key, U128 hash, U64 endt_us) } internal void -geo_u2x_dequeue_req(U128 *key_out, U128 *hash_out) +geo_u2x_dequeue_req(U128 *hash_out) { OS_MutexScope(geo_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = geo_shared->u2x_ring_write_pos-geo_shared->u2x_ring_read_pos; - if(unconsumed_size >= sizeof(*key_out)+sizeof(*hash_out)) + if(unconsumed_size >= sizeof(*hash_out)) { - geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, key_out); geo_shared->u2x_ring_read_pos += ring_read_struct(geo_shared->u2x_ring_base, geo_shared->u2x_ring_size, geo_shared->u2x_ring_read_pos, hash_out); break; } @@ -293,16 +262,13 @@ geo_u2x_dequeue_req(U128 *key_out, U128 *hash_out) internal void geo_xfer_thread__entry_point(void *p) { - TCTX tctx_ = {0}; - tctx_init_and_equip(&tctx_); for(;;) { HS_Scope *scope = hs_scope_open(); //- rjf: decode - U128 key = {0}; U128 hash = {0}; - geo_u2x_dequeue_req(&key, &hash); + geo_u2x_dequeue_req(&hash); //- rjf: unpack hash U64 slot_idx = hash.u64[1]%geo_shared->slots_count; @@ -353,34 +319,6 @@ geo_xfer_thread__entry_point(void *p) } } - //- rjf: commit this key/hash pair to fallback cache - if(got_task && !u128_match(key, u128_zero()) && !u128_match(hash, u128_zero())) - { - U64 fallback_slot_idx = key.u64[1]%geo_shared->fallback_slots_count; - U64 fallback_stripe_idx = fallback_slot_idx%geo_shared->fallback_stripes_count; - GEO_KeyFallbackSlot *fallback_slot = &geo_shared->fallback_slots[fallback_slot_idx]; - GEO_Stripe *fallback_stripe = &geo_shared->fallback_stripes[fallback_stripe_idx]; - OS_MutexScopeW(fallback_stripe->rw_mutex) - { - GEO_KeyFallbackNode *node = 0; - for(GEO_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(fallback_stripe->arena, GEO_KeyFallbackNode, 1); - SLLQueuePush(fallback_slot->first, fallback_slot->last, node); - } - node->key = key; - node->hash = hash; - } - } - hs_scope_close(scope); } } diff --git a/src/geo_cache/geo_cache.h b/src/geo_cache/geo_cache.h index 256f29ac..60d882b3 100644 --- a/src/geo_cache/geo_cache.h +++ b/src/geo_cache/geo_cache.h @@ -7,21 +7,6 @@ //////////////////////////////// //~ rjf: Cache Types -typedef struct GEO_KeyFallbackNode GEO_KeyFallbackNode; -struct GEO_KeyFallbackNode -{ - GEO_KeyFallbackNode *next; - U128 key; - U128 hash; -}; - -typedef struct GEO_KeyFallbackSlot GEO_KeyFallbackSlot; -struct GEO_KeyFallbackSlot -{ - GEO_KeyFallbackNode *first; - GEO_KeyFallbackNode *last; -}; - typedef struct GEO_Node GEO_Node; struct GEO_Node { @@ -97,12 +82,6 @@ struct GEO_Shared GEO_Stripe *stripes; GEO_Node **stripes_free_nodes; - // rjf: fallback cache - U64 fallback_slots_count; - U64 fallback_stripes_count; - GEO_KeyFallbackSlot *fallback_slots; - GEO_Stripe *fallback_stripes; - // rjf: user -> xfer thread U64 u2x_ring_size; U8 *u2x_ring_base; @@ -151,13 +130,14 @@ internal void geo_scope_touch_node__stripe_r_guarded(GEO_Scope *scope, GEO_Node //////////////////////////////// //~ rjf: Cache Lookups -internal R_Handle geo_buffer_from_key_hash(GEO_Scope *scope, U128 key, U128 hash); +internal R_Handle geo_buffer_from_hash(GEO_Scope *scope, U128 hash); +internal R_Handle geo_buffer_from_key(GEO_Scope *scope, U128 key); //////////////////////////////// //~ rjf: Transfer Threads -internal B32 geo_u2x_enqueue_req(U128 key, U128 hash, U64 endt_us); -internal void geo_u2x_dequeue_req(U128 *key_out, U128 *hash_out); +internal B32 geo_u2x_enqueue_req(U128 hash, U64 endt_us); +internal void geo_u2x_dequeue_req(U128 *hash_out); internal void geo_xfer_thread__entry_point(void *p); //////////////////////////////// diff --git a/src/hash_store/hash_store.c b/src/hash_store/hash_store.c index c80cd191..501d888a 100644 --- a/src/hash_store/hash_store.c +++ b/src/hash_store/hash_store.c @@ -28,7 +28,7 @@ hs_init(void) hs_shared = push_array(arena, HS_Shared, 1); hs_shared->arena = arena; hs_shared->slots_count = 4096; - hs_shared->stripes_count = 64; + hs_shared->stripes_count = Min(hs_shared->slots_count, os_logical_core_count()); hs_shared->slots = push_array(arena, HS_Slot, hs_shared->slots_count); hs_shared->stripes = push_array(arena, HS_Stripe, hs_shared->stripes_count); hs_shared->stripes_free_nodes = push_array(arena, HS_Node *, hs_shared->stripes_count); @@ -40,7 +40,7 @@ hs_init(void) stripe->cv = os_condition_variable_alloc(); } hs_shared->key_slots_count = 4096; - hs_shared->key_stripes_count = 64; + hs_shared->key_stripes_count = Min(hs_shared->key_slots_count, os_logical_core_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); for(U64 idx = 0; idx < hs_shared->key_stripes_count; idx += 1) @@ -84,7 +84,7 @@ hs_submit_data(U128 key, Arena **data_arena, String8 data) HS_Stripe *stripe = &hs_shared->stripes[stripe_idx]; //- rjf: commit data to cache - if already there, just bump key refcount - OS_MutexScopeW(stripe->rw_mutex) + ProfScope("commit data to cache - if already there, just bump key refcount") OS_MutexScopeW(stripe->rw_mutex) { HS_Node *existing_node = 0; for(HS_Node *n = slot->first; n != 0; n = n->next) @@ -123,7 +123,7 @@ hs_submit_data(U128 key, Arena **data_arena, String8 data) //- rjf: commit this hash to key cache U128 key_expired_hash = {0}; - OS_MutexScopeW(key_stripe->rw_mutex) + ProfScope("commit this hash to key cache") OS_MutexScopeW(key_stripe->rw_mutex) { HS_KeyNode *key_node = 0; for(HS_KeyNode *n = key_slot->first; n != 0; n = n->next) @@ -152,7 +152,8 @@ hs_submit_data(U128 key, Arena **data_arena, String8 data) } //- rjf: if this key's history cache was full, dec key ref count of oldest hash - if(!u128_match(key_expired_hash, u128_zero())) + ProfScope("if this key's history cache was full, dec key ref count of oldest hash") + if(!u128_match(key_expired_hash, u128_zero())) { U64 old_hash_slot_idx = key_expired_hash.u64[1]%hs_shared->slots_count; U64 old_hash_stripe_idx = old_hash_slot_idx%hs_shared->stripes_count; diff --git a/src/raddbg_markup/raddbg_markup.h b/src/lib_raddbg_markup/raddbg_markup.h similarity index 96% rename from src/raddbg_markup/raddbg_markup.h rename to src/lib_raddbg_markup/raddbg_markup.h index 66b0fa31..bd0b0cc4 100644 --- a/src/raddbg_markup/raddbg_markup.h +++ b/src/lib_raddbg_markup/raddbg_markup.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_MARKUP_H -#define RADDBG_MARKUP_H +#ifndef RDI_MARKUP_H +#define RDI_MARKUP_H //////////////////////////////// //~ Usage Macros @@ -75,4 +75,4 @@ raddbg_log__impl(char *fmt, ...) #endif // defined(_WIN32) -#endif // RADDBG_MARKUP_H +#endif // RDI_MARKUP_H diff --git a/src/lib_raddbgi_format/raddbgi_format.c b/src/lib_raddbgi_format/raddbgi_format.c new file mode 100644 index 00000000..8d5ea8b8 --- /dev/null +++ b/src/lib_raddbgi_format/raddbgi_format.c @@ -0,0 +1,97 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +// Functions + +RDI_PROC RDI_U64 +rdi_hash(RDI_U8 *ptr, RDI_U64 size){ + RDI_U64 result = 5381; + RDI_U8 *opl = ptr + size; + for (; ptr < opl; ptr += 1){ + result = ((result << 5) + result) + *ptr; + } + return(result); +} + +RDI_PROC RDI_U32 +rdi_size_from_basic_type_kind(RDI_TypeKind kind){ + RDI_U32 result = 0; + switch (kind){ +#define X(N,C) +#define XZ(N,C,Z) case C: result = Z; break; +#define Y(A,N) + RDI_TypeKindXList(X,XZ,Y) +#undef X +#undef XZ +#undef Y + } + return(result); +} + +RDI_PROC RDI_U32 +rdi_addr_size_from_arch(RDI_Arch arch){ + RDI_U32 result = 0; + switch (arch){ +#define X(N,C,Z) case C: result = Z; break; + RDI_ArchXList(X) +#undef X + } + return(result); +} + +//- eval helpers + +RDI_PROC RDI_EvalConversionKind +rdi_eval_conversion_rule(RDI_EvalTypeGroup in, RDI_EvalTypeGroup out){ + RDI_EvalConversionKind result = 0; + switch (in + (out << 8)){ +#define Y(i,o) case ((RDI_EvalTypeGroup_##i) + ((RDI_EvalTypeGroup_##o) << 8)): +#define Xb(c) +#define Xe(c) result = RDI_EvalConversionKind_##c; break; + RDI_EvalConversionKindFromTypeGroupPairMap(Y,Xb,Xe) +#undef Xe +#undef Xb +#undef Y + } + return(result); +} + +RDI_PROC RDI_U8* +rdi_eval_conversion_message(RDI_EvalConversionKind conversion_kind, RDI_U64 *lenout){ + RDI_U8 *result = 0; + switch (conversion_kind){ +#define X(N,msg) \ +case RDI_EvalConversionKind_##N: result = (RDI_U8*)msg; *lenout = sizeof(msg) - 1; break; + RDI_EvalConversionKindXList(X) +#undef X + } + return(result); +} + +RDI_PROC RDI_S32 +rdi_eval_opcode_type_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group){ + RDI_S32 result = 0; + switch (op){ + case RDI_EvalOp_Neg: case RDI_EvalOp_Add: case RDI_EvalOp_Sub: + case RDI_EvalOp_Mul: case RDI_EvalOp_Div: + case RDI_EvalOp_EqEq:case RDI_EvalOp_NtEq: + case RDI_EvalOp_LsEq:case RDI_EvalOp_GrEq: + case RDI_EvalOp_Less:case RDI_EvalOp_Grtr: + { + if (group != RDI_EvalTypeGroup_Other){ + result = 1; + } + }break; + case RDI_EvalOp_Mod:case RDI_EvalOp_LShift:case RDI_EvalOp_RShift: + case RDI_EvalOp_BitNot:case RDI_EvalOp_BitAnd:case RDI_EvalOp_BitXor: + case RDI_EvalOp_BitOr:case RDI_EvalOp_LogNot:case RDI_EvalOp_LogAnd: + case RDI_EvalOp_LogOr: + { + if (group == RDI_EvalTypeGroup_S || group == RDI_EvalTypeGroup_U){ + result = 1; + } + }break; + } + return(result); +} diff --git a/src/raddbg_format/raddbg_format.h b/src/lib_raddbgi_format/raddbgi_format.h similarity index 52% rename from src/raddbg_format/raddbg_format.h rename to src/lib_raddbgi_format/raddbgi_format.h index 0dd4fa0d..16a03d44 100644 --- a/src/raddbg_format/raddbg_format.h +++ b/src/lib_raddbgi_format/raddbgi_format.h @@ -1,60 +1,66 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_FORMAT_H -#define RADDBG_FORMAT_H +//////////////////////////////////////////////////////////////// +// RAD Debug Info, (R)AD(D)BG(I) Format Library +// +// Defines standard RADDBGI debug information format types and +// functions. + +#ifndef RADDBGI_FORMAT_H +#define RADDBGI_FORMAT_H //////////////////////////////////////////////////////////////// // Overridable procedure decoration -#if !defined(RADDBG_PROC) -# define RADDBG_PROC static +#if !defined(RDI_PROC) +# define RDI_PROC static #endif //////////////////////////////////////////////////////////////// // Overridable integer types -#if !defined(RADDBG_U8) -# define RADDBG_U8 RADDBG_U8 -# define RADDBG_U16 RADDBG_U16 -# define RADDBG_U32 RADDBG_U32 -# define RADDBG_U64 RADDBG_U64 -# define RADDBG_S8 RADDBG_S8 -# define RADDBG_S16 RADDBG_S16 -# define RADDBG_S32 RADDBG_S32 -# define RADDBG_S64 RADDBG_S64 +#if !defined(RDI_U8) +# define RDI_U8 RDI_U8 +# define RDI_U16 RDI_U16 +# define RDI_U32 RDI_U32 +# define RDI_U64 RDI_U64 +# define RDI_S8 RDI_S8 +# define RDI_S16 RDI_S16 +# define RDI_S32 RDI_S32 +# define RDI_S64 RDI_S64 #include -typedef uint8_t RADDBG_U8; -typedef uint16_t RADDBG_U16; -typedef uint32_t RADDBG_U32; -typedef uint64_t RADDBG_U64; -typedef int8_t RADDBG_S8; -typedef int16_t RADDBG_S16; -typedef int32_t RADDBG_S32; -typedef int64_t RADDBG_S64; +typedef uint8_t RDI_U8; +typedef uint16_t RDI_U16; +typedef uint32_t RDI_U32; +typedef uint64_t RDI_U64; +typedef int8_t RDI_S8; +typedef int16_t RDI_S16; +typedef int32_t RDI_S32; +typedef int64_t RDI_S64; #endif //////////////////////////////////////////////////////////////// // Architecture Constants -#define RADDBG_ArchXList(X)\ +#define RDI_ArchXList(X)\ X(NULL, 0, 0)\ X(X86, 1, 4)\ X(X64, 2, 8) -typedef RADDBG_U32 RADDBG_Arch; -typedef enum RADDBG_ArchEnum{ -#define X(N,C,Z) RADDBG_Arch_##N = C, - RADDBG_ArchXList(X) +typedef RDI_U32 RDI_Arch; +typedef enum RDI_ArchEnum{ +#define X(N,C,Z) RDI_Arch_##N = C, + RDI_ArchXList(X) #undef X -} RADDBG_ArchEnum; +} RDI_ArchEnum; -typedef RADDBG_U8 RADDBG_RegisterCode; +typedef RDI_U8 RDI_RegisterCode; // x86 registers -#define RADDBG_RegisterCode_X86_XList(X) \ +#define RDI_RegisterCode_X86_XList(X) \ X(nil, 0) \ X(eax, 1) \ X(ecx, 2) \ @@ -118,14 +124,14 @@ X(ymm6, 59) \ X(ymm7, 60) \ X(COUNT, 61) -typedef enum RADDBG_RegisterCode_X86_Enum{ -#define X(N,C) RADDBG_RegisterCode_X86_##N = C, - RADDBG_RegisterCode_X86_XList(X) +typedef enum RDI_RegisterCode_X86_Enum{ +#define X(N,C) RDI_RegisterCode_X86_##N = C, + RDI_RegisterCode_X86_XList(X) #undef X -} RADDBG_RegisterCode_X86_Enum; +} RDI_RegisterCode_X86_Enum; // x64 registers -#define RADDBG_RegisterCode_X64_XList(X) \ +#define RDI_RegisterCode_X64_XList(X) \ X(nil, 0) \ X(rax, 1) \ X(rcx, 2) \ @@ -205,48 +211,48 @@ X(fdp, 75) \ X(mxcsr_mask, 76) \ X(COUNT, 77) -typedef enum RADDBG_RegisterCode_X64_Enum{ -#define X(N,C) RADDBG_RegisterCode_X64_##N = C, - RADDBG_RegisterCode_X64_XList(X) +typedef enum RDI_RegisterCode_X64_Enum{ +#define X(N,C) RDI_RegisterCode_X64_##N = C, + RDI_RegisterCode_X64_XList(X) #undef X -} RADDBG_RegisterCode_X64_Enum; +} RDI_RegisterCode_X64_Enum; //////////////////////////////////////////////////////////////// // Format types // "raddbg\0\0" -#define RADDBG_MAGIC_CONSTANT 0x0000676264646172 -#define RADDBG_ENCODING_VERSION 1 +#define RDI_MAGIC_CONSTANT 0x0000676264646172 +#define RDI_ENCODING_VERSION 1 -#define RADDBG_LanguageXList(X) \ +#define RDI_LanguageXList(X) \ X(NULL, 0) \ X(C, 1) \ X(CPlusPlus, 2) -typedef RADDBG_U32 RADDBG_Language; -typedef enum RADDBG_LanguageEnum{ -#define X(N,C) RADDBG_Language_##N = C, - RADDBG_LanguageXList(X) +typedef RDI_U32 RDI_Language; +typedef enum RDI_LanguageEnum{ +#define X(N,C) RDI_Language_##N = C, + RDI_LanguageXList(X) #undef X -} RADDBG_LanguageEnum; +} RDI_LanguageEnum; -typedef struct RADDBG_Header{ +typedef struct RDI_Header{ // identification - RADDBG_U64 magic; - RADDBG_U32 encoding_version; + RDI_U64 magic; + RDI_U32 encoding_version; // data sections - RADDBG_U32 data_section_off; - RADDBG_U32 data_section_count; -} RADDBG_Header; + RDI_U32 data_section_off; + RDI_U32 data_section_count; +} RDI_Header; //- data sections -#define RADDBG_DataSectionTag_SECONDARY 0x80000000 +#define RDI_DataSectionTag_SECONDARY 0x80000000 -#define RADDBG_DataSectionTagXList(X,Y) \ +#define RDI_DataSectionTagXList(X,Y) \ X(NULL, 0x0000)\ X(TopLevelInfo, 0x0001)\ X(StringData, 0x0002)\ @@ -273,131 +279,131 @@ X(LocationBlocks, 0x0016)\ X(LocationData, 0x0017)\ X(NameMaps, 0x0018)\ Y(PRIMARY_COUNT)\ -X(SKIP, RADDBG_DataSectionTag_SECONDARY|0x0000)\ -X(LineInfoVoffs, RADDBG_DataSectionTag_SECONDARY|0x0001)\ -X(LineInfoData, RADDBG_DataSectionTag_SECONDARY|0x0002)\ -X(LineInfoColumns, RADDBG_DataSectionTag_SECONDARY|0x0003)\ -X(LineMapNumbers, RADDBG_DataSectionTag_SECONDARY|0x0004)\ -X(LineMapRanges, RADDBG_DataSectionTag_SECONDARY|0x0005)\ -X(LineMapVoffs, RADDBG_DataSectionTag_SECONDARY|0x0006)\ -X(NameMapBuckets, RADDBG_DataSectionTag_SECONDARY|0x0007)\ -X(NameMapNodes, RADDBG_DataSectionTag_SECONDARY|0x0008) +X(SKIP, RDI_DataSectionTag_SECONDARY|0x0000)\ +X(LineInfoVoffs, RDI_DataSectionTag_SECONDARY|0x0001)\ +X(LineInfoData, RDI_DataSectionTag_SECONDARY|0x0002)\ +X(LineInfoColumns, RDI_DataSectionTag_SECONDARY|0x0003)\ +X(LineMapNumbers, RDI_DataSectionTag_SECONDARY|0x0004)\ +X(LineMapRanges, RDI_DataSectionTag_SECONDARY|0x0005)\ +X(LineMapVoffs, RDI_DataSectionTag_SECONDARY|0x0006)\ +X(NameMapBuckets, RDI_DataSectionTag_SECONDARY|0x0007)\ +X(NameMapNodes, RDI_DataSectionTag_SECONDARY|0x0008) -typedef RADDBG_U32 RADDBG_DataSectionTag; -typedef enum RADDBG_DataSectionTagEnum{ -#define X(N,C) RADDBG_DataSectionTag_##N = C, -#define Y(N) RADDBG_DataSectionTag_##N, - RADDBG_DataSectionTagXList(X,Y) +typedef RDI_U32 RDI_DataSectionTag; +typedef enum RDI_DataSectionTagEnum{ +#define X(N,C) RDI_DataSectionTag_##N = C, +#define Y(N) RDI_DataSectionTag_##N, + RDI_DataSectionTagXList(X,Y) #undef X #undef Y -} RADDBG_DataSectionTagEnum; +} RDI_DataSectionTagEnum; -#define RADDBG_DataSectionEncodingXList(X) \ +#define RDI_DataSectionEncodingXList(X) \ X(Unpacked, 0) -typedef RADDBG_U32 RADDBG_DataSectionEncoding; -typedef enum RADDBG_DataSectionEncodingEnum{ -#define X(N,C) RADDBG_DataSectionEncoding_##N = C, - RADDBG_DataSectionEncodingXList(X) +typedef RDI_U32 RDI_DataSectionEncoding; +typedef enum RDI_DataSectionEncodingEnum{ +#define X(N,C) RDI_DataSectionEncoding_##N = C, + RDI_DataSectionEncodingXList(X) #undef X -} RADDBG_DataSectionEncodingEnum; +} RDI_DataSectionEncodingEnum; -typedef struct RADDBG_DataSection{ - RADDBG_DataSectionTag tag; - RADDBG_DataSectionEncoding encoding; - RADDBG_U64 off; - RADDBG_U64 encoded_size; - RADDBG_U64 unpacked_size; -} RADDBG_DataSection; +typedef struct RDI_DataSection{ + RDI_DataSectionTag tag; + RDI_DataSectionEncoding encoding; + RDI_U64 off; + RDI_U64 encoded_size; + RDI_U64 unpacked_size; +} RDI_DataSection; //- common types -typedef struct RADDBG_VMapEntry{ - RADDBG_U64 voff; - RADDBG_U64 idx; -} RADDBG_VMapEntry; +typedef struct RDI_VMapEntry{ + RDI_U64 voff; + RDI_U64 idx; +} RDI_VMapEntry; //- top level info -typedef struct RADDBG_TopLevelInfo{ - RADDBG_Arch architecture; - RADDBG_U32 exe_name_string_idx; - RADDBG_U64 exe_hash; - RADDBG_U64 voff_max; -} RADDBG_TopLevelInfo; +typedef struct RDI_TopLevelInfo{ + RDI_Arch architecture; + RDI_U32 exe_name_string_idx; + RDI_U64 exe_hash; + RDI_U64 voff_max; +} RDI_TopLevelInfo; //- binary sections -typedef RADDBG_U32 RADDBG_BinarySectionFlags; -typedef enum RADDBG_BinarySectionFlagsEnum{ - RADDBG_BinarySectionFlag_Read = (1 << 0), - RADDBG_BinarySectionFlag_Write = (1 << 1), - RADDBG_BinarySectionFlag_Execute = (1 << 2) -} RADDBG_BinarySectionFlagsEnum; +typedef RDI_U32 RDI_BinarySectionFlags; +typedef enum RDI_BinarySectionFlagsEnum{ + RDI_BinarySectionFlag_Read = (1 << 0), + RDI_BinarySectionFlag_Write = (1 << 1), + RDI_BinarySectionFlag_Execute = (1 << 2) +} RDI_BinarySectionFlagsEnum; -typedef struct RADDBG_BinarySection{ - RADDBG_U32 name_string_idx; - RADDBG_BinarySectionFlags flags; - RADDBG_U64 voff_first; - RADDBG_U64 voff_opl; - RADDBG_U64 foff_first; - RADDBG_U64 foff_opl; -} RADDBG_BinarySection; +typedef struct RDI_BinarySection{ + RDI_U32 name_string_idx; + RDI_BinarySectionFlags flags; + RDI_U64 voff_first; + RDI_U64 voff_opl; + RDI_U64 foff_first; + RDI_U64 foff_opl; +} RDI_BinarySection; //- file & file system info -typedef struct RADDBG_FilePathNode{ - RADDBG_U32 name_string_idx; - RADDBG_U32 parent_path_node; - RADDBG_U32 first_child; - RADDBG_U32 next_sibling; - RADDBG_U32 source_file_idx; -} RADDBG_FilePathNode; +typedef struct RDI_FilePathNode{ + RDI_U32 name_string_idx; + RDI_U32 parent_path_node; + RDI_U32 first_child; + RDI_U32 next_sibling; + RDI_U32 source_file_idx; +} RDI_FilePathNode; -typedef struct RADDBG_SourceFile{ - RADDBG_U32 file_path_node_idx; +typedef struct RDI_SourceFile{ + RDI_U32 file_path_node_idx; - RADDBG_U32 normal_full_path_string_idx; + RDI_U32 normal_full_path_string_idx; // usage of line map to go from a line number to an array of voffs // (line_map_nums * line_number) -> (nil | index) // (line_map_data * index) -> (range) // (line_map_voff_data * range) -> (array(voff)) - RADDBG_U32 line_map_count; - RADDBG_U32 line_map_nums_data_idx; // U32[line_map_count] (sorted - not closed ranges) - RADDBG_U32 line_map_range_data_idx; // U32[line_map_count + 1] (pairs form ranges) - RADDBG_U32 line_map_voff_data_idx; // U64[...] (idx by line_map_range_data) -} RADDBG_SourceFile; + RDI_U32 line_map_count; + RDI_U32 line_map_nums_data_idx; // U32[line_map_count] (sorted - not closed ranges) + RDI_U32 line_map_range_data_idx; // U32[line_map_count + 1] (pairs form ranges) + RDI_U32 line_map_voff_data_idx; // U64[...] (idx by line_map_range_data) +} RDI_SourceFile; //- units & line info -typedef struct RADDBG_Unit{ - RADDBG_U32 unit_name_string_idx; - RADDBG_U32 compiler_name_string_idx; - RADDBG_U32 source_file_path_node; - RADDBG_U32 object_file_path_node; - RADDBG_U32 archive_file_path_node; - RADDBG_U32 build_path_node; - RADDBG_Language language; +typedef struct RDI_Unit{ + RDI_U32 unit_name_string_idx; + RDI_U32 compiler_name_string_idx; + RDI_U32 source_file_path_node; + RDI_U32 object_file_path_node; + RDI_U32 archive_file_path_node; + RDI_U32 build_path_node; + RDI_Language language; // usage of line info to go from voff to file & line number: // (line_info_voffs * voff) -> (nil + index) - // (line_info_data * index) -> (RADDBG_Line = (file_idx * line_number)) + // (line_info_data * index) -> (RDI_Line = (file_idx * line_number)) - RADDBG_U32 line_info_voffs_data_idx; // U64[line_info_count + 1] (sorted ranges) - RADDBG_U32 line_info_data_idx; // RADDBG_Line[line_info_count] - RADDBG_U32 line_info_col_data_idx; // RADDBG_Col[line_info_count] - RADDBG_U32 line_info_count; -} RADDBG_Unit; + RDI_U32 line_info_voffs_data_idx; // U64[line_info_count + 1] (sorted ranges) + RDI_U32 line_info_data_idx; // RDI_Line[line_info_count] + RDI_U32 line_info_col_data_idx; // RDI_Col[line_info_count] + RDI_U32 line_info_count; +} RDI_Unit; -typedef struct RADDBG_Line{ - RADDBG_U32 file_idx; - RADDBG_U32 line_num; -} RADDBG_Line; +typedef struct RDI_Line{ + RDI_U32 file_idx; + RDI_U32 line_num; +} RDI_Line; -typedef struct RADDBG_Column{ - RADDBG_U16 col_first; - RADDBG_U16 col_opl; -} RADDBG_Column; +typedef struct RDI_Column{ + RDI_U16 col_first; + RDI_U16 col_opl; +} RDI_Column; //- type info @@ -405,7 +411,7 @@ typedef struct RADDBG_Column{ // X(name,code) - defines a primary code // XZ(name,code size) - defines a primary code & associates a size // Y(alias_name,name) - defines an alias for bookends -#define RADDBG_TypeKindXList(X,XZ,Y)\ +#define RDI_TypeKindXList(X,XZ,Y)\ X(NULL, 0x0000) \ \ XZ(Void, 0x0001, 0) Y(FirstBuiltIn, Void) \ @@ -466,23 +472,23 @@ Y(LastUserDefined, IncompleteEnum) \ X(Bitfield, 0xF000) \ X(Variadic, 0xF001) -typedef RADDBG_U16 RADDBG_TypeKind; -typedef enum RADDBG_TypeKindEnum{ +typedef RDI_U16 RDI_TypeKind; +typedef enum RDI_TypeKindEnum{ -#define X(name,code) RADDBG_TypeKind_##name = code, +#define X(name,code) RDI_TypeKind_##name = code, #define XZ(name,code,size) X(name,code) -#define Y(alias_name,name) RADDBG_TypeKind_##alias_name = RADDBG_TypeKind_##name, - RADDBG_TypeKindXList(X,XZ,Y) +#define Y(alias_name,name) RDI_TypeKind_##alias_name = RDI_TypeKind_##name, + RDI_TypeKindXList(X,XZ,Y) #undef X #undef XZ #undef Y -} RADDBG_TypeKindEnum; +} RDI_TypeKindEnum; -typedef RADDBG_U16 RADDBG_TypeModifierFlags; +typedef RDI_U16 RDI_TypeModifierFlags; enum{ - RADDBG_TypeModifierFlag_Const = (1 << 0), - RADDBG_TypeModifierFlag_Volatile = (1 << 1), + RDI_TypeModifierFlag_Const = (1 << 0), + RDI_TypeModifierFlag_Volatile = (1 << 1), }; // IMPORTANT NOTE: All type nodes in a valid raddbg are *topologically sorted*. @@ -493,65 +499,66 @@ enum{ // This restriction does not apply to the members of a type that are // attached through a "UDT" though. -typedef struct RADDBG_TypeNode{ - RADDBG_TypeKind kind; - // when kind is 'Modifier' -> RADDBG_TypeModifierFlags - RADDBG_U16 flags; +typedef struct RDI_TypeNode{ + RDI_TypeKind kind; + // when kind is 'Modifier' -> RDI_TypeModifierFlags + RDI_U16 flags; - RADDBG_U32 byte_size; + RDI_U32 byte_size; union{ // kind is 'built-in' struct{ - RADDBG_U32 name_string_idx; + RDI_U32 name_string_idx; } built_in; // kind is 'constructed' struct{ - RADDBG_U32 direct_type_idx; - RADDBG_U32 count; + RDI_U32 direct_type_idx; + RDI_U32 count; union{ // when kind is 'Function' or 'Method' - RADDBG_U32 param_idx_run_first; + RDI_U32 param_idx_run_first; // when kind is 'MemberPtr' - RADDBG_U32 owner_type_idx; + RDI_U32 owner_type_idx; }; } constructed; // kind is 'user defined' struct{ - RADDBG_U32 name_string_idx; - RADDBG_U32 direct_type_idx; - RADDBG_U32 udt_idx; + RDI_U32 name_string_idx; + RDI_U32 direct_type_idx; + RDI_U32 udt_idx; } user_defined; // (kind = Bitfield) struct{ - RADDBG_U32 off; - RADDBG_U32 size; + RDI_U32 direct_type_idx; + RDI_U32 off; + RDI_U32 size; } bitfield; }; -} RADDBG_TypeNode; +} RDI_TypeNode; -typedef RADDBG_U32 RADDBG_UserDefinedTypeFlags; +typedef RDI_U32 RDI_UserDefinedTypeFlags; enum{ - RADDBG_UserDefinedTypeFlag_EnumMembers = (1 << 0), + RDI_UserDefinedTypeFlag_EnumMembers = (1 << 0), }; -typedef struct RADDBG_UDT{ - RADDBG_U32 self_type_idx; - RADDBG_UserDefinedTypeFlags flags; +typedef struct RDI_UDT{ + RDI_U32 self_type_idx; + RDI_UserDefinedTypeFlags flags; // when EnumMembers flag is set, indexes into enum "enum_members" instead of "members" - RADDBG_U32 member_first; - RADDBG_U32 member_count; + RDI_U32 member_first; + RDI_U32 member_count; - RADDBG_U32 file_idx; - RADDBG_U32 line; - RADDBG_U32 col; -} RADDBG_UDT; + RDI_U32 file_idx; + RDI_U32 line; + RDI_U32 col; +} RDI_UDT; -#define RADDBG_MemberKindXList(X) \ +#define RDI_MemberKindXList(X) \ X(NULL, 0x0000) \ X(DataField, 0x0001) \ X(StaticData, 0x0002) \ @@ -563,12 +570,12 @@ X(Base, 0x0201) \ X(VirtualBase, 0x0202) \ X(NestedType, 0x0300) -typedef RADDBG_U16 RADDBG_MemberKind; -typedef enum RADDBG_MemberKindEnum{ -#define X(N,C) RADDBG_MemberKind_##N = C, - RADDBG_MemberKindXList(X) +typedef RDI_U16 RDI_MemberKind; +typedef enum RDI_MemberKindEnum{ +#define X(N,C) RDI_MemberKind_##N = C, + RDI_MemberKindXList(X) #undef X -} RADDBG_MemberKindEnum; +} RDI_MemberKindEnum; // TODO(allen): need a way to equip methods and some virtual methods // with procedure symbol information. I'm thinking a seperate data @@ -578,141 +585,141 @@ typedef enum RADDBG_MemberKindEnum{ // like 'associate_method_to_proc' that can be used *after* both the // method and proc are known, rather than one that forces us to know // the association when constructing the member data. -typedef struct RADDBG_Member{ - RADDBG_MemberKind kind; - RADDBG_U16 __unused__; +typedef struct RDI_Member{ + RDI_MemberKind kind; + RDI_U16 __unused__; - RADDBG_U32 name_string_idx; - RADDBG_U32 type_idx; - RADDBG_U32 off; -} RADDBG_Member; + RDI_U32 name_string_idx; + RDI_U32 type_idx; + RDI_U32 off; +} RDI_Member; -typedef struct RADDBG_EnumMember{ - RADDBG_U32 name_string_idx; - RADDBG_U32 __unused__; - RADDBG_U64 val; -} RADDBG_EnumMember; +typedef struct RDI_EnumMember{ + RDI_U32 name_string_idx; + RDI_U32 __unused__; + RDI_U64 val; +} RDI_EnumMember; //- symbol info -typedef RADDBG_U32 RADDBG_LinkFlags; +typedef RDI_U32 RDI_LinkFlags; enum{ - RADDBG_LinkFlag_External = (1 << 0), + RDI_LinkFlag_External = (1 << 0), // NOTE: Scope flags are mutually exclusive. // A symbol is either global scoped, type scoped, or procedure scoped. - RADDBG_LinkFlag_TypeScoped = (1 << 1), - RADDBG_LinkFlag_ProcScoped = (1 << 2), + RDI_LinkFlag_TypeScoped = (1 << 1), + RDI_LinkFlag_ProcScoped = (1 << 2), }; -typedef struct RADDBG_GlobalVariable{ - RADDBG_U32 name_string_idx; +typedef struct RDI_GlobalVariable{ + RDI_U32 name_string_idx; // NOTE: "global variables" can be scoped in *any* way. The scope flags here refer to // *namespace* scoping. "global variables" are all in the data section of the // final exe/dll type file, so they are "global" in the life-time sense of the // word. In the namespace sense of the word, they can be scoped globally, by type, // or by procedure. - RADDBG_LinkFlags link_flags; - RADDBG_U64 voff; - RADDBG_U32 type_idx; + RDI_LinkFlags link_flags; + RDI_U64 voff; + RDI_U32 type_idx; // container_idx: UDT for "TypeScoped", Procedure for "ProcScoped" - RADDBG_U32 container_idx; -} RADDBG_GlobalVariable; + RDI_U32 container_idx; +} RDI_GlobalVariable; -typedef struct RADDBG_ThreadVariable{ - RADDBG_U32 name_string_idx; +typedef struct RDI_ThreadVariable{ + RDI_U32 name_string_idx; // NOTE: See the note in GlobalVariable regarding scoping. The same concept applies here. - RADDBG_LinkFlags link_flags; - RADDBG_U32 tls_off; - RADDBG_U32 type_idx; + RDI_LinkFlags link_flags; + RDI_U32 tls_off; + RDI_U32 type_idx; // container_idx: UDT for "TypeScoped", Procedure for "ProcScoped" - RADDBG_U32 container_idx; -} RADDBG_ThreadVariable; + RDI_U32 container_idx; +} RDI_ThreadVariable; -typedef struct RADDBG_Procedure{ - RADDBG_U32 name_string_idx; - RADDBG_U32 link_name_string_idx; +typedef struct RDI_Procedure{ + RDI_U32 name_string_idx; + RDI_U32 link_name_string_idx; // NOTE: See the note in GlobalVariable regarding scoping. The same concept applies here. - RADDBG_LinkFlags link_flags; - RADDBG_U32 type_idx; - RADDBG_U32 root_scope_idx; + RDI_LinkFlags link_flags; + RDI_U32 type_idx; + RDI_U32 root_scope_idx; // container_idx: UDT for "TypeScoped", Procedure for "ProcScoped" - RADDBG_U32 container_idx; -} RADDBG_Procedure; + RDI_U32 container_idx; +} RDI_Procedure; -typedef struct RADDBG_Scope{ - RADDBG_U32 proc_idx; - RADDBG_U32 parent_scope_idx; - RADDBG_U32 first_child_scope_idx; - RADDBG_U32 next_sibling_scope_idx; +typedef struct RDI_Scope{ + RDI_U32 proc_idx; + RDI_U32 parent_scope_idx; + RDI_U32 first_child_scope_idx; + RDI_U32 next_sibling_scope_idx; - RADDBG_U32 voff_range_first; - RADDBG_U32 voff_range_opl; + RDI_U32 voff_range_first; + RDI_U32 voff_range_opl; // indexes into "locals" - RADDBG_U32 local_first; - RADDBG_U32 local_count; + RDI_U32 local_first; + RDI_U32 local_count; - RADDBG_U32 static_local_idx_run_first; - RADDBG_U32 static_local_count; + RDI_U32 static_local_idx_run_first; + RDI_U32 static_local_count; // TODO(allen): attach less common scope-relevant info -} RADDBG_Scope; +} RDI_Scope; -typedef RADDBG_U32 RADDBG_LocalKind; +typedef RDI_U32 RDI_LocalKind; typedef enum{ - RADDBG_LocalKind_NULL, - RADDBG_LocalKind_Parameter, - RADDBG_LocalKind_Variable, - RADDBG_LocalKind_COUNT -} RADDBG_LocalKindEnum; + RDI_LocalKind_NULL, + RDI_LocalKind_Parameter, + RDI_LocalKind_Variable, + RDI_LocalKind_COUNT +} RDI_LocalKindEnum; -typedef struct RADDBG_Local{ - RADDBG_LocalKind kind; - RADDBG_U32 name_string_idx; - RADDBG_U64 type_idx; +typedef struct RDI_Local{ + RDI_LocalKind kind; + RDI_U32 name_string_idx; + RDI_U64 type_idx; // indexes into "location_blocks" - RADDBG_U32 location_first; - RADDBG_U32 location_opl; -} RADDBG_Local; + RDI_U32 location_first; + RDI_U32 location_opl; +} RDI_Local; -typedef struct RADDBG_LocationBlock{ - RADDBG_U32 scope_off_first; - RADDBG_U32 scope_off_opl; - RADDBG_U32 location_data_off; -} RADDBG_LocationBlock; +typedef struct RDI_LocationBlock{ + RDI_U32 scope_off_first; + RDI_U32 scope_off_opl; + RDI_U32 location_data_off; +} RDI_LocationBlock; -typedef RADDBG_U8 RADDBG_LocationKind; +typedef RDI_U8 RDI_LocationKind; typedef enum{ - RADDBG_LocationKind_NULL, - RADDBG_LocationKind_AddrBytecodeStream, - RADDBG_LocationKind_ValBytecodeStream, - RADDBG_LocationKind_AddrRegisterPlusU16, - RADDBG_LocationKind_AddrAddrRegisterPlusU16, - RADDBG_LocationKind_ValRegister, - RADDBG_LocationKind_COUNT -} RADDBG_LocationKindEnum; + RDI_LocationKind_NULL, + RDI_LocationKind_AddrBytecodeStream, + RDI_LocationKind_ValBytecodeStream, + RDI_LocationKind_AddrRegisterPlusU16, + RDI_LocationKind_AddrAddrRegisterPlusU16, + RDI_LocationKind_ValRegister, + RDI_LocationKind_COUNT +} RDI_LocationKindEnum; -typedef struct RADDBG_LocationBytecodeStream{ - RADDBG_LocationKind kind; - // [... 0] null terminated byte sequence RADDBG_EvalBytecodeStream -} RADDBG_LocationBytecodeStream; +typedef struct RDI_LocationBytecodeStream{ + RDI_LocationKind kind; + // [... 0] null terminated byte sequence RDI_EvalBytecodeStream +} RDI_LocationBytecodeStream; -typedef struct RADDBG_LocationRegisterPlusU16{ - RADDBG_LocationKind kind; - RADDBG_RegisterCode register_code; - RADDBG_U16 offset; -} RADDBG_LocationRegisterPlusU16; +typedef struct RDI_LocationRegisterPlusU16{ + RDI_LocationKind kind; + RDI_RegisterCode register_code; + RDI_U16 offset; +} RDI_LocationRegisterPlusU16; -typedef struct RADDBG_LocationRegister{ - RADDBG_LocationKind kind; - RADDBG_RegisterCode register_code; -} RADDBG_LocationRegister; +typedef struct RDI_LocationRegister{ + RDI_LocationKind kind; + RDI_RegisterCode register_code; +} RDI_LocationRegister; //- name map types -#define RADDBG_NameMapXList(X)\ +#define RDI_NameMapXList(X)\ X(NULL, 0)\ X(GlobalVariables, 1)\ X(ThreadVariables, 2)\ @@ -721,42 +728,42 @@ X(Types, 4)\ X(LinkNameProcedures, 5)\ X(NormalSourcePaths, 6) -typedef RADDBG_U32 RADDBG_NameMapKind; -typedef enum RADDBG_NameMapKindEnum{ -#define X(N,C) RADDBG_NameMapKind_##N = C, - RADDBG_NameMapXList(X) +typedef RDI_U32 RDI_NameMapKind; +typedef enum RDI_NameMapKindEnum{ +#define X(N,C) RDI_NameMapKind_##N = C, + RDI_NameMapXList(X) #undef X - RADDBG_NameMapKind_COUNT -} RADDBG_NameMapKindEnum; + RDI_NameMapKind_COUNT +} RDI_NameMapKindEnum; // TODO(allen): documentation here for the hashing and probing strategy for this table -typedef struct RADDBG_NameMap{ - RADDBG_NameMapKind kind; - RADDBG_U32 bucket_data_idx; - RADDBG_U32 node_data_idx; -} RADDBG_NameMap; +typedef struct RDI_NameMap{ + RDI_NameMapKind kind; + RDI_U32 bucket_data_idx; + RDI_U32 node_data_idx; +} RDI_NameMap; -typedef struct RADDBG_NameMapBucket{ - RADDBG_U32 first_node; - RADDBG_U32 node_count; -} RADDBG_NameMapBucket; +typedef struct RDI_NameMapBucket{ + RDI_U32 first_node; + RDI_U32 node_count; +} RDI_NameMapBucket; -typedef struct RADDBG_NameMapNode{ - RADDBG_U32 string_idx; - RADDBG_U32 match_count; +typedef struct RDI_NameMapNode{ + RDI_U32 string_idx; + RDI_U32 match_count; // NOTE: if (match_count == 1) then this is the index of the matching item // if (match_count > 1) then this is the first for an index run of all the matches - RADDBG_U32 match_idx_or_idx_run_first; -} RADDBG_NameMapNode; + RDI_U32 match_idx_or_idx_run_first; +} RDI_NameMapNode; //////////////////////////////// // Eval Bytecode // (Name, decodeN, popN, pushN) -#define RADDBG_EvalOpXList(X)\ +#define RDI_EvalOpXList(X)\ X(Stop, 0, 0, 0)\ X(Noop, 0, 0, 0)\ X(Cond, 1, 1, 0)\ @@ -803,7 +810,7 @@ X(Pop, 0, 1, 0)\ X(Insert, 1, 0, 0) // (Name) -#define RADDBG_EvalTypeGroupXList(X)\ +#define RDI_EvalTypeGroupXList(X)\ X(Other)\ X(U)\ X(S)\ @@ -811,7 +818,7 @@ X(F32)\ X(F64) // (Name, error-message) -#define RADDBG_EvalConversionKindXList(X)\ +#define RDI_EvalConversionKindXList(X)\ X(Noop, "")\ X(Legal, "")\ X(OtherToOther, "cannot convert between these types")\ @@ -819,7 +826,7 @@ X(ToOther, "cannot convert to this type")\ X(FromOther, "cannot convert this type") // Xb(EvalTypeGroup) Y(TypeKind) Xe(EvalTypeGroup) -#define RADDBG_EvalTypeGroupFromKindMap(Y,Xb,Xe)\ +#define RDI_EvalTypeGroupFromKindMap(Y,Xb,Xe)\ \ Xb(U) Y(U8) Y(U16) Y(U32) Y(U64) Y(Bool) Y(Ptr) Y(Enum)\ Xe(U)\ @@ -834,7 +841,7 @@ Xb(F64) Y(F64)\ Xe(F64) // Xb(EvalConversionKind) Y(EvalTypeGroup, EvalTypeGroup) Xe(EvalConversionKind) -#define RADDBG_EvalConversionKindFromTypeGroupPairMap(Y,Xb,Xe)\ +#define RDI_EvalConversionKindFromTypeGroupPairMap(Y,Xb,Xe)\ \ Xb(Noop) Y(U, U) Y(S, S) Y(F32, F32) Y(F64, F64) Y(U, S) Y(S, U)\ Xe(Noop)\ @@ -855,69 +862,65 @@ Xb(FromOther) Y(Other, U) Y(Other, S) Y(Other, F32) Y(Other, F64)\ Xe(FromOther) // eval interpretation macros -#define RADDBG_EncodeRegReadParam(reg,bytesize,bytepos) ((reg)|((bytesize)<<8)|((bytepos)<<16)) +#define RDI_EncodeRegReadParam(reg,bytesize,bytepos) ((reg)|((bytesize)<<8)|((bytepos)<<16)) // eval enums -typedef RADDBG_U8 RADDBG_EvalOp; +typedef RDI_U8 RDI_EvalOp; -typedef enum RADDBG_EvalOpEnum{ -#define X(N,dec,pop,push) RADDBG_EvalOp_##N, - RADDBG_EvalOpXList(X) +typedef enum RDI_EvalOpEnum{ +#define X(N,dec,pop,push) RDI_EvalOp_##N, + RDI_EvalOpXList(X) #undef X - RADDBG_EvalOp_COUNT -} RADDBG_EvalOpEnum; + RDI_EvalOp_COUNT +} RDI_EvalOpEnum; -typedef RADDBG_U8 RADDBG_EvalTypeGroup; +typedef RDI_U8 RDI_EvalTypeGroup; -typedef enum RADDBG_EvalTypeGroupEnum{ -#define X(N) RADDBG_EvalTypeGroup_##N, - RADDBG_EvalTypeGroupXList(X) +typedef enum RDI_EvalTypeGroupEnum{ +#define X(N) RDI_EvalTypeGroup_##N, + RDI_EvalTypeGroupXList(X) #undef X - RADDBG_EvalTypeGroup_COUNT, -} RADDBG_EvalTypeGroupEnum; + RDI_EvalTypeGroup_COUNT, +} RDI_EvalTypeGroupEnum; -typedef RADDBG_U8 RADDBG_EvalConversionKind; +typedef RDI_U8 RDI_EvalConversionKind; -typedef enum RADDBG_EvalConversionKindEnum{ -#define X(N,msg) RADDBG_EvalConversionKind_##N, - RADDBG_EvalConversionKindXList(X) +typedef enum RDI_EvalConversionKindEnum{ +#define X(N,msg) RDI_EvalConversionKind_##N, + RDI_EvalConversionKindXList(X) #undef X - RADDBG_EvalConversionKind_COUNT, -} RADDBG_EvalConversionKindEnum; + RDI_EvalConversionKind_COUNT, +} RDI_EvalConversionKindEnum; //- eval data tables -#define RADDBG_EVAL_CTRLBITS(decodeN,popN,pushN) ((decodeN) | ((popN) << 4) | ((pushN) << 6)) -#define RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits) ((ctrlbits) & 0xf) -#define RADDBG_POPN_FROM_CTRLBITS(ctrlbits) (((ctrlbits) >> 4) & 0x3) -#define RADDBG_PUSHN_FROM_CTRLBITS(ctrlbits) (((ctrlbits) >> 6) & 0x3) +#define RDI_EVAL_CTRLBITS(decodeN,popN,pushN) ((decodeN) | ((popN) << 4) | ((pushN) << 6)) +#define RDI_DECODEN_FROM_CTRLBITS(ctrlbits) ((ctrlbits) & 0xf) +#define RDI_POPN_FROM_CTRLBITS(ctrlbits) (((ctrlbits) >> 4) & 0x3) +#define RDI_PUSHN_FROM_CTRLBITS(ctrlbits) (((ctrlbits) >> 6) & 0x3) -static RADDBG_U8 raddbg_eval_opcode_ctrlbits[] = { -#define X(Name, decodeN, popN, pushN) RADDBG_EVAL_CTRLBITS(decodeN,popN,pushN), - RADDBG_EvalOpXList(X) +static RDI_U8 rdi_eval_opcode_ctrlbits[] = { +#define X(Name, decodeN, popN, pushN) RDI_EVAL_CTRLBITS(decodeN,popN,pushN), + RDI_EvalOpXList(X) #undef X }; //////////////////////////////// // Functions -RADDBG_PROC RADDBG_U64 raddbg_hash(RADDBG_U8 *ptr, RADDBG_U64 size); -RADDBG_PROC RADDBG_U32 raddbg_size_from_basic_type_kind(RADDBG_TypeKind kind); -RADDBG_PROC RADDBG_U32 raddbg_addr_size_from_arch(RADDBG_Arch arch); +RDI_PROC RDI_U64 rdi_hash(RDI_U8 *ptr, RDI_U64 size); +RDI_PROC RDI_U32 rdi_size_from_basic_type_kind(RDI_TypeKind kind); +RDI_PROC RDI_U32 rdi_addr_size_from_arch(RDI_Arch arch); //- eval helpers -RADDBG_PROC RADDBG_EvalConversionKind -raddbg_eval_conversion_rule(RADDBG_EvalTypeGroup in, RADDBG_EvalTypeGroup out); -RADDBG_PROC RADDBG_U8* -raddbg_eval_conversion_message(RADDBG_EvalConversionKind conversion_kind, RADDBG_U64 *lennout); +RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_rule(RDI_EvalTypeGroup in, RDI_EvalTypeGroup out); +RDI_PROC RDI_U8* rdi_eval_conversion_message(RDI_EvalConversionKind conversion_kind, RDI_U64 *lennout); +RDI_PROC RDI_S32 rdi_eval_opcode_type_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group); -RADDBG_PROC RADDBG_S32 -raddbg_eval_opcode_type_compatible(RADDBG_EvalOp op, RADDBG_EvalTypeGroup group); - -#endif // RADDBG_FORMAT_H +#endif // RADDBGI_FORMAT_H diff --git a/src/lib_raddbgi_format/raddbgi_format_parse.c b/src/lib_raddbgi_format/raddbgi_format_parse.c new file mode 100644 index 00000000..4f6e0b4e --- /dev/null +++ b/src/lib_raddbgi_format/raddbgi_format_parse.c @@ -0,0 +1,559 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ RADDBG Parse API + +RDI_PROC RDI_ParseStatus +rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out) +{ + RDI_ParseStatus result = RDI_ParseStatus_Good; + + // out header + RDI_Header *hdr = 0; + { + if (sizeof(*hdr) <= size){ + hdr = (RDI_Header*)data; + } + + // (errors) + if (hdr == 0 || hdr->magic != RDI_MAGIC_CONSTANT){ + hdr = 0; + result = RDI_ParseStatus_HeaderDoesNotMatch; + } + if (hdr != 0 && hdr->encoding_version != 1){ + hdr = 0; + result = RDI_ParseStatus_UnsupportedVersionNumber; + } + } + + // out data sections + RDI_DataSection *dsecs = 0; + RDI_U32 dsec_count = 0; + if (hdr != 0){ + RDI_U64 opl = (RDI_U64)hdr->data_section_off + (RDI_U64)hdr->data_section_count*sizeof(*dsecs); + if (opl <= size){ + dsecs = (RDI_DataSection*)(data + hdr->data_section_off); + dsec_count = hdr->data_section_count; + } + + // (errors) + if (dsecs == 0){ + result = RDI_ParseStatus_InvalidDataSecionLayout; + } + } + + // extract primary data section indexes + RDI_U32 dsec_idx[RDI_DataSectionTag_PRIMARY_COUNT] = {0}; + if (result == RDI_ParseStatus_Good){ + RDI_DataSection *sec_ptr = dsecs; + for (RDI_U32 i = 0; i < dsec_count; i += 1, sec_ptr += 1){ + if (sec_ptr->tag < RDI_DataSectionTag_PRIMARY_COUNT){ + dsec_idx[sec_ptr->tag] = i; + } + } + } + + // fill out data block (part 1) + if (result == RDI_ParseStatus_Good){ + out->raw_data = data; + out->raw_data_size = size; + out->dsecs = dsecs; + out->dsec_count = dsec_count; + for (RDI_U32 i = 0; i < RDI_DataSectionTag_PRIMARY_COUNT; i += 1){ + out->dsec_idx[i] = dsec_idx[i]; + } + } + + // out string table + RDI_U8 *string_data = 0; + RDI_U64 string_opl = 0; + RDI_U32 *string_offs = 0; + RDI_U64 string_count = 0; + if (result == RDI_ParseStatus_Good){ + rdi_parse__extract_primary(out, string_data, &string_opl, + RDI_DataSectionTag_StringData); + + RDI_U64 table_entry_count = 0; + rdi_parse__extract_primary(out, string_offs, &table_entry_count, + RDI_DataSectionTag_StringTable); + if (table_entry_count > 0){ + string_count = table_entry_count - 1; + } + + // (errors) + if (string_data == 0){ + result = RDI_ParseStatus_MissingStringDataSection; + } + else if (string_offs == 0){ + result = RDI_ParseStatus_MissingStringTableSection; + } + } + + // out index runs + RDI_U32 *idx_run_data = 0; + RDI_U64 idx_run_count = 0; + if (result == RDI_ParseStatus_Good){ + rdi_parse__extract_primary(out, idx_run_data, &idx_run_count, + RDI_DataSectionTag_IndexRuns); + + // (errors) + if (idx_run_data == 0){ + result = RDI_ParseStatus_MissingIndexRunSection; + } + } + + if (result == RDI_ParseStatus_Good){ + // fill out primary data structures (part 2) + out->string_data = string_data; + out->string_offs = string_offs; + out->string_data_size = string_opl; + out->string_count = string_count; + out->idx_run_data = idx_run_data; + out->idx_run_count = idx_run_count; + + { + RDI_TopLevelInfo *tli = 0; + RDI_U64 dummy = 0; + rdi_parse__extract_primary(out, tli, &dummy, RDI_DataSectionTag_TopLevelInfo); + if (dummy != 1){ + tli = 0; + } + out->top_level_info = tli; + } + + rdi_parse__extract_primary(out, out->binary_sections, &out->binary_sections_count, + RDI_DataSectionTag_BinarySections); + + rdi_parse__extract_primary(out, out->file_paths, &out->file_paths_count, + RDI_DataSectionTag_FilePathNodes); + + rdi_parse__extract_primary(out, out->source_files, &out->source_files_count, + RDI_DataSectionTag_SourceFiles); + + rdi_parse__extract_primary(out, out->units, &out->units_count, + RDI_DataSectionTag_Units); + + rdi_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, + RDI_DataSectionTag_UnitVmap); + + rdi_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, + RDI_DataSectionTag_UnitVmap); + + rdi_parse__extract_primary(out, out->type_nodes, &out->type_nodes_count, + RDI_DataSectionTag_TypeNodes); + + rdi_parse__extract_primary(out, out->udts, &out->udts_count, + RDI_DataSectionTag_UDTs); + + rdi_parse__extract_primary(out, out->members, &out->members_count, + RDI_DataSectionTag_Members); + + rdi_parse__extract_primary(out, out->enum_members, &out->enum_members_count, + RDI_DataSectionTag_EnumMembers); + + rdi_parse__extract_primary(out, out->global_variables, &out->global_variables_count, + RDI_DataSectionTag_GlobalVariables); + + rdi_parse__extract_primary(out, out->global_vmap, &out->global_vmap_count, + RDI_DataSectionTag_GlobalVmap); + + rdi_parse__extract_primary(out, out->thread_variables, &out->thread_variables_count, + RDI_DataSectionTag_ThreadVariables); + + rdi_parse__extract_primary(out, out->procedures, &out->procedures_count, + RDI_DataSectionTag_Procedures); + + rdi_parse__extract_primary(out, out->scopes, &out->scopes_count, + RDI_DataSectionTag_Scopes); + + rdi_parse__extract_primary(out, out->scope_voffs, &out->scope_voffs_count, + RDI_DataSectionTag_ScopeVoffData); + + rdi_parse__extract_primary(out, out->scope_vmap, &out->scope_vmap_count, + RDI_DataSectionTag_ScopeVmap); + + rdi_parse__extract_primary(out, out->locals, &out->locals_count, + RDI_DataSectionTag_Locals); + + rdi_parse__extract_primary(out, out->location_blocks, &out->location_blocks_count, + RDI_DataSectionTag_LocationBlocks); + + rdi_parse__extract_primary(out, out->location_data, &out->location_data_size, + RDI_DataSectionTag_LocationData); + + { + rdi_parse__extract_primary(out, out->name_maps, &out->name_maps_count, + RDI_DataSectionTag_NameMaps); + + RDI_NameMap *name_map_ptr = out->name_maps; + RDI_NameMap *name_map_opl = out->name_maps + out->name_maps_count; + for (; name_map_ptr < name_map_opl; name_map_ptr += 1){ + if (out->name_maps_by_kind[name_map_ptr->kind] == 0){ + out->name_maps_by_kind[name_map_ptr->kind] = name_map_ptr; + } + } + } + } + +#if !defined(RDI_DISABLE_NILS) + if(out->top_level_info == 0) { out->top_level_info = &rdi_top_level_info_nil; } + if(out->binary_sections == 0) { out->binary_sections = &rdi_binary_section_nil; out->binary_sections_count = 1; } + if(out->file_paths == 0) { out->file_paths = &rdi_file_path_node_nil; out->file_paths_count = 1; } + if(out->source_files == 0) { out->source_files = &rdi_source_file_nil; out->source_files_count = 1; } + if(out->units == 0) { out->units = &rdi_unit_nil; out->units_count = 1; } + if(out->unit_vmap == 0) { out->unit_vmap = &rdi_vmap_entry_nil; out->unit_vmap_count = 1; } + if(out->type_nodes == 0) { out->type_nodes = &rdi_type_node_nil; out->type_nodes_count = 1; } + if(out->udts == 0) { out->udts = &rdi_udt_nil; out->udts_count = 1; } + if(out->members == 0) { out->members = &rdi_member_nil; out->members_count = 1; } + if(out->enum_members == 0) { out->enum_members = &rdi_enum_member_nil; out->enum_members_count = 1; } + if(out->global_variables == 0) { out->global_variables = &rdi_global_variable_nil; out->global_variables_count = 1; } + if(out->global_vmap == 0) { out->global_vmap = &rdi_vmap_entry_nil; out->global_vmap_count = 1; } + if(out->thread_variables == 0) { out->thread_variables = &rdi_thread_variable_nil; out->thread_variables_count = 1; } + if(out->procedures == 0) { out->procedures = &rdi_procedure_nil; out->procedures_count = 1; } + if(out->scopes == 0) { out->scopes = &rdi_scope_nil; out->scopes_count = 1; } + if(out->scope_voffs == 0) { out->scope_voffs = &rdi_voff_nil; out->scope_voffs_count = 1; } + if(out->scope_vmap == 0) { out->scope_vmap = &rdi_vmap_entry_nil; out->scope_vmap_count = 1; } + if(out->locals == 0) { out->locals = &rdi_local_nil; out->locals_count = 1; } + if(out->location_blocks == 0) { out->location_blocks = &rdi_location_block_nil; out->location_blocks_count = 1; } +#endif + + return(result); +} + +RDI_PROC RDI_U8* +rdi_string_from_idx(RDI_Parsed *parsed, RDI_U32 idx, RDI_U64 *len_out){ + RDI_U8 *result = 0; + RDI_U64 len_result = 0; + if (idx < parsed->string_count){ + RDI_U32 off_raw = parsed->string_offs[idx]; + RDI_U32 opl_raw = parsed->string_offs[idx + 1]; + RDI_U32 opl = rdi_parse__min(opl_raw, parsed->string_data_size); + RDI_U32 off = rdi_parse__min(off_raw, opl); + result = parsed->string_data + off; + len_result = opl - off; + } + *len_out = len_result; + return(result); +} + +RDI_PROC RDI_U32* +rdi_idx_run_from_first_count(RDI_Parsed *parsed, + RDI_U32 raw_first, RDI_U32 raw_count, + RDI_U32 *n_out){ + RDI_U32 raw_opl = raw_first + raw_count; + RDI_U32 opl = rdi_parse__min(raw_opl, parsed->idx_run_count); + RDI_U32 first = rdi_parse__min(raw_first, opl); + + RDI_U32 *result = 0; + if (first < parsed->idx_run_count){ + result = parsed->idx_run_data + first; + } + *n_out = opl - first; + return(result); +} + +//- line info + +RDI_PROC void +rdi_line_info_from_unit(RDI_Parsed *p, RDI_Unit *unit, RDI_ParsedLineInfo *out){ + RDI_U64 line_info_voff_count = 0; + RDI_U64 *voffs = (RDI_U64*) + rdi_data_from_dsec(p, unit->line_info_voffs_data_idx, sizeof(RDI_U64), + RDI_DataSectionTag_LineInfoVoffs, + &line_info_voff_count); + + RDI_U64 line_info_count_raw = 0; + RDI_Line *lines = (RDI_Line*) + rdi_data_from_dsec(p, unit->line_info_data_idx, sizeof(RDI_Line), + RDI_DataSectionTag_LineInfoData, + &line_info_count_raw); + + RDI_U64 column_info_count_raw = 0; + RDI_Column *cols = (RDI_Column*) + rdi_data_from_dsec(p, unit->line_info_col_data_idx, sizeof(RDI_Column), + RDI_DataSectionTag_LineInfoColumns, + &column_info_count_raw); + + RDI_U32 line_info_count_a = (line_info_voff_count > 0)?line_info_voff_count - 1:0; + RDI_U32 line_info_count = rdi_parse__min(line_info_count_a, line_info_count_raw); + RDI_U32 column_info_count = rdi_parse__min(column_info_count_raw, line_info_count); + + out->voffs = voffs; + out->lines = lines; + out->cols = cols; + out->count = line_info_count; + out->col_count = column_info_count; +} + +RDI_PROC RDI_U64 +rdi_line_info_idx_from_voff(RDI_ParsedLineInfo *line_info, RDI_U64 voff) +{ + RDI_U64 result = 0; + if (line_info->count > 0 && line_info->voffs[0] <= voff && voff < line_info->voffs[line_info->count - 1]){ + // assuming: (i < j) -> (vmap[i].voff < vmap[j].voff) + // find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff) + RDI_U32 first = 0; + RDI_U32 opl = line_info->count; + for (;;){ + RDI_U32 mid = (first + opl)/2; + if (line_info->voffs[mid] < voff){ + first = mid; + } + else if (line_info->voffs[mid] > voff){ + opl = mid; + } + else{ + first = mid; + break; + } + if (opl - first <= 1){ + break; + } + } + result = (RDI_U64)first; + } + return(result); +} + +RDI_PROC void +rdi_line_map_from_source_file(RDI_Parsed *p, RDI_SourceFile *srcfile, + RDI_ParsedLineMap *out){ + RDI_U64 num_count = 0; + RDI_U32 *nums = (RDI_U32*) + rdi_data_from_dsec(p, srcfile->line_map_nums_data_idx, sizeof(RDI_U32), + RDI_DataSectionTag_LineMapNumbers, + &num_count); + + RDI_U64 range_count = 0; + RDI_U32 *ranges = (RDI_U32*) + rdi_data_from_dsec(p, srcfile->line_map_range_data_idx, sizeof(RDI_U32), + RDI_DataSectionTag_LineMapRanges, + &range_count); + + RDI_U64 voff_count = 0; + RDI_U64 *voffs = (RDI_U64*) + rdi_data_from_dsec(p, srcfile->line_map_voff_data_idx, sizeof(RDI_U64), + RDI_DataSectionTag_LineMapVoffs, + &voff_count); + + RDI_U32 count_a = (range_count > 0)?(range_count - 1):0; + RDI_U32 count_b = rdi_parse__min(count_a, num_count); + RDI_U32 count = rdi_parse__min(count_b, srcfile->line_map_count); + + out->nums = nums; + out->ranges = ranges; + out->voffs = voffs; + out->count = count; + out->voff_count = voff_count; +} + +RDI_PROC RDI_U64* +rdi_line_voffs_from_num(RDI_ParsedLineMap *map, RDI_U32 linenum, RDI_U32 *n_out){ + RDI_U64 *result = 0; + *n_out = 0; + + RDI_U32 closest_i = 0; + if (map->count > 0 && map->nums[0] <= linenum){ + // assuming: (i < j) -> (nums[i] < nums[j]) + // find i such that: (nums[i] <= linenum) && (linenum < nums[i + 1]) + RDI_U32 *nums = map->nums; + RDI_U32 first = 0; + RDI_U32 opl = map->count; + for (;;){ + RDI_U32 mid = (first + opl)/2; + if (nums[mid] < linenum){ + first = mid; + } + else if (nums[mid] > linenum){ + opl = mid; + } + else{ + first = mid; + break; + } + if (opl - first <= 1){ + break; + } + } + closest_i = first; + } + + // round up instead of down if possible + if (closest_i + 1 < map->count && + map->nums[closest_i] < linenum){ + closest_i += 1; + } + + // set result if possible + if (closest_i < map->count){ + RDI_U32 first = map->ranges[closest_i]; + RDI_U32 opl = map->ranges[closest_i + 1]; + if (opl < map->voff_count){ + result = map->voffs + first; + *n_out = opl - first; + } + } + + return(result); +} + + +//- vmaps + +RDI_PROC RDI_U64 +rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U32 vmap_count, RDI_U64 voff){ + RDI_U64 result = 0; + if (vmap_count > 0 && vmap[0].voff <= voff && voff < vmap[vmap_count - 1].voff){ + // assuming: (i < j) -> (vmap[i].voff < vmap[j].voff) + // find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff) + RDI_U32 first = 0; + RDI_U32 opl = vmap_count; + for (;;){ + RDI_U32 mid = (first + opl)/2; + if (vmap[mid].voff < voff){ + first = mid; + } + else if (vmap[mid].voff > voff){ + opl = mid; + } + else{ + first = mid; + break; + } + if (opl - first <= 1){ + break; + } + } + result = (RDI_U64)vmap[first].idx; + } + return(result); +} + +//- name maps + +RDI_PROC RDI_NameMap* +rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind){ + RDI_NameMap *result = 0; + if (0 < kind && kind < RDI_NameMapKind_COUNT){ + result = p->name_maps_by_kind[kind]; + } + return(result); +} + +RDI_PROC void +rdi_name_map_parse(RDI_Parsed *p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out){ + out->buckets = 0; + out->bucket_count = 0; + if (mapptr != 0){ + out->buckets = (RDI_NameMapBucket*) + rdi_data_from_dsec(p, mapptr->bucket_data_idx, sizeof(RDI_NameMapBucket), + RDI_DataSectionTag_NameMapBuckets, &out->bucket_count); + out->nodes = (RDI_NameMapNode*) + rdi_data_from_dsec(p, mapptr->node_data_idx, sizeof(RDI_NameMapNode), + RDI_DataSectionTag_NameMapNodes, &out->node_count); + } +} + +RDI_PROC RDI_NameMapNode* +rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, + RDI_U8 *str, RDI_U64 len){ + RDI_NameMapNode *result = 0; + if (map->bucket_count > 0){ + RDI_NameMapBucket *buckets = map->buckets; + RDI_U64 bucket_count = map->bucket_count; + RDI_U64 hash = rdi_hash(str, len); + RDI_U64 bucket_index = hash%bucket_count; + RDI_NameMapBucket *bucket = map->buckets + bucket_index; + + RDI_NameMapNode *node = map->nodes + bucket->first_node; + RDI_NameMapNode *node_opl = node + bucket->node_count; + for (;node < node_opl; node += 1){ + // extract a string from this node + RDI_U64 nlen = 0; + RDI_U8 *nstr = rdi_string_from_idx(p, node->string_idx, &nlen); + + // compare this to the needle string + RDI_S32 match = 0; + if (nlen == len){ + RDI_U8 *a = str; + RDI_U8 *aopl = str + len; + RDI_U8 *b = nstr; + for (;a < aopl && *a == *b; a += 1, b += 1); + match = (a == aopl); + } + + // stop with a matching node in result + if (match){ + result = node; + break; + } + + } + } + return(result); +} + +RDI_PROC RDI_U32* +rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, + RDI_U32 *n_out){ + RDI_U32 *result = 0; + *n_out = 0; + if (node != 0){ + if (node->match_count == 1){ + result = &node->match_idx_or_idx_run_first; + *n_out = 1; + } + else{ + result = rdi_idx_run_from_first_count(p, node->match_idx_or_idx_run_first, + node->match_count, n_out); + } + } + return(result); +} + +//- common helpers + +RDI_PROC RDI_U64 +rdi_first_voff_from_proc(RDI_Parsed *p, RDI_U32 proc_id){ + RDI_U64 result = 0; + if (0 < proc_id && proc_id < p->procedures_count){ + RDI_Procedure *proc = p->procedures + proc_id; + RDI_U32 scope_id = proc->root_scope_idx; + if (0 < scope_id && scope_id < p->scopes_count){ + RDI_Scope *scope = p->scopes + scope_id; + if (scope->voff_range_first < scope->voff_range_opl && + scope->voff_range_first < p->scope_voffs_count){ + result = p->scope_voffs[scope->voff_range_first]; + } + } + } + return(result); +} + +//////////////////////////////// +//~ RADDBG Parsing Helpers + +RDI_PROC void* +rdi_data_from_dsec(RDI_Parsed *parsed, RDI_U32 idx, RDI_U32 item_size, + RDI_DataSectionTag expected_tag, + RDI_U64 *count_out){ + void *result = 0; + RDI_U32 count_result = 0; + + // TODO(allen): need a version of this that works with encodings other than "Unpacked" + + if (0 < idx && idx < parsed->dsec_count){ + RDI_DataSection *ds = parsed->dsecs + idx; + if (ds->tag == expected_tag){ + RDI_U64 opl = ds->off + ds->encoded_size; + if (opl <= parsed->raw_data_size){ + count_result = ds->encoded_size/item_size; + result = (parsed->raw_data + ds->off); + } + } + } + + *count_out = count_result; + return(result); +} diff --git a/src/lib_raddbgi_format/raddbgi_format_parse.h b/src/lib_raddbgi_format/raddbgi_format_parse.h new file mode 100644 index 00000000..9e97bcb3 --- /dev/null +++ b/src/lib_raddbgi_format/raddbgi_format_parse.h @@ -0,0 +1,220 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RDI_PARSE_H +#define RDI_PARSE_H + +//////////////////////////////// +//~ RADDBG Parsing Helpers + +typedef struct RDI_Parsed{ + // raw data & data sections (part 1) + RDI_U8 *raw_data; + RDI_U64 raw_data_size; + RDI_DataSection *dsecs; + RDI_U64 dsec_count; + RDI_U32 dsec_idx[RDI_DataSectionTag_PRIMARY_COUNT]; + + // primary data structures (part 2) + + // handled by helper APIs + RDI_U8* string_data; + RDI_U64 string_data_size; + RDI_U32* string_offs; + RDI_U64 string_count; + RDI_U32* idx_run_data; + RDI_U32 idx_run_count; + + // directly readable by users + // (any of these may be empty and null even in a successful parse) + RDI_TopLevelInfo* top_level_info; + + RDI_BinarySection* binary_sections; + RDI_U64 binary_sections_count; + RDI_FilePathNode* file_paths; + RDI_U64 file_paths_count; + RDI_SourceFile* source_files; + RDI_U64 source_files_count; + RDI_Unit* units; + RDI_U64 units_count; + RDI_VMapEntry* unit_vmap; + RDI_U64 unit_vmap_count; + RDI_TypeNode* type_nodes; + RDI_U64 type_nodes_count; + RDI_UDT* udts; + RDI_U64 udts_count; + RDI_Member* members; + RDI_U64 members_count; + RDI_EnumMember* enum_members; + RDI_U64 enum_members_count; + RDI_GlobalVariable* global_variables; + RDI_U64 global_variables_count; + RDI_VMapEntry* global_vmap; + RDI_U64 global_vmap_count; + RDI_ThreadVariable* thread_variables; + RDI_U64 thread_variables_count; + RDI_Procedure* procedures; + RDI_U64 procedures_count; + RDI_Scope* scopes; + RDI_U64 scopes_count; + RDI_U64* scope_voffs; + RDI_U64 scope_voffs_count; + RDI_VMapEntry* scope_vmap; + RDI_U64 scope_vmap_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; + RDI_NameMap* name_maps; + RDI_U64 name_maps_count; + + // other helpers + + RDI_NameMap* name_maps_by_kind[RDI_NameMapKind_COUNT]; + +} RDI_Parsed; + +typedef enum{ + RDI_ParseStatus_Good = 0, + RDI_ParseStatus_HeaderDoesNotMatch = 1, + RDI_ParseStatus_UnsupportedVersionNumber = 2, + RDI_ParseStatus_InvalidDataSecionLayout = 3, + RDI_ParseStatus_MissingStringDataSection = 4, + RDI_ParseStatus_MissingStringTableSection = 5, + RDI_ParseStatus_MissingIndexRunSection = 6, +} RDI_ParseStatus; + +typedef struct RDI_ParsedLineInfo{ + // NOTE: Mapping VOFF -> LINE_INFO + // + // * [ voff[i], voff[i + 1] ) forms the voff range + // * for the line info at lines[i] (and cols[i] if i < col_count) + + RDI_U64* voffs; // [count + 1] sorted + RDI_Line* lines; // [count] + RDI_Column* cols; // [col_count] + RDI_U64 count; + RDI_U64 col_count; +} RDI_ParsedLineInfo; + +typedef struct RDI_ParsedLineMap{ + // NOTE: Mapping LINE_NUMBER -> VOFFs + // + // * nums[i] gives a line number + // * that line number has one or more associated voffs + // + // * to find all associated voffs for the line number nums[i] : + // * let k span over the range [ ranges[i], ranges[i + 1] ) + // * voffs[k] gives the associated voffs + + RDI_U32* nums; // [count] sorted + RDI_U32* ranges; // [count + 1] + RDI_U64* voffs; // [voff_count] + RDI_U64 count; + RDI_U64 voff_count; +} RDI_ParsedLineMap; + + +typedef struct RDI_ParsedNameMap{ + RDI_NameMapBucket *buckets; + RDI_NameMapNode *nodes; + RDI_U64 bucket_count; + RDI_U64 node_count; +} RDI_ParsedNameMap; + +//////////////////////////////// +//~ Global Nils + +#if !defined(RDI_DISABLE_NILS) +static RDI_TopLevelInfo rdi_top_level_info_nil = {0}; +static RDI_BinarySection rdi_binary_section_nil = {0}; +static RDI_FilePathNode rdi_file_path_node_nil = {0}; +static RDI_SourceFile rdi_source_file_nil = {0}; +static RDI_Unit rdi_unit_nil = {0}; +static RDI_VMapEntry rdi_vmap_entry_nil = {0}; +static RDI_TypeNode rdi_type_node_nil = {0}; +static RDI_UDT rdi_udt_nil = {0}; +static RDI_Member rdi_member_nil = {0}; +static RDI_EnumMember rdi_enum_member_nil = {0}; +static RDI_GlobalVariable rdi_global_variable_nil = {0}; +static RDI_ThreadVariable rdi_thread_variable_nil = {0}; +static RDI_Procedure rdi_procedure_nil = {0}; +static RDI_Scope rdi_scope_nil = {0}; +static RDI_U64 rdi_voff_nil = 0; +static RDI_LocationBlock rdi_location_block_nil = {0}; +static RDI_Local rdi_local_nil = {0}; +#endif + +//////////////////////////////// +//~ RADDBG Parse API + +RDI_PROC RDI_ParseStatus +rdi_parse(RDI_U8 *data, RDI_U64 size, RDI_Parsed *out); + +RDI_PROC RDI_U8* +rdi_string_from_idx(RDI_Parsed *parsed, RDI_U32 idx, RDI_U64 *len_out); + +RDI_PROC RDI_U32* +rdi_idx_run_from_first_count(RDI_Parsed *parsed, RDI_U32 first, RDI_U32 raw_count, + RDI_U32 *n_out); + +//- table lookups +#define rdi_element_from_idx(parsed, name, idx) ((0 <= (idx) && (idx) < (parsed)->name##_count) ? &(parsed)->name[idx] : (parsed)->name ? &(parsed)->name[0] : 0) + +//- line info +RDI_PROC void +rdi_line_info_from_unit(RDI_Parsed *p, RDI_Unit *unit, RDI_ParsedLineInfo *out); + +RDI_PROC RDI_U64 +rdi_line_info_idx_from_voff(RDI_ParsedLineInfo *line_info, RDI_U64 voff); + +RDI_PROC void +rdi_line_map_from_source_file(RDI_Parsed *p, RDI_SourceFile *srcfile, + RDI_ParsedLineMap *out); + +RDI_PROC RDI_U64* +rdi_line_voffs_from_num(RDI_ParsedLineMap *map, RDI_U32 linenum, RDI_U32 *n_out); + + +//- vmaps +RDI_PROC RDI_U64 +rdi_vmap_idx_from_voff(RDI_VMapEntry *vmap, RDI_U32 vmap_count, RDI_U64 voff); + + +//- name maps +RDI_PROC RDI_NameMap* +rdi_name_map_from_kind(RDI_Parsed *p, RDI_NameMapKind kind); + +RDI_PROC void +rdi_name_map_parse(RDI_Parsed* p, RDI_NameMap *mapptr, RDI_ParsedNameMap *out); + +RDI_PROC RDI_NameMapNode* +rdi_name_map_lookup(RDI_Parsed *p, RDI_ParsedNameMap *map, + RDI_U8 *str, RDI_U64 len); + +RDI_PROC RDI_U32* +rdi_matches_from_map_node(RDI_Parsed *p, RDI_NameMapNode *node, RDI_U32 *n_out); + + +//- common helpers +RDI_PROC RDI_U64 +rdi_first_voff_from_proc(RDI_Parsed *p, RDI_U32 proc_id); + + + +//////////////////////////////// +//~ RADDBG Parsing Helpers + +#define rdi_parse__extract_primary(p,outptr,outn,pritag) \ +( (*(void**)&(outptr)) = \ +rdi_data_from_dsec((p),(p)->dsec_idx[pritag],sizeof(*(outptr)),(pritag),(outn)) ) + +RDI_PROC void* +rdi_data_from_dsec(RDI_Parsed *p, RDI_U32 idx, RDI_U32 item_size, + RDI_DataSectionTag expected_tag, RDI_U64 *n_out); + +#define rdi_parse__min(a,b) (((a)<(b))?(a):(b)) + +#endif // RDI_PARSE_H diff --git a/src/lib_raddbgi_make/raddbgi_make.c b/src/lib_raddbgi_make/raddbgi_make.c new file mode 100644 index 00000000..7f15dcbe --- /dev/null +++ b/src/lib_raddbgi_make/raddbgi_make.c @@ -0,0 +1,3609 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: API Implementation Helper Macros + +#define rdim_require(root, b32, else_code, error_msg) do { if(!(b32)) {rdim_push_msg((root), (error_msg)); else_code;} }while(0) +#define rdim_requiref(root, b32, else_code, fmt, ...) do { if(!(b32)) {rdim_push_msgf((root), (fmt), __VA_ARGS__); else_code;} }while(0) + +//////////////////////////////// +//~ rjf: Basic Helpers + +//- rjf: memory set + +#if !defined(RDIM_MEMSET_OVERRIDE) +RDI_PROC void * +rdim_memset_fallback(void *dst, RDI_U8 c, RDI_U64 size) +{ + for(RDI_U64 idx = 0; idx < size; idx += 1) + { + ((RDI_U8 *)dst)[idx] = c; + } + return dst; +} +#endif + +#if !defined(RDIM_MEMCPY_OVERRIDE) +RDI_PROC void * +rdim_memcpy_fallback(void *dst, void *src, RDI_U64 size) +{ + for(RDI_U64 idx = 0; idx < size; idx += 1) + { + ((RDI_U8 *)dst)[idx] = ((RDI_U8 *)src)[idx]; + } + return dst; +} +#endif + +//- rjf: arenas + +#if !defined (RDIM_ARENA_OVERRIDE) + +RDI_PROC RDIM_Arena * +rdim_arena_alloc_fallback(void) +{ + RDIM_Arena *arena = 0; + // TODO(rjf) + return arena; +} + +RDI_PROC void +rdim_arena_release_fallback(RDIM_Arena *arena) +{ + // TODO(rjf) +} + +RDI_PROC RDI_U64 +rdim_arena_pos_fallback(RDIM_Arena *arena) +{ + // TODO(rjf) + return 0; +} + +RDI_PROC void * +rdim_arena_push_fallback(RDIM_Arena *arena, RDI_U64 size) +{ + // TODO(rjf) + return 0; +} + +RDI_PROC void +rdim_arena_pop_to_fallback(RDIM_Arena *arena, RDI_U64 pos) +{ + // TODO(rjf) +} + +#endif + +//- rjf: thread-local scratch arenas + +#if !defined (RDIM_SCRATCH_OVERRIDE) +static RDIM_THREAD_LOCAL RDIM_Arena *rdim_thread_scratches[2]; + +RDI_PROC RDIM_Temp +rdim_scratch_begin_fallback(RDIM_Arena **conflicts, RDI_U64 conflicts_count) +{ + if(rdim_thread_scratches[0] == 0) + { + rdim_thread_scratches[0] = rdim_arena_alloc(); + rdim_thread_scratches[1] = rdim_arena_alloc(); + } + RDIM_Arena *arena = 0; + for(RDI_U64 scratch_idx = 0; + scratch_idx < sizeof(rdim_thread_scratches)/sizeof(rdim_thread_scratches[0]); + scratch_idx += 1) + { + RDI_S32 scratch_conflicts = 0; + for(RDI_U64 conflict_idx = 0; conflict_idx < conflicts_count; conflict_idx += 1) + { + if(conflicts[conflict_idx] == rdim_thread_scratches[scratch_idx]) + { + scratch_conflicts = 1; + break; + } + } + if(!scratch_conflicts) + { + arena = rdim_thread_scratches[scratch_idx]; + } + } + RDIM_Temp temp; + temp.arena = arena; + temp.pos = rdim_arena_pos(arena); + return temp; +} + +RDI_PROC void +rdim_scratch_end_fallback(RDIM_Temp temp) +{ + rdim_arena_pop_to(temp.arena, temp.pos); +} + +#endif + +//- rjf: strings + +RDI_PROC RDIM_String8 +rdim_str8(RDI_U8 *str, RDI_U64 size) +{ + RDIM_String8 result; + result.RDIM_String8_BaseMember = str; + result.RDIM_String8_SizeMember = size; + return result; +} + +RDI_PROC RDIM_String8 +rdim_str8_copy(RDIM_Arena *arena, RDIM_String8 src) +{ + RDIM_String8 dst; + dst.RDIM_String8_SizeMember = src.RDIM_String8_SizeMember; + dst.RDIM_String8_BaseMember = rdim_push_array_no_zero(arena, RDI_U8, dst.RDIM_String8_SizeMember+1); + rdim_memcpy(dst.RDIM_String8_BaseMember, src.RDIM_String8_BaseMember, src.RDIM_String8_SizeMember); + dst.RDIM_String8_BaseMember[dst.RDIM_String8_SizeMember] = 0; + return dst; +} + +RDI_PROC RDIM_String8 +rdim_str8f(RDIM_Arena *arena, char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + RDIM_String8 result = rdim_str8fv(arena, fmt, args); + va_end(args); + return(result); +} + +RDI_PROC RDIM_String8 +rdim_str8fv(RDIM_Arena *arena, char *fmt, va_list args) +{ + va_list args2; + va_copy(args2, args); + RDI_U32 needed_bytes = rdim_vsnprintf(0, 0, fmt, args) + 1; + RDIM_String8 result = {0}; + result.RDIM_String8_BaseMember = rdim_push_array_no_zero(arena, RDI_U8, needed_bytes); + result.RDIM_String8_SizeMember = rdim_vsnprintf((char*)result.str, needed_bytes, fmt, args2); + result.RDIM_String8_BaseMember[result.RDIM_String8_SizeMember] = 0; + va_end(args2); + return(result); +} + +RDI_PROC RDI_S32 +rdim_str8_match(RDIM_String8 a, RDIM_String8 b, RDIM_StringMatchFlags flags) +{ + RDI_S32 result = 0; + if(a.RDIM_String8_SizeMember == b.RDIM_String8_SizeMember) + { + RDI_S32 case_insensitive = (flags & RDIM_StringMatchFlag_CaseInsensitive); + RDI_U64 size = a.RDIM_String8_SizeMember; + result = 1; + for(RDI_U64 idx = 0; idx < size; idx += 1) + { + RDI_U8 at = a.RDIM_String8_BaseMember[idx]; + RDI_U8 bt = b.RDIM_String8_BaseMember[idx]; + if(case_insensitive) + { + at = ('a' <= at && at <= 'z') ? at-('a'-'A') : at; + bt = ('a' <= bt && bt <= 'z') ? bt-('a'-'A') : bt; + } + if(at != bt) + { + result = 0; + break; + } + } + } + return result; +} + +//- rjf: string lists + +RDI_PROC void +rdim_str8_list_push(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string) +{ + RDIM_String8Node *n = rdim_push_array(arena, RDIM_String8Node, 1); + n->RDIM_String8Node_StringMember = string; + RDIM_SLLQueuePush_N(list->RDIM_String8List_FirstMember, list->RDIM_String8List_LastMember, n, RDIM_String8Node_NextPtrMember); + list->RDIM_String8List_NodeCountMember += 1; + list->RDIM_String8List_TotalSizeMember += string.RDIM_String8_SizeMember; +} + +RDI_PROC void +rdim_str8_list_push_front(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string) +{ + RDIM_String8Node *n = rdim_push_array(arena, RDIM_String8Node, 1); + n->RDIM_String8Node_StringMember = string; + RDIM_SLLQueuePushFront_N(list->RDIM_String8List_FirstMember, list->RDIM_String8List_LastMember, n, RDIM_String8Node_NextPtrMember); + list->RDIM_String8List_NodeCountMember += 1; + list->RDIM_String8List_TotalSizeMember += string.RDIM_String8_SizeMember; +} + +RDI_PROC void +rdim_str8_list_push_align(RDIM_Arena *arena, RDIM_String8List *list, RDI_U64 align) +{ + RDI_U64 total_size_pre_align = list->total_size; + RDI_U64 total_size_post_align = (total_size_pre_align + (align-1))&(~(align-1)); + RDI_U64 needed_size = total_size_post_align - total_size_pre_align; + if(needed_size != 0) + { + RDI_U8 *padding = rdim_push_array(arena, RDI_U8, needed_size); + rdim_str8_list_push(arena, list, rdim_str8(padding, needed_size)); + } +} + +RDI_PROC RDIM_String8 +rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep) +{ + RDIM_String8 result; + rdim_memzero_struct(&result); + RDI_U64 sep_count = (list->RDIM_String8List_NodeCountMember > 1) ? (list->RDIM_String8List_NodeCountMember-1) : 0; + result.RDIM_String8_SizeMember = list->RDIM_String8List_TotalSizeMember+sep_count*sep.RDIM_String8_SizeMember; + result.RDIM_String8_BaseMember = rdim_push_array_no_zero(arena, RDI_U8, result.RDIM_String8_SizeMember+1); + RDI_U64 off = 0; + for(RDIM_String8Node *node = list->RDIM_String8List_FirstMember; + node != 0; + node = node->RDIM_String8Node_NextPtrMember) + { + rdim_memcpy((RDI_U8*)result.RDIM_String8_BaseMember+off, + node->RDIM_String8Node_StringMember.RDIM_String8_BaseMember, + node->RDIM_String8Node_StringMember.RDIM_String8_SizeMember); + off += node->RDIM_String8Node_StringMember.RDIM_String8_SizeMember; + if(sep.RDIM_String8_SizeMember != 0 && node->RDIM_String8Node_NextPtrMember != 0) + { + rdim_memcpy((RDI_U8*)result.RDIM_String8_BaseMember+off, + sep.RDIM_String8_BaseMember, + sep.RDIM_String8_SizeMember); + off += sep.RDIM_String8_SizeMember; + } + } + result.RDIM_String8_BaseMember[off] = 0; + return result; +} + +//- rjf: sortable range sorting + +RDI_PROC RDIM_SortKey * +rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count) +{ + // This sort is designed to take advantage of lots of pre-existing sorted ranges. + // Most line info is already sorted or close to already sorted. + // Similarly most vmap data has lots of pre-sorted ranges. etc. etc. + // Also - this sort should be a "stable" sort. In the use case of sorting vmap + // ranges, we want to be able to rely on order, so it needs to be preserved here. + + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + RDIM_SortKey *result = 0; + + if(count <= 1) + { + result = keys; + } + else + { + RDIM_OrderedRange *ranges_first = 0; + RDIM_OrderedRange *ranges_last = 0; + RDI_U64 range_count = 0; + { + RDI_U64 pos = 0; + for(;pos < count;) + { + // identify ordered range + RDI_U64 first = pos; + RDI_U64 opl = pos + 1; + for(; opl < count && keys[opl - 1].key <= keys[opl].key; opl += 1); + + // generate an ordered range node + RDIM_OrderedRange *new_range = rdim_push_array(rdim_temp_arena(scratch), RDIM_OrderedRange, 1); + SLLQueuePush(ranges_first, ranges_last, new_range); + range_count += 1; + new_range->first = first; + new_range->opl = opl; + + // update pos + pos = opl; + } + } + + if(range_count == 1) + { + result = keys; + } + else + { + RDIM_SortKey *keys_swap = rdim_push_array_no_zero(arena, RDIM_SortKey, count); + RDIM_SortKey *src = keys; + RDIM_SortKey *dst = keys_swap; + RDIM_OrderedRange *src_ranges = ranges_first; + RDIM_OrderedRange *dst_ranges = 0; + RDIM_OrderedRange *dst_ranges_last = 0; + + for(;;) + { + // begin a pass + for(;;) + { + // end pass when out of ranges + if(src_ranges == 0) + { + break; + } + + // get first range + RDIM_OrderedRange *range1 = src_ranges; + SLLStackPop(src_ranges); + + // if this range is the whole array, we are done + if(range1->first == 0 && range1->opl == count) + { + result = src; + goto sort_done; + } + + // if there is not a second range, save this range for next time and end this pass + if(src_ranges == 0) + { + RDI_U64 first = range1->first; + rdim_memcpy(dst + first, src + first, sizeof(*src)*(range1->opl - first)); + SLLQueuePush(dst_ranges, dst_ranges_last, range1); + break; + } + + // get second range + RDIM_OrderedRange *range2 = src_ranges; + SLLStackPop(src_ranges); + + rdim_assert(range1->opl == range2->first); + + // merge these ranges + RDI_U64 jd = range1->first; + RDI_U64 j1 = range1->first; + RDI_U64 j1_opl = range1->opl; + RDI_U64 j2 = range2->first; + RDI_U64 j2_opl = range2->opl; + for(;;) + { + if(src[j1].key <= src[j2].key) + { + rdim_memcpy(dst + jd, src + j1, sizeof(*src)); + j1 += 1; + jd += 1; + if(j1 >= j1_opl) + { + break; + } + } + else + { + rdim_memcpy(dst + jd, src + j2, sizeof(*src)); + j2 += 1; + jd += 1; + if(j2 >= j2_opl) + { + break; + } + } + } + if(j1 < j1_opl) + { + rdim_memcpy(dst + jd, src + j1, sizeof(*src)*(j1_opl - j1)); + } + else + { + rdim_memcpy(dst + jd, src + j2, sizeof(*src)*(j2_opl - j2)); + } + + // save this as one range + range1->opl = range2->opl; + SLLQueuePush(dst_ranges, dst_ranges_last, range1); + } + + // end pass by swapping buffers and range nodes + { + RDIM_SortKey *temp = src; + src = dst; + dst = temp; + } + src_ranges = dst_ranges; + dst_ranges = 0; + dst_ranges_last = 0; + } + } + } + sort_done:; + +#if 0 + // assert sortedness + for(RDI_U64 i = 1; i < count; i += 1) + { + rdim_assert(result[i - 1].key <= result[i].key); + } +#endif + + scratch_end(scratch); + return result; +} + +//- rjf: rng1u64 list + +RDI_PROC void +rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDIM_Rng1U64 r) +{ + RDIM_Rng1U64Node *n = rdim_push_array(arena, RDIM_Rng1U64Node, 1); + n->v = r; + RDIM_SLLQueuePush(list->first, list->last, n); + list->count += 1; + if(list->count == 1 || r.min < list->min) + { + list->min = r.min; + } +} + +//////////////////////////////// +//~ rjf: [Building] Binary Section List Building + +RDI_PROC RDIM_BinarySection * +rdim_binary_section_list_push(RDIM_Arena *arena, RDIM_BinarySectionList *list) +{ + RDIM_BinarySectionNode *n = rdim_push_array(arena, RDIM_BinarySectionNode, 1); + RDIM_SLLQueuePush(list->first, list->last, n); + list->count += 1; + RDIM_BinarySection *result = &n->v; + return result; +} + +//////////////////////////////// +//~ rjf: [Building] Source File Info Building + +RDI_PROC RDIM_SrcFile * +rdim_src_file_chunk_list_push(RDIM_Arena *arena, RDIM_SrcFileChunkList *list, RDI_U64 cap) +{ + RDIM_SrcFileChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_SrcFileChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_SrcFile, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_SrcFile *src_file = &n->v[n->count]; + src_file->chunk = n; + n->count += 1; + list->total_count += 1; + return src_file; +} + +RDI_PROC RDI_U64 +rdim_idx_from_src_file(RDIM_SrcFile *src_file) +{ + RDI_U64 idx = 0; + if(src_file != 0 && src_file->chunk != 0) + { + idx = src_file->chunk->base_idx + (src_file - src_file->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_src_file_chunk_list_concat_in_place(RDIM_SrcFileChunkList *dst, RDIM_SrcFileChunkList *to_push) +{ + for(RDIM_SrcFileChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RDI_PROC void +rdim_src_file_push_line_sequence(RDIM_Arena *arena, RDIM_SrcFileChunkList *src_files, RDIM_SrcFile *src_file, RDIM_LineSequence *seq) +{ + RDIM_SrcFileLineMapFragment *fragment = rdim_push_array(arena, RDIM_SrcFileLineMapFragment, 1); + fragment->seq = seq; + RDIM_SLLQueuePush(src_file->first_line_map_fragment, src_file->last_line_map_fragment, fragment); +} + +//////////////////////////////// +//~ rjf: [Building] Unit List Building + +RDI_PROC RDIM_Unit * +rdim_unit_chunk_list_push(RDIM_Arena *arena, RDIM_UnitChunkList *list, RDI_U64 cap) +{ + RDIM_UnitChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_UnitChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_Unit, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_Unit *unit = &n->v[n->count]; + unit->chunk = n; + n->count += 1; + list->total_count += 1; + return unit; +} + +RDI_PROC RDI_U64 +rdim_idx_from_unit(RDIM_Unit *unit) +{ + RDI_U64 idx = 0; + if(unit != 0 && unit->chunk != 0) + { + idx = unit->chunk->base_idx + (unit - unit->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList *to_push) +{ + for(RDIM_UnitChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RDI_PROC RDIM_LineSequence * +rdim_line_sequence_list_push(RDIM_Arena *arena, RDIM_LineSequenceList *list) +{ + RDIM_LineSequenceNode *n = rdim_push_array(arena, RDIM_LineSequenceNode, 1); + RDIM_SLLQueuePush(list->first, list->last, n); + list->count += 1; + return &n->v; +} + +//////////////////////////////// +//~ rjf: [Building] Type Info Building + +RDI_PROC RDIM_Type * +rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 cap) +{ + RDIM_TypeChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_TypeChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_Type, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_Type *result = &n->v[n->count]; + result->chunk = n; + n->count += 1; + list->total_count += 1; + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_type(RDIM_Type *type) +{ + RDI_U64 idx = 0; + if(type != 0 && type->chunk != 0) + { + idx = type->chunk->base_idx + (type - type->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push) +{ + for(RDIM_TypeChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RDI_PROC RDIM_UDT * +rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap) +{ + RDIM_UDTChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_UDTChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_UDT, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_UDT *result = &n->v[n->count]; + result->chunk = n; + n->count += 1; + list->total_count += 1; + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_udt(RDIM_UDT *udt) +{ + RDI_U64 idx = 0; + if(udt != 0 && udt->chunk != 0) + { + idx = udt->chunk->base_idx + (udt - udt->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push) +{ + for(RDIM_UDTChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + dst->total_member_count += to_push->total_member_count; + dst->total_enum_val_count += to_push->total_enum_val_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RDI_PROC RDIM_UDTMember * +rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt) +{ + RDIM_UDTMember *mem = rdim_push_array(arena, RDIM_UDTMember, 1); + RDIM_SLLQueuePush(udt->first_member, udt->last_member, mem); + udt->member_count += 1; + list->total_member_count += 1; + return mem; +} + +RDI_PROC RDIM_UDTEnumVal * +rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt) +{ + RDIM_UDTEnumVal *mem = rdim_push_array(arena, RDIM_UDTEnumVal, 1); + RDIM_SLLQueuePush(udt->first_enum_val, udt->last_enum_val, mem); + udt->enum_val_count += 1; + list->total_enum_val_count += 1; + return mem; +} + +//////////////////////////////// +//~ rjf: [Building] Symbol Info Building + +RDI_PROC RDIM_Symbol * +rdim_symbol_chunk_list_push(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDI_U64 cap) +{ + RDIM_SymbolChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_SymbolChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_Symbol, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_Symbol *result = &n->v[n->count]; + result->chunk = n; + n->count += 1; + list->total_count += 1; + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_symbol(RDIM_Symbol *symbol) +{ + RDI_U64 idx = 0; + if(symbol != 0 && symbol->chunk != 0) + { + idx = symbol->chunk->base_idx + (symbol - symbol->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_symbol_chunk_list_concat_in_place(RDIM_SymbolChunkList *dst, RDIM_SymbolChunkList *to_push) +{ + for(RDIM_SymbolChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +//////////////////////////////// +//~ rjf: [Building] Scope Info Building + +//- rjf: scopes + +RDI_PROC RDIM_Scope * +rdim_scope_chunk_list_push(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDI_U64 cap) +{ + RDIM_ScopeChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_ScopeChunkNode, 1); + n->cap = cap; + n->base_idx = list->total_count; + n->v = rdim_push_array(arena, RDIM_Scope, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_Scope *result = &n->v[n->count]; + result->chunk = n; + n->count += 1; + list->total_count += 1; + return result; +} + +RDI_PROC RDI_U64 +rdim_idx_from_scope(RDIM_Scope *scope) +{ + RDI_U64 idx = 0; + if(scope != 0 && scope->chunk != 0) + { + idx = scope->chunk->base_idx + (scope - scope->chunk->v) + 1; + } + return idx; +} + +RDI_PROC void +rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push) +{ + for(RDIM_ScopeChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + dst->scope_voff_count += to_push->scope_voff_count; + dst->local_count += to_push->local_count; + dst->location_count += to_push->location_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RDI_PROC void +rdim_scope_push_voff_range(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDIM_Scope *scope, RDIM_Rng1U64 range) +{ + rdim_rng1u64_list_push(arena, &scope->voff_ranges, range); + list->scope_voff_count += 2; +} + +RDI_PROC RDIM_Local * +rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *scope) +{ + RDIM_Local *local = rdim_push_array(arena, RDIM_Local, 1); + RDIM_SLLQueuePush(scope->first_local, scope->last_local, local); + scope->local_count += 1; + scopes->local_count += 1; + return local; +} + +//- rjf: bytecode + +RDI_PROC void +rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p) +{ + RDI_U8 ctrlbits = rdi_eval_opcode_ctrlbits[op]; + RDI_U32 p_size = RDI_DECODEN_FROM_CTRLBITS(ctrlbits); + + RDIM_EvalBytecodeOp *node = rdim_push_array(arena, RDIM_EvalBytecodeOp, 1); + node->op = op; + node->p_size = p_size; + node->p = p; + + RDIM_SLLQueuePush(bytecode->first_op, bytecode->last_op, node); + bytecode->op_count += 1; + bytecode->encoded_size += 1 + p_size; +} + +RDI_PROC void +rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x) +{ + if(x <= 0xFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU8, x); + } + else if(x <= 0xFFFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU16, x); + } + else if(x <= 0xFFFFFFFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU32, x); + } + else + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU64, x); + } +} + +RDI_PROC void +rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x) +{ + if(-0x80 <= x && x <= 0x7F) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU8, (RDI_U64)x); + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 8); + } + else if(-0x8000 <= x && x <= 0x7FFF) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU16, (RDI_U64)x); + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 16); + } + else if(-0x80000000ll <= x && x <= 0x7FFFFFFFll) + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU32, (RDI_U64)x); + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_TruncSigned, 32); + } + else + { + rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_ConstU64, (RDI_U64)x); + } +} + +RDI_PROC void +rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed) +{ + if(right_destroyed->first_op != 0) + { + if(left_dst->first_op == 0) + { + rdim_memcpy_struct(left_dst, right_destroyed); + } + 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; + } + rdim_memzero_struct(right_destroyed); + } +} + +//- rjf: individual locations + +RDI_PROC RDIM_Location * +rdim_push_location_addr_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode) +{ + RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); + result->kind = RDI_LocationKind_AddrBytecodeStream; + result->bytecode = *bytecode; + return result; +} + +RDI_PROC RDIM_Location * +rdim_push_location_val_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode) +{ + RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); + result->kind = RDI_LocationKind_ValBytecodeStream; + result->bytecode = *bytecode; + return result; +} + +RDI_PROC RDIM_Location * +rdim_push_location_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset) +{ + RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); + result->kind = RDI_LocationKind_AddrRegisterPlusU16; + result->register_code = reg_code; + result->offset = offset; + return result; +} + +RDI_PROC RDIM_Location * +rdim_push_location_addr_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset) +{ + RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); + result->kind = RDI_LocationKind_AddrAddrRegisterPlusU16; + result->register_code = reg_code; + result->offset = offset; + return result; +} + +RDI_PROC RDIM_Location * +rdim_push_location_val_reg(RDIM_Arena *arena, RDI_U8 reg_code) +{ + RDIM_Location *result = rdim_push_array(arena, RDIM_Location, 1); + result->kind = RDI_LocationKind_ValRegister; + result->register_code = reg_code; + return result; +} + +//- 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) +{ + RDIM_LocationCase *location_case = rdim_push_array(arena, RDIM_LocationCase, 1); + SLLQueuePush(locset->first_location_case, locset->last_location_case, location_case); + locset->location_case_count += 1; + location_case->voff_range = voff_range; + location_case->location = location; + scopes->location_count +=1; +} + +//////////////////////////////// +//~ rjf: [Baking Helpers] Baked File Layout Calculations + +RDI_PROC RDI_U64 +rdim_bake_section_count_from_params(RDIM_BakeParams *params) +{ + RDI_U64 section_count = 0; + { + section_count += RDI_DataSectionTag_PRIMARY_COUNT; + section_count += params->units.total_count; // PER-UNIT line info voffs + section_count += params->units.total_count; // PER-UNIT line info data + section_count += params->units.total_count; // PER-UNIT line info columns + section_count += params->src_files.total_count; // PER-SOURCE-FILE line map numbers + section_count += params->src_files.total_count; // PER-SOURCE-FILE line map ranges + section_count += params->src_files.total_count; // PER-SOURCE-FILE line map voffs + section_count += RDI_NameMapKind_COUNT-1; // PER-NAME-MAP buckets section + section_count += RDI_NameMapKind_COUNT-1; // PER-NAME-MAP nodes section + } + return section_count; +} + +RDI_PROC RDI_U64 +rdim_bake_section_idx_from_params_tag_idx(RDIM_BakeParams *params, RDI_DataSectionTag tag, RDI_U64 idx) +{ + RDI_U64 result = 0; + if(tag < RDI_DataSectionTag_PRIMARY_COUNT) + { + result = (RDI_U64)tag; + } + else switch(tag) + { + default:{}break; + + //- rjf: per-unit sections + case (RDI_U32)RDI_DataSectionTag_LineInfoVoffs: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 0*params->units.total_count + (idx-1)%params->units.total_count; + }break; + case (RDI_U32)RDI_DataSectionTag_LineInfoData: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 1*params->units.total_count + (idx-1)%params->units.total_count; + }break; + case (RDI_U32)RDI_DataSectionTag_LineInfoColumns: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 2*params->units.total_count + (idx-1)%params->units.total_count; + }break; + + //- rjf: per-source-file sections + case (RDI_U32)RDI_DataSectionTag_LineMapNumbers: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 3*params->units.total_count + 0*params->src_files.total_count + (idx-1)%params->src_files.total_count; + }break; + case (RDI_U32)RDI_DataSectionTag_LineMapRanges: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 3*params->units.total_count + 1*params->src_files.total_count + (idx-1)%params->src_files.total_count; + }break; + case (RDI_U32)RDI_DataSectionTag_LineMapVoffs: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 3*params->units.total_count + 2*params->src_files.total_count + (idx-1)%params->src_files.total_count; + }break; + + //- rjf: per-name-map sections + case (RDI_U32)RDI_DataSectionTag_NameMapBuckets: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 3*params->units.total_count + 3*params->src_files.total_count + 0*(RDI_NameMapKind_COUNT-1) + (idx-1)%(RDI_NameMapKind_COUNT-1); + }break; + case (RDI_U32)RDI_DataSectionTag_NameMapNodes: + if(idx != 0) + { + result = RDI_DataSectionTag_PRIMARY_COUNT + 3*params->units.total_count + 3*params->src_files.total_count + 1*(RDI_NameMapKind_COUNT-1) + (idx-1)%(RDI_NameMapKind_COUNT-1); + }break; + } + return result; +} + +//////////////////////////////// +//~ rjf: [Baking Helpers] Baked VMap Building + +RDI_PROC RDIM_BakeVMap +rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_SortKey *keys, RDI_U64 marker_count) +{ + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + //- rjf: sort markers + RDIM_SortKey *sorted_keys = rdim_sort_key_array(scratch.arena, keys, marker_count); + + //- rjf: determine if an extra vmap entry for zero is needed + RDI_U32 extra_vmap_entry = 0; + if(marker_count > 0 && sorted_keys[0].key != 0) + { + extra_vmap_entry = 1; + } + + //- rjf: fill output vmap entries + RDI_U32 vmap_count_raw = marker_count - 1 + extra_vmap_entry; + RDI_VMapEntry *vmap = rdim_push_array_no_zero(arena, RDI_VMapEntry, vmap_count_raw + 1); + RDI_U32 vmap_entry_count_pass_1 = 0; + { + typedef struct RDIM_VMapRangeTracker RDIM_VMapRangeTracker; + struct RDIM_VMapRangeTracker + { + RDIM_VMapRangeTracker *next; + RDI_U32 idx; + }; + RDI_VMapEntry *vmap_ptr = vmap; + if(extra_vmap_entry) + { + vmap_ptr->voff = 0; + vmap_ptr->idx = 0; + vmap_ptr += 1; + } + RDIM_VMapRangeTracker *tracker_stack = 0; + RDIM_VMapRangeTracker *tracker_free = 0; + RDIM_SortKey *key_ptr = sorted_keys; + RDIM_SortKey *key_opl = sorted_keys + marker_count; + for(;key_ptr < key_opl;) + { + // rjf: get initial map state from tracker stack + RDI_U32 initial_idx = (RDI_U32)0xffffffff; + if(tracker_stack != 0) + { + initial_idx = tracker_stack->idx; + } + + // rjf: update tracker stack + // + // * we must process _all_ of the changes that apply at this voff before moving on + // + RDI_U64 voff = key_ptr->key; + + for(;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1) + { + RDIM_VMapMarker *marker = (RDIM_VMapMarker*)key_ptr->val; + RDI_U32 idx = marker->idx; + + // rjf: range begin -> push to stack + if(marker->begin_range) + { + RDIM_VMapRangeTracker *new_tracker = tracker_free; + if(new_tracker != 0) + { + RDIM_SLLStackPop(tracker_free); + } + else + { + new_tracker = rdim_push_array(scratch.arena, RDIM_VMapRangeTracker, 1); + } + RDIM_SLLStackPush(tracker_stack, new_tracker); + new_tracker->idx = idx; + } + + // rjf: range ending -> pop matching node from stack (not always the top) + else + { + RDIM_VMapRangeTracker **ptr_in = &tracker_stack; + RDIM_VMapRangeTracker *match = 0; + for(RDIM_VMapRangeTracker *node = tracker_stack; node != 0;) + { + if(node->idx == idx) + { + match = node; + break; + } + ptr_in = &node->next; + node = node->next; + } + if(match != 0) + { + *ptr_in = match->next; + RDIM_SLLStackPush(tracker_free, match); + } + } + } + + // rjf: get final map state from tracker stack + RDI_U32 final_idx = 0; + if(tracker_stack != 0) + { + final_idx = tracker_stack->idx; + } + + // rjf: if final is different from initial - emit new vmap entry + if(final_idx != initial_idx) + { + vmap_ptr->voff = voff; + vmap_ptr->idx = final_idx; + vmap_ptr += 1; + } + } + + vmap_entry_count_pass_1 = (RDI_U32)(vmap_ptr - vmap); // TODO(rjf): @u64_to_u32 + } + + //- rjf: combine duplicate neighbors + RDI_U32 vmap_entry_count = 0; + { + RDI_VMapEntry *vmap_ptr = vmap; + RDI_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; + RDI_VMapEntry *vmap_out = vmap; + for(;vmap_ptr < vmap_opl;) + { + RDI_VMapEntry *vmap_range_first = vmap_ptr; + RDI_U64 idx = vmap_ptr->idx; + vmap_ptr += 1; + for(;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; + rdim_memcpy_struct(vmap_out, vmap_range_first); + vmap_out += 1; + } + vmap_entry_count = (RDI_U32)(vmap_out - vmap); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill result + RDIM_BakeVMap result = {0}; + result.vmap = vmap; + result.count = vmap_entry_count-1; + rdim_scratch_end(scratch); + return result; +} + +//////////////////////////////// +//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers + +//- rjf: bake string chunk lists + +RDI_PROC RDIM_BakeString * +rdim_bake_string_chunk_list_push(RDIM_Arena *arena, RDIM_BakeStringChunkList *list, RDI_U64 cap) +{ + RDIM_BakeStringChunkNode *n = list->last; + if(n == 0 || n->count >= n->cap) + { + n = rdim_push_array(arena, RDIM_BakeStringChunkNode, 1); + n->cap = cap; + n->v = rdim_push_array(arena, RDIM_BakeString, n->cap); + RDIM_SLLQueuePush(list->first, list->last, n); + list->chunk_count += 1; + } + RDIM_BakeString *s = &n->v[n->count]; + n->count += 1; + list->total_count += 1; + return s; +} + +RDI_PROC void +rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_BakeStringChunkList *to_push) +{ + for(RDIM_BakeStringChunkNode *n = to_push->first; n != 0; n = n->next) + { + n->base_idx += dst->total_count; + } + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->chunk_count += to_push->chunk_count; + dst->total_count += to_push->total_count; + } + else if(dst->first == 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +RDI_PROC RDIM_BakeStringChunkList +rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStringChunkList *src) +{ + //- rjf: produce unsorted destination list with single chunk node + RDIM_BakeStringChunkList dst = {0}; + for(RDIM_BakeStringChunkNode *n = src->first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDIM_BakeString *src_str = &n->v[idx]; + RDIM_BakeString *dst_str = rdim_bake_string_chunk_list_push(arena, &dst, src->total_count); + rdim_memcpy_struct(dst_str, src_str); + } + } + + //- rjf: sort chunk node + if(dst.first != 0) + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + typedef struct SortTask SortTask; + struct SortTask + { + SortTask *next; + RDI_U64 string_off; + RDIM_BakeString *v; + RDI_U64 count; + }; + SortTask start_task = {0, 0, dst.first->v, dst.first->count}; + SortTask *first_task = &start_task; + SortTask *last_task = &start_task; + + //- rjf: for each sort task range: + for(SortTask *t = first_task; t != 0; t = t->next) + { + //- rjf: loop through range, drop each element into bucket according to byte in string at task offset + RDIM_BakeStringChunkList *buckets = rdim_push_array(scratch.arena, RDIM_BakeStringChunkList, 256); + for(RDI_U64 idx = 0; idx < t->count; idx += 1) + { + U8 byte = t->string_off < t->v[idx].string.size ? t->v[idx].string.str[t->string_off] : 0; + RDIM_BakeStringChunkList *bucket = &buckets[byte]; + RDIM_BakeString *bstr = rdim_bake_string_chunk_list_push(scratch.arena, bucket, 8); + rdim_memcpy_struct(bstr, &t->v[idx]); + } + + //- rjf: in-place mutate the original source array to reflect the order per the buckets. + // build new sort tasks for buckets with many elements + { + RDI_U64 write_idx = 0; + for(U64 bucket_idx = 0; bucket_idx < 256; bucket_idx += 1) + { + // rjf: write each chunk node's array into original array, detect if there is size left to sort + RDI_U64 bucket_base_idx = write_idx; + RDI_U64 max_size_left_to_sort = 0; + for(RDIM_BakeStringChunkNode *n = buckets[bucket_idx].first; n != 0; n = n->next) + { + rdim_memcpy(t->v+write_idx, n->v, sizeof(n->v[0])*n->count); + write_idx += n->count; + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + if(n->v[idx].string.size > t->string_off+1) + { + max_size_left_to_sort = Max(max_size_left_to_sort, (n->v[idx].string.size - t->string_off+1)); + } + } + } + + // rjf: if any bucket has >1 element & has some amount of size left to sort, push new task for this + // bucket's region in the array, and for remainder of keys + if(buckets[bucket_idx].total_count > 1 && max_size_left_to_sort > 0) + { + SortTask *new_task = rdim_push_array(scratch.arena, SortTask, 1); + RDIM_SLLQueuePush(first_task, last_task, new_task); + new_task->string_off = t->string_off+1; + new_task->v = t->v + bucket_base_idx; + new_task->count = write_idx-bucket_base_idx; + } + } + } + } + scratch_end(scratch); + } + + return dst; +} + +//- rjf: bake string chunk list maps + +RDI_PROC RDIM_BakeStringMapLoose * +rdim_bake_string_map_loose_make(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top) +{ + RDIM_BakeStringMapLoose *map = rdim_push_array(arena, RDIM_BakeStringMapLoose, 1); + map->slots = rdim_push_array(arena, RDIM_BakeStringChunkList *, top->slots_count); + return map; +} + +RDI_PROC void +rdim_bake_string_map_loose_insert(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map, RDI_U64 chunk_cap, RDIM_String8 string) +{ + RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember); + RDI_U64 slot_idx = hash%map_topology->slots_count; + RDIM_BakeStringChunkList *slot = map->slots[slot_idx]; + if(slot == 0) + { + slot = map->slots[slot_idx] = rdim_push_array(arena, RDIM_BakeStringChunkList, 1); + } + RDI_S32 is_duplicate = 0; + for(RDIM_BakeStringChunkNode *n = slot->first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + if(rdim_str8_match(n->v[idx].string, string, 0)) + { + is_duplicate = 1; + goto break_all; + } + } + } + break_all:; + if(!is_duplicate) + { + RDIM_BakeString *bstr = rdim_bake_string_chunk_list_push(arena, slot, chunk_cap); + bstr->string = string; + bstr->hash = hash; + } +} + +RDI_PROC void +rdim_bake_string_map_loose_join_in_place(RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *dst, RDIM_BakeStringMapLoose *src) +{ + for(RDI_U64 idx = 0; idx < map_topology->slots_count; idx += 1) + { + if(dst->slots[idx] == 0) + { + dst->slots[idx] = src->slots[idx]; + } + else if(src->slots[idx] != 0) + { + rdim_bake_string_chunk_list_concat_in_place(dst->slots[idx], src->slots[idx]); + } + } + rdim_memzero_struct(src); +} + +RDI_PROC RDIM_BakeStringMapBaseIndices +rdim_bake_string_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map) +{ + RDIM_BakeStringMapBaseIndices indices = {0}; + indices.slots_base_idxs = rdim_push_array(arena, RDI_U64, map_topology->slots_count+1); + RDI_U64 total_count = 0; + for(RDI_U64 idx = 0; idx < map_topology->slots_count; idx += 1) + { + indices.slots_base_idxs[idx] += total_count; + if(map->slots[idx] != 0) + { + total_count += map->slots[idx]->total_count; + } + } + indices.slots_base_idxs[map_topology->slots_count] = total_count; + return indices; +} + +//- rjf: finalized bake string map + +RDI_PROC RDIM_BakeStringMapTight +rdim_bake_string_map_tight_from_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapBaseIndices *map_base_indices, RDIM_BakeStringMapLoose *map) +{ + RDIM_BakeStringMapTight m = {0}; + m.slots_count = map_topology->slots_count; + m.slots = rdim_push_array(arena, RDIM_BakeStringChunkList, m.slots_count); + m.slots_base_idxs = map_base_indices->slots_base_idxs; + for(RDI_U64 idx = 0; idx < m.slots_count; idx += 1) + { + if(map->slots[idx] != 0) + { + rdim_memcpy_struct(&m.slots[idx], map->slots[idx]); + } + } + m.total_count = m.slots_base_idxs[m.slots_count]; + return m; +} + +RDI_PROC RDI_U64 +rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string) +{ + RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember); + RDI_U64 slot_idx = hash%map->slots_count; + RDI_U64 idx = 0; + for(RDIM_BakeStringChunkNode *n = map->slots[slot_idx].first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + if(n->v[chunk_idx].hash == hash && rdim_str8_match(n->v[chunk_idx].string, string, 0)) + { + idx = map->slots_base_idxs[slot_idx] + n->base_idx + chunk_idx; + break; + } + } + } + return idx; +} + +//- rjf: bake idx run map reading/writing + +RDI_PROC RDI_U64 +rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count) +{ + RDI_U64 hash = 5381; + RDI_U32 *ptr = idx_run; + RDI_U32 *opl = idx_run + count; + for(;ptr < opl; ptr += 1) + { + hash = ((hash << 5) + hash) + (*ptr); + } + return hash; +} + +RDI_PROC RDI_U32 +rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count) +{ + RDI_U64 hash = rdim_hash_from_idx_run(idx_run, count); + RDI_U64 slot_idx = hash%map->slots_count; + + // rjf: find existing node + RDIM_BakeIdxRunNode *node = 0; + for(RDIM_BakeIdxRunNode *n = map->slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->hash == hash) + { + RDI_S32 is_match = 1; + RDI_U32 *n_idx = n->idx_run; + for(RDI_U32 i = 0; i < count; i += 1) + { + if(n_idx[i] != idx_run[i]) + { + is_match = 0; + break; + } + } + if(is_match) + { + node = n; + break; + } + } + } + + // rjf: node -> index + RDI_U32 result = node ? node->first_idx : 0; + return result; +} + +RDI_PROC RDI_U32 +rdim_bake_idx_run_map_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count) +{ + RDI_U64 hash = rdim_hash_from_idx_run(idx_run, count); + RDI_U64 slot_idx = hash%map->slots_count; + + // rjf: find existing node + RDIM_BakeIdxRunNode *node = 0; + for(RDIM_BakeIdxRunNode *n = map->slots[slot_idx]; n != 0; n = n->hash_next) + { + if(n->hash == hash) + { + RDI_S32 is_match = 1; + RDI_U32 *n_idx = n->idx_run; + for(RDI_U32 i = 0; i < count; i += 1) + { + if(n_idx[i] != idx_run[i]) + { + is_match = 0; + break; + } + } + if(is_match) + { + node = n; + break; + } + } + } + + // rjf: no node -> make new node + if(node == 0) + { + node = rdim_push_array_no_zero(arena, RDIM_BakeIdxRunNode, 1); + RDI_U32 *idx_run_copy = rdim_push_array_no_zero(arena, RDI_U32, count); + for(RDI_U32 i = 0; i < count; i += 1) + { + idx_run_copy[i] = idx_run[i]; + } + node->idx_run = idx_run_copy; + node->hash = hash; + node->count = count; + node->first_idx = map->idx_count; + map->count += 1; + map->idx_count += count; + RDIM_SLLQueuePush_N(map->order_first, map->order_last, node, order_next); + RDIM_SLLStackPush_N(map->slots[slot_idx], node, hash_next); + map->slot_collision_count += (node->hash_next != 0); + } + + // rjf: node -> index + RDI_U32 result = node->first_idx; + return result; +} + +//- rjf: bake path tree reading/writing + +RDI_PROC RDIM_BakePathNode * +rdim_bake_path_node_from_string(RDIM_BakePathTree *tree, RDIM_String8 string) +{ + RDIM_BakePathNode *node = &tree->root; + RDI_U8 *ptr = string.str; + RDI_U8 *opl = string.str + string.size; + for(;ptr < opl && node != 0;) + { + // rjf: skip past slashes + for(;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); + + // rjf: save beginning of non-slash range + RDI_U8 *range_first = ptr; + + // rjf: skip past non-slashes + for(;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); + + // rjf: empty range -> continue + if(range_first >= ptr) + { + continue; + } + + // rjf: range -> sub-directory string + RDIM_String8 sub_dir = rdim_str8(range_first, (RDI_U64)(ptr-range_first)); + + // rjf: sub-directory string -> find child of node + RDIM_BakePathNode *sub_dir_node = 0; + for(RDIM_BakePathNode *child = node->first_child; child != 0; child = child->next_sibling) + { + if(rdim_str8_match(child->name, sub_dir, RDIM_StringMatchFlag_CaseInsensitive)) + { + sub_dir_node = child; + } + } + + // rjf: descend to child + node = sub_dir_node; + } + return node; +} + +RDI_PROC RDI_U32 +rdim_bake_path_node_idx_from_string(RDIM_BakePathTree *tree, RDIM_String8 string) +{ + RDIM_BakePathNode *path_node = rdim_bake_path_node_from_string(tree, string); + return path_node ? path_node->idx : 0; +} + +RDI_PROC RDIM_BakePathNode * +rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string) +{ + RDIM_BakePathNode *node = &tree->root; + RDI_U8 *ptr = string.str; + RDI_U8 *opl = string.str + string.size; + for(;ptr < opl;) + { + // rjf: skip past slashes + for(;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); + + // rjf: save beginning of non-slash range + RDI_U8 *range_first = ptr; + + // rjf: skip past non-slashes + for(;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); + + // rjf: empty range -> continue + if(range_first >= ptr) + { + continue; + } + + // rjf: range -> sub-directory string + RDIM_String8 sub_dir = rdim_str8(range_first, (RDI_U64)(ptr-range_first)); + + // rjf: sub-directory string -> find child of node + RDIM_BakePathNode *sub_dir_node = 0; + for(RDIM_BakePathNode *child = node->first_child; child != 0; child = child->next_sibling) + { + if(rdim_str8_match(child->name, sub_dir, RDIM_StringMatchFlag_CaseInsensitive)) + { + sub_dir_node = child; + } + } + + // rjf: no child -> make one + 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); + sub_dir_node->parent = node; + RDIM_SLLQueuePush_N(node->first_child, node->last_child, sub_dir_node, next_sibling); + sub_dir_node->name = rdim_str8_copy(arena, sub_dir); + sub_dir_node->idx = tree->count; + tree->count += 1; + } + + // rjf: descend to child + node = sub_dir_node; + } + return node; +} + +//- rjf: bake name maps writing + +RDI_PROC void +rdim_bake_name_map_push(RDIM_Arena *arena, RDIM_BakeNameMap *map, RDIM_String8 string, RDI_U32 idx) +{ + if(string.size == 0) {return;} + + // rjf: hash + RDI_U64 hash = rdi_hash(string.RDIM_String8_BaseMember, string.RDIM_String8_SizeMember); + RDI_U64 slot_idx = hash%map->slots_count; + + // rjf: find existing node + RDIM_BakeNameMapNode *node = 0; + for(RDIM_BakeNameMapNode *n = map->slots[slot_idx]; n != 0; n = n->slot_next) + { + if(rdim_str8_match(string, n->string, 0)) + { + node = n; + break; + } + } + + // rjf: make node if necessary + if(node == 0) + { + node = rdim_push_array(arena, RDIM_BakeNameMapNode, 1); + node->string = string; + RDIM_SLLStackPush_N(map->slots[slot_idx], node, slot_next); + RDIM_SLLQueuePush_N(map->first, map->last, node, order_next); + map->name_count += 1; + map->slot_collision_count += (node->slot_next != 0); + } + + // rjf: find existing idx + RDI_S32 existing_idx = 0; + for(RDIM_BakeNameMapValNode *n = node->val_first; n != 0; n = n->next) + { + for(RDI_U32 i = 0; i < sizeof(n->val)/sizeof(n->val[0]); i += 1) + { + if(n->val[i] == 0) + { + break; + } + if(n->val[i] == idx) + { + existing_idx = 1; + break; + } + } + } + + // rjf: insert new idx if necessary + if(!existing_idx) + { + RDIM_BakeNameMapValNode *val_node = node->val_last; + RDI_U32 insert_i = node->val_count%(sizeof(val_node->val)/sizeof(val_node->val[0])); + if(insert_i == 0) + { + val_node = rdim_push_array(arena, RDIM_BakeNameMapValNode, 1); + SLLQueuePush(node->val_first, node->val_last, val_node); + } + val_node->val[insert_i] = idx; + node->val_count += 1; + } +} + +//////////////////////////////// +//~ rjf: [Baking Helpers] Data Section List Building Helpers + +RDI_PROC RDIM_BakeSection * +rdim_bake_section_list_push(RDIM_Arena *arena, RDIM_BakeSectionList *list) +{ + RDIM_BakeSectionNode *n = rdim_push_array(arena, RDIM_BakeSectionNode, 1); + RDIM_SLLQueuePush(list->first, list->last, n); + list->count += 1; + RDIM_BakeSection *result = &n->v; + return result; +} + +RDI_PROC RDIM_BakeSection * +rdim_bake_section_list_push_new(RDIM_Arena *arena, RDIM_BakeSectionList *list, void *data, RDI_U64 size, RDI_DataSectionTag tag, RDI_U64 tag_idx) +{ + RDIM_BakeSection *section = rdim_bake_section_list_push(arena, list); + section->data = data; + section->size = size; + section->tag = tag; + section->tag_idx = tag_idx; + return section; +} + +RDI_PROC void +rdim_bake_section_list_concat_in_place(RDIM_BakeSectionList *dst, RDIM_BakeSectionList *to_push) +{ + if(dst->last != 0 && to_push->first != 0) + { + dst->last->next = to_push->first; + dst->last = to_push->last; + dst->count += to_push->count; + } + else if(to_push->first != 0) + { + rdim_memcpy_struct(dst, to_push); + } + rdim_memzero_struct(to_push); +} + +//////////////////////////////// +//~ rjf: [Baking] Build Artifacts -> Interned/Deduplicated Data Structures + +//- rjf: basic bake string gathering passes + +RDI_PROC void +rdim_bake_string_map_loose_push_top_level_info(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TopLevelInfo *tli) +{ + rdim_bake_string_map_loose_insert(arena, top, map, 1, tli->exe_name); +} + +RDI_PROC void +rdim_bake_string_map_loose_push_binary_sections(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BinarySectionList *secs) +{ + for(RDIM_BinarySectionNode *n = secs->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_insert(arena, top, map, 1, n->v.name); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_path_tree(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BakePathTree *path_tree) +{ + for(RDIM_BakePathNode *n = path_tree->first; n != 0; n = n->next_order) + { + rdim_bake_string_map_loose_insert(arena, top, map, 1, n->name); + } +} + +//- rjf: chunk-granularity bake string gathering passes + +RDI_PROC void +rdim_bake_string_map_loose_push_src_file_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFile *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + rdim_bake_string_map_loose_insert(arena, top, map, 1, v[idx].normal_full_path); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_unit_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Unit *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].unit_name); + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].compiler_name); + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].source_file); + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].object_file); + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].archive_file); + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].build_path); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Type *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + for(RDIM_UDTMember *mem = v[idx].first_member; mem != 0; mem = mem->next) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, mem->name); + } + for(RDIM_UDTEnumVal *mem = v[idx].first_enum_val; mem != 0; mem = mem->next) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, mem->name); + } + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Symbol *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].name); + rdim_bake_string_map_loose_insert(arena, top, map, 4, v[idx].link_name); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count) +{ + for(RDI_U64 idx = 0; idx < count; idx += 1) + { + for(RDIM_Local *local = v[idx].first_local; local != 0; local = local->next) + { + rdim_bake_string_map_loose_insert(arena, top, map, 4, local->name); + } + } +} + +//- rjf: list-granularity bake string gathering passes + +RDI_PROC void +rdim_bake_string_map_loose_push_src_files(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFileChunkList *list) +{ + for(RDIM_SrcFileChunkNode *n = list->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_src_file_slice(arena, top, map, n->v, n->count); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_units(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UnitChunkList *list) +{ + for(RDIM_UnitChunkNode *n = list->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_unit_slice(arena, top, map, n->v, n->count); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_types(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TypeChunkList *list) +{ + for(RDIM_TypeChunkNode *n = list->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_type_slice(arena, top, map, n->v, n->count); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_udts(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTChunkList *list) +{ + for(RDIM_UDTChunkNode *n = list->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_udt_slice(arena, top, map, n->v, n->count); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_symbols(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SymbolChunkList *list) +{ + for(RDIM_SymbolChunkNode *n = list->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_symbol_slice(arena, top, map, n->v, n->count); + } +} + +RDI_PROC void +rdim_bake_string_map_loose_push_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_ScopeChunkList *list) +{ + for(RDIM_ScopeChunkNode *n = list->first; n != 0; n = n->next) + { + rdim_bake_string_map_loose_push_scope_slice(arena, top, map, n->v, n->count); + } +} + +//- rjf: bake name map building + +RDI_PROC RDIM_BakeNameMap * +rdim_bake_name_map_from_kind_params(RDIM_Arena *arena, RDI_NameMapKind kind, RDIM_BakeParams *params) +{ + RDIM_BakeNameMap *map = rdim_push_array(arena, RDIM_BakeNameMap, 1); + switch(kind) + { + default:{}break; + case RDI_NameMapKind_GlobalVariables: + { + map->slots_count = params->global_variables.total_count*2; + map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); + for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 + rdim_bake_name_map_push(arena, map, n->v[idx].name, symbol_idx); + } + } + }break; + case RDI_NameMapKind_ThreadVariables: + { + map->slots_count = params->thread_variables.total_count*2; + map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); + for(RDIM_SymbolChunkNode *n = params->thread_variables.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 + rdim_bake_name_map_push(arena, map, n->v[idx].name, symbol_idx); + } + } + }break; + case RDI_NameMapKind_Procedures: + { + map->slots_count = params->procedures.total_count*2; + map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); + for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 + rdim_bake_name_map_push(arena, map, n->v[idx].name, symbol_idx); + } + } + }break; + case RDI_NameMapKind_Types: + { + map->slots_count = params->types.total_count; + map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); + for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) + { + 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 + rdim_bake_name_map_push(arena, map, n->v[idx].name, type_idx); + } + } + }break; + case RDI_NameMapKind_LinkNameProcedures: + { + map->slots_count = params->procedures.total_count*2; + map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); + for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + if(n->v[idx].link_name.size == 0) {continue;} + RDI_U32 symbol_idx = (RDI_U32)rdim_idx_from_symbol(&n->v[idx]); // TODO(rjf): @u64_to_u32 + rdim_bake_name_map_push(arena, map, n->v[idx].link_name, symbol_idx); + } + } + }break; + case RDI_NameMapKind_NormalSourcePaths: + { + map->slots_count = params->src_files.total_count*2; + map->slots = rdim_push_array(arena, RDIM_BakeNameMapNode *, map->slots_count); + for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDI_U32 src_file_idx = (RDI_U32)rdim_idx_from_src_file(&n->v[idx]); // TODO(rjf): @u64_to_u32 + rdim_bake_name_map_push(arena, map, n->v[idx].normal_full_path, src_file_idx); + } + } + }break; + } + return map; +} + +//- rjf: idx run map building + +RDI_PROC RDIM_BakeIdxRunMap * +rdim_bake_idx_run_map_from_params(RDIM_Arena *arena, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT], RDIM_BakeParams *params) +{ + //- rjf: set up map + RDIM_BakeIdxRunMap *idx_runs = rdim_push_array(arena, RDIM_BakeIdxRunMap, 1); + idx_runs->slots_count = params->procedures.total_count*2 + params->global_variables.total_count*2 + params->thread_variables.total_count*2 + params->types.total_count*2; + idx_runs->slots = rdim_push_array(arena, RDIM_BakeIdxRunNode *, idx_runs->slots_count); + rdim_bake_idx_run_map_insert(arena, idx_runs, 0, 0); + + //- rjf: bake runs of function-type parameter lists + for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_Type *type = &n->v[chunk_idx]; + if(type->kind == RDI_TypeKind_Function || type->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = type->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(type->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + rdim_bake_idx_run_map_insert(arena, idx_runs, param_idx_run, param_idx_run_count); + } + } + } + + //- rjf: bake runs of name map match lists + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + RDIM_BakeNameMap *name_map = name_maps[k]; + if(name_map != 0 && name_map->name_count != 0) + { + for(RDIM_BakeNameMapNode *n = name_map->first; n != 0; n = n->order_next) + { + if(n->val_count > 1) + { + RDI_U32 *idx_run = rdim_push_array(arena, RDI_U32, n->val_count); + RDI_U64 val_idx = 0; + for(RDIM_BakeNameMapValNode *idxnode = n->val_first; + idxnode != 0; + idxnode = idxnode->next) + { + for(RDI_U32 i = 0; i < sizeof(idxnode->val)/sizeof(idxnode->val[0]); i += 1) + { + if(idxnode->val[i] == 0) + { + goto dblbreak; + } + idx_run[val_idx] = idxnode->val[i]; + val_idx += 1; + } + } + dblbreak:; + rdim_bake_idx_run_map_insert(arena, idx_runs, idx_run, (RDI_U32)n->val_count); // TODO(rjf): @u64_to_u32 + } + } + } + } + + return idx_runs; +} + +//- rjf: bake path tree building + +RDI_PROC RDIM_BakePathTree * +rdim_bake_path_tree_from_params(RDIM_Arena *arena, RDIM_BakeParams *params) +{ + //- rjf: set up tree + RDIM_BakePathTree *tree = rdim_push_array(arena, RDIM_BakePathTree, 1); + rdim_bake_path_tree_insert(arena, tree, rdim_str8_lit("")); + + //- rjf: bake unit file paths + RDIM_ProfScope("bake unit file paths") + { + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + rdim_bake_path_tree_insert(arena, tree, n->v[idx].source_file); + rdim_bake_path_tree_insert(arena, tree, n->v[idx].object_file); + rdim_bake_path_tree_insert(arena, tree, n->v[idx].archive_file); + rdim_bake_path_tree_insert(arena, tree, n->v[idx].build_path); + } + } + } + + //- rjf: bake source file paths + RDIM_ProfScope("bake source file paths") + { + for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDIM_BakePathNode *node = rdim_bake_path_tree_insert(arena, tree, n->v[idx].normal_full_path); + node->src_file = &n->v[idx]; + } + } + } + + return tree; +} + +//////////////////////////////// +//~ rjf: [Baking] Build Artifacts -> Data Section Lists + +//- rjf: top-level info + +RDI_PROC RDIM_BakeSectionList +rdim_bake_top_level_info_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params) +{ + RDIM_BakeSectionList sections = {0}; + RDI_TopLevelInfo *dst_tli = rdim_push_array(arena, RDI_TopLevelInfo, 1); + RDIM_TopLevelInfo *src_tli = ¶ms->top_level_info; + dst_tli->architecture = src_tli->arch; + dst_tli->exe_name_string_idx = rdim_bake_idx_from_string(strings, src_tli->exe_name); + dst_tli->exe_hash = src_tli->exe_hash; + dst_tli->voff_max = src_tli->voff_max; + rdim_bake_section_list_push_new(arena, §ions, dst_tli, sizeof(*dst_tli), RDI_DataSectionTag_TopLevelInfo, 0); + return sections; +} + +//- rjf: binary sections + +RDI_PROC RDIM_BakeSectionList +rdim_bake_binary_section_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params) +{ + RDIM_BakeSectionList sections = {0}; + RDIM_BinarySectionList *src_list = ¶ms->binary_sections; + RDI_BinarySection *dst_base = rdim_push_array(arena, RDI_BinarySection, src_list->count+1); + U64 dst_idx = 1; + for(RDIM_BinarySectionNode *src_n = src_list->first; src_n != 0; src_n = src_n->next, dst_idx += 1) + { + RDIM_BinarySection *src = &src_n->v; + RDI_BinarySection *dst = &dst_base[dst_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); + dst->flags = src->flags; + dst->voff_first = src->voff_first; + dst->voff_opl = src->voff_opl; + dst->foff_first = src->foff_first; + dst->foff_opl = src->foff_opl; + } + rdim_bake_section_list_push_new(arena, §ions, dst_base, sizeof(*dst_base)*dst_idx, RDI_DataSectionTag_BinarySections, 0); + return sections; +} + +//- rjf: units + +RDI_PROC RDIM_BakeSectionList +rdim_bake_section_list_from_unit(RDIM_Arena *arena, RDIM_Unit *unit) +{ + RDIM_BakeSectionList sections = {0}; + + //////////////////////// + //- rjf: produce combined unit line info + // + RDI_U64 *unit_voffs = 0; + RDI_Line *unit_lines = 0; + RDI_U16 *unit_cols = 0; + RDI_U32 unit_line_count = 0; + RDIM_ProfScope("produce combined unit line info") + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + //- rjf: gather up all line info into two arrays: + // + // [1] keys: sortable array; pairs voffs with line info records; null records are sequence enders + // [2] recs: contains all the source coordinates for a range of voffs + // + typedef struct RDIM_LineRec RDIM_LineRec; + struct RDIM_LineRec + { + RDI_U32 file_id; + RDI_U32 line_num; + RDI_U16 col_first; + RDI_U16 col_opl; + }; + RDI_U64 line_count = 0; + RDI_U64 seq_count = 0; + for(RDIM_LineSequenceNode *seq_n = unit->line_sequences.first; seq_n != 0; seq_n = seq_n->next) + { + seq_count += 1; + line_count += seq_n->v.line_count; + } + RDI_U64 key_count = line_count + seq_count; + RDIM_SortKey *line_keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, key_count); + RDIM_LineRec *line_recs = rdim_push_array_no_zero(scratch.arena, RDIM_LineRec, line_count); + { + RDIM_SortKey *key_ptr = line_keys; + RDIM_LineRec *rec_ptr = line_recs; + for(RDIM_LineSequenceNode *seq_n = unit->line_sequences.first; seq_n != 0; seq_n = seq_n->next) + { + RDIM_LineSequence *seq = &seq_n->v; + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) + { + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) + { + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + } + rec_ptr += 1; + } + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; + } + } + + //- rjf: sort + RDIM_SortKey *sorted_line_keys = 0; + RDIM_ProfScope("sort") + { + sorted_line_keys = rdim_sort_key_array(scratch.arena, line_keys, key_count); + } + + // TODO(rjf): do a pass over sorted keys to make sure duplicate keys + // are sorted with null record first, and no more than one null + // record and one non-null record + + //- rjf: arrange output + RDI_U64 *arranged_voffs = rdim_push_array_no_zero(arena, RDI_U64, key_count + 1); + RDI_Line *arranged_lines = rdim_push_array_no_zero(arena, RDI_Line, key_count); + RDIM_ProfScope("arrange output") + { + for(RDI_U64 i = 0; i < key_count; i += 1) + { + arranged_voffs[i] = sorted_line_keys[i].key; + } + arranged_voffs[key_count] = ~0ull; + for(RDI_U64 i = 0; i < key_count; i += 1) + { + RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[i].val; + if(rec != 0) + { + arranged_lines[i].file_idx = rec->file_id; + arranged_lines[i].line_num = rec->line_num; + } + else + { + arranged_lines[i].file_idx = 0; + arranged_lines[i].line_num = 0; + } + } + } + + //- rjf: fill output + unit_voffs = arranged_voffs; + unit_lines = arranged_lines; + unit_cols = 0; + unit_line_count = key_count; + rdim_scratch_end(scratch); + } + + //////////////////////// + //- rjf: build line info sections + // + U64 unit_idx = rdim_idx_from_unit(unit); + rdim_bake_section_list_push_new(arena, §ions, unit_voffs, sizeof(RDI_U64)*(unit_line_count+1), RDI_DataSectionTag_LineInfoVoffs, unit_idx); + rdim_bake_section_list_push_new(arena, §ions, unit_lines, sizeof(RDI_Line)*unit_line_count, RDI_DataSectionTag_LineInfoData, unit_idx); + if(unit_cols != 0) + { + rdim_bake_section_list_push_new(arena, §ions, unit_cols, sizeof(RDI_Column)*unit_line_count, RDI_DataSectionTag_LineInfoColumns, unit_idx); + } + + return sections; +} + +RDI_PROC RDIM_BakeSectionList +rdim_bake_unit_top_level_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_BakeParams *params) +{ + RDIM_BakeSectionList sections = {0}; + RDI_Unit *dst_base = rdim_push_array(arena, RDI_Unit, params->units.total_count+1); + RDI_U64 dst_idx = 1; + for(RDIM_UnitChunkNode *src_n = params->units.first; src_n != 0; src_n = src_n->next) + { + for(RDI_U64 src_chunk_idx = 0; src_chunk_idx < src_n->count; src_chunk_idx += 1, dst_idx += 1) + { + RDIM_Unit *src = &src_n->v[src_chunk_idx]; + RDI_Unit *dst = &dst_base[dst_idx]; + + //////////////////////// + //- rjf: produce combined unit line info + // + RDI_U64 *unit_voffs = 0; + RDI_Line *unit_lines = 0; + RDI_U16 *unit_cols = 0; + RDI_U32 unit_line_count = 0; + RDIM_ProfScope("produce combined unit line info") + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + //- rjf: gather up all line info into two arrays: + // + // [1] keys: sortable array; pairs voffs with line info records; null records are sequence enders + // [2] recs: contains all the source coordinates for a range of voffs + // + typedef struct RDIM_LineRec RDIM_LineRec; + struct RDIM_LineRec + { + RDI_U32 file_id; + RDI_U32 line_num; + RDI_U16 col_first; + RDI_U16 col_opl; + }; + RDI_U64 line_count = 0; + RDI_U64 seq_count = 0; + for(RDIM_LineSequenceNode *seq_n = src->line_sequences.first; seq_n != 0; seq_n = seq_n->next) + { + seq_count += 1; + line_count += seq_n->v.line_count; + } + RDI_U64 key_count = line_count + seq_count; + RDIM_SortKey *line_keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, key_count); + RDIM_LineRec *line_recs = rdim_push_array_no_zero(scratch.arena, RDIM_LineRec, line_count); + { + RDIM_SortKey *key_ptr = line_keys; + RDIM_LineRec *rec_ptr = line_recs; + for(RDIM_LineSequenceNode *seq_n = src->line_sequences.first; seq_n != 0; seq_n = seq_n->next) + { + RDIM_LineSequence *seq = &seq_n->v; + for(RDI_U64 line_idx = 0; line_idx < seq->line_count; line_idx += 1) + { + key_ptr->key = seq->voffs[line_idx]; + key_ptr->val = rec_ptr; + key_ptr += 1; + rec_ptr->file_id = (RDI_U32)rdim_idx_from_src_file(seq->src_file); // TODO(rjf): @u64_to_u32 + rec_ptr->line_num = seq->line_nums[line_idx]; + if(seq->col_nums != 0) + { + rec_ptr->col_first = seq->col_nums[line_idx*2]; + rec_ptr->col_opl = seq->col_nums[line_idx*2 + 1]; + } + rec_ptr += 1; + } + key_ptr->key = seq->voffs[seq->line_count]; + key_ptr->val = 0; + key_ptr += 1; + } + } + + //- rjf: sort + RDIM_SortKey *sorted_line_keys = 0; + RDIM_ProfScope("sort") + { + sorted_line_keys = rdim_sort_key_array(scratch.arena, line_keys, key_count); + } + + // TODO(rjf): do a pass over sorted keys to make sure duplicate keys + // are sorted with null record first, and no more than one null + // record and one non-null record + + //- rjf: arrange output + RDI_U64 *arranged_voffs = rdim_push_array_no_zero(arena, RDI_U64, key_count + 1); + RDI_Line *arranged_lines = rdim_push_array_no_zero(arena, RDI_Line, key_count); + RDIM_ProfScope("arrange output") + { + for(RDI_U64 i = 0; i < key_count; i += 1) + { + arranged_voffs[i] = sorted_line_keys[i].key; + } + arranged_voffs[key_count] = ~0ull; + for(RDI_U64 i = 0; i < key_count; i += 1) + { + RDIM_LineRec *rec = (RDIM_LineRec*)sorted_line_keys[i].val; + if(rec != 0) + { + arranged_lines[i].file_idx = rec->file_id; + arranged_lines[i].line_num = rec->line_num; + } + else + { + arranged_lines[i].file_idx = 0; + arranged_lines[i].line_num = 0; + } + } + } + + //- rjf: fill output + unit_voffs = arranged_voffs; + unit_lines = arranged_lines; + unit_cols = 0; + unit_line_count = key_count; + rdim_scratch_end(scratch); + } + + //////////////////////// + //- rjf: build line info sections + // + rdim_bake_section_list_push_new(arena, §ions, unit_voffs, sizeof(RDI_U64)*(unit_line_count+1), RDI_DataSectionTag_LineInfoVoffs, dst_idx); + rdim_bake_section_list_push_new(arena, §ions, unit_lines, sizeof(RDI_Line)*unit_line_count, RDI_DataSectionTag_LineInfoData, dst_idx); + if(unit_cols != 0) + { + rdim_bake_section_list_push_new(arena, §ions, unit_cols, sizeof(RDI_Column)*unit_line_count, RDI_DataSectionTag_LineInfoColumns, dst_idx); + } + + //////////////////////// + //- rjf: fill output + // + dst->unit_name_string_idx = rdim_bake_idx_from_string(strings, src->unit_name); + dst->compiler_name_string_idx = rdim_bake_idx_from_string(strings, src->compiler_name); + dst->source_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->source_file); + dst->object_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->object_file); + dst->archive_file_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->archive_file); + dst->build_path_node = rdim_bake_path_node_idx_from_string(path_tree, src->build_path); + dst->language = src->language; + dst->line_info_voffs_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_LineInfoVoffs, dst_idx); // TODO(rjf): @u64_to_u32 + dst->line_info_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_LineInfoData, dst_idx); // TODO(rjf): @u64_to_u32 + dst->line_info_col_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_LineInfoColumns, dst_idx); // TODO(rjf): @u64_to_u32 + } + } + rdim_bake_section_list_push_new(arena, §ions, dst_base, sizeof(*dst_base)*dst_idx, RDI_DataSectionTag_Units, 0); + return sections; +} + +//- rjf: unit vmap + +RDI_PROC RDIM_BakeSectionList +rdim_bake_unit_vmap_section_list_from_params(RDIM_Arena *arena, RDIM_BakeParams *params) +{ + //- rjf: build vmap from unit voff ranges + RDIM_BakeVMap unit_vmap = {0}; + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + // rjf: count voff ranges + RDI_U64 voff_range_count = 0; + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + for(RDI_U64 idx = 0; idx < n->count; idx += 1) + { + RDIM_Unit *unit = &n->v[idx]; + voff_range_count += unit->voff_ranges.count; + } + } + + // rjf: count necessary markers + RDI_U64 marker_count = voff_range_count*2; + + // rjf: build keys/markers arrays + RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, marker_count); + RDIM_VMapMarker *markers = rdim_push_array_no_zero(scratch.arena, RDIM_VMapMarker, marker_count); + { + RDIM_SortKey *key_ptr = keys; + RDIM_VMapMarker *marker_ptr = markers; + RDI_U32 unit_idx = 1; + for(RDIM_UnitChunkNode *unit_chunk_n = params->units.first; + unit_chunk_n != 0; + unit_chunk_n = unit_chunk_n->next) + { + for(RDI_U64 idx = 0; idx < unit_chunk_n->count; idx += 1) + { + RDIM_Unit *unit = &unit_chunk_n->v[idx]; + for(RDIM_Rng1U64Node *n = unit->voff_ranges.first; n != 0; n = n->next) + { + RDIM_Rng1U64 range = n->v; + if(range.min < range.max) + { + key_ptr->key = range.min; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = range.max; + key_ptr->val = marker_ptr; + marker_ptr->idx = unit_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + unit_idx += 1; + } + } + } + + // rjf: keys/markers -> unit vmap + unit_vmap = rdim_bake_vmap_from_markers(arena, markers, keys, marker_count); + rdim_scratch_end(scratch); + } + + //- rjf: build section + RDIM_BakeSectionList sections = {0}; + RDI_U64 unit_vmap_size = sizeof(unit_vmap.vmap[0])*(unit_vmap.count+1); + rdim_bake_section_list_push_new(arena, §ions, unit_vmap.vmap, unit_vmap_size, RDI_DataSectionTag_UnitVmap, 0); + return sections; +} + +//- rjf: source files + +RDI_PROC RDIM_BakeSectionList +rdim_bake_src_file_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_BakeParams *params) +{ + RDIM_BakeSectionList sections = {0}; + + //////////////////////////// + //- rjf: iterate all source files, fill serialized version, build sections for line info + // + RDI_U32 dst_files_count = params->src_files.total_count + 1; + RDI_SourceFile *dst_files = rdim_push_array(arena, RDI_SourceFile, dst_files_count); + RDI_U32 dst_file_idx = 1; + for(RDIM_SrcFileChunkNode *chunk_n = params->src_files.first; + chunk_n != 0; + chunk_n = chunk_n->next) + { + for(RDI_U64 idx = 0; idx < chunk_n->count; idx += 1, dst_file_idx += 1) + { + RDIM_SrcFile *src_file = &chunk_n->v[idx]; + RDI_SourceFile *dst_file = &dst_files[dst_file_idx]; + + //////////////////////// + //- rjf: fill basics + // + dst_file->file_path_node_idx = rdim_bake_path_node_idx_from_string(path_tree, src_file->normal_full_path); + dst_file->normal_full_path_string_idx = rdim_bake_idx_from_string(strings, src_file->normal_full_path); + + //////////////////////// + //- rjf: produce combined source file line info + // + RDI_U32 *src_file_line_nums = 0; + RDI_U32 *src_file_line_ranges = 0; + RDI_U64 *src_file_voffs = 0; + RDI_U32 src_file_line_count = 0; + RDI_U32 src_file_voff_count = 0; + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + //- rjf: gather line number map + typedef struct RDIM_SrcLineMapVoffBlock RDIM_SrcLineMapVoffBlock; + struct RDIM_SrcLineMapVoffBlock + { + RDIM_SrcLineMapVoffBlock *next; + RDI_U64 voff; + }; + typedef struct RDIM_SrcLineMapBucket RDIM_SrcLineMapBucket; + struct RDIM_SrcLineMapBucket + { + RDIM_SrcLineMapBucket *order_next; + RDIM_SrcLineMapBucket *hash_next; + RDI_U32 line_num; + RDIM_SrcLineMapVoffBlock *first_voff_block; + RDIM_SrcLineMapVoffBlock *last_voff_block; + RDI_U64 voff_count; + }; + RDIM_SrcLineMapBucket *first_bucket = 0; + RDIM_SrcLineMapBucket *last_bucket = 0; + RDI_U64 line_hash_slots_count = 2048; + RDIM_SrcLineMapBucket **line_hash_slots = rdim_push_array(scratch.arena, RDIM_SrcLineMapBucket *, line_hash_slots_count); + RDI_U64 line_count = 0; + RDI_U64 voff_count = 0; + RDI_U64 max_line_num = 0; + { + for(RDIM_SrcFileLineMapFragment *map_fragment = src_file->first_line_map_fragment; + map_fragment != 0; + map_fragment = map_fragment->next) + { + RDIM_LineSequence *sequence = map_fragment->seq; + RDI_U64 *seq_voffs = sequence->voffs; + RDI_U32 *seq_line_nums = sequence->line_nums; + RDI_U64 seq_line_count = sequence->line_count; + for(RDI_U64 i = 0; i < seq_line_count; i += 1) + { + RDI_U32 line_num = seq_line_nums[i]; + RDI_U64 voff = seq_voffs[i]; + RDI_U64 line_hash_slot_idx = line_num%line_hash_slots_count; + + // rjf: update unique voff counter & max line number + voff_count += 1; + max_line_num = Max(max_line_num, line_num); + + // rjf: find match + RDIM_SrcLineMapBucket *match = 0; + { + for(RDIM_SrcLineMapBucket *node = line_hash_slots[line_hash_slot_idx]; + node != 0; + node = node->hash_next) + { + if(node->line_num == line_num) + { + match = node; + break; + } + } + } + + // rjf: introduce new map if no match + if(match == 0) + { + match = rdim_push_array(scratch.arena, RDIM_SrcLineMapBucket, 1); + RDIM_SLLQueuePush_N(first_bucket, last_bucket, match, order_next); + RDIM_SLLStackPush_N(line_hash_slots[line_hash_slot_idx], match, hash_next); + match->line_num = line_num; + line_count += 1; + } + + // rjf: insert new voff + { + RDIM_SrcLineMapVoffBlock *block = rdim_push_array(scratch.arena, RDIM_SrcLineMapVoffBlock, 1); + RDIM_SLLQueuePush(match->first_voff_block, match->last_voff_block, block); + match->voff_count += 1; + block->voff = voff; + } + } + } + } + + //- rjf: bake sortable keys array + RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, line_count); + { + RDIM_SortKey *key_ptr = keys; + for(RDIM_SrcLineMapBucket *node = first_bucket; + node != 0; + node = node->order_next, key_ptr += 1){ + key_ptr->key = node->line_num; + key_ptr->val = node; + } + } + + //- rjf: sort keys array + RDIM_SortKey *sorted_keys = rdim_sort_key_array(scratch.arena, keys, line_count); + + //- rjf: bake result + RDI_U32 *line_nums = rdim_push_array_no_zero(arena, RDI_U32, line_count); + RDI_U32 *line_ranges = rdim_push_array_no_zero(arena, RDI_U32, line_count + 1); + RDI_U64 *voffs = rdim_push_array_no_zero(arena, RDI_U64, voff_count); + { + RDI_U64 *voff_ptr = voffs; + for(RDI_U32 i = 0; i < line_count; i += 1) + { + line_nums[i] = sorted_keys[i].key; + line_ranges[i] = (RDI_U32)(voff_ptr - voffs); // TODO(rjf): @u64_to_u32 + RDIM_SrcLineMapBucket *bucket = (RDIM_SrcLineMapBucket*)sorted_keys[i].val; + for(RDIM_SrcLineMapVoffBlock *node = bucket->first_voff_block; node != 0; node = node->next) + { + *voff_ptr = node->voff; + voff_ptr += 1; + } + } + line_ranges[line_count] = voff_count; + } + + //- rjf: fill output + src_file_line_nums = line_nums; + src_file_line_ranges = line_ranges; + src_file_line_count = line_count; + src_file_voffs = voffs; + src_file_voff_count = voff_count; + rdim_scratch_end(scratch); + } + + ////////////////////////// + //- rjf: produce data sections for this source file's line info tables + // + if(src_file_line_count != 0) + { + dst_file->line_map_count = src_file_line_count; + dst_file->line_map_nums_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_LineMapNumbers, dst_file_idx); // TODO(rjf): @u64_to_u32 + dst_file->line_map_range_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_LineMapRanges, dst_file_idx); // TODO(rjf): @u64_to_u32 + dst_file->line_map_voff_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_LineMapVoffs, dst_file_idx); // TODO(rjf): @u64_to_u32 + rdim_bake_section_list_push_new(arena, §ions, src_file_line_nums, sizeof(*src_file_line_nums)*src_file_line_count, RDI_DataSectionTag_LineMapNumbers, dst_file_idx); + rdim_bake_section_list_push_new(arena, §ions, src_file_line_ranges, sizeof(*src_file_line_ranges)*(src_file_line_count + 1), RDI_DataSectionTag_LineMapRanges, dst_file_idx); + rdim_bake_section_list_push_new(arena, §ions, src_file_voffs, sizeof(*src_file_voffs)*src_file_voff_count, RDI_DataSectionTag_LineMapVoffs, dst_file_idx); + } + } + } + + //////////////////////////// + //- rjf: build section for all source files + // + rdim_bake_section_list_push_new(arena, §ions, dst_files, sizeof(RDI_SourceFile)*dst_files_count, RDI_DataSectionTag_SourceFiles, 0); + + return sections; +} + +//- rjf: type nodes + +RDI_PROC RDIM_BakeSectionList +rdim_bake_type_node_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeParams *params) +{ + //- rjf: build all type nodes + RDI_TypeNode *type_nodes = push_array(arena, RDI_TypeNode, params->types.total_count+1); + RDIM_ProfScope("push all type nodes") + { + RDI_U32 dst_idx = 1; + for(RDIM_TypeChunkNode *n = params->types.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) + { + RDIM_Type *src = &n->v[chunk_idx]; + RDI_TypeNode *dst = &type_nodes[dst_idx]; + + //- rjf: fill shared type node info + dst->kind = src->kind; + dst->byte_size = src->byte_size; + + //- rjf: fill built-in-only type node info + if(RDI_TypeKind_FirstBuiltIn <= dst->kind && dst->kind <= RDI_TypeKind_LastBuiltIn) + { + dst->built_in.name_string_idx = rdim_bake_idx_from_string(strings, src->name); + } + + //- rjf: fill constructed type node info + else if(RDI_TypeKind_FirstConstructed <= dst->kind && dst->kind <= RDI_TypeKind_LastConstructed) + { + dst->constructed.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->constructed.count = src->count; + if(dst->kind == RDI_TypeKind_Function || dst->kind == RDI_TypeKind_Method) + { + RDI_U32 param_idx_run_count = src->count; + RDI_U32 *param_idx_run = rdim_push_array_no_zero(arena, RDI_U32, param_idx_run_count); + for(RDI_U32 idx = 0; idx < param_idx_run_count; idx += 1) + { + param_idx_run[idx] = (RDI_U32)rdim_idx_from_type(src->param_types[idx]); // TODO(rjf): @u64_to_u32 + } + dst->constructed.param_idx_run_first = rdim_bake_idx_from_idx_run(idx_runs, param_idx_run, param_idx_run_count); + } + else if(dst->kind == RDI_TypeKind_MemberPtr) + { + // TODO(rjf): member pointers not currently supported. + } + } + + //- rjf: fill user-defined-type info + else if(RDI_TypeKind_FirstUserDefined <= dst->kind && dst->kind <= RDI_TypeKind_LastUserDefined) + { + dst->user_defined.name_string_idx = rdim_bake_idx_from_string(strings, src->name); + dst->user_defined.udt_idx = (RDI_U32)rdim_idx_from_udt(src->udt); // TODO(rjf): @u64_to_u32 + dst->user_defined.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + } + + //- rjf: fill bitfield info + else if(dst->kind == RDI_TypeKind_Bitfield) + { + dst->bitfield.direct_type_idx = (RDI_U32)rdim_idx_from_type(src->direct_type); // TODO(rjf): @u64_to_u32 + dst->bitfield.off = src->off; + dst->bitfield.size = src->count; + } + } + } + } + + + //- rjf: build sections + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, type_nodes, sizeof(RDI_TypeNode)*(params->types.total_count+1), RDI_DataSectionTag_TypeNodes, 0); + return sections; +} + +//- rjf: UDTs + +RDI_PROC RDIM_BakeSectionList +rdim_bake_udt_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params) +{ + //- rjf: build tables + RDI_UDT * udts = push_array(arena, RDI_UDT, params->udts.total_count+1); + RDI_Member * members = push_array(arena, RDI_Member, params->udts.total_member_count+1); + RDI_EnumMember *enum_members = push_array(arena, RDI_EnumMember, params->udts.total_enum_val_count+1); + { + RDI_U32 dst_udt_idx = 1; + RDI_U32 dst_member_idx = 1; + RDI_U32 dst_enum_member_idx = 1; + for(RDIM_UDTChunkNode *n = params->udts.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_udt_idx += 1) + { + RDIM_UDT *src_udt = &n->v[chunk_idx]; + RDI_UDT *dst_udt = &udts[dst_udt_idx]; + + //- rjf: fill basics + dst_udt->self_type_idx = (RDI_U32)rdim_idx_from_type(src_udt->self_type); // TODO(rjf): @u64_to_u32 + dst_udt->file_idx = (RDI_U32)rdim_idx_from_src_file(src_udt->src_file); // TODO(rjf): @u64_to_u32 + dst_udt->line = src_udt->line; + dst_udt->col = src_udt->col; + + //- rjf: fill members + if(src_udt->member_count != 0) + { + dst_udt->member_first = dst_member_idx; + dst_udt->member_count = src_udt->member_count; + for(RDIM_UDTMember *src_member = src_udt->first_member; + src_member != 0; + src_member = src_member->next, dst_member_idx += 1) + { + RDI_Member *dst_member = &members[dst_member_idx]; + dst_member->kind = src_member->kind; + dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); + dst_member->type_idx = (RDI_U32)rdim_idx_from_type(src_member->type); // TODO(rjf): @u64_to_u32 + dst_member->off = src_member->off; + } + } + + //- rjf: fill enum members + else if(src_udt->enum_val_count != 0) + { + dst_udt->flags |= RDI_UserDefinedTypeFlag_EnumMembers; + dst_udt->member_first = dst_enum_member_idx; + dst_udt->member_count = src_udt->enum_val_count; + for(RDIM_UDTEnumVal *src_member = src_udt->first_enum_val; + src_member != 0; + src_member = src_member->next, dst_enum_member_idx += 1) + { + RDI_EnumMember *dst_member = &enum_members[dst_enum_member_idx]; + dst_member->name_string_idx = rdim_bake_idx_from_string(strings, src_member->name); + dst_member->val = src_member->val; + } + } + } + } + } + + //- rjf: build sections + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, udts, sizeof(RDI_UDT) * (params->udts.total_count+1), RDI_DataSectionTag_UDTs, 0); + rdim_bake_section_list_push_new(arena, §ions, members , sizeof(RDI_Member) * (params->udts.total_member_count+1), RDI_DataSectionTag_Members, 0); + rdim_bake_section_list_push_new(arena, §ions, enum_members, sizeof(RDI_EnumMember) * (params->udts.total_enum_val_count+1), RDI_DataSectionTag_EnumMembers, 0); + return sections; +} + +//- rjf: global variables + +RDI_PROC RDIM_BakeSectionList +rdim_bake_global_variable_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params) +{ + //- rjf: build all global variables + RDI_GlobalVariable *global_variables = push_array(arena, RDI_GlobalVariable, params->global_variables.total_count+1); + { + RDI_U32 dst_idx = 1; + for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) + { + RDIM_Symbol *src = &n->v[chunk_idx]; + RDI_GlobalVariable *dst = &global_variables[dst_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); + dst->voff = src->offset; + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); // TODO(rjf): @u64_to_u32 + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: build sections + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, global_variables, sizeof(RDI_GlobalVariable)*(params->global_variables.total_count+1), RDI_DataSectionTag_GlobalVariables, 0); + return sections; +} + +//- rjf: global vmap + +RDI_PROC RDIM_BakeSectionList +rdim_bake_global_vmap_section_list_from_params(RDIM_Arena *arena, RDIM_BakeParams *params) +{ + //- rjf: build global vmap + RDIM_BakeVMap global_vmap = {0}; + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + //- rjf: allocate keys/markers + RDI_U64 marker_count = params->global_variables.total_count*2; + RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, marker_count); + RDIM_VMapMarker *markers = rdim_push_array_no_zero(scratch.arena, RDIM_VMapMarker, marker_count); + + //- rjf: fill + { + RDIM_SortKey *key_ptr = keys; + RDIM_VMapMarker *marker_ptr = markers; + + // rjf: fill actual globals + for(RDIM_SymbolChunkNode *n = params->global_variables.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_Symbol *global_var = &n->v[chunk_idx]; + RDI_U32 global_var_idx = (RDI_U32)rdim_idx_from_symbol(global_var); // TODO(rjf): @u64_to_u32 + + RDI_U64 first = global_var->offset; + RDI_U64 opl = first + global_var->type->byte_size; + + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_var_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_var_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + // rjf: fill nil global + { + RDI_U32 global_idx = 0; + RDI_U64 first = 0; + RDI_U64 opl = 0xffffffffffffffffull; + key_ptr->key = first; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + key_ptr->key = opl; + key_ptr->val = marker_ptr; + marker_ptr->idx = global_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + + // rjf: construct vmap + global_vmap = rdim_bake_vmap_from_markers(arena, markers, keys, marker_count); + + rdim_scratch_end(scratch); + } + + //- rjf: build sections + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, global_vmap.vmap, sizeof(RDI_VMapEntry)*(global_vmap.count+1), RDI_DataSectionTag_GlobalVmap, 0); + return sections; +} + +//- rjf: thread variables + +RDI_PROC RDIM_BakeSectionList +rdim_bake_thread_variable_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params) +{ + //- rjf: build all thread variables + RDI_ThreadVariable *thread_variables = push_array(arena, RDI_ThreadVariable, params->thread_variables.total_count+1); + { + RDI_U32 dst_idx = 1; + for(RDIM_SymbolChunkNode *n = params->thread_variables.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) + { + RDIM_Symbol *src = &n->v[chunk_idx]; + RDI_ThreadVariable *dst = &thread_variables[dst_idx]; + dst->name_string_idx = rdim_bake_idx_from_string(strings, src->name); + dst->tls_off = (RDI_U32)src->offset; // TODO(rjf): @u64_to_u32 + dst->type_idx = (RDI_U32)rdim_idx_from_type(src->type); + if(src->is_extern) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + dst->link_flags |= RDI_LinkFlag_ProcScoped; + dst->container_idx = (RDI_U32)rdim_idx_from_symbol(src->container_symbol); // TODO(rjf): @u64_to_u32 + } + } + } + } + + //- rjf: build sections + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, thread_variables, sizeof(RDI_ThreadVariable)*(params->thread_variables.total_count+1), RDI_DataSectionTag_ThreadVariables, 0); + return sections; +} + +//- rjf: procedures + +RDI_PROC RDIM_BakeSectionList +rdim_bake_procedure_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params) +{ + //- rjf: build all procedures + RDI_Procedure *procedures = push_array(arena, RDI_Procedure, params->procedures.total_count+1); + { + RDI_U32 dst_idx = 1; + for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, dst_idx += 1) + { + RDIM_Symbol *src = &n->v[chunk_idx]; + RDI_Procedure *dst = &procedures[dst_idx]; + 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) + { + dst->link_flags |= RDI_LinkFlag_External; + } + if(src->container_type != 0) + { + dst->link_flags |= RDI_LinkFlag_TypeScoped; + dst->container_idx = src->container_type ? (RDI_U32)rdim_idx_from_udt(src->container_type->udt) : 0; // TODO(rjf): @u64_to_u32 + } + else if(src->container_symbol != 0) + { + 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 + } + } + } + + //- rjf: build sections + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, procedures, sizeof(RDI_Procedure)*(params->procedures.total_count+1), RDI_DataSectionTag_Procedures, 0); + return sections; +} + +//- rjf: scopes + +RDI_PROC RDIM_BakeSectionList +rdim_bake_scope_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params) +{ + 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, params->scopes.total_count+1); + RDI_U64 * scope_voffs = rdim_push_array(arena, RDI_U64, params->scopes.scope_voff_count+1); + RDI_Local * locals = rdim_push_array(arena, RDI_Local, params->scopes.local_count+1); + RDI_LocationBlock * location_blocks = rdim_push_array(arena, RDI_LocationBlock, params->scopes.location_count+1); + RDIM_String8List location_data_blobs = {0}; + RDIM_ProfScope("build all scopes, scope voffs, locals, and location blocks") + { + 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; + for(RDIM_ScopeChunkNode *chunk_n = params->scopes.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]; + + //- rjf: push scope's voffs + RDI_U64 voff_idx_first = dst_scope_voff_idx; + { + for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) + { + scope_voffs[dst_scope_voff_idx] = n->v.min; + dst_scope_voff_idx += 1; + scope_voffs[dst_scope_voff_idx] = n->v.max; + dst_scope_voff_idx += 1; + } + } + RDI_U64 voff_idx_opl = dst_scope_voff_idx; + + //- rjf: push locals + RDI_U64 local_idx_first = dst_local_idx; + for(RDIM_Local *src_local = src_scope->first_local; + 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_AddrRegisterPlusU16: + case RDI_LocationKind_AddrAddrRegisterPlusU16: + { + RDI_LocationRegisterPlusU16 loc = {0}; + loc.kind = src_location->kind; + loc.register_code = src_location->register_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_ValRegister: + { + RDI_LocationRegister loc = {0}; + loc.kind = src_location->kind; + loc.register_code = src_location->register_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; + + //- rjf: fill local + 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 + } + RDI_U64 local_idx_opl = dst_local_idx; + + //- rjf: fill scope + dst_scope->proc_idx = (RDI_U32)rdim_idx_from_symbol(src_scope->symbol); // TODO(rjf): @u64_to_u32 + dst_scope->parent_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->parent_scope); // TODO(rjf): @u64_to_u32 + dst_scope->first_child_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->first_child); // TODO(rjf): @u64_to_u32 + dst_scope->next_sibling_scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope->next_sibling); // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_first = (RDI_U32)voff_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->voff_range_opl = (RDI_U32)voff_idx_opl; // TODO(rjf): @u64_to_u32 + dst_scope->local_first = (RDI_U32)local_idx_first; // TODO(rjf): @u64_to_u32 + dst_scope->local_count = (RDI_U32)(local_idx_opl - local_idx_first); // TODO(rjf): @u64_to_u32 + } + } + } + + //////////////////////////// + //- 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: push all sections + // + RDIM_BakeSectionList sections = {0}; + RDIM_ProfScope("push all symbol info sections") + { + rdim_bake_section_list_push_new(arena, §ions, scopes, sizeof(RDI_Scope) * (params->scopes.total_count+1), RDI_DataSectionTag_Scopes, 0); + rdim_bake_section_list_push_new(arena, §ions, scope_voffs, sizeof(RDI_U64) * (params->scopes.scope_voff_count+1), RDI_DataSectionTag_ScopeVoffData, 0); + rdim_bake_section_list_push_new(arena, §ions, locals, sizeof(RDI_Local) * (params->scopes.local_count+1), RDI_DataSectionTag_Locals, 0); + rdim_bake_section_list_push_new(arena, §ions, location_blocks, sizeof(RDI_LocationBlock) * (params->scopes.location_count+1), RDI_DataSectionTag_LocationBlocks, 0); + rdim_bake_section_list_push_new(arena, §ions, location_data_blob.str, location_data_blob.size, RDI_DataSectionTag_LocationData, 0); + } + rdim_scratch_end(scratch); + return sections; +} + +//- rjf: scope vmap + +RDI_PROC RDIM_BakeSectionList +rdim_bake_scope_vmap_section_list_from_params(RDIM_Arena *arena, RDIM_BakeParams *params) +{ + //- rjf: build scope vmap + RDIM_BakeVMap scope_vmap = {0}; + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + // rjf: allocate keys/markers + RDI_U64 marker_count = params->scopes.scope_voff_count; + RDIM_SortKey *keys = rdim_push_array_no_zero(scratch.arena, RDIM_SortKey, marker_count); + RDIM_VMapMarker *markers = rdim_push_array_no_zero(scratch.arena, RDIM_VMapMarker, marker_count); + + // rjf: fill + { + RDIM_SortKey *key_ptr = keys; + RDIM_VMapMarker *marker_ptr = markers; + for(RDIM_ScopeChunkNode *chunk_n = params->scopes.first; chunk_n != 0; chunk_n = chunk_n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < chunk_n->count; chunk_idx += 1) + { + RDIM_Scope *src_scope = &chunk_n->v[chunk_idx]; + RDI_U32 scope_idx = (RDI_U32)rdim_idx_from_scope(src_scope); // TODO(rjf): @u64_to_u32 + for(RDIM_Rng1U64Node *n = src_scope->voff_ranges.first; n != 0; n = n->next) + { + key_ptr->key = n->v.min; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 1; + key_ptr += 1; + marker_ptr += 1; + + key_ptr->key = n->v.max; + key_ptr->val = marker_ptr; + marker_ptr->idx = scope_idx; + marker_ptr->begin_range = 0; + key_ptr += 1; + marker_ptr += 1; + } + } + } + } + + // rjf: produce vmap + scope_vmap = rdim_bake_vmap_from_markers(arena, markers, keys, marker_count); + rdim_scratch_end(scratch); + } + + //- rjf: build sections + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, scope_vmap.vmap, sizeof(RDI_VMapEntry)*(scope_vmap.count+1), RDI_DataSectionTag_ScopeVmap, 0); + return sections; +} + +//- rjf: name maps + +RDI_PROC RDIM_BakeSectionList +rdim_bake_top_level_name_map_section_list_from_params_maps(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeParams *params, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT]) +{ + RDIM_BakeSectionList sections = {0}; + + //- rjf: count the # of name maps we have with any content + RDI_U32 name_map_count = 0; + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + if(name_maps[k] != 0 && name_maps[k]->name_count != 0) + { + name_map_count += 1; + } + } + + //- rjf: allocate & fill baked name maps + RDI_NameMap *dst_maps = rdim_push_array(arena, RDI_NameMap, name_map_count); + { + RDI_U64 dst_map_idx = 0; + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + RDI_NameMap *dst_map = &dst_maps[dst_map_idx]; + RDIM_BakeNameMap *src_map = name_maps[k]; + if(src_map == 0 || src_map->name_count == 0) { continue; } + dst_map->kind = k; + dst_map->bucket_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_NameMapBuckets, (RDI_U64)k); // TODO(rjf): @u64_to_u32 + dst_map->node_data_idx = (RDI_U32)rdim_bake_section_idx_from_params_tag_idx(params, RDI_DataSectionTag_NameMapNodes, (RDI_U64)k); // TODO(rjf): @u64_to_u32 + dst_map_idx += 1; + } + } + + // rjf: push section for all name maps + rdim_bake_section_list_push_new(arena, §ions, dst_maps, sizeof(RDI_NameMap)*name_map_count, RDI_DataSectionTag_NameMaps, 0); + return sections; +} + +RDI_PROC RDIM_BakeSectionList +rdim_bake_name_map_section_list_from_params_kind_map(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeParams *params, RDI_NameMapKind k, RDIM_BakeNameMap *map) +{ + RDIM_BakeSectionList sections = {0}; + if(map != 0 && map->name_count != 0) + { + RDI_U32 baked_buckets_count = map->name_count; + RDI_U32 baked_nodes_count = map->name_count; + RDI_NameMapBucket *baked_buckets = rdim_push_array(arena, RDI_NameMapBucket, baked_buckets_count); + RDI_NameMapNode *baked_nodes = rdim_push_array_no_zero(arena, RDI_NameMapNode, baked_nodes_count); + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + // rjf: setup the final bucket layouts + typedef struct RDIM_NameMapSemiNode RDIM_NameMapSemiNode; + struct RDIM_NameMapSemiNode + { + RDIM_NameMapSemiNode *next; + RDIM_BakeNameMapNode *node; + }; + typedef struct RDIM_NameMapSemiBucket RDIM_NameMapSemiBucket; + struct RDIM_NameMapSemiBucket + { + RDIM_NameMapSemiNode *first; + RDIM_NameMapSemiNode *last; + RDI_U64 count; + }; + RDIM_NameMapSemiBucket *sbuckets = rdim_push_array(scratch.arena, RDIM_NameMapSemiBucket, baked_buckets_count); + for(RDIM_BakeNameMapNode *node = map->first; + node != 0; + node = node->order_next) + { + RDI_U64 hash = rdi_hash(node->string.str, node->string.size); + RDI_U64 bi = hash%baked_buckets_count; + RDIM_NameMapSemiNode *snode = rdim_push_array(scratch.arena, RDIM_NameMapSemiNode, 1); + SLLQueuePush(sbuckets[bi].first, sbuckets[bi].last, snode); + snode->node = node; + sbuckets[bi].count += 1; + } + + // rjf: convert to serialized buckets & nodes + { + RDI_NameMapBucket *bucket_ptr = baked_buckets; + RDI_NameMapNode *node_ptr = baked_nodes; + for(RDI_U32 i = 0; i < baked_buckets_count; i += 1, bucket_ptr += 1) + { + bucket_ptr->first_node = (RDI_U32)(node_ptr - baked_nodes); + bucket_ptr->node_count = sbuckets[i].count; + for(RDIM_NameMapSemiNode *snode = sbuckets[i].first; + snode != 0; + snode = snode->next) + { + RDIM_BakeNameMapNode *node = snode->node; + + // rjf: cons name and index(es) + RDI_U32 string_idx = rdim_bake_idx_from_string(strings, node->string); + RDI_U32 match_count = node->val_count; + RDI_U32 idx = 0; + if(match_count == 1) + { + idx = node->val_first->val[0]; + } + else + { + RDI_U64 temp_pos = rdim_arena_pos(scratch.arena); + RDI_U32 *idx_run = rdim_push_array_no_zero(scratch.arena, RDI_U32, match_count); + RDI_U32 *idx_ptr = idx_run; + for(RDIM_BakeNameMapValNode *idxnode = node->val_first; + idxnode != 0; + idxnode = idxnode->next) + { + for(RDI_U32 i = 0; i < sizeof(idxnode->val)/sizeof(idxnode->val[0]); i += 1) + { + if(idxnode->val[i] == 0) + { + goto dblbreak; + } + *idx_ptr = idxnode->val[i]; + idx_ptr += 1; + } + } + dblbreak:; + idx = rdim_bake_idx_from_idx_run(idx_runs, idx_run, match_count); + rdim_arena_pop_to(scratch.arena, temp_pos); + } + + // rjf: write to node + node_ptr->string_idx = string_idx; + node_ptr->match_count = match_count; + node_ptr->match_idx_or_idx_run_first = idx; + node_ptr += 1; + } + } + } + rdim_scratch_end(scratch); + } + + // rjf: sections for buckets/nodes + rdim_bake_section_list_push_new(arena, §ions, baked_buckets, sizeof(RDI_NameMapBucket)* baked_buckets_count, RDI_DataSectionTag_NameMapBuckets, (RDI_U64)k); + rdim_bake_section_list_push_new(arena, §ions, baked_nodes, sizeof(RDI_NameMapNode) * baked_nodes_count, RDI_DataSectionTag_NameMapNodes, (RDI_U64)k); + } + return sections; +} + +//- rjf: file paths + +RDI_PROC RDIM_BakeSectionList +rdim_bake_file_path_section_list_from_path_tree(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree) +{ + RDI_U32 dst_nodes_count = path_tree->count; + RDI_FilePathNode *dst_nodes = rdim_push_array(arena, RDI_FilePathNode, dst_nodes_count); + { + RDI_U32 dst_node_idx = 0; + for(RDIM_BakePathNode *src_node = path_tree->first; + src_node != 0; + src_node = src_node->next_order, dst_node_idx += 1) + { + RDI_FilePathNode *dst_node = &dst_nodes[dst_node_idx]; + dst_node->name_string_idx = rdim_bake_idx_from_string(strings, src_node->name); + dst_node->source_file_idx = rdim_idx_from_src_file(src_node->src_file); + if(src_node->parent != 0) + { + dst_node->parent_path_node = src_node->parent->idx; + } + if(src_node->first_child != 0) + { + dst_node->first_child = src_node->first_child->idx; + } + if(src_node->next_sibling != 0) + { + dst_node->next_sibling = src_node->next_sibling->idx; + } + } + } + RDIM_BakeSectionList sections = {0}; + rdim_bake_section_list_push_new(arena, §ions, dst_nodes, sizeof(RDI_FilePathNode)*dst_nodes_count, RDI_DataSectionTag_FilePathNodes, 0); + return sections; +} + +//- rjf: strings + +RDI_PROC RDIM_BakeSectionList +rdim_bake_string_section_list_from_string_map(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings) +{ + RDIM_BakeSectionList sections = {0}; + RDI_U32 *str_offs = rdim_push_array_no_zero(arena, RDI_U32, strings->total_count + 1); + RDI_U32 off_cursor = 0; + { + RDI_U32 *off_ptr = str_offs; + *off_ptr = 0; + off_ptr += 1; + for(RDI_U64 slot_idx = 0; slot_idx < strings->slots_count; slot_idx += 1) + { + for(RDIM_BakeStringChunkNode *n = strings->slots[slot_idx].first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_BakeString *bake_string = &n->v[chunk_idx]; + off_cursor += bake_string->string.size; + *off_ptr = off_cursor; + off_ptr += 1; + } + } + } + } + RDI_U8 *buf = rdim_push_array(arena, RDI_U8, off_cursor); + { + RDI_U8 *ptr = buf; + for(RDI_U64 slot_idx = 0; slot_idx < strings->slots_count; slot_idx += 1) + { + for(RDIM_BakeStringChunkNode *n = strings->slots[slot_idx].first; n != 0; n = n->next) + { + for(RDI_U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1) + { + RDIM_BakeString *bake_string = &n->v[chunk_idx]; + rdim_memcpy(ptr, bake_string->string.str, bake_string->string.size); + ptr += bake_string->string.size; + } + } + } + } + rdim_bake_section_list_push_new(arena, §ions, str_offs, sizeof(RDI_U32)*(strings->total_count+1), RDI_DataSectionTag_StringTable, 0); + rdim_bake_section_list_push_new(arena, §ions, buf, off_cursor, RDI_DataSectionTag_StringData, 0); + return sections; +} + +//- rjf: index runs + +RDI_PROC RDIM_BakeSectionList +rdim_bake_idx_run_section_list_from_idx_run_map(RDIM_Arena *arena, RDIM_BakeIdxRunMap *idx_runs) +{ + RDIM_BakeSectionList sections = {0}; + RDI_U32 *idx_data = rdim_push_array_no_zero(arena, RDI_U32, idx_runs->idx_count); + { + RDI_U32 *out_ptr = idx_data; + RDI_U32 *opl = out_ptr + idx_runs->idx_count; + for(RDIM_BakeIdxRunNode *node = idx_runs->order_first; + node != 0 && out_ptr < opl; + node = node->order_next) + { + rdim_memcpy(out_ptr, node->idx_run, sizeof(*node->idx_run)*node->count); + out_ptr += node->count; + } + } + rdim_bake_section_list_push_new(arena, §ions, idx_data, sizeof(RDI_U32)*idx_runs->idx_count, RDI_DataSectionTag_IndexRuns, 0); + return sections; +} + +//////////////////////////////// +//~ rjf: [Serializing] Baked Data Section List -> Serialized Binary Strings + +RDI_PROC RDIM_String8List +rdim_serialized_strings_from_params_bake_section_list(RDIM_Arena *arena, RDIM_BakeParams *params, RDIM_BakeSectionList *sections) +{ + RDIM_String8List strings; + rdim_memzero_struct(&strings); + { + RDIM_Temp scratch = rdim_scratch_begin(&arena, 1); + + //- rjf: calculate total possible section count, given these params + RDI_U64 section_count = rdim_bake_section_count_from_params(params); + + //- rjf: make table for actually laid out sections + RDIM_BakeSection **bake_sections = rdim_push_array(scratch.arena, RDIM_BakeSection *, section_count); + for(RDIM_BakeSectionNode *n = sections->first; n != 0; n = n->next) + { + RDIM_BakeSection *bake_section = &n->v; + RDI_U64 idx = rdim_bake_section_idx_from_params_tag_idx(params, bake_section->tag, bake_section->tag_idx); + if(0 <= idx && idx < section_count) + { + if(bake_sections[idx] != 0) + { + // TODO(rjf): error - malformed input! we have a duplicate section. + } + else + { + bake_sections[idx] = bake_section; + } + } + } + + //- rjf: push empty header & data section table + RDI_Header *rdi_header = rdim_push_array(arena, RDI_Header, 1); + RDI_DataSection *rdi_sections = rdim_push_array(arena, RDI_DataSection, section_count); + rdim_str8_list_push(arena, &strings, rdim_str8_struct(rdi_header)); + rdim_str8_list_push_align(arena, &strings, 8); + U32 data_section_off = (U32)strings.total_size; + rdim_str8_list_push(arena, &strings, rdim_str8((RDI_U8 *)rdi_sections, sizeof(RDI_DataSection)*section_count)); + + // rjf: fill baked header + { + rdi_header->magic = RDI_MAGIC_CONSTANT; + rdi_header->encoding_version = RDI_ENCODING_VERSION; + rdi_header->data_section_off = data_section_off; + rdi_header->data_section_count = section_count; + } + + // rjf: fill baked data section table + U64 dst_idx = 0; + for(RDI_U64 src_idx = 0; src_idx < section_count; src_idx += 1, dst_idx += 1) + { + RDIM_BakeSection *src = bake_sections[src_idx]; + if(src == 0) { continue; } + RDI_DataSection *dst = rdi_sections+dst_idx; + U64 data_section_off = 0; + if(src->size != 0) + { + rdim_str8_list_push_align(arena, &strings, 8); + data_section_off = strings.total_size; + rdim_str8_list_push(arena, &strings, rdim_str8((RDI_U8 *)src->data, src->size)); + } + dst->tag = src->tag; + dst->encoding = RDI_DataSectionEncoding_Unpacked; + dst->off = data_section_off; + dst->encoded_size = src->size; + dst->unpacked_size = src->size; + } + + rdim_scratch_end(scratch); + } + return strings; +} diff --git a/src/lib_raddbgi_make/raddbgi_make.h b/src/lib_raddbgi_make/raddbgi_make.h new file mode 100644 index 00000000..3cb989f0 --- /dev/null +++ b/src/lib_raddbgi_make/raddbgi_make.h @@ -0,0 +1,1253 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////////////////////////////////////// +// RAD Debug Info Make, (R)AD(D)BG(I) (M)ake Library +// +// Library for building loose data structures which contain +// RADDBGI debug information, and baking that down into the +// proper flattened RADDBGI format. +// +// Requires prior inclusion of the RAD Debug Info, (R)AD(D)BG(I) +// Format Library, in raddbgi_format.h. + +#ifndef RADDBGI_MAKE_H +#define RADDBGI_MAKE_H + +//////////////////////////////// +//~ rjf: Overrideable Memory Operations + +// To override the slow/default memset implementation used by the library, +// do the following: +// +// #define RDIM_MEMSET_OVERRIDE +// #define rdim_memset + +#if !defined(rdim_memset) +# define rdim_memset rdim_memset_fallback +#endif + +// To override the slow/default memcpy implementation used by the library, +// do the following: +// +// #define RDIM_MEMCPY_OVERRIDE +// #define rdim_memcpy + +#if !defined(rdim_memset) +# define rdim_memset rdim_memset_fallback +#endif + +#if !defined(rdim_memcpy) +# define rdim_memcpy rdim_memcpy_fallback +#endif + +//////////////////////////////// +//~ rjf: Overrideable sprintf Functions + +#if !defined(rdim_vsnprintf) +# include +# define rdim_vsnprintf vsnprintf +#endif + +//////////////////////////////// +//~ rjf: Overrideable String View Types + +// To override the string view type used by the library, do the following: +// +// #define RDIM_STRING8_OVERRIDE +// #define RDIM_String8 +// #define RDIM_String8_BaseMember +// #define RDIM_String8_SizeMember + +// To override the string view list type used by the library, do the following: +// +// #define RDIM_STRING8LIST_OVERRIDE +// #define RDIM_String8Node +// #define RDIM_String8_NextPtrMember +// #define RDIM_String8_StringMember +// #define RDIM_String8List +// #define RDIM_String8_FirstMember +// #define RDIM_String8_LastMember +// #define RDIM_String8_NodeCount +// #define RDIM_String8_TotalSizeMember + +#if !defined(RDIM_String8) +#define RDIM_String8 RDIM_String8 +#define RDIM_String8_BaseMember str +#define RDIM_String8_SizeMember size +typedef struct RDIM_String8 RDIM_String8; +struct RDIM_String8 +{ + RDI_U8 *str; + RDI_U64 size; +}; +#endif + +#if !defined(RDIM_String8Node) +#define RDIM_String8Node RDIM_String8Node +#define RDIM_String8Node_NextPtrMember next +#define RDIM_String8Node_StringMember string +typedef struct RDIM_String8Node RDIM_String8Node; +struct RDIM_String8Node +{ + RDIM_String8Node *next; + RDIM_String8 string; +}; +#endif + +#if !defined(RDIM_String8List) +#define RDIM_String8List RDIM_String8List +#define RDIM_String8List_FirstMember first +#define RDIM_String8List_LastMember last +#define RDIM_String8List_NodeCountMember node_count +#define RDIM_String8List_TotalSizeMember total_size +typedef struct RDIM_String8List RDIM_String8List; +struct RDIM_String8List +{ + RDIM_String8Node *first; + RDIM_String8Node *last; + RDI_U64 node_count; + RDI_U64 total_size; +}; +#endif + +typedef RDI_U32 RDIM_StringMatchFlags; +enum +{ + RDIM_StringMatchFlag_CaseInsensitive = (1<<0), +}; + +//////////////////////////////// +//~ rjf: Overrideable Arena Allocator Types + +// To override the arena allocator type used by the library, do the following: +// +// #define RDIM_ARENA_OVERRIDE +// #define RDIM_Arena +// #define rdim_arena_alloc Arena*> +// #define rdim_arena_release void> +// #define rdim_arena_pos U64> +// #define rdim_arena_push void*> +// #define rdim_arena_pop_to void> + +#if !defined(RDIM_Arena) +# define RDIM_Arena RDIM_Arena +typedef struct RDIM_Arena RDIM_Arena; +struct RDIM_Arena +{ + RDIM_Arena *prev; + RDIM_Arena *current; + RDI_U64 base_pos; + RDI_U64 pos; + RDI_U64 cmt; + RDI_U64 res; + RDI_U64 align; + RDI_S8 grow; +}; +#endif + +#if !defined(rdim_arena_alloc) +# define rdim_arena_alloc rdim_arena_alloc_fallback +#endif +#if !defined(rdim_arena_release) +# define rdim_arena_release rdim_arena_release_fallback +#endif +#if !defined(rdim_arena_pos) +# define rdim_arena_pos rdim_arena_pos_fallback +#endif +#if !defined(rdim_arena_push) +# define rdim_arena_push rdim_arena_push_fallback +#endif + +//////////////////////////////// +//~ rjf: Overrideable Thread-Local Scratch Arenas + +// To override the default thread-local scratch arenas used by the library, +// do the following: +// +// #define RDIM_SCRATCH_OVERRIDE +// #define RDIM_Temp arena implementation - must be (Temp) -> (Arena*)> +// #define rdim_scratch_begin Temp> +// #define rdim_scratch_end void + +#if !defined(RDIM_Temp) +# define RDIM_Temp RDIM_Temp +typedef struct RDIM_Temp RDIM_Temp; +struct RDIM_Temp +{ + RDIM_Arena *arena; + RDI_U64 pos; +}; +#define rdim_temp_arena(t) ((t).arena) +#endif + +#if !defined(rdim_scratch_begin) +# define rdim_scratch_begin rdim_scratch_begin_fallback +#endif +#if !defined(rdim_scratch_end) +# define rdim_scratch_end rdim_scratch_end_fallback +#endif + +//////////////////////////////// +//~ rjf: Overrideable Profile Markup + +// To override the default profiling markup, do the following: +// +// #define RDIM_ProfBegin(...) +// #define RDIM_ProfEnd() + +#if !defined(RDIM_ProfBegin) +# define RDIM_ProfBegin(...) ((void)0) +#endif +#if !defined(RDIM_ProfEnd) +# define RDIM_ProfEnd() ((void)0) +#endif + +#define RDIM_ProfScope(...) for(int _i_ = ((RDIM_ProfBegin(__VA_ARGS__)), 0); !_i_; _i_ += 1, (RDIM_ProfEnd())) + +//////////////////////////////// +//~ rjf: Linked List Helper Macros + +#define RDIM_CheckNil(nil,p) ((p) == 0 || (p) == nil) +#define RDIM_SetNil(nil,p) ((p) = nil) + +//- rjf: Base Doubly-Linked-List Macros +#define RDIM_DLLInsert_NPZ(nil,f,l,p,n,next,prev) (RDIM_CheckNil(nil,f) ? \ +((f) = (l) = (n), RDIM_SetNil(nil,(n)->next), RDIM_SetNil(nil,(n)->prev)) :\ +RDIM_CheckNil(nil,p) ? \ +((n)->next = (f), (f)->prev = (n), (f) = (n), RDIM_SetNil(nil,(n)->prev)) :\ +((p)==(l)) ? \ +((l)->next = (n), (n)->prev = (l), (l) = (n), RDIM_SetNil(nil, (n)->next)) :\ +(((!RDIM_CheckNil(nil,p) && RDIM_CheckNil(nil,(p)->next)) ? (0) : ((p)->next->prev = (n))), ((n)->next = (p)->next), ((p)->next = (n)), ((n)->prev = (p)))) +#define RDIM_DLLPushBack_NPZ(nil,f,l,n,next,prev) RDIM_DLLInsert_NPZ(nil,f,l,l,n,next,prev) +#define RDIM_DLLPushFront_NPZ(nil,f,l,n,next,prev) RDIM_DLLInsert_NPZ(nil,l,f,f,n,prev,next) +#define RDIM_DLLRemove_NPZ(nil,f,l,n,next,prev) (((n) == (f) ? (f) = (n)->next : (0)),\ +((n) == (l) ? (l) = (l)->prev : (0)),\ +(RDIM_CheckNil(nil,(n)->prev) ? (0) :\ +((n)->prev->next = (n)->next)),\ +(RDIM_CheckNil(nil,(n)->next) ? (0) :\ +((n)->next->prev = (n)->prev))) + +//- rjf: Base Singly-Linked-List Queue Macros +#define RDIM_SLLQueuePush_NZ(nil,f,l,n,next) (RDIM_CheckNil(nil,f)?\ +((f)=(l)=(n),RDIM_SetNil(nil,(n)->next)):\ +((l)->next=(n),(l)=(n),RDIM_SetNil(nil,(n)->next))) +#define RDIM_SLLQueuePushFront_NZ(nil,f,l,n,next) (RDIM_CheckNil(nil,f)?\ +((f)=(l)=(n),RDIM_SetNil(nil,(n)->next)):\ +((n)->next=(f),(f)=(n))) +#define RDIM_SLLQueuePop_NZ(nil,f,l,next) ((f)==(l)?\ +(RDIM_SetNil(nil,f), RDIM_SetNil(nil,l)):\ +((f)=(f)->next)) + +//- rjf: Base Singly-Linked-List Stack Macros +#define RDIM_SLLStackPush_N(f,n,next) ((n)->next=(f), (f)=(n)) +#define RDIM_SLLStackPop_N(f,next) ((f)=(f)->next) + +//////////////////////////////// +//~ rjf: Convenience Wrappers + +//- rjf: Doubly-Linked-List Wrappers +#define RDIM_DLLInsert_NP(f,l,p,n,next,prev) RDIM_DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define RDIM_DLLPushBack_NP(f,l,n,next,prev) RDIM_DLLPushBack_NPZ(0,f,l,n,next,prev) +#define RDIM_DLLPushFront_NP(f,l,n,next,prev) RDIM_DLLPushFront_NPZ(0,f,l,n,next,prev) +#define RDIM_DLLRemove_NP(f,l,n,next,prev) RDIM_DLLRemove_NPZ(0,f,l,n,next,prev) +#define RDIM_DLLInsert(f,l,p,n) RDIM_DLLInsert_NPZ(0,f,l,p,n,next,prev) +#define RDIM_DLLPushBack(f,l,n) RDIM_DLLPushBack_NPZ(0,f,l,n,next,prev) +#define RDIM_DLLPushFront(f,l,n) RDIM_DLLPushFront_NPZ(0,f,l,n,next,prev) +#define RDIM_DLLRemove(f,l,n) RDIM_DLLRemove_NPZ(0,f,l,n,next,prev) + +//- rjf: Singly-Linked-List Queue Wrappers +#define RDIM_SLLQueuePush_N(f,l,n,next) RDIM_SLLQueuePush_NZ(0,f,l,n,next) +#define RDIM_SLLQueuePushFront_N(f,l,n,next) RDIM_SLLQueuePushFront_NZ(0,f,l,n,next) +#define RDIM_SLLQueuePop_N(f,l,next) RDIM_SLLQueuePop_NZ(0,f,l,next) +#define RDIM_SLLQueuePush(f,l,n) RDIM_SLLQueuePush_NZ(0,f,l,n,next) +#define RDIM_SLLQueuePushFront(f,l,n) RDIM_SLLQueuePushFront_NZ(0,f,l,n,next) +#define RDIM_SLLQueuePop(f,l) RDIM_SLLQueuePop_NZ(0,f,l,next) + +//- rjf: Singly-Linked-List Stack Wrappers +#define RDIM_SLLStackPush(f,n) RDIM_SLLStackPush_N(f,n,next) +#define RDIM_SLLStackPop(f) RDIM_SLLStackPop_N(f,next) + +//////////////////////////////// +//~ rjf: Helper Macros + +#if defined(_MSC_VER) +# define RDIM_THREAD_LOCAL __declspec(thread) +#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +# define RDIM_THREAD_LOCAL __thread +#else +# error RDIM_THREAD_LOCAL not defined for this compiler. +#endif + +#if defined(_MSC_VER) +# define rdim_trap() __debugbreak() +#elif defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) +# define rdim_trap() __builtin_trap() +#else +# error "rdim_trap not defined for this compiler." +#endif + +#define rdim_assert_always(x) do{if(!(x)) {rdim_trap();}}while(0) +#if !defined(NDEBUG) +# define rdim_assert(x) rdim_assert_always(x) +#else +# define rdim_assert(x) (void)(x) +#endif +#define rdim_noop ((void)0) + +//////////////////////////////// +//~ rjf: Auxiliary Data Structure Types + +//- rjf: 1-dimensional U64 ranges + +typedef struct RDIM_Rng1U64 RDIM_Rng1U64; +struct RDIM_Rng1U64 +{ + RDI_U64 min; + RDI_U64 max; +}; + +typedef struct RDIM_Rng1U64Node RDIM_Rng1U64Node; +struct RDIM_Rng1U64Node +{ + RDIM_Rng1U64Node *next; + RDIM_Rng1U64 v; +}; + +typedef struct RDIM_Rng1U64List RDIM_Rng1U64List; +struct RDIM_Rng1U64List +{ + RDIM_Rng1U64Node *first; + RDIM_Rng1U64Node *last; + RDI_U64 count; + RDI_U64 min; +}; + +//- rjf: u64 -> pointer map + +typedef struct RDIM_U64ToPtrNode RDIM_U64ToPtrNode; +struct RDIM_U64ToPtrNode +{ + RDIM_U64ToPtrNode *next; + RDI_U64 _padding_; + RDI_U64 key[1]; + void *ptr[1]; +}; + +typedef struct RDIM_U64ToPtrMap RDIM_U64ToPtrMap; +struct RDIM_U64ToPtrMap +{ + RDIM_U64ToPtrNode **buckets; + RDI_U64 buckets_count; + RDI_U64 bucket_collision_count; + RDI_U64 pair_count; +}; + +typedef struct RDIM_U64ToPtrLookup RDIM_U64ToPtrLookup; +struct RDIM_U64ToPtrLookup +{ + void *match; + RDIM_U64ToPtrNode *fill_node; + RDI_U32 fill_k; +}; + +//- rjf: string8 -> pointer map + +typedef struct RDIM_Str8ToPtrNode RDIM_Str8ToPtrNode; +struct RDIM_Str8ToPtrNode +{ + struct RDIM_Str8ToPtrNode *next; + RDIM_String8 key; + RDI_U64 hash; + void *ptr; +}; + +typedef struct RDIM_Str8ToPtrMap RDIM_Str8ToPtrMap; +struct RDIM_Str8ToPtrMap +{ + RDIM_Str8ToPtrNode **buckets; + RDI_U64 buckets_count; + RDI_U64 bucket_collision_count; + RDI_U64 pair_count; +}; + +//- rjf: sortable range data structure + +typedef struct RDIM_SortKey RDIM_SortKey; +struct RDIM_SortKey +{ + RDI_U64 key; + void *val; +}; + +typedef struct RDIM_OrderedRange RDIM_OrderedRange; +struct RDIM_OrderedRange +{ + RDIM_OrderedRange *next; + RDI_U64 first; + RDI_U64 opl; +}; + +//////////////////////////////// +//~ rjf: Error/Warning/Note Message Types + +typedef struct RDIM_Msg RDIM_Msg; +struct RDIM_Msg +{ + RDIM_Msg *next; + RDIM_String8 string; +}; + +typedef struct RDIM_MsgList RDIM_MsgList; +struct RDIM_MsgList +{ + RDIM_Msg *first; + RDIM_Msg *last; + RDI_U64 count; +}; + +//////////////////////////////// +//~ rjf: Top-Level Debug Info Types + +typedef struct RDIM_TopLevelInfo RDIM_TopLevelInfo; +struct RDIM_TopLevelInfo +{ + RDI_Arch arch; + RDIM_String8 exe_name; + RDI_U64 exe_hash; + RDI_U64 voff_max; +}; + +//////////////////////////////// +//~ rjf: Binary Section Types + +typedef struct RDIM_BinarySection RDIM_BinarySection; +struct RDIM_BinarySection +{ + RDIM_String8 name; + RDI_BinarySectionFlags flags; + RDI_U64 voff_first; + RDI_U64 voff_opl; + RDI_U64 foff_first; + RDI_U64 foff_opl; +}; + +typedef struct RDIM_BinarySectionNode RDIM_BinarySectionNode; +struct RDIM_BinarySectionNode +{ + RDIM_BinarySectionNode *next; + RDIM_BinarySection v; +}; + +typedef struct RDIM_BinarySectionList RDIM_BinarySectionList; +struct RDIM_BinarySectionList +{ + RDIM_BinarySectionNode *first; + RDIM_BinarySectionNode *last; + RDI_U64 count; +}; + +//////////////////////////////// +//~ rjf: Source File Info Types + +typedef struct RDIM_SrcFileLineMapFragment RDIM_SrcFileLineMapFragment; +struct RDIM_SrcFileLineMapFragment +{ + RDIM_SrcFileLineMapFragment *next; + struct RDIM_LineSequence *seq; +}; + +typedef struct RDIM_SrcFile RDIM_SrcFile; +struct RDIM_SrcFile +{ + struct RDIM_SrcFileChunkNode *chunk; + RDIM_String8 normal_full_path; + RDIM_SrcFileLineMapFragment *first_line_map_fragment; + RDIM_SrcFileLineMapFragment *last_line_map_fragment; +}; + +typedef struct RDIM_SrcFileChunkNode RDIM_SrcFileChunkNode; +struct RDIM_SrcFileChunkNode +{ + RDIM_SrcFileChunkNode *next; + RDIM_SrcFile *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_SrcFileChunkList RDIM_SrcFileChunkList; +struct RDIM_SrcFileChunkList +{ + RDIM_SrcFileChunkNode *first; + RDIM_SrcFileChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +//////////////////////////////// +//~ rjf: Per-Compilation-Unit Info Types + +typedef struct RDIM_LineSequence RDIM_LineSequence; +struct RDIM_LineSequence +{ + RDIM_SrcFile *src_file; + RDI_U64 *voffs; // [line_count + 1] (sorted) + RDI_U32 *line_nums; // [line_count] + RDI_U16 *col_nums; // [2*line_count] + RDI_U64 line_count; +}; + +typedef struct RDIM_LineSequenceNode RDIM_LineSequenceNode; +struct RDIM_LineSequenceNode +{ + RDIM_LineSequenceNode *next; + RDIM_LineSequence v; +}; + +typedef struct RDIM_LineSequenceList RDIM_LineSequenceList; +struct RDIM_LineSequenceList +{ + RDIM_LineSequenceNode *first; + RDIM_LineSequenceNode *last; + RDI_U64 count; +}; + +typedef struct RDIM_Unit RDIM_Unit; +struct RDIM_Unit +{ + struct RDIM_UnitChunkNode *chunk; + RDIM_String8 unit_name; + RDIM_String8 compiler_name; + RDIM_String8 source_file; + RDIM_String8 object_file; + RDIM_String8 archive_file; + RDIM_String8 build_path; + RDI_Language language; + RDIM_LineSequenceList line_sequences; + RDIM_Rng1U64List voff_ranges; +}; + +typedef struct RDIM_UnitChunkNode RDIM_UnitChunkNode; +struct RDIM_UnitChunkNode +{ + RDIM_UnitChunkNode *next; + RDIM_Unit *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_UnitChunkList RDIM_UnitChunkList; +struct RDIM_UnitChunkList +{ + RDIM_UnitChunkNode *first; + RDIM_UnitChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +//////////////////////////////// +//~ rjf: Type System Node Types + +typedef struct RDIM_Type RDIM_Type; +struct RDIM_Type +{ + struct RDIM_TypeChunkNode *chunk; + RDI_TypeKind kind; + RDI_U32 byte_size; + RDI_U32 flags; + RDI_U32 off; + RDI_U32 count; + RDIM_String8 name; + RDIM_Type *direct_type; + RDIM_Type **param_types; + struct RDIM_UDT *udt; +}; + +typedef struct RDIM_TypeChunkNode RDIM_TypeChunkNode; +struct RDIM_TypeChunkNode +{ + RDIM_TypeChunkNode *next; + RDIM_Type *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_TypeChunkList RDIM_TypeChunkList; +struct RDIM_TypeChunkList +{ + RDIM_TypeChunkNode *first; + RDIM_TypeChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +//////////////////////////////// +//~ rjf: User-Defined-Type Info Types + +typedef struct RDIM_UDTMember RDIM_UDTMember; +struct RDIM_UDTMember +{ + RDIM_UDTMember *next; + RDI_MemberKind kind; + RDIM_String8 name; + RDIM_Type *type; + RDI_U32 off; +}; + +typedef struct RDIM_UDTEnumVal RDIM_UDTEnumVal; +struct RDIM_UDTEnumVal +{ + RDIM_UDTEnumVal *next; + RDIM_String8 name; + RDI_U64 val; +}; + +typedef struct RDIM_UDT RDIM_UDT; +struct RDIM_UDT +{ + struct RDIM_UDTChunkNode *chunk; + RDIM_Type *self_type; + RDIM_UDTMember *first_member; + RDIM_UDTMember *last_member; + RDIM_UDTEnumVal *first_enum_val; + RDIM_UDTEnumVal *last_enum_val; + RDI_U32 member_count; + RDI_U32 enum_val_count; + RDIM_SrcFile *src_file; + RDI_U32 line; + RDI_U32 col; +}; + +typedef struct RDIM_UDTChunkNode RDIM_UDTChunkNode; +struct RDIM_UDTChunkNode +{ + RDIM_UDTChunkNode *next; + RDIM_UDT *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_UDTChunkList RDIM_UDTChunkList; +struct RDIM_UDTChunkList +{ + RDIM_UDTChunkNode *first; + RDIM_UDTChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; + RDI_U64 total_member_count; + RDI_U64 total_enum_val_count; +}; + +//////////////////////////////// +//~ rjf: Location Info Types + +typedef struct RDIM_EvalBytecodeOp RDIM_EvalBytecodeOp; +struct RDIM_EvalBytecodeOp +{ + RDIM_EvalBytecodeOp *next; + RDI_EvalOp op; + RDI_U32 p_size; + RDI_U64 p; +}; + +typedef struct RDIM_EvalBytecode RDIM_EvalBytecode; +struct RDIM_EvalBytecode +{ + RDIM_EvalBytecodeOp *first_op; + RDIM_EvalBytecodeOp *last_op; + RDI_U32 op_count; + RDI_U32 encoded_size; +}; + +typedef struct RDIM_Location RDIM_Location; +struct RDIM_Location +{ + RDI_LocationKind kind; + RDI_U8 register_code; + RDI_U16 offset; + RDIM_EvalBytecode bytecode; +}; + +typedef struct RDIM_LocationCase RDIM_LocationCase; +struct RDIM_LocationCase +{ + RDIM_LocationCase *next; + RDIM_Rng1U64 voff_range; + RDIM_Location *location; +}; + +typedef struct RDIM_LocationSet RDIM_LocationSet; +struct RDIM_LocationSet +{ + RDIM_LocationCase *first_location_case; + RDIM_LocationCase *last_location_case; + RDI_U64 location_case_count; +}; + +//////////////////////////////// +//~ rjf: Symbol Info Types + +typedef enum RDIM_SymbolKind +{ + RDIM_SymbolKind_NULL, + RDIM_SymbolKind_GlobalVariable, + RDIM_SymbolKind_ThreadVariable, + RDIM_SymbolKind_Procedure, + RDIM_SymbolKind_COUNT +} +RDIM_SymbolKind; + +typedef struct RDIM_Symbol RDIM_Symbol; +struct RDIM_Symbol +{ + struct RDIM_SymbolChunkNode *chunk; + RDI_S32 is_extern; + RDIM_String8 name; + RDIM_String8 link_name; + RDIM_Type *type; + RDI_U64 offset; + RDIM_Symbol *container_symbol; + RDIM_Type *container_type; + struct RDIM_Scope *root_scope; +}; + +typedef struct RDIM_SymbolChunkNode RDIM_SymbolChunkNode; +struct RDIM_SymbolChunkNode +{ + RDIM_SymbolChunkNode *next; + RDIM_Symbol *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_SymbolChunkList RDIM_SymbolChunkList; +struct RDIM_SymbolChunkList +{ + RDIM_SymbolChunkNode *first; + RDIM_SymbolChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +//////////////////////////////// +//~ rjf: Scope Info Types + +typedef struct RDIM_Local RDIM_Local; +struct RDIM_Local +{ + RDIM_Local *next; + RDI_LocalKind kind; + RDIM_String8 name; + RDIM_Type *type; + RDIM_LocationSet locset; +}; + +typedef struct RDIM_Scope RDIM_Scope; +struct RDIM_Scope +{ + struct RDIM_ScopeChunkNode *chunk; + RDIM_Symbol *symbol; + RDIM_Scope *parent_scope; + RDIM_Scope *first_child; + RDIM_Scope *last_child; + RDIM_Scope *next_sibling; + RDIM_Rng1U64List voff_ranges; + RDIM_Local *first_local; + RDIM_Local *last_local; + RDI_U32 local_count; +}; + +typedef struct RDIM_ScopeChunkNode RDIM_ScopeChunkNode; +struct RDIM_ScopeChunkNode +{ + RDIM_ScopeChunkNode *next; + RDIM_Scope *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_ScopeChunkList RDIM_ScopeChunkList; +struct RDIM_ScopeChunkList +{ + RDIM_ScopeChunkNode *first; + RDIM_ScopeChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; + RDI_U64 scope_voff_count; + RDI_U64 local_count; + RDI_U64 location_count; +}; + +//////////////////////////////// +//~ rjf: Baking Types + +//- rjf: baking parameters + +typedef struct RDIM_BakeParams RDIM_BakeParams; +struct RDIM_BakeParams +{ + RDIM_TopLevelInfo top_level_info; + RDIM_BinarySectionList binary_sections; + RDIM_UnitChunkList units; + RDIM_TypeChunkList types; + RDIM_UDTChunkList udts; + RDIM_SrcFileChunkList src_files; + RDIM_SymbolChunkList global_variables; + RDIM_SymbolChunkList thread_variables; + RDIM_SymbolChunkList procedures; + RDIM_ScopeChunkList scopes; +}; + +//- rjf: data sections + +typedef struct RDIM_BakeSection RDIM_BakeSection; +struct RDIM_BakeSection +{ + void *data; + RDI_U64 size; + RDI_DataSectionTag tag; + RDI_U64 tag_idx; +}; + +typedef struct RDIM_BakeSectionNode RDIM_BakeSectionNode; +struct RDIM_BakeSectionNode +{ + RDIM_BakeSectionNode *next; + RDIM_BakeSection v; +}; + +typedef struct RDIM_BakeSectionList RDIM_BakeSectionList; +struct RDIM_BakeSectionList +{ + RDIM_BakeSectionNode *first; + RDIM_BakeSectionNode *last; + RDI_U64 count; +}; + +//- rjf: interned string type + +typedef struct RDIM_BakeString RDIM_BakeString; +struct RDIM_BakeString +{ + RDI_U64 hash; + RDIM_String8 string; +}; + +typedef struct RDIM_BakeStringChunkNode RDIM_BakeStringChunkNode; +struct RDIM_BakeStringChunkNode +{ + RDIM_BakeStringChunkNode *next; + RDIM_BakeString *v; + RDI_U64 count; + RDI_U64 cap; + RDI_U64 base_idx; +}; + +typedef struct RDIM_BakeStringChunkList RDIM_BakeStringChunkList; +struct RDIM_BakeStringChunkList +{ + RDIM_BakeStringChunkNode *first; + RDIM_BakeStringChunkNode *last; + RDI_U64 chunk_count; + RDI_U64 total_count; +}; + +typedef struct RDIM_BakeStringMapTopology RDIM_BakeStringMapTopology; +struct RDIM_BakeStringMapTopology +{ + RDI_U64 slots_count; +}; + +typedef struct RDIM_BakeStringMapBaseIndices RDIM_BakeStringMapBaseIndices; +struct RDIM_BakeStringMapBaseIndices +{ + RDI_U64 *slots_base_idxs; +}; + +typedef struct RDIM_BakeStringMapLoose RDIM_BakeStringMapLoose; +struct RDIM_BakeStringMapLoose +{ + RDIM_BakeStringChunkList **slots; +}; + +typedef struct RDIM_BakeStringMapTight RDIM_BakeStringMapTight; +struct RDIM_BakeStringMapTight +{ + RDIM_BakeStringChunkList *slots; + RDI_U64 *slots_base_idxs; + RDI_U64 slots_count; + RDI_U64 total_count; +}; + +//- rjf: index runs + +typedef struct RDIM_BakeIdxRunNode RDIM_BakeIdxRunNode; +struct RDIM_BakeIdxRunNode +{ + RDIM_BakeIdxRunNode *hash_next; + RDIM_BakeIdxRunNode *order_next; + RDI_U32 *idx_run; + RDI_U64 hash; + RDI_U32 count; + RDI_U32 first_idx; +}; + +typedef struct RDIM_BakeIdxRunMap RDIM_BakeIdxRunMap; +struct RDIM_BakeIdxRunMap +{ + RDIM_BakeIdxRunNode *order_first; + RDIM_BakeIdxRunNode *order_last; + RDIM_BakeIdxRunNode **slots; + RDI_U64 slots_count; + RDI_U64 slot_collision_count; + RDI_U32 count; + RDI_U32 idx_count; +}; + +//- rjf: source info & path tree + +typedef struct RDIM_BakePathNode RDIM_BakePathNode; +struct RDIM_BakePathNode +{ + RDIM_BakePathNode *next_order; + RDIM_BakePathNode *parent; + RDIM_BakePathNode *first_child; + RDIM_BakePathNode *last_child; + RDIM_BakePathNode *next_sibling; + RDIM_String8 name; + RDIM_SrcFile *src_file; + RDI_U32 idx; +}; + +typedef struct RDIM_BakeLineMapFragment RDIM_BakeLineMapFragment; +struct RDIM_BakeLineMapFragment +{ + RDIM_BakeLineMapFragment *next; + RDIM_LineSequence *seq; +}; + +typedef struct RDIM_BakePathTree RDIM_BakePathTree; +struct RDIM_BakePathTree +{ + RDIM_BakePathNode root; + RDIM_BakePathNode *first; + RDIM_BakePathNode *last; + RDI_U32 count; +}; + +//- rjf: name maps + +typedef struct RDIM_BakeNameMapValNode RDIM_BakeNameMapValNode; +struct RDIM_BakeNameMapValNode +{ + RDIM_BakeNameMapValNode *next; + RDI_U32 val[6]; +}; + +typedef struct RDIM_BakeNameMapNode RDIM_BakeNameMapNode; +struct RDIM_BakeNameMapNode +{ + RDIM_BakeNameMapNode *slot_next; + RDIM_BakeNameMapNode *order_next; + RDIM_String8 string; + RDIM_BakeNameMapValNode *val_first; + RDIM_BakeNameMapValNode *val_last; + RDI_U64 val_count; +}; + +typedef struct RDIM_BakeNameMap RDIM_BakeNameMap; +struct RDIM_BakeNameMap +{ + RDIM_BakeNameMapNode **slots; + RDI_U64 slots_count; + RDI_U64 slot_collision_count; + RDIM_BakeNameMapNode *first; + RDIM_BakeNameMapNode *last; + RDI_U64 name_count; +}; + +//- rjf: vmaps + +typedef struct RDIM_BakeVMap RDIM_BakeVMap; +struct RDIM_BakeVMap +{ + RDI_VMapEntry *vmap; // [count + 1] + RDI_U32 count; +}; + +typedef struct RDIM_VMapMarker RDIM_VMapMarker; +struct RDIM_VMapMarker +{ + RDI_U32 idx; + RDI_U32 begin_range; +}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +//- rjf: memory operations +#if !defined(RDIM_MEMSET_OVERRIDE) +RDI_PROC void *rdim_memset_fallback(void *dst, RDI_U8 c, RDI_U64 size); +#endif +#if !defined(RDIM_MEMCPY_OVERRIDE) +RDI_PROC void *rdim_memcpy_fallback(void *dst, void *src, RDI_U64 size); +#endif +#define rdim_memzero(ptr, size) rdim_memset((ptr), 0, (size)) +#define rdim_memzero_struct(ptr) rdim_memset((ptr), 0, sizeof(*(ptr))) +#define rdim_memcpy_struct(dst, src) rdim_memcpy((dst), (src), sizeof(*(dst))) + +//- rjf: arenas +#if !defined(RDIM_ARENA_OVERRIDE) +RDI_PROC RDIM_Arena *rdim_arena_alloc_fallback(void); +RDI_PROC void rdim_arena_release_fallback(RDIM_Arena *arena); +RDI_PROC RDI_U64 rdim_arena_pos_fallback(RDIM_Arena *arena); +RDI_PROC void *rdim_arena_push_fallback(RDIM_Arena *arena, RDI_U64 size); +RDI_PROC void rdim_arena_pop_to_fallback(RDIM_Arena *arena, RDI_U64 pos); +#endif +#define rdim_push_array_no_zero(a,T,c) (T*)rdim_arena_push((a), sizeof(T)*(c)) +#define rdim_push_array(a,T,c) (T*)rdim_memzero(rdim_push_array_no_zero(a,T,c), sizeof(T)*(c)) + +//- rjf: thread-local scratch arenas +#if !defined (RDIM_SCRATCH_OVERRIDE) +RDI_PROC RDIM_Temp rdim_scratch_begin_fallback(RDIM_Arena **conflicts, RDI_U64 conflicts_count); +RDI_PROC void rdim_scratch_end_fallback(RDIM_Temp temp); +#endif + +//- rjf: strings +RDI_PROC RDIM_String8 rdim_str8(RDI_U8 *str, RDI_U64 size); +RDI_PROC RDIM_String8 rdim_str8_copy(RDIM_Arena *arena, RDIM_String8 src); +RDI_PROC RDIM_String8 rdim_str8f(RDIM_Arena *arena, char *fmt, ...); +RDI_PROC RDIM_String8 rdim_str8fv(RDIM_Arena *arena, char *fmt, va_list args); +RDI_PROC RDI_S32 rdim_str8_match(RDIM_String8 a, RDIM_String8 b, RDIM_StringMatchFlags flags); +#define rdim_str8_lit(S) rdim_str8((RDI_U8*)(S), sizeof(S) - 1) +#define rdim_str8_struct(S) rdim_str8((RDI_U8*)(S), sizeof(*(S))) + +//- rjf: string lists +RDI_PROC void rdim_str8_list_push(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string); +RDI_PROC void rdim_str8_list_push_front(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 string); +RDI_PROC void rdim_str8_list_push_align(RDIM_Arena *arena, RDIM_String8List *list, RDI_U64 align); +RDI_PROC RDIM_String8 rdim_str8_list_join(RDIM_Arena *arena, RDIM_String8List *list, RDIM_String8 sep); + +//- rjf: sortable range sorting +RDI_PROC RDIM_SortKey *rdim_sort_key_array(RDIM_Arena *arena, RDIM_SortKey *keys, RDI_U64 count); + +//- rjf: rng1u64 list +RDI_PROC void rdim_rng1u64_list_push(RDIM_Arena *arena, RDIM_Rng1U64List *list, RDIM_Rng1U64 r); + +//////////////////////////////// +//~ rjf: [Building] Binary Section Info Building + +RDI_PROC RDIM_BinarySection *rdim_binary_section_list_push(RDIM_Arena *arena, RDIM_BinarySectionList *list); + +//////////////////////////////// +//~ rjf: [Building] Source File Info Building + +RDI_PROC RDIM_SrcFile *rdim_src_file_chunk_list_push(RDIM_Arena *arena, RDIM_SrcFileChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_src_file(RDIM_SrcFile *src_file); +RDI_PROC void rdim_src_file_chunk_list_concat_in_place(RDIM_SrcFileChunkList *dst, RDIM_SrcFileChunkList *to_push); +RDI_PROC void rdim_src_file_push_line_sequence(RDIM_Arena *arena, RDIM_SrcFileChunkList *src_files, RDIM_SrcFile *src_file, RDIM_LineSequence *seq); + +//////////////////////////////// +//~ rjf: [Building] Unit Info Building + +RDI_PROC RDIM_Unit *rdim_unit_chunk_list_push(RDIM_Arena *arena, RDIM_UnitChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_unit(RDIM_Unit *unit); +RDI_PROC void rdim_unit_chunk_list_concat_in_place(RDIM_UnitChunkList *dst, RDIM_UnitChunkList *to_push); +RDI_PROC RDIM_LineSequence *rdim_line_sequence_list_push(RDIM_Arena *arena, RDIM_LineSequenceList *list); + +//////////////////////////////// +//~ rjf: [Building] Type Info & UDT Building + +RDI_PROC RDIM_Type *rdim_type_chunk_list_push(RDIM_Arena *arena, RDIM_TypeChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_type(RDIM_Type *type); +RDI_PROC void rdim_type_chunk_list_concat_in_place(RDIM_TypeChunkList *dst, RDIM_TypeChunkList *to_push); +RDI_PROC RDIM_UDT *rdim_udt_chunk_list_push(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_udt(RDIM_UDT *udt); +RDI_PROC void rdim_udt_chunk_list_concat_in_place(RDIM_UDTChunkList *dst, RDIM_UDTChunkList *to_push); +RDI_PROC RDIM_UDTMember *rdim_udt_push_member(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); +RDI_PROC RDIM_UDTEnumVal *rdim_udt_push_enum_val(RDIM_Arena *arena, RDIM_UDTChunkList *list, RDIM_UDT *udt); + +//////////////////////////////// +//~ rjf: [Building] Symbol Info Building + +RDI_PROC RDIM_Symbol *rdim_symbol_chunk_list_push(RDIM_Arena *arena, RDIM_SymbolChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_symbol(RDIM_Symbol *symbol); +RDI_PROC void rdim_symbol_chunk_list_concat_in_place(RDIM_SymbolChunkList *dst, RDIM_SymbolChunkList *to_push); + +//////////////////////////////// +//~ rjf: [Building] Scope Info Building + +//- rjf: scopes +RDI_PROC RDIM_Scope *rdim_scope_chunk_list_push(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDI_U64 cap); +RDI_PROC RDI_U64 rdim_idx_from_scope(RDIM_Scope *scope); +RDI_PROC void rdim_scope_chunk_list_concat_in_place(RDIM_ScopeChunkList *dst, RDIM_ScopeChunkList *to_push); +RDI_PROC void rdim_scope_push_voff_range(RDIM_Arena *arena, RDIM_ScopeChunkList *list, RDIM_Scope *scope, RDIM_Rng1U64 range); +RDI_PROC RDIM_Local *rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *scope); + +//- rjf: bytecode +RDI_PROC void rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p); +RDI_PROC void rdim_bytecode_push_uconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_U64 x); +RDI_PROC void rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S64 x); +RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed); + +//- rjf: individual locations +RDI_PROC RDIM_Location *rdim_push_location_addr_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode); +RDI_PROC RDIM_Location *rdim_push_location_val_bytecode_stream(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode); +RDI_PROC RDIM_Location *rdim_push_location_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset); +RDI_PROC RDIM_Location *rdim_push_location_addr_addr_reg_plus_u16(RDIM_Arena *arena, RDI_U8 reg_code, RDI_U16 offset); +RDI_PROC RDIM_Location *rdim_push_location_val_reg(RDIM_Arena *arena, RDI_U8 reg_code); + +//- rjf: location sets +RDI_PROC void rdim_location_set_push_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_LocationSet *locset, RDIM_Rng1U64 voff_range, RDIM_Location *location); + +//////////////////////////////// +//~ rjf: [Baking Helpers] Baked File Layout Calculations + +RDI_PROC RDI_U64 rdim_bake_section_count_from_params(RDIM_BakeParams *params); +RDI_PROC RDI_U64 rdim_bake_section_idx_from_params_tag_idx(RDIM_BakeParams *params, RDI_DataSectionTag tag, RDI_U64 idx); + +//////////////////////////////// +//~ rjf: [Baking Helpers] Baked VMap Building + +RDI_PROC RDIM_BakeVMap rdim_bake_vmap_from_markers(RDIM_Arena *arena, RDIM_VMapMarker *markers, RDIM_SortKey *keys, RDI_U64 marker_count); + +//////////////////////////////// +//~ rjf: [Baking Helpers] Interned / Deduplicated Blob Data Structure Helpers + +//- rjf: bake string chunk lists +RDI_PROC RDIM_BakeString *rdim_bake_string_chunk_list_push(RDIM_Arena *arena, RDIM_BakeStringChunkList *list, RDI_U64 cap); +RDI_PROC void rdim_bake_string_chunk_list_concat_in_place(RDIM_BakeStringChunkList *dst, RDIM_BakeStringChunkList *to_push); +RDI_PROC RDIM_BakeStringChunkList rdim_bake_string_chunk_list_sorted_from_unsorted(RDIM_Arena *arena, RDIM_BakeStringChunkList *src); + +//- rjf: bake string chunk list maps +RDI_PROC RDIM_BakeStringMapLoose *rdim_bake_string_map_loose_make(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top); +RDI_PROC void rdim_bake_string_map_loose_insert(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map, RDI_U64 chunk_cap, RDIM_String8 string); +RDI_PROC void rdim_bake_string_map_loose_join_in_place(RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *dst, RDIM_BakeStringMapLoose *src); +RDI_PROC RDIM_BakeStringMapBaseIndices rdim_bake_string_map_base_indices_from_map_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapLoose *map); + +//- rjf: finalized bake string map +RDI_PROC RDIM_BakeStringMapTight rdim_bake_string_map_tight_from_loose(RDIM_Arena *arena, RDIM_BakeStringMapTopology *map_topology, RDIM_BakeStringMapBaseIndices *map_base_indices, RDIM_BakeStringMapLoose *map); +RDI_PROC RDI_U64 rdim_bake_idx_from_string(RDIM_BakeStringMapTight *map, RDIM_String8 string); + +//- rjf: bake idx run map reading/writing +RDI_PROC RDI_U64 rdim_hash_from_idx_run(RDI_U32 *idx_run, RDI_U32 count); +RDI_PROC RDI_U32 rdim_bake_idx_from_idx_run(RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count); +RDI_PROC RDI_U32 rdim_bake_idx_run_map_insert(RDIM_Arena *arena, RDIM_BakeIdxRunMap *map, RDI_U32 *idx_run, RDI_U32 count); + +//- rjf: bake path tree reading/writing +RDI_PROC RDIM_BakePathNode *rdim_bake_path_node_from_string(RDIM_BakePathTree *tree, RDIM_String8 string); +RDI_PROC RDI_U32 rdim_bake_path_node_idx_from_string(RDIM_BakePathTree *tree, RDIM_String8 string); +RDI_PROC RDIM_BakePathNode *rdim_bake_path_tree_insert(RDIM_Arena *arena, RDIM_BakePathTree *tree, RDIM_String8 string); + +//- rjf: bake name maps writing +RDI_PROC void rdim_bake_name_map_push(RDIM_Arena *arena, RDIM_BakeNameMap *map, RDIM_String8 string, RDI_U32 idx); + +//////////////////////////////// +//~ rjf: [Baking Helpers] Data Section List Building Helpers + +RDI_PROC RDIM_BakeSection *rdim_bake_section_list_push(RDIM_Arena *arena, RDIM_BakeSectionList *list); +RDI_PROC RDIM_BakeSection *rdim_bake_section_list_push_new(RDIM_Arena *arena, RDIM_BakeSectionList *list, void *data, RDI_U64 size, RDI_DataSectionTag tag, RDI_U64 tag_idx); +RDI_PROC void rdim_bake_section_list_concat_in_place(RDIM_BakeSectionList *dst, RDIM_BakeSectionList *to_push); + +//////////////////////////////// +//~ rjf: [Baking] Build Artifacts -> Interned/Deduplicated Data Structures + +//- rjf: basic bake string gathering passes +RDI_PROC void rdim_bake_string_map_loose_push_top_level_info(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TopLevelInfo *tli); +RDI_PROC void rdim_bake_string_map_loose_push_binary_sections(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BinarySectionList *secs); +RDI_PROC void rdim_bake_string_map_loose_push_path_tree(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_BakePathTree *path_tree); + +//- rjf: slice-granularity bake string gathering passes +RDI_PROC void rdim_bake_string_map_loose_push_src_file_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFile *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_unit_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Unit *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_type_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Type *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_udt_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDT *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_symbol_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Symbol *v, RDI_U64 count); +RDI_PROC void rdim_bake_string_map_loose_push_scope_slice(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_Scope *v, RDI_U64 count); + +//- rjf: list-granularity bake string gathering passes +RDI_PROC void rdim_bake_string_map_loose_push_src_files(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SrcFileChunkList *list); +RDI_PROC void rdim_bake_string_map_loose_push_units(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UnitChunkList *list); +RDI_PROC void rdim_bake_string_map_loose_push_types(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_TypeChunkList *list); +RDI_PROC void rdim_bake_string_map_loose_push_udts(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_UDTChunkList *list); +RDI_PROC void rdim_bake_string_map_loose_push_symbols(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_SymbolChunkList *list); +RDI_PROC void rdim_bake_string_map_loose_push_scopes(RDIM_Arena *arena, RDIM_BakeStringMapTopology *top, RDIM_BakeStringMapLoose *map, RDIM_ScopeChunkList *list); + +//- rjf: bake name map building +RDI_PROC RDIM_BakeNameMap *rdim_bake_name_map_from_kind_params(RDIM_Arena *arena, RDI_NameMapKind kind, RDIM_BakeParams *params); + +//- rjf: bake idx run map building +RDI_PROC RDIM_BakeIdxRunMap *rdim_bake_idx_run_map_from_params(RDIM_Arena *arena, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT], RDIM_BakeParams *params); + +//- rjf: bake path tree building +RDI_PROC RDIM_BakePathTree *rdim_bake_path_tree_from_params(RDIM_Arena *arena, RDIM_BakeParams *params); + +//////////////////////////////// +//~ rjf: [Baking] Build Artifacts -> Data Section Lists + +//- rjf: top-level info +RDI_PROC RDIM_BakeSectionList rdim_bake_top_level_info_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params); + +//- rjf: binary sections +RDI_PROC RDIM_BakeSectionList rdim_bake_binary_section_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params); + +//- rjf: units +RDI_PROC RDIM_BakeSectionList rdim_bake_section_list_from_unit(RDIM_Arena *arena, RDIM_Unit *unit); +RDI_PROC RDIM_BakeSectionList rdim_bake_unit_top_level_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_BakeParams *params); + +//- rjf: unit vmap +RDI_PROC RDIM_BakeSectionList rdim_bake_unit_vmap_section_list_from_params(RDIM_Arena *arena, RDIM_BakeParams *params); + +//- rjf: source files +RDI_PROC RDIM_BakeSectionList rdim_bake_src_file_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree, RDIM_BakeParams *params); + +//- rjf: type nodes +RDI_PROC RDIM_BakeSectionList rdim_bake_type_node_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeParams *params); + +//- rjf: UDTs +RDI_PROC RDIM_BakeSectionList rdim_bake_udt_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params); + +//- rjf: global variables +RDI_PROC RDIM_BakeSectionList rdim_bake_global_variable_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params); + +//- rjf: global vmap +RDI_PROC RDIM_BakeSectionList rdim_bake_global_vmap_section_list_from_params(RDIM_Arena *arena, RDIM_BakeParams *params); + +//- rjf: thread variables +RDI_PROC RDIM_BakeSectionList rdim_bake_thread_variable_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params); + +//- rjf: procedures +RDI_PROC RDIM_BakeSectionList rdim_bake_procedure_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params); + +//- rjf: scopes +RDI_PROC RDIM_BakeSectionList rdim_bake_scope_section_list_from_params(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeParams *params); + +//- rjf: scope vmap +RDI_PROC RDIM_BakeSectionList rdim_bake_scope_vmap_section_list_from_params(RDIM_Arena *arena, RDIM_BakeParams *params); + +//- rjf: name maps +RDI_PROC RDIM_BakeSectionList rdim_bake_top_level_name_map_section_list_from_params_maps(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeParams *params, RDIM_BakeNameMap *name_maps[RDI_NameMapKind_COUNT]); +RDI_PROC RDIM_BakeSectionList rdim_bake_name_map_section_list_from_params_kind_map(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakeIdxRunMap *idx_runs, RDIM_BakeParams *params, RDI_NameMapKind k, RDIM_BakeNameMap *map); + +//- rjf: file paths +RDI_PROC RDIM_BakeSectionList rdim_bake_file_path_section_list_from_path_tree(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings, RDIM_BakePathTree *path_tree); + +//- rjf: strings +RDI_PROC RDIM_BakeSectionList rdim_bake_string_section_list_from_string_map(RDIM_Arena *arena, RDIM_BakeStringMapTight *strings); + +//- rjf: index runs +RDI_PROC RDIM_BakeSectionList rdim_bake_idx_run_section_list_from_idx_run_map(RDIM_Arena *arena, RDIM_BakeIdxRunMap *idx_runs); + +//////////////////////////////// +//~ rjf: [Serializing] Baked Data Section List -> Serialized Binary Strings + +RDI_PROC RDIM_String8List rdim_serialized_strings_from_params_bake_section_list(RDIM_Arena *arena, RDIM_BakeParams *params, RDIM_BakeSectionList *sections); + +#endif // RADDBGI_MAKE_H diff --git a/src/metagen/metagen.c b/src/metagen/metagen.c index 73fe8a35..5da28126 100644 --- a/src/metagen/metagen.c +++ b/src/metagen/metagen.c @@ -112,6 +112,18 @@ mg_txt_pt_from_string_off(String8 string, U64 off) return pt; } +//////////////////////////////// +//~ rjf: Message Lists + +internal void +mg_msg_list_push(Arena *arena, MG_MsgList *msgs, MG_Msg *msg) +{ + MG_MsgNode *n = push_array(arena, MG_MsgNode, 1); + MemoryCopyStruct(&n->v, msg); + SLLQueuePush(msgs->first, msgs->last, n); + msgs->count += 1; +} + //////////////////////////////// //~ rjf: String Escaping @@ -360,7 +372,7 @@ mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node //- rjf: consume prefix operators MG_StrExpr *leafmost_op = &mg_str_expr_nil; - for(;it < opl && !md_node_is_nil(it);) + for(;it != opl && !md_node_is_nil(it);) { MG_StrExprOp found_op = MG_StrExprOp_Null; for(MG_StrExprOp op = (MG_StrExprOp)(MG_StrExprOp_Null+1); @@ -419,7 +431,7 @@ mg_str_expr_parse_from_first_opl__min_prec(Arena *arena, MD_Node *first, MD_Node } //- rjf: parse binary operator extensions at this precedence level - for(;it < opl && !md_node_is_nil(it);) + for(;it != opl && !md_node_is_nil(it);) { // rjf: find binary op kind of `it` MG_StrExprOp found_op = MG_StrExprOp_Null; diff --git a/src/metagen/metagen.h b/src/metagen/metagen.h index 3c86bce6..d15fbe74 100644 --- a/src/metagen/metagen.h +++ b/src/metagen/metagen.h @@ -4,6 +4,32 @@ #ifndef METAGEN_H #define METAGEN_H +//////////////////////////////// +//~ rjf: Message Type + +typedef struct MG_Msg MG_Msg; +struct MG_Msg +{ + String8 location; + String8 kind; + String8 msg; +}; + +typedef struct MG_MsgNode MG_MsgNode; +struct MG_MsgNode +{ + MG_MsgNode *next; + MG_Msg v; +}; + +typedef struct MG_MsgList MG_MsgList; +struct MG_MsgList +{ + MG_MsgNode *first; + MG_MsgNode *last; + U64 count; +}; + //////////////////////////////// //~ rjf: Parse Artifact Types @@ -230,6 +256,11 @@ read_only global MG_StrExpr mg_str_expr_nil = {&mg_str_expr_nil, &mg_str_expr_ni internal U64 mg_hash_from_string(String8 string); internal TxtPt mg_txt_pt_from_string_off(String8 string, U64 off); +//////////////////////////////// +//~ rjf: Message Lists + +internal void mg_msg_list_push(Arena *arena, MG_MsgList *msgs, MG_Msg *msg); + //////////////////////////////// //~ rjf: String Escaping diff --git a/src/metagen/metagen_main.c b/src/metagen/metagen_main.c index 6942687a..7ad38268 100644 --- a/src/metagen/metagen_main.c +++ b/src/metagen/metagen_main.c @@ -1,6 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Build Options + +#define BUILD_CONSOLE_INTERFACE 1 + //////////////////////////////// //~ rjf: Includes @@ -28,6 +33,7 @@ int main(int argument_count, char **arguments) ////////////////////////////// //- rjf: set up state // + MG_MsgList msgs = {0}; mg_arena = arena_alloc__sized(GB(64), MB(64)); mg_state = push_array(mg_arena, MG_State, 1); mg_state->slots_count = 256; @@ -91,16 +97,26 @@ int main(int argument_count, char **arguments) String8 data = os_data_from_file_path(mg_arena, file_path); MD_TokenizeResult tokenize = md_tokenize_from_text(mg_arena, data); MD_ParseResult parse = md_parse_from_text_tokens(mg_arena, file_path, data, tokenize.tokens); + for(MD_Msg *m = parse.msgs.first; m != 0; m = m->next) + { + TxtPt pt = mg_txt_pt_from_string_off(data, m->node->src_offset); + String8 msg_kind_string = {0}; + switch(m->kind) + { + default:{}break; + case MD_MsgKind_Note: {msg_kind_string = str8_lit("note");}break; + case MD_MsgKind_Warning: {msg_kind_string = str8_lit("warning");}break; + case MD_MsgKind_Error: {msg_kind_string = str8_lit("error");}break; + case MD_MsgKind_FatalError: {msg_kind_string = str8_lit("fatal error");}break; + } + String8 location = push_str8f(mg_arena, "%S:%I64d:%I64d", file_path, pt.line, pt.column); + MG_Msg dst_m = {location, msg_kind_string, m->string}; + mg_msg_list_push(mg_arena, &msgs, &dst_m); + } MG_FileParseNode *parse_n = push_array(mg_arena, MG_FileParseNode, 1); SLLQueuePush(parses.first, parses.last, parse_n); parse_n->v.root = parse.root; parses.count += 1; - for(MD_Msg *msg = parse.msgs.first; msg != 0; msg = msg->next) - { - TxtPt pt = mg_txt_pt_from_string_off(data, msg->node->src_offset); - // TODO(rjf): error kind display & locations - fprintf(stderr, "%.*s:%i:%i %.*s\n", str8_varg(file_path), (int)pt.line, (int)pt.column, str8_varg(msg->string)); - } } } } @@ -134,39 +150,55 @@ int main(int argument_count, char **arguments) } ////////////////////////////// - //- rjf: generate table enums + //- rjf: generate enums // for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) { MD_Node *file = n->v.root; for(MD_EachNode(node, file->first)) { - if(md_node_has_tag(node, str8_lit("table_gen_enum"), 0)) + MD_Node *tag = md_tag_from_string(node, str8_lit("enum"), 0); + if(!md_node_is_nil(tag)) { + String8 enum_base_type_name = tag->first->string; String8 layer_key = mg_layer_key_from_path(file->string); MG_Layer *layer = mg_layer_from_key(layer_key); String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node); - str8_list_pushf(mg_arena, &layer->enums, "typedef enum %S\n{\n", node->string); + if(enum_base_type_name.size == 0) + { + str8_list_pushf(mg_arena, &layer->enums, "typedef enum %S\n{\n", node->string); + } + else + { + str8_list_pushf(mg_arena, &layer->enums, "typedef %S %S;\n", enum_base_type_name, node->string); + str8_list_pushf(mg_arena, &layer->enums, "typedef enum %SEnum\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_push(mg_arena, &layer->enums, escaped); - str8_list_push(mg_arena, &layer->enums, str8_lit("\n")); + str8_list_pushf(mg_arena, &layer->enums, "%S_%S,\n", node->string, escaped); + } + if(enum_base_type_name.size == 0) + { + str8_list_pushf(mg_arena, &layer->enums, "} %S;\n\n", node->string); + } + else + { + str8_list_pushf(mg_arena, &layer->enums, "} %SEnum;\n\n", node->string); } - str8_list_pushf(mg_arena, &layer->enums, "} %S;\n\n", node->string); } } } ////////////////////////////// - //- rjf: generate table structs + //- rjf: generate structs // for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) { MD_Node *file = n->v.root; for(MD_EachNode(node, file->first)) { - if(md_node_has_tag(node, str8_lit("table_gen_struct"), 0)) + if(md_node_has_tag(node, str8_lit("struct"), 0)) { String8 layer_key = mg_layer_key_from_path(file->string); MG_Layer *layer = mg_layer_from_key(layer_key); @@ -176,8 +208,7 @@ int main(int argument_count, char **arguments) for(String8Node *n = gen_strings.first; n != 0; n = n->next) { String8 escaped = mg_escaped_from_str8(mg_arena, n->string); - str8_list_push(mg_arena, &layer->structs, escaped); - str8_list_push(mg_arena, &layer->structs, str8_lit("\n")); + str8_list_pushf(mg_arena, &layer->structs, "%S;\n", escaped); } str8_list_pushf(mg_arena, &layer->structs, "};\n\n"); } @@ -185,48 +216,88 @@ int main(int argument_count, char **arguments) } ////////////////////////////// - //- rjf: generate table data tables + //- rjf: generate data tables // for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) { MD_Node *file = n->v.root; for(MD_EachNode(node, file->first)) { - MD_Node *tag = md_tag_from_string(node, str8_lit("table_gen_data"), 0); + MD_Node *tag = md_tag_from_string(node, str8_lit("data"), 0); if(!md_node_is_nil(tag)) { + String8 element_type = tag->first->string; String8 layer_key = mg_layer_key_from_path(file->string); MG_Layer *layer = mg_layer_from_key(layer_key); - String8List *out = md_node_has_tag(node, str8_lit("c_file"), 0) ? &layer->c_tables : &layer->h_tables; - MD_Node *type = md_child_from_string(tag, str8_lit("type"), 0)->first; - MD_Node *fallback = md_child_from_string(tag, str8_lit("fallback"), 0)->first; - String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, fallback->string, node); - str8_list_pushf(mg_arena, out, "%S %S[] =\n{\n", type->string, node->string); + String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node); + if(!md_node_has_tag(node, str8_lit("c_file"), 0)) + { + str8_list_pushf(mg_arena, &layer->h_tables, "extern %S %S[%I64u];\n", element_type, node->string, gen_strings.node_count); + } + 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_push(mg_arena, out, escaped); - str8_list_push(mg_arena, out, str8_lit("\n")); + str8_list_pushf(mg_arena, &layer->c_tables, "%S,\n", escaped); } - str8_list_push(mg_arena, out, str8_lit("};\n\n")); + str8_list_push(mg_arena, &layer->c_tables, str8_lit("};\n\n")); } } } ////////////////////////////// - //- rjf: generate table catch-all generations + //- rjf: generate enum -> string mapping functions // for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) { MD_Node *file = n->v.root; for(MD_EachNode(node, file->first)) { - MD_Node *tag = md_tag_from_string(node, str8_lit("table_gen"), 0); + MD_Node *tag = md_tag_from_string(node, str8_lit("enum2string_switch"), 0); + if(!md_node_is_nil(tag)) + { + String8 enum_type = tag->first->string; + String8 layer_key = mg_layer_key_from_path(file->string); + MG_Layer *layer = mg_layer_from_key(layer_key); + String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node); + str8_list_pushf(mg_arena, &layer->h_functions, "internal String8 %S(%S v);\n", node->string, enum_type); + str8_list_pushf(mg_arena, &layer->c_functions, "internal String8\n%S(%S v)\n{\n", node->string, enum_type); + str8_list_pushf(mg_arena, &layer->c_functions, "String8 result = str8_lit(\"\");\n", enum_type); + str8_list_pushf(mg_arena, &layer->c_functions, "switch(v)\n"); + str8_list_pushf(mg_arena, &layer->c_functions, "{\n"); + 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, "}\n"); + str8_list_pushf(mg_arena, &layer->c_functions, "return result;\n"); + str8_list_pushf(mg_arena, &layer->c_functions, "}\n\n"); + } + } + } + + ////////////////////////////// + //- rjf: generate catch-all generations + // + for(MG_FileParseNode *n = parses.first; n != 0; n = n->next) + { + MD_Node *file = n->v.root; + for(MD_EachNode(node, file->first)) + { + MD_Node *tag = md_tag_from_string(node, str8_lit("gen"), 0); if(!md_node_is_nil(tag)) { String8 layer_key = mg_layer_key_from_path(file->string); MG_Layer *layer = mg_layer_from_key(layer_key); - String8List *out = md_node_has_tag(node, str8_lit("c_file"), 0) ? &layer->c_catchall : &layer->h_catchall; + B32 prefer_c_file = md_node_has_tag(node, str8_lit("c_file"), 0); + String8List *out = prefer_c_file ? &layer->c_catchall : &layer->h_catchall; + if(tag->first->string.size == 0){} + else if(str8_match(tag->first->string, str8_lit("enums"), 0)) { out = &layer->enums; } + else if(str8_match(tag->first->string, str8_lit("structs"), 0)) { out = &layer->structs; } + else if(str8_match(tag->first->string, str8_lit("functions"), 0)) { out = prefer_c_file ? &layer->c_functions : &layer->h_functions; } + else if(str8_match(tag->first->string, str8_lit("tables"), 0)) { out = prefer_c_file ? &layer->c_tables : &layer->h_tables; } String8List gen_strings = mg_string_list_from_table_gen(mg_arena, table_grid_map, table_col_map, str8_lit(""), node); for(String8Node *n = gen_strings.first; n != 0; n = n->next) { @@ -377,11 +448,13 @@ int main(int argument_count, char **arguments) { fwrite(n->string.str, n->string.size, 1, h); } + fprintf(h, "C_LINKAGE_BEGIN\n"); for(String8Node *n = layer->h_tables.first; n != 0; n = n->next) { fwrite(n->string.str, n->string.size, 1, h); } - fprintf(h, "\n#endif // %.*s_META_H\n", str8_varg(layer_key_filename_upper)); + fprintf(h, "C_LINKAGE_END\n\n"); + fprintf(h, "#endif // %.*s_META_H\n", str8_varg(layer_key_filename_upper)); fclose(h); } { @@ -397,10 +470,12 @@ int main(int argument_count, char **arguments) { fwrite(n->string.str, n->string.size, 1, c); } + fprintf(c, "C_LINKAGE_BEGIN\n"); for(String8Node *n = layer->c_tables.first; n != 0; n = n->next) { fwrite(n->string.str, n->string.size, 1, c); } + fprintf(c, "C_LINKAGE_END\n\n"); fclose(c); } } @@ -408,5 +483,14 @@ int main(int argument_count, char **arguments) } } + ////////////////////////////// + //- rjf: write out all messages to stderr + // + for(MG_MsgNode *n = msgs.first; n != 0; n = n->next) + { + MG_Msg *msg = &n->v; + fprintf(stderr, "%.*s: %.*s: %.*s\n", str8_varg(msg->location), str8_varg(msg->kind), str8_varg(msg->msg)); + } + return 0; } diff --git a/src/raddbg_convert/pdb/raddbg_msf.c b/src/msf/msf.c similarity index 92% rename from src/raddbg_convert/pdb/raddbg_msf.c rename to src/msf/msf.c index 39b01999..70f7533f 100644 --- a/src/raddbg_convert/pdb/raddbg_msf.c +++ b/src/msf/msf.c @@ -2,43 +2,44 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ MSF Parser Function +//~ rjf: MSF Parser Functions -static MSF_Parsed* -msf_parsed_from_data(Arena *arena, String8 msf_data){ - ProfBegin("msf_parsed_from_data"); - +internal MSF_Parsed* +msf_parsed_from_data(Arena *arena, String8 msf_data) +{ Temp scratch = scratch_begin(&arena, 1); - MSF_Parsed *result = 0; //- determine msf type U32 index_size = 0; - if (msf_data.size >= MSF_MIN_SIZE){ - if (str8_match(msf_data, str8_lit(msf_msf20_magic), - StringMatchFlag_RightSideSloppy)){ + if(msf_data.size >= MSF_MIN_SIZE) + { + if(str8_match(msf_data, str8_lit(msf_msf20_magic), StringMatchFlag_RightSideSloppy)) + { index_size = 2; } - else if (str8_match(msf_data, str8_lit(msf_msf70_magic), - StringMatchFlag_RightSideSloppy)){ + else if(str8_match(msf_data, str8_lit(msf_msf70_magic), StringMatchFlag_RightSideSloppy)) + { index_size = 4; } } - if (index_size == 2 || index_size == 4){ - + if(index_size == 2 || index_size == 4) + { //- extract info from header U32 block_size_raw = 0; U32 whole_file_block_count_raw = 0; U32 directory_size_raw = 0; U32 directory_super_map_raw = 0; - if (index_size == 2){ + if(index_size == 2) + { MSF_Header20 *header = (MSF_Header20*)(msf_data.str + MSF_MSF20_MAGIC_SIZE); block_size_raw = header->block_size; whole_file_block_count_raw = header->block_count; directory_size_raw = header->directory_size; } - else if (index_size == 4){ + else if(index_size == 4) + { MSF_Header70 *header = (MSF_Header70*)(msf_data.str + MSF_MSF70_MAGIC_SIZE); block_size_raw = header->block_size; whole_file_block_count_raw = header->block_count; @@ -91,7 +92,6 @@ msf_parsed_from_data(Arena *arena, String8 msf_data){ //- parse stream directory U8 *directory_buf = push_array(scratch.arena, U8, directory_size); B32 got_directory = 1; - { U32 directory_super_map_dummy = 0; U32 *directory_super_map = 0; @@ -174,7 +174,8 @@ msf_parsed_from_data(Arena *arena, String8 msf_data){ B32 got_streams = 0; String8 *streams = 0; - if (got_directory){ + if(got_directory) + { got_streams = 1; // read stream count @@ -198,7 +199,8 @@ msf_parsed_from_data(Arena *arena, String8 msf_data){ U32 entry_cursor = all_stream_entries_off; U32 index_cursor = all_indices_off; String8 *stream_ptr = streams; - for (U32 i = 0; i < stream_count; i += 1){ + for (U32 i = 0; i < stream_count; i += 1) + { // read stream size U32 stream_size_raw = *(U32*)(directory_buf + entry_cursor); if (stream_size_raw == 0xffffffff){ @@ -258,7 +260,8 @@ msf_parsed_from_data(Arena *arena, String8 msf_data){ parse_streams_done:; } - if (got_streams){ + if(got_streams) + { result = push_array(arena, MSF_Parsed, 1); result->streams = streams; result->stream_count = stream_count; @@ -268,16 +271,15 @@ msf_parsed_from_data(Arena *arena, String8 msf_data){ } scratch_end(scratch); - - ProfEnd(); - - return(result); + return result; } -static String8 -msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn){ +internal String8 +msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn) +{ String8 result = {0}; - if (sn < msf->stream_count){ + if(sn < msf->stream_count) + { result = msf->streams[sn]; } return(result); diff --git a/src/raddbg_convert/pdb/raddbg_msf.h b/src/msf/msf.h similarity index 67% rename from src/raddbg_convert/pdb/raddbg_msf.h rename to src/msf/msf.h index 62f671fd..77f7eebf 100644 --- a/src/raddbg_convert/pdb/raddbg_msf.h +++ b/src/msf/msf.h @@ -1,11 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_MSF_H -#define RADDBG_MSF_H +#ifndef MSF_H +#define MSF_H //////////////////////////////// -//~ MSF Format Types +//~ rjf: MSF Format Types #define MSF_INVALID_STREAM_NUMBER 0xFFFF typedef U16 MSF_StreamNumber; @@ -17,23 +17,27 @@ static char msf_msf70_magic[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"; #define MSF_MSF70_MAGIC_SIZE 32 #define MSF_MAX_MAGIC_SIZE 44 -typedef struct MSF_Header20{ +typedef struct MSF_Header20 MSF_Header20; +struct MSF_Header20 +{ U32 block_size; U16 free_block_map_block; U16 block_count; U32 directory_size; U32 unknown; U16 directory_map; -} MSF_Header20; +}; -typedef struct MSF_Header70{ +typedef struct MSF_Header70 MSF_Header70; +struct MSF_Header70 +{ U32 block_size; U32 free_block_map_block; U32 block_count; U32 directory_size; U32 unknown; U32 directory_super_map; -} MSF_Header70; +}; // magic(20) + header(20) = 44 + 20 = 64 // magic(70) + header(70) = 32 + 24 = 56 @@ -41,20 +45,21 @@ typedef struct MSF_Header70{ #define MSF_MIN_SIZE 64 //////////////////////////////// -//~ MSF Parser Helper Types +//~ rjf: MSF Parser Helper Types -typedef struct MSF_Parsed{ +typedef struct MSF_Parsed MSF_Parsed; +struct MSF_Parsed +{ String8 *streams; U64 stream_count; - U64 block_size; U64 block_count; -} MSF_Parsed; +}; //////////////////////////////// -//~ MSF Parser Function +//~ rjf: MSF Parser Functions -static MSF_Parsed* msf_parsed_from_data(Arena *arena, String8 msf_data); -static String8 msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn); +internal MSF_Parsed* msf_parsed_from_data(Arena *arena, String8 msf_data); +internal String8 msf_data_from_stream(MSF_Parsed *msf, MSF_StreamNumber sn); -#endif //RADDBG_MSF_H +#endif // MSF_H diff --git a/src/mule/mule_main.cpp b/src/mule/mule_main.cpp index 87f6c7ef..1260db25 100644 --- a/src/mule/mule_main.cpp +++ b/src/mule/mule_main.cpp @@ -6,7 +6,7 @@ ** stepping, breakpoints, evaluation, cross-module calls. */ -#include "raddbg_markup/raddbg_markup.h" +#include "lib_raddbg_markup/raddbg_markup.h" //////////////////////////////// // NOTE(allen): System For DLL Testing @@ -274,6 +274,9 @@ type_coverage_eval_tests(void){ "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; diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index 2907ffac..f8b07e81 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -788,8 +788,8 @@ lnx_thread_base(void *ptr){ TCTX tctx_; tctx_init_and_equip(&tctx_); - func(thread_ptr); + tctx_release(); // remove my bit U32 result = __sync_fetch_and_and(&entity->reference_mask, ~0x2); @@ -813,7 +813,7 @@ lnx_safe_call_sig_handler(int){ //~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) internal void -os_init(int argc, char **argv) +os_init(void) { // NOTE(allen): Initialize linux layer mutex { @@ -984,7 +984,7 @@ os_logical_core_count(void) } //////////////////////////////// -//~ rjf: @os_hooks Process Info (Implemented Per-OS) +//~ rjf: @os_hooks Process & Thread Info (Implemented Per-OS) internal String8List os_get_command_line_arguments(void) diff --git a/src/os/core/os_core.c b/src/os/core/os_core.c index e1429d1d..b3cad911 100644 --- a/src/os/core/os_core.c +++ b/src/os/core/os_core.c @@ -67,19 +67,6 @@ os_string_list_from_argcv(Arena *arena, int argc, char **argv) return result; } -//////////////////////////////// -//~ rjf: Process Helpers (Helper, Implemented Once) - -internal void -os_relaunch_self(void){ - Temp scratch = scratch_begin(0, 0); - OS_LaunchOptions opts = {0}; - opts.cmd_line = os_get_command_line_arguments(); - opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Initial); - os_launch_process(&opts, 0); - scratch_end(scratch); -} - //////////////////////////////// //~ rjf: Filesystem Helpers (Helpers, Implemented Once) @@ -163,67 +150,49 @@ os_string_from_file_range(Arena *arena, OS_Handle file, Rng1U64 range) internal void os_mutex_take(OS_Handle mutex){ - ProfBeginLockWait((void *)(mutex.u64[0]), "take mutex"); os_mutex_take_(mutex); - ProfEndLockWait(); - ProfLockTake((void *)(mutex.u64[0]), "take mutex"); } internal void os_mutex_drop(OS_Handle mutex){ os_mutex_drop_(mutex); - ProfLockDrop((void *)(mutex.u64[0])); } internal void os_rw_mutex_take_r(OS_Handle rw_mutex){ - ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take r"); os_rw_mutex_take_r_(rw_mutex); - ProfEndLockWait(); - ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take r"); } internal void os_rw_mutex_drop_r(OS_Handle rw_mutex){ os_rw_mutex_drop_r_(rw_mutex); - ProfLockDrop((void *)(rw_mutex.u64[0])); } internal void os_rw_mutex_take_w(OS_Handle rw_mutex){ - ProfBeginLockWait((void *)(rw_mutex.u64[0]), "rw mutex take rw"); os_rw_mutex_take_w_(rw_mutex); - ProfEndLockWait(); - ProfLockTake((void *)(rw_mutex.u64[0]), "rw mutex take rw"); } internal void os_rw_mutex_drop_w(OS_Handle rw_mutex){ os_rw_mutex_drop_w_(rw_mutex); - ProfLockDrop((void *)(rw_mutex.u64[0])); } internal B32 os_condition_variable_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us){ - ProfLockDrop((void *)(mutex.u64[0])); B32 result = os_condition_variable_wait_(cv, mutex, endt_us); - ProfLockTake((void *)(mutex.u64[0]), "wait cv"); return(result); } internal B32 os_condition_variable_wait_rw_r(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ - ProfLockDrop((void *)(mutex_rw.u64[0])); B32 result = os_condition_variable_wait_rw_r_(cv, mutex_rw, endt_us); - ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw r"); return(result); } internal B32 os_condition_variable_wait_rw_w(OS_Handle cv, OS_Handle mutex_rw, U64 endt_us){ - ProfLockDrop((void *)(mutex_rw.u64[0])); B32 result = os_condition_variable_wait_rw_w_(cv, mutex_rw, endt_us); - ProfLockTake((void *)(mutex_rw.u64[0]), "wait cv rw w"); return(result); } diff --git a/src/os/core/os_core.h b/src/os/core/os_core.h index 3ee15bd4..ea82c9d2 100644 --- a/src/os/core/os_core.h +++ b/src/os/core/os_core.h @@ -165,11 +165,6 @@ internal String8 os_string_from_system_path(Arena *arena, OS_SystemPath path); internal String8List os_string_list_from_argcv(Arena *arena, int argc, char **argv); -//////////////////////////////// -//~ rjf: Process Helpers (Helper, Implemented Once) - -internal void os_relaunch_self(void); - //////////////////////////////// //~ rjf: Filesystem Helpers (Helpers, Implemented Once) @@ -204,7 +199,7 @@ internal void os_condition_variable_broadcast(OS_Handle cv); //////////////////////////////// //~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) -internal void os_init(int argc, char **argv); +internal void os_init(void); //////////////////////////////// //~ rjf: @os_hooks Memory Allocation (Implemented Per-OS) @@ -232,14 +227,18 @@ internal U64 os_allocation_granularity(void); internal U64 os_logical_core_count(void); //////////////////////////////// -//~ rjf: @os_hooks Process Info (Implemented Per-OS) +//~ rjf: @os_hooks Process & Thread Info (Implemented Per-OS) -internal String8List os_get_command_line_arguments(void); internal S32 os_get_pid(void); internal S32 os_get_tid(void); internal String8List os_get_environment(void); internal U64 os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *out); +//////////////////////////////// +//~ rjf: @os_hooks Thread Names + +internal void os_set_thread_name(String8 string); + //////////////////////////////// //~ rjf: @os_hooks Process Control (Implemented Per-OS) @@ -306,6 +305,7 @@ internal void os_process_release_handle(OS_Handle handle); //~ rjf: @os_hooks Threads (Implemented Per-OS) internal OS_Handle os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params); +internal B32 os_thread_wait(OS_Handle handle, U64 endt_us); internal void os_release_thread_handle(OS_Handle thread); //////////////////////////////// @@ -364,4 +364,15 @@ internal void os_safe_call(OS_ThreadFunctionType *func, OS_ThreadFunctionType *f internal OS_Guid os_make_guid(void); internal String8 os_string_from_guid(Arena *arena, OS_Guid guid); +//////////////////////////////// +//~ rjf: @os_hooks Entry Points (Implemented Per-OS) + +// NOTE(rjf): The implementation of `os_core` will define low-level entry +// points if BUILD_ENTRY_DEFINING_UNIT is defined to 1. These will call +// into the standard codebase program entry points, named "entry_point". + +#if BUILD_ENTRY_DEFINING_UNIT +internal void entry_point(CmdLine *cmdline); +#endif + #endif // OS_CORE_H diff --git a/src/os/core/win32/os_core_win32.c b/src/os/core/win32/os_core_win32.c index d0ced51b..0d13d0e4 100644 --- a/src/os/core/win32/os_core_win32.c +++ b/src/os/core/win32/os_core_win32.c @@ -167,7 +167,10 @@ w32_thread_base(void *ptr){ OS_ThreadFunctionType *func = entity->thread.func; void *thread_ptr = entity->thread.ptr; + TCTX tctx_; + tctx_init_and_equip(&tctx_); func(thread_ptr); + tctx_release(); // remove my bit LONG result = InterlockedAnd((LONG*)&entity->reference_mask, ~0x2); @@ -182,7 +185,8 @@ w32_thread_base(void *ptr){ //~ rjf: @os_hooks Main Initialization API (Implemented Per-OS) internal void -os_init(int argc, char **argv){ +os_init(void) +{ // Load Fancy Memory Functions { HMODULE module = LoadLibraryA("kernel32.dll"); @@ -211,12 +215,9 @@ os_init(int argc, char **argv){ // Setup initial path w32_initial_path = os_string_from_system_path(w32_perm_arena, OS_SystemPath_Current); - // Setup command line arguments - w32_cmd_line_args = os_string_list_from_argcv(w32_perm_arena, argc, argv); - // rjf: setup environment variables { - CHAR *this_proc_env = GetEnvironmentStrings(); + WCHAR *this_proc_env = GetEnvironmentStringsW(); U64 start_idx = 0; for(U64 idx = 0;; idx += 1) { @@ -228,7 +229,8 @@ os_init(int argc, char **argv){ } else { - String8 string = str8((U8 *)this_proc_env + start_idx, idx - start_idx); + String16 string16 = str16((U16 *)this_proc_env + start_idx, idx - start_idx); + String8 string = str8_from_16(w32_perm_arena, string16); str8_list_push(w32_perm_arena, &w32_environment, string); start_idx = idx+1; } @@ -467,12 +469,6 @@ os_logical_core_count(void) //////////////////////////////// //~ rjf: @os_hooks Process Info (Implemented Per-OS) -internal String8List -os_get_command_line_arguments(void) -{ - return w32_cmd_line_args; -} - internal S32 os_get_pid(void){ DWORD id = GetCurrentProcessId(); @@ -592,6 +588,54 @@ os_string_list_from_system_path(Arena *arena, OS_SystemPath path, String8List *o return(result); } +//////////////////////////////// +//~ rjf: @os_hooks Thread Names + +internal void +os_set_thread_name(String8 name) +{ + Temp scratch = scratch_begin(0, 0); + + // rjf: windows 10 style + { + String16 name16 = str16_from_8(scratch.arena, name); + HRESULT hr = SetThreadDescription(GetCurrentThread(), (WCHAR*)name16.str); + } + + // rjf: raise-exception style + { + String8 name_copy = push_str8_copy(scratch.arena, name); +#pragma pack(push,8) + typedef struct THREADNAME_INFO THREADNAME_INFO; + struct THREADNAME_INFO + { + U32 dwType; // Must be 0x1000. + char *szName; // Pointer to name (in user addr space). + U32 dwThreadID; // Thread ID (-1=caller thread). + U32 dwFlags; // Reserved for future use, must be zero. + }; +#pragma pack(pop) + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = (char *)name_copy.str; + info.dwThreadID = os_get_tid(); + info.dwFlags = 0; +#pragma warning(push) +#pragma warning(disable: 6320 6322) + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } +#pragma warning(pop) + } + + scratch_end(scratch); +} + + //////////////////////////////// //~ rjf: @os_hooks Process Control (Implemented Per-OS) @@ -618,7 +662,7 @@ os_file_open(OS_AccessFlags flags, String8 path) 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;} + if(flags & OS_AccessFlag_ShareWrite) {share_mode |= FILE_SHARE_WRITE|FILE_SHARE_DELETE;} if(flags & OS_AccessFlag_Write) {creation_disposition = CREATE_ALWAYS;} HANDLE file = CreateFileW((WCHAR *)path16.str, access_flags, share_mode, 0, creation_disposition, FILE_ATTRIBUTE_NORMAL, 0); if(file != INVALID_HANDLE_VALUE) @@ -634,7 +678,8 @@ os_file_close(OS_Handle file) { if(os_handle_match(file, os_handle_zero())) { return; } HANDLE handle = (HANDLE)file.u64[0]; - CloseHandle(handle); + BOOL result = CloseHandle(handle); + (void)result; } internal U64 @@ -852,7 +897,8 @@ internal void os_file_map_close(OS_Handle map) { HANDLE handle = (HANDLE)map.u64[0]; - CloseHandle(handle); + BOOL result = CloseHandle(handle); + (void)result; } internal void * @@ -895,7 +941,8 @@ os_file_map_view_open(OS_Handle map, OS_AccessFlags flags, Rng1U64 range) internal void os_file_map_view_close(OS_Handle map, void *ptr) { - UnmapViewOfFile(ptr); + BOOL result = UnmapViewOfFile(ptr); + (void)result; } //- rjf: directory iteration @@ -1180,7 +1227,7 @@ os_launch_process(OS_LaunchOptions *options, OS_Handle *handle_out){ env16 = str16_from_8(scratch.arena, env); } - DWORD creation_flags = 0; + DWORD creation_flags = CREATE_UNICODE_ENVIRONMENT; if(options->consoleless) { creation_flags |= CREATE_NO_WINDOW; @@ -1233,6 +1280,19 @@ os_launch_thread(OS_ThreadFunctionType *func, void *ptr, void *params){ return(result); } +internal B32 +os_thread_wait(OS_Handle handle, U64 endt_us) +{ + DWORD sleep_ms = w32_sleep_ms_from_endt_us(endt_us); + W32_Entity *entity = (W32_Entity *)PtrFromInt(handle.u64[0]); + DWORD wait_result = WAIT_OBJECT_0; + if(entity != 0) + { + wait_result = WaitForSingleObject(entity->thread.handle, sleep_ms); + } + return (wait_result == WAIT_OBJECT_0); +} + internal void os_release_thread_handle(OS_Handle thread){ W32_Entity *entity = (W32_Entity*)PtrFromInt(thread.u64[0]); @@ -1491,7 +1551,8 @@ os_make_guid(void) OS_Guid result; MemoryZeroStruct(&result); UUID uuid; RPC_STATUS rpc_status = UuidCreate(&uuid); - if (rpc_status == RPC_S_OK) { + if(rpc_status == RPC_S_OK) + { result.data1 = uuid.Data1; result.data2 = uuid.Data2; result.data3 = uuid.Data3; @@ -1500,3 +1561,247 @@ os_make_guid(void) return result; } +//////////////////////////////// +//~ rjf: @os_hooks Entry Points (Implemented Per-OS) + +#include +#undef OS_WINDOWS // shlwapi uses its own OS_WINDOWS include inside +#include + +internal B32 win32_g_is_quiet = 0; + +internal HRESULT WINAPI +win32_dialog_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, LONG_PTR data) +{ + if(msg == TDN_HYPERLINK_CLICKED) + { + ShellExecuteW(NULL, L"open", (LPWSTR)lparam, NULL, NULL, SW_SHOWNORMAL); + } + return S_OK; +} + +internal LONG WINAPI +win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) +{ + if(win32_g_is_quiet) + { + ExitProcess(1); + } + + static volatile LONG first = 0; + if(InterlockedCompareExchange(&first, 1, 0) != 0) + { + // prevent failures in other threads to popup same message box + // this handler just shows first thread that crashes + // we are terminating afterwards anyway + for (;;) Sleep(1000); + } + + WCHAR buffer[4096] = {0}; + int buflen = 0; + + DWORD exception_code = exception_ptrs->ExceptionRecord->ExceptionCode; + 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 + HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); + if(dbghelp) + { + DWORD (WINAPI *dbg_SymSetOptions)(DWORD SymOptions); + BOOL (WINAPI *dbg_SymInitializeW)(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess); + BOOL (WINAPI *dbg_StackWalk64)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, + LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); + PVOID (WINAPI *dbg_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); + DWORD64 (WINAPI *dbg_SymGetModuleBase64)(HANDLE hProcess, DWORD64 qwAddr); + BOOL (WINAPI *dbg_SymFromAddrW)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFOW Symbol); + BOOL (WINAPI *dbg_SymGetLineFromAddrW64)(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line); + BOOL (WINAPI *dbg_SymGetModuleInfoW64)(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULEW64 ModuleInfo); + + *(FARPROC*)&dbg_SymSetOptions = GetProcAddress(dbghelp, "SymSetOptions"); + *(FARPROC*)&dbg_SymInitializeW = GetProcAddress(dbghelp, "SymInitializeW"); + *(FARPROC*)&dbg_StackWalk64 = GetProcAddress(dbghelp, "StackWalk64"); + *(FARPROC*)&dbg_SymFunctionTableAccess64 = GetProcAddress(dbghelp, "SymFunctionTableAccess64"); + *(FARPROC*)&dbg_SymGetModuleBase64 = GetProcAddress(dbghelp, "SymGetModuleBase64"); + *(FARPROC*)&dbg_SymFromAddrW = GetProcAddress(dbghelp, "SymFromAddrW"); + *(FARPROC*)&dbg_SymGetLineFromAddrW64 = GetProcAddress(dbghelp, "SymGetLineFromAddrW64"); + *(FARPROC*)&dbg_SymGetModuleInfoW64 = GetProcAddress(dbghelp, "SymGetModuleInfoW64"); + + if(dbg_SymSetOptions && dbg_SymInitializeW && dbg_StackWalk64 && dbg_SymFunctionTableAccess64 && dbg_SymGetModuleBase64 && dbg_SymFromAddrW && dbg_SymGetLineFromAddrW64 && dbg_SymGetModuleInfoW64) + { + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + CONTEXT* context = exception_ptrs->ContextRecord; + + dbg_SymSetOptions(SYMOPT_EXACT_SYMBOLS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + if(dbg_SymInitializeW(process, L"", TRUE)) + { + // check that raddbg.pdb file is good + B32 raddbg_pdb_valid = 0; + { + IMAGEHLP_MODULEW64 module = {0}; + module.SizeOfStruct = sizeof(module); + if(dbg_SymGetModuleInfoW64(process, (DWORD64)&win32_exception_filter, &module)) + { + raddbg_pdb_valid = (module.SymType == SymPdb); + } + } + + if(!raddbg_pdb_valid) + { + buflen += wnsprintfW(buffer + buflen, sizeof(buffer) - buflen, + L"\nThe PDB debug information file for this executable is not valid or was not found. Please rebuild binary to get the call stack.\n"); + } + else + { + STACKFRAME64 frame = {0}; + DWORD image_type; +#if defined(_M_AMD64) + image_type = IMAGE_FILE_MACHINE_AMD64; + frame.AddrPC.Offset = context->Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context->Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context->Rsp; + frame.AddrStack.Mode = AddrModeFlat; +#elif defined(_M_ARM64) + image_type = IMAGE_FILE_MACHINE_ARM64; + frame.AddrPC.Offset = context->Pc; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context->Fp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context->Sp; + frame.AddrStack.Mode = AddrModeFlat; +#else +# error Architecture not supported! +#endif + + for(U32 idx=0; ;idx++) + { + const U32 max_frames = 32; + if(idx == max_frames) + { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"..."); + break; + } + + if(!dbg_StackWalk64(image_type, process, thread, &frame, context, 0, dbg_SymFunctionTableAccess64, dbg_SymGetModuleBase64, 0)) + { + break; + } + + U64 address = frame.AddrPC.Offset; + if(address == 0) + { + break; + } + + if(idx==0) + { +#if BUILD_CONSOLE_INTERFACE + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nCreate a new issue with this report at %S.\n\n", BUILD_ISSUES_LINK_STRING_LITERAL); +#else + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, + L"\nPress Ctrl+C to copy this text to clipboard, then create a new issue at\n" + L"%S\n\n", BUILD_ISSUES_LINK_STRING_LITERAL, BUILD_ISSUES_LINK_STRING_LITERAL); +#endif + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"Call stack:\n"); + } + + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"%u. [0x%I64x]", idx + 1, address); + + struct { + SYMBOL_INFOW info; + WCHAR name[MAX_SYM_NAME]; + } symbol = {0}; + + symbol.info.SizeOfStruct = sizeof(symbol.info); + symbol.info.MaxNameLen = MAX_SYM_NAME; + + DWORD64 displacement = 0; + if(dbg_SymFromAddrW(process, address, &displacement, &symbol.info)) + { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s +%u", symbol.info.Name, (DWORD)displacement); + + IMAGEHLP_LINEW64 line = {0}; + line.SizeOfStruct = sizeof(line); + + DWORD line_displacement = 0; + if(dbg_SymGetLineFromAddrW64(process, address, &line_displacement, &line)) + { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L", %s line %u", PathFindFileNameW(line.FileName), line.LineNumber); + } + } + else + { + IMAGEHLP_MODULEW64 module = {0}; + module.SizeOfStruct = sizeof(module); + if(dbg_SymGetModuleInfoW64(process, address, &module)) + { + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s", module.ModuleName); + } + } + + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\n"); + } + } + } + } + } + + buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nVersion: %S%S", BUILD_VERSION_STRING_LITERAL, BUILD_GIT_HASH_STRING_LITERAL_APPEND); + +#if BUILD_CONSOLE_INTERFACE + fwprintf(stderr, L"\n--- Fatal Exception ---\n"); + fwprintf(stderr, L"%s\n\n", buffer); +#else + TASKDIALOGCONFIG dialog = {0}; + dialog.cbSize = sizeof(dialog); + dialog.dwFlags = TDF_SIZE_TO_CONTENT | TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION; + dialog.pszMainIcon = TD_ERROR_ICON; + dialog.dwCommonButtons = TDCBF_CLOSE_BUTTON; + dialog.pszWindowTitle = L"Fatal Exception"; + dialog.pszContent = buffer; + dialog.pfCallback = &win32_dialog_callback; + TaskDialogIndirect(&dialog, 0, 0, 0); +#endif + + ExitProcess(1); +} + +#undef OS_WINDOWS // shlwapi uses its own OS_WINDOWS include inside +#define OS_WINDOWS 1 + +internal void +w32_entry_point_caller(int argc, WCHAR **wargv) +{ + SetUnhandledExceptionFilter(&win32_exception_filter); + Arena *args_arena = arena_alloc__sized(MB(1), KB(32)); + char **argv = push_array(args_arena, char *, argc); + for(int i = 0; i < argc; i += 1) + { + String16 arg16 = str16_cstring((U16 *)wargv[i]); + String8 arg8 = str8_from_16(args_arena, arg16); + if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive)) + { + win32_g_is_quiet = 1; + } + argv[i] = (char *)arg8.str; + } + main_thread_base_entry_point(entry_point, argv, (U64)argc); +} + +#if BUILD_CONSOLE_INTERFACE +int wmain(int argc, WCHAR **argv) +{ + w32_entry_point_caller(argc, argv); + return 0; +} +#else +int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) +{ + w32_entry_point_caller(__argc, __wargv); + return 0; +} +#endif diff --git a/src/os/gfx/generated/os_gfx.meta.c b/src/os/gfx/generated/os_gfx.meta.c index b9d27fe6..04e5dc17 100644 --- a/src/os/gfx/generated/os_gfx.meta.c +++ b/src/os/gfx/generated/os_gfx.meta.c @@ -3,3 +3,300 @@ //- GENERATED CODE +C_LINKAGE_BEGIN +String8 os_g_key_display_string_table[143] = +{ +str8_lit_comp("Invalid Key"), +str8_lit_comp("Escape"), +str8_lit_comp("F1"), +str8_lit_comp("F2"), +str8_lit_comp("F3"), +str8_lit_comp("F4"), +str8_lit_comp("F5"), +str8_lit_comp("F6"), +str8_lit_comp("F7"), +str8_lit_comp("F8"), +str8_lit_comp("F9"), +str8_lit_comp("F10"), +str8_lit_comp("F11"), +str8_lit_comp("F12"), +str8_lit_comp("F13"), +str8_lit_comp("F14"), +str8_lit_comp("F15"), +str8_lit_comp("F16"), +str8_lit_comp("F17"), +str8_lit_comp("F18"), +str8_lit_comp("F19"), +str8_lit_comp("F20"), +str8_lit_comp("F21"), +str8_lit_comp("F22"), +str8_lit_comp("F23"), +str8_lit_comp("F24"), +str8_lit_comp("Tick"), +str8_lit_comp("0"), +str8_lit_comp("1"), +str8_lit_comp("2"), +str8_lit_comp("3"), +str8_lit_comp("4"), +str8_lit_comp("5"), +str8_lit_comp("6"), +str8_lit_comp("7"), +str8_lit_comp("8"), +str8_lit_comp("9"), +str8_lit_comp("Minus"), +str8_lit_comp("Equal"), +str8_lit_comp("Backspace"), +str8_lit_comp("Tab"), +str8_lit_comp("Q"), +str8_lit_comp("W"), +str8_lit_comp("E"), +str8_lit_comp("R"), +str8_lit_comp("T"), +str8_lit_comp("Y"), +str8_lit_comp("U"), +str8_lit_comp("I"), +str8_lit_comp("O"), +str8_lit_comp("P"), +str8_lit_comp("Left Bracket"), +str8_lit_comp("Right Bracket"), +str8_lit_comp("Back Slash"), +str8_lit_comp("Caps Lock"), +str8_lit_comp("A"), +str8_lit_comp("S"), +str8_lit_comp("D"), +str8_lit_comp("F"), +str8_lit_comp("G"), +str8_lit_comp("H"), +str8_lit_comp("J"), +str8_lit_comp("K"), +str8_lit_comp("L"), +str8_lit_comp("Semicolon"), +str8_lit_comp("Quote"), +str8_lit_comp("Return"), +str8_lit_comp("Shift"), +str8_lit_comp("Z"), +str8_lit_comp("X"), +str8_lit_comp("C"), +str8_lit_comp("V"), +str8_lit_comp("B"), +str8_lit_comp("N"), +str8_lit_comp("M"), +str8_lit_comp("Comma"), +str8_lit_comp("Period"), +str8_lit_comp("Slash"), +str8_lit_comp("Ctrl"), +str8_lit_comp("Alt"), +str8_lit_comp("Space"), +str8_lit_comp("Menu"), +str8_lit_comp("Scroll Lock"), +str8_lit_comp("Pause"), +str8_lit_comp("Insert"), +str8_lit_comp("Home"), +str8_lit_comp("Page Up"), +str8_lit_comp("Delete"), +str8_lit_comp("End"), +str8_lit_comp("Page Down"), +str8_lit_comp("Up"), +str8_lit_comp("Left"), +str8_lit_comp("Down"), +str8_lit_comp("Right"), +str8_lit_comp("Ex0"), +str8_lit_comp("Ex1"), +str8_lit_comp("Ex2"), +str8_lit_comp("Ex3"), +str8_lit_comp("Ex4"), +str8_lit_comp("Ex5"), +str8_lit_comp("Ex6"), +str8_lit_comp("Ex7"), +str8_lit_comp("Ex8"), +str8_lit_comp("Ex9"), +str8_lit_comp("Ex10"), +str8_lit_comp("Ex11"), +str8_lit_comp("Ex12"), +str8_lit_comp("Ex13"), +str8_lit_comp("Ex14"), +str8_lit_comp("Ex15"), +str8_lit_comp("Ex16"), +str8_lit_comp("Ex17"), +str8_lit_comp("Ex18"), +str8_lit_comp("Ex19"), +str8_lit_comp("Ex20"), +str8_lit_comp("Ex21"), +str8_lit_comp("Ex22"), +str8_lit_comp("Ex23"), +str8_lit_comp("Ex24"), +str8_lit_comp("Ex25"), +str8_lit_comp("Ex26"), +str8_lit_comp("Ex27"), +str8_lit_comp("Ex28"), +str8_lit_comp("Ex29"), +str8_lit_comp("Num Lock"), +str8_lit_comp("Numpad Slash"), +str8_lit_comp("Numpad Star"), +str8_lit_comp("Numpad Minus"), +str8_lit_comp("Numpad Plus"), +str8_lit_comp("Numpad Period"), +str8_lit_comp("Numpad 0"), +str8_lit_comp("Numpad 1"), +str8_lit_comp("Numpad 2"), +str8_lit_comp("Numpad 3"), +str8_lit_comp("Numpad 4"), +str8_lit_comp("Numpad 5"), +str8_lit_comp("Numpad 6"), +str8_lit_comp("Numpad 7"), +str8_lit_comp("Numpad 8"), +str8_lit_comp("Numpad 9"), +str8_lit_comp("Left Mouse Button"), +str8_lit_comp("Middle Mouse Button"), +str8_lit_comp("Right Mouse Button"), +}; + +String8 os_g_key_cfg_string_table[143] = +{ +str8_lit_comp("null"), +str8_lit_comp("esc"), +str8_lit_comp("f1"), +str8_lit_comp("f2"), +str8_lit_comp("f3"), +str8_lit_comp("f4"), +str8_lit_comp("f5"), +str8_lit_comp("f6"), +str8_lit_comp("f7"), +str8_lit_comp("f8"), +str8_lit_comp("f9"), +str8_lit_comp("f10"), +str8_lit_comp("f11"), +str8_lit_comp("f12"), +str8_lit_comp("f13"), +str8_lit_comp("f14"), +str8_lit_comp("f15"), +str8_lit_comp("f16"), +str8_lit_comp("f17"), +str8_lit_comp("f18"), +str8_lit_comp("f19"), +str8_lit_comp("f20"), +str8_lit_comp("f21"), +str8_lit_comp("f22"), +str8_lit_comp("f23"), +str8_lit_comp("f24"), +str8_lit_comp("tick"), +str8_lit_comp("0"), +str8_lit_comp("1"), +str8_lit_comp("2"), +str8_lit_comp("3"), +str8_lit_comp("4"), +str8_lit_comp("5"), +str8_lit_comp("6"), +str8_lit_comp("7"), +str8_lit_comp("8"), +str8_lit_comp("9"), +str8_lit_comp("minus"), +str8_lit_comp("equal"), +str8_lit_comp("backspace"), +str8_lit_comp("tab"), +str8_lit_comp("q"), +str8_lit_comp("w"), +str8_lit_comp("e"), +str8_lit_comp("r"), +str8_lit_comp("t"), +str8_lit_comp("y"), +str8_lit_comp("u"), +str8_lit_comp("i"), +str8_lit_comp("o"), +str8_lit_comp("p"), +str8_lit_comp("left_bracket"), +str8_lit_comp("right_bracket"), +str8_lit_comp("backslash"), +str8_lit_comp("caps_lock"), +str8_lit_comp("a"), +str8_lit_comp("s"), +str8_lit_comp("d"), +str8_lit_comp("f"), +str8_lit_comp("g"), +str8_lit_comp("h"), +str8_lit_comp("j"), +str8_lit_comp("k"), +str8_lit_comp("l"), +str8_lit_comp("semicolon"), +str8_lit_comp("quote"), +str8_lit_comp("return"), +str8_lit_comp("shift"), +str8_lit_comp("z"), +str8_lit_comp("x"), +str8_lit_comp("c"), +str8_lit_comp("v"), +str8_lit_comp("b"), +str8_lit_comp("n"), +str8_lit_comp("m"), +str8_lit_comp("comma"), +str8_lit_comp("period"), +str8_lit_comp("slash"), +str8_lit_comp("ctrl"), +str8_lit_comp("alt"), +str8_lit_comp("space"), +str8_lit_comp("menu"), +str8_lit_comp("scroll_lock"), +str8_lit_comp("pause"), +str8_lit_comp("insert"), +str8_lit_comp("home"), +str8_lit_comp("page_up"), +str8_lit_comp("delete"), +str8_lit_comp("end"), +str8_lit_comp("page_down"), +str8_lit_comp("up"), +str8_lit_comp("left"), +str8_lit_comp("down"), +str8_lit_comp("right"), +str8_lit_comp("ex0"), +str8_lit_comp("ex1"), +str8_lit_comp("ex2"), +str8_lit_comp("ex3"), +str8_lit_comp("ex4"), +str8_lit_comp("ex5"), +str8_lit_comp("ex6"), +str8_lit_comp("ex7"), +str8_lit_comp("ex8"), +str8_lit_comp("ex9"), +str8_lit_comp("ex10"), +str8_lit_comp("ex11"), +str8_lit_comp("ex12"), +str8_lit_comp("ex13"), +str8_lit_comp("ex14"), +str8_lit_comp("ex15"), +str8_lit_comp("ex16"), +str8_lit_comp("ex17"), +str8_lit_comp("ex18"), +str8_lit_comp("ex19"), +str8_lit_comp("ex20"), +str8_lit_comp("ex21"), +str8_lit_comp("ex22"), +str8_lit_comp("ex23"), +str8_lit_comp("ex24"), +str8_lit_comp("ex25"), +str8_lit_comp("ex26"), +str8_lit_comp("ex27"), +str8_lit_comp("ex28"), +str8_lit_comp("ex29"), +str8_lit_comp("num_lock"), +str8_lit_comp("numpad_slash"), +str8_lit_comp("numpad_star"), +str8_lit_comp("numpad_minus"), +str8_lit_comp("numpad_plus"), +str8_lit_comp("numpad_period"), +str8_lit_comp("numpad_0"), +str8_lit_comp("numpad_1"), +str8_lit_comp("numpad_2"), +str8_lit_comp("numpad_3"), +str8_lit_comp("numpad_4"), +str8_lit_comp("numpad_5"), +str8_lit_comp("numpad_6"), +str8_lit_comp("numpad_7"), +str8_lit_comp("numpad_8"), +str8_lit_comp("numpad_9"), +str8_lit_comp("left_mouse"), +str8_lit_comp("middle_mouse"), +str8_lit_comp("right_mouse"), +}; + +C_LINKAGE_END + diff --git a/src/os/gfx/generated/os_gfx.meta.h b/src/os/gfx/generated/os_gfx.meta.h index 9ce39166..ffa90e62 100644 --- a/src/os/gfx/generated/os_gfx.meta.h +++ b/src/os/gfx/generated/os_gfx.meta.h @@ -151,302 +151,12 @@ OS_Key_Num9, OS_Key_LeftMouseButton, OS_Key_MiddleMouseButton, OS_Key_RightMouseButton, -OS_Key_COUNT +OS_Key_COUNT, } OS_Key; -String8 os_g_key_display_string_table[] = -{ -str8_lit_comp("Invalid Key"), -str8_lit_comp("Escape"), -str8_lit_comp("F1"), -str8_lit_comp("F2"), -str8_lit_comp("F3"), -str8_lit_comp("F4"), -str8_lit_comp("F5"), -str8_lit_comp("F6"), -str8_lit_comp("F7"), -str8_lit_comp("F8"), -str8_lit_comp("F9"), -str8_lit_comp("F10"), -str8_lit_comp("F11"), -str8_lit_comp("F12"), -str8_lit_comp("F13"), -str8_lit_comp("F14"), -str8_lit_comp("F15"), -str8_lit_comp("F16"), -str8_lit_comp("F17"), -str8_lit_comp("F18"), -str8_lit_comp("F19"), -str8_lit_comp("F20"), -str8_lit_comp("F21"), -str8_lit_comp("F22"), -str8_lit_comp("F23"), -str8_lit_comp("F24"), -str8_lit_comp("Tick"), -str8_lit_comp("0"), -str8_lit_comp("1"), -str8_lit_comp("2"), -str8_lit_comp("3"), -str8_lit_comp("4"), -str8_lit_comp("5"), -str8_lit_comp("6"), -str8_lit_comp("7"), -str8_lit_comp("8"), -str8_lit_comp("9"), -str8_lit_comp("Minus"), -str8_lit_comp("Equal"), -str8_lit_comp("Backspace"), -str8_lit_comp("Tab"), -str8_lit_comp("Q"), -str8_lit_comp("W"), -str8_lit_comp("E"), -str8_lit_comp("R"), -str8_lit_comp("T"), -str8_lit_comp("Y"), -str8_lit_comp("U"), -str8_lit_comp("I"), -str8_lit_comp("O"), -str8_lit_comp("P"), -str8_lit_comp("Left Bracket"), -str8_lit_comp("Right Bracket"), -str8_lit_comp("Back Slash"), -str8_lit_comp("Caps Lock"), -str8_lit_comp("A"), -str8_lit_comp("S"), -str8_lit_comp("D"), -str8_lit_comp("F"), -str8_lit_comp("G"), -str8_lit_comp("H"), -str8_lit_comp("J"), -str8_lit_comp("K"), -str8_lit_comp("L"), -str8_lit_comp("Semicolon"), -str8_lit_comp("Quote"), -str8_lit_comp("Return"), -str8_lit_comp("Shift"), -str8_lit_comp("Z"), -str8_lit_comp("X"), -str8_lit_comp("C"), -str8_lit_comp("V"), -str8_lit_comp("B"), -str8_lit_comp("N"), -str8_lit_comp("M"), -str8_lit_comp("Comma"), -str8_lit_comp("Period"), -str8_lit_comp("Slash"), -str8_lit_comp("Ctrl"), -str8_lit_comp("Alt"), -str8_lit_comp("Space"), -str8_lit_comp("Menu"), -str8_lit_comp("Scroll Lock"), -str8_lit_comp("Pause"), -str8_lit_comp("Insert"), -str8_lit_comp("Home"), -str8_lit_comp("Page Up"), -str8_lit_comp("Delete"), -str8_lit_comp("End"), -str8_lit_comp("Page Down"), -str8_lit_comp("Up"), -str8_lit_comp("Left"), -str8_lit_comp("Down"), -str8_lit_comp("Right"), -str8_lit_comp("Ex0"), -str8_lit_comp("Ex1"), -str8_lit_comp("Ex2"), -str8_lit_comp("Ex3"), -str8_lit_comp("Ex4"), -str8_lit_comp("Ex5"), -str8_lit_comp("Ex6"), -str8_lit_comp("Ex7"), -str8_lit_comp("Ex8"), -str8_lit_comp("Ex9"), -str8_lit_comp("Ex10"), -str8_lit_comp("Ex11"), -str8_lit_comp("Ex12"), -str8_lit_comp("Ex13"), -str8_lit_comp("Ex14"), -str8_lit_comp("Ex15"), -str8_lit_comp("Ex16"), -str8_lit_comp("Ex17"), -str8_lit_comp("Ex18"), -str8_lit_comp("Ex19"), -str8_lit_comp("Ex20"), -str8_lit_comp("Ex21"), -str8_lit_comp("Ex22"), -str8_lit_comp("Ex23"), -str8_lit_comp("Ex24"), -str8_lit_comp("Ex25"), -str8_lit_comp("Ex26"), -str8_lit_comp("Ex27"), -str8_lit_comp("Ex28"), -str8_lit_comp("Ex29"), -str8_lit_comp("Num Lock"), -str8_lit_comp("Numpad Slash"), -str8_lit_comp("Numpad Star"), -str8_lit_comp("Numpad Minus"), -str8_lit_comp("Numpad Plus"), -str8_lit_comp("Numpad Period"), -str8_lit_comp("Numpad 0"), -str8_lit_comp("Numpad 1"), -str8_lit_comp("Numpad 2"), -str8_lit_comp("Numpad 3"), -str8_lit_comp("Numpad 4"), -str8_lit_comp("Numpad 5"), -str8_lit_comp("Numpad 6"), -str8_lit_comp("Numpad 7"), -str8_lit_comp("Numpad 8"), -str8_lit_comp("Numpad 9"), -str8_lit_comp("Left Mouse Button"), -str8_lit_comp("Middle Mouse Button"), -str8_lit_comp("Right Mouse Button"), -}; - -String8 os_g_key_cfg_string_table[] = -{ -str8_lit_comp("null"), -str8_lit_comp("esc"), -str8_lit_comp("f1"), -str8_lit_comp("f2"), -str8_lit_comp("f3"), -str8_lit_comp("f4"), -str8_lit_comp("f5"), -str8_lit_comp("f6"), -str8_lit_comp("f7"), -str8_lit_comp("f8"), -str8_lit_comp("f9"), -str8_lit_comp("f10"), -str8_lit_comp("f11"), -str8_lit_comp("f12"), -str8_lit_comp("f13"), -str8_lit_comp("f14"), -str8_lit_comp("f15"), -str8_lit_comp("f16"), -str8_lit_comp("f17"), -str8_lit_comp("f18"), -str8_lit_comp("f19"), -str8_lit_comp("f20"), -str8_lit_comp("f21"), -str8_lit_comp("f22"), -str8_lit_comp("f23"), -str8_lit_comp("f24"), -str8_lit_comp("tick"), -str8_lit_comp("0"), -str8_lit_comp("1"), -str8_lit_comp("2"), -str8_lit_comp("3"), -str8_lit_comp("4"), -str8_lit_comp("5"), -str8_lit_comp("6"), -str8_lit_comp("7"), -str8_lit_comp("8"), -str8_lit_comp("9"), -str8_lit_comp("minus"), -str8_lit_comp("equal"), -str8_lit_comp("backspace"), -str8_lit_comp("tab"), -str8_lit_comp("q"), -str8_lit_comp("w"), -str8_lit_comp("e"), -str8_lit_comp("r"), -str8_lit_comp("t"), -str8_lit_comp("y"), -str8_lit_comp("u"), -str8_lit_comp("i"), -str8_lit_comp("o"), -str8_lit_comp("p"), -str8_lit_comp("left_bracket"), -str8_lit_comp("right_bracket"), -str8_lit_comp("backslash"), -str8_lit_comp("caps_lock"), -str8_lit_comp("a"), -str8_lit_comp("s"), -str8_lit_comp("d"), -str8_lit_comp("f"), -str8_lit_comp("g"), -str8_lit_comp("h"), -str8_lit_comp("j"), -str8_lit_comp("k"), -str8_lit_comp("l"), -str8_lit_comp("semicolon"), -str8_lit_comp("quote"), -str8_lit_comp("return"), -str8_lit_comp("shift"), -str8_lit_comp("z"), -str8_lit_comp("x"), -str8_lit_comp("c"), -str8_lit_comp("v"), -str8_lit_comp("b"), -str8_lit_comp("n"), -str8_lit_comp("m"), -str8_lit_comp("comma"), -str8_lit_comp("period"), -str8_lit_comp("slash"), -str8_lit_comp("ctrl"), -str8_lit_comp("alt"), -str8_lit_comp("space"), -str8_lit_comp("menu"), -str8_lit_comp("scroll_lock"), -str8_lit_comp("pause"), -str8_lit_comp("insert"), -str8_lit_comp("home"), -str8_lit_comp("page_up"), -str8_lit_comp("delete"), -str8_lit_comp("end"), -str8_lit_comp("page_down"), -str8_lit_comp("up"), -str8_lit_comp("left"), -str8_lit_comp("down"), -str8_lit_comp("right"), -str8_lit_comp("ex0"), -str8_lit_comp("ex1"), -str8_lit_comp("ex2"), -str8_lit_comp("ex3"), -str8_lit_comp("ex4"), -str8_lit_comp("ex5"), -str8_lit_comp("ex6"), -str8_lit_comp("ex7"), -str8_lit_comp("ex8"), -str8_lit_comp("ex9"), -str8_lit_comp("ex10"), -str8_lit_comp("ex11"), -str8_lit_comp("ex12"), -str8_lit_comp("ex13"), -str8_lit_comp("ex14"), -str8_lit_comp("ex15"), -str8_lit_comp("ex16"), -str8_lit_comp("ex17"), -str8_lit_comp("ex18"), -str8_lit_comp("ex19"), -str8_lit_comp("ex20"), -str8_lit_comp("ex21"), -str8_lit_comp("ex22"), -str8_lit_comp("ex23"), -str8_lit_comp("ex24"), -str8_lit_comp("ex25"), -str8_lit_comp("ex26"), -str8_lit_comp("ex27"), -str8_lit_comp("ex28"), -str8_lit_comp("ex29"), -str8_lit_comp("num_lock"), -str8_lit_comp("numpad_slash"), -str8_lit_comp("numpad_star"), -str8_lit_comp("numpad_minus"), -str8_lit_comp("numpad_plus"), -str8_lit_comp("numpad_period"), -str8_lit_comp("numpad_0"), -str8_lit_comp("numpad_1"), -str8_lit_comp("numpad_2"), -str8_lit_comp("numpad_3"), -str8_lit_comp("numpad_4"), -str8_lit_comp("numpad_5"), -str8_lit_comp("numpad_6"), -str8_lit_comp("numpad_7"), -str8_lit_comp("numpad_8"), -str8_lit_comp("numpad_9"), -str8_lit_comp("left_mouse"), -str8_lit_comp("middle_mouse"), -str8_lit_comp("right_mouse"), -}; - +C_LINKAGE_BEGIN +extern String8 os_g_key_display_string_table[143]; +extern String8 os_g_key_cfg_string_table[143]; +C_LINKAGE_END #endif // OS_GFX_META_H diff --git a/src/os/gfx/os_gfx.c b/src/os/gfx/os_gfx.c index d7962d84..4e957a88 100644 --- a/src/os/gfx/os_gfx.c +++ b/src/os/gfx/os_gfx.c @@ -1,6 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/os_gfx.meta.c" + //////////////////////////////// //~ rjf: Event Functions (Helpers, Implemented Once) diff --git a/src/os/gfx/os_gfx.mdesk b/src/os/gfx/os_gfx.mdesk index 297f6ecf..bb399f3c 100644 --- a/src/os/gfx/os_gfx.mdesk +++ b/src/os/gfx/os_gfx.mdesk @@ -155,21 +155,18 @@ OS_KeyTable: //////////////////////////////// //~ rjf: Generators -@table_gen_enum -OS_Key: +@enum OS_Key: { - @expand(OS_KeyTable a) `OS_Key_$(a.name),`; - `OS_Key_COUNT`; + @expand(OS_KeyTable a) `$(a.name)`, + COUNT, } -@table_gen_data(type: String8, fallback:`{0}`) -os_g_key_display_string_table: +@data(String8) os_g_key_display_string_table: { - @expand(OS_KeyTable a) `str8_lit_comp("$(a.display_string)"),`; + @expand(OS_KeyTable a) `str8_lit_comp("$(a.display_string)")`; } -@table_gen_data(type: String8, fallback:`{0}`) -os_g_key_cfg_string_table: +@data(String8) os_g_key_cfg_string_table: { - @expand(OS_KeyTable a) `str8_lit_comp("$(a.cfg_string)"),`; + @expand(OS_KeyTable a) `str8_lit_comp("$(a.cfg_string)")`; } diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index 12f103d4..94d93f00 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -417,8 +417,8 @@ w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) event->key = OS_Key_RightMouseButton; }break; } - event->pos.x = (F32)LOWORD(lParam); - event->pos.y = (F32)HIWORD(lParam); + event->pos.x = (F32)(S16)LOWORD(lParam); + event->pos.y = (F32)(S16)HIWORD(lParam); if(release) { ReleaseCapture(); @@ -432,14 +432,20 @@ w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_MOUSEMOVE: { OS_Event *event = w32_push_event(OS_EventKind_MouseMove, window); - event->pos.x = (F32)LOWORD(lParam); - event->pos.y = (F32)HIWORD(lParam); + event->pos.x = (F32)(S16)LOWORD(lParam); + event->pos.y = (F32)(S16)HIWORD(lParam); }break; case WM_MOUSEWHEEL: { S16 wheel_delta = HIWORD(wParam); OS_Event *event = w32_push_event(OS_EventKind_Scroll, window); + POINT p; + p.x = (S32)(S16)LOWORD(lParam); + p.y = (S32)(S16)HIWORD(lParam); + ScreenToClient(window->hwnd, &p); + event->pos.x = (F32)p.x; + event->pos.y = (F32)p.y; event->delta = v2f32(0.f, -(F32)wheel_delta); }break; @@ -447,6 +453,12 @@ w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { S16 wheel_delta = HIWORD(wParam); OS_Event *event = w32_push_event(OS_EventKind_Scroll, window); + POINT p; + p.x = (S32)(S16)LOWORD(lParam); + p.y = (S32)(S16)HIWORD(lParam); + ScreenToClient(window->hwnd, &p); + event->pos.x = (F32)p.x; + event->pos.y = (F32)p.y; event->delta = v2f32((F32)wheel_delta, 0.f); }break; diff --git a/src/raddbg_convert/pdb/raddbg_pdb.c b/src/pdb/pdb.c similarity index 98% rename from src/raddbg_convert/pdb/raddbg_pdb.c rename to src/pdb/pdb.c index 0460653a..c6eed0b4 100644 --- a/src/raddbg_convert/pdb/raddbg_pdb.c +++ b/src/pdb/pdb.c @@ -4,7 +4,7 @@ //////////////////////////////// //~ PDB Parser Functions -static PDB_Info* +internal PDB_Info* pdb_info_from_data(Arena *arena, String8 data){ ProfBegin("pdb_info_from_data"); @@ -110,7 +110,7 @@ pdb_info_from_data(Arena *arena, String8 data){ return(result); } -static PDB_NamedStreamTable* +internal PDB_NamedStreamTable* pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info){ ProfBegin("pdb_named_stream_table_from_info"); @@ -156,7 +156,7 @@ pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info){ return(result); } -static PDB_Strtbl* +internal PDB_Strtbl* pdb_strtbl_from_data(Arena *arena, String8 data){ ProfBegin("pdb_strtbl_from_data"); @@ -191,7 +191,7 @@ pdb_strtbl_from_data(Arena *arena, String8 data){ result->strblock_min = strblock_off; result->strblock_max = strblock_off + strblock_size; result->buckets_min = bucket_array_off; - result->buckets_min = bucket_array_off + bucket_array_size; + result->buckets_max = bucket_array_off + bucket_array_size; } } @@ -200,7 +200,7 @@ pdb_strtbl_from_data(Arena *arena, String8 data){ return(result); } -static PDB_DbiParsed* +internal PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 data){ ProfBegin("pdb_dbi_from_data"); @@ -225,7 +225,7 @@ pdb_dbi_from_data(Arena *arena, String8 data){ // fill result result = push_array(arena, PDB_DbiParsed, 1); result->data = data; - result->arch = header->machine; + result->machine_type = header->machine; result->gsi_sn = header->gsi_sn; result->psi_sn = header->psi_sn; result->sym_sn = header->sym_sn; @@ -260,7 +260,7 @@ pdb_dbi_from_data(Arena *arena, String8 data){ return(result); } -static PDB_TpiParsed* +internal PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 data){ ProfBegin("pdb_tpi_from_data"); @@ -302,7 +302,7 @@ pdb_tpi_from_data(Arena *arena, String8 data){ return(result); } -static PDB_TpiHashParsed* +internal PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, String8 data, String8 aux_data){ ProfBegin("pdb_tpi_hash_from_data"); @@ -310,7 +310,7 @@ pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, Str U32 stride = tpi->hash_key_size; U32 bucket_count = tpi->hash_bucket_count; - if (1 <= stride && stride <= 8 && bucket_count > 0){ + if (1 <= stride && stride <= 8 && bucket_count > 0 && data.str != 0){ // allocate buckets PDB_TpiHashBlock **buckets = push_array(arena, PDB_TpiHashBlock*, bucket_count); @@ -434,7 +434,7 @@ pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, Str return(result); } -static PDB_GsiParsed* +internal PDB_GsiParsed* pdb_gsi_from_data(Arena *arena, String8 data){ ProfBegin("pdb_gsi_from_data"); @@ -563,7 +563,7 @@ pdb_gsi_from_data(Arena *arena, String8 data){ return(result); } -static PDB_CoffSectionArray* +internal PDB_CoffSectionArray* pdb_coff_section_array_from_data(Arena *arena, String8 data){ U64 count = data.size/sizeof(COFF_SectionHeader); @@ -573,7 +573,7 @@ pdb_coff_section_array_from_data(Arena *arena, String8 data){ return(result); } -static PDB_CompUnitArray* +internal PDB_CompUnitArray* pdb_comp_unit_array_from_data(Arena *arena, String8 data){ PDB_CompUnitNode *first = 0; PDB_CompUnitNode *last = 0; @@ -649,7 +649,7 @@ pdb_comp_unit_array_from_data(Arena *arena, String8 data){ return(result); } -static PDB_CompUnitContributionArray* +internal PDB_CompUnitContributionArray* pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, PDB_CoffSectionArray *sections){ PDB_CompUnitContribution *contributions = 0; @@ -715,7 +715,7 @@ pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 data, //////////////////////////////// //~ PDB Definition Functions -static U32 +internal U32 pdb_string_hash1(String8 string){ U32 result = 0; U8 *ptr = string.str; @@ -733,7 +733,7 @@ pdb_string_hash1(String8 string){ //////////////////////////////// //~ PDB Dbi Functions -static String8 +internal String8 pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range){ String8 result = {0}; if (range < PDB_DbiRange_COUNT){ @@ -745,7 +745,7 @@ pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range){ return(result); } -static String8 +internal String8 pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit, PDB_DbiCompUnitRange range){ String8 result = {0}; if (range < PDB_DbiCompUnitRange_COUNT){ @@ -765,7 +765,7 @@ pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit, PDB_DbiCompUnitRan //////////////////////////////// //~ PDB Tpi Functions -static String8 +internal String8 pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi){ String8 data = tpi->data; U8 *first = data.str + tpi->leaf_first; @@ -774,11 +774,9 @@ pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi){ return(result); } -static CV_TypeIdArray +internal CV_TypeIdArray pdb_tpi_itypes_from_name(Arena *arena, PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *leaf, String8 name, B32 compare_unique_name, U32 output_cap){ - ProfBegin("pdb_tpi_itypes_from_name"); - U32 hash = pdb_string_hash1(name); U32 bucket_idx = ((tpi_hash->bucket_mask != 0) ? hash&tpi_hash->bucket_mask : @@ -964,16 +962,12 @@ pdb_tpi_itypes_from_name(Arena *arena, PDB_TpiHashParsed *tpi_hash, CV_LeafParse scratch_end(scratch); - ProfEnd(); - return(result); } -static CV_TypeId +internal CV_TypeId pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *tpi_leaf, String8 name, B32 compare_unique_name){ - ProfBegin("pdb_tpi_first_itype_from_name"); - Temp scratch = scratch_begin(0, 0); CV_TypeIdArray array = pdb_tpi_itypes_from_name(scratch.arena, tpi_hash, tpi_leaf, name, compare_unique_name, 1); @@ -983,15 +977,13 @@ pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, CV_LeafParsed *tpi_le } scratch_end(scratch); - ProfEnd(); - return(result); } //////////////////////////////// //~ PDB Strtbl Functions -static String8 +internal String8 pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off){ U32 strblock_max = strtbl->strblock_max; U32 full_off_raw = strtbl->strblock_min + off; @@ -1001,7 +993,7 @@ pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off){ return(result); } -static String8 +internal String8 pdb_strtbl_string_from_index(PDB_Strtbl *strtbl, PDB_StringIndex idx){ String8 result = {0}; if (idx < strtbl->bucket_count){ diff --git a/src/raddbg_convert/pdb/raddbg_pdb.h b/src/pdb/pdb.h similarity index 76% rename from src/raddbg_convert/pdb/raddbg_pdb.h rename to src/pdb/pdb.h index 1c60789c..e86f6851 100644 --- a/src/raddbg_convert/pdb/raddbg_pdb.h +++ b/src/pdb/pdb.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_PDB_H -#define RADDBG_PDB_H +#ifndef PDB_H +#define PDB_H // https://github.com/microsoft/microsoft-pdb/tree/master/PDB @@ -127,7 +127,7 @@ typedef struct PDB_DbiHeader{ U32 ec_info_size; PDB_DbiHeaderFlags flags; - COFF_Arch machine; + COFF_MachineType machine; U32 reserved; } PDB_DbiHeader; @@ -307,7 +307,7 @@ typedef struct PDB_Strtbl{ typedef struct PDB_DbiParsed{ String8 data; - COFF_Arch arch; + COFF_MachineType machine_type; MSF_StreamNumber gsi_sn; MSF_StreamNumber psi_sn; MSF_StreamNumber sym_sn; @@ -400,63 +400,63 @@ typedef struct PDB_CompUnitContributionArray{ //////////////////////////////// //~ PDB Parser Functions -static PDB_Info* pdb_info_from_data(Arena *arena, String8 pdb_info_data); -static PDB_NamedStreamTable*pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info); -static PDB_Strtbl* pdb_strtbl_from_data(Arena *arena, String8 strtbl_data); +internal PDB_Info* pdb_info_from_data(Arena *arena, String8 pdb_info_data); +internal PDB_NamedStreamTable*pdb_named_stream_table_from_info(Arena *arena, PDB_Info *info); +internal PDB_Strtbl* pdb_strtbl_from_data(Arena *arena, String8 strtbl_data); -static PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 dbi_data); -static PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 tpi_data); -static PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena, - PDB_Strtbl *strtbl, - PDB_TpiParsed *tpi, - String8 tpi_hash_data, - String8 tpi_hash_aux_data); -static PDB_GsiParsed* pdb_gsi_from_data(Arena *arena, String8 gsi_data); +internal PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 dbi_data); +internal PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 tpi_data); +internal PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena, + PDB_Strtbl *strtbl, + PDB_TpiParsed *tpi, + String8 tpi_hash_data, + String8 tpi_hash_aux_data); +internal PDB_GsiParsed* pdb_gsi_from_data(Arena *arena, String8 gsi_data); -static PDB_CoffSectionArray*pdb_coff_section_array_from_data(Arena *arena, - String8 section_data); +internal PDB_CoffSectionArray*pdb_coff_section_array_from_data(Arena *arena, + String8 section_data); -static PDB_CompUnitArray* pdb_comp_unit_array_from_data(Arena *arena, - String8 module_info_data); +internal PDB_CompUnitArray* pdb_comp_unit_array_from_data(Arena *arena, + String8 module_info_data); -static PDB_CompUnitContributionArray* +internal PDB_CompUnitContributionArray* pdb_comp_unit_contribution_array_from_data(Arena *arena, String8 seccontrib_data, PDB_CoffSectionArray *sections); //////////////////////////////// //~ PDB Definition Functions -static U32 pdb_string_hash1(String8 string); +internal U32 pdb_string_hash1(String8 string); //////////////////////////////// //~ PDB Dbi Functions -static String8 pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range); -static String8 pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit, - PDB_DbiCompUnitRange range); +internal String8 pdb_data_from_dbi_range(PDB_DbiParsed *dbi, PDB_DbiRange range); +internal String8 pdb_data_from_unit_range(MSF_Parsed *msf, PDB_CompUnit *unit, + PDB_DbiCompUnitRange range); //////////////////////////////// //~ PDB Tpi Functions -static String8 pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi); +internal String8 pdb_leaf_data_from_tpi(PDB_TpiParsed *tpi); -static CV_TypeIdArray pdb_tpi_itypes_from_name(Arena *arena, - PDB_TpiHashParsed *tpi_hash, - CV_LeafParsed *tpi_leaf, - String8 name, - B32 compare_unique_name, - U32 output_cap); +internal CV_TypeIdArray pdb_tpi_itypes_from_name(Arena *arena, + PDB_TpiHashParsed *tpi_hash, + CV_LeafParsed *tpi_leaf, + String8 name, + B32 compare_unique_name, + U32 output_cap); -static CV_TypeId pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, - CV_LeafParsed *tpi_leaf, - String8 name, - B32 compare_unique_name); +internal CV_TypeId pdb_tpi_first_itype_from_name(PDB_TpiHashParsed *tpi_hash, + CV_LeafParsed *tpi_leaf, + String8 name, + B32 compare_unique_name); //////////////////////////////// //~ PDB Strtbl Functions -static String8 pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off); -static String8 pdb_strtbl_string_from_index(PDB_Strtbl *strtbl, - PDB_StringIndex idx); +internal String8 pdb_strtbl_string_from_off(PDB_Strtbl *strtbl, U32 off); +internal String8 pdb_strtbl_string_from_index(PDB_Strtbl *strtbl, + PDB_StringIndex idx); -#endif //RADDBG_PDB_H +#endif // PDB_H diff --git a/src/raddbg_convert/pdb/raddbg_pdb_stringize.c b/src/pdb/pdb_stringize.c similarity index 98% rename from src/raddbg_convert/pdb/raddbg_pdb_stringize.c rename to src/pdb/pdb_stringize.c index a1726d28..7cd3f7e2 100644 --- a/src/raddbg_convert/pdb/raddbg_pdb_stringize.c +++ b/src/pdb/pdb_stringize.c @@ -4,7 +4,7 @@ //////////////////////////////// //~ PDB Stringize Functions -static void +internal void pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash){ U32 bucket_count = hash->bucket_count; str8_list_pushf(arena, out, "bucket_count=%u\n\n", bucket_count); diff --git a/src/pdb/pdb_stringize.h b/src/pdb/pdb_stringize.h new file mode 100644 index 00000000..db0ca656 --- /dev/null +++ b/src/pdb/pdb_stringize.h @@ -0,0 +1,12 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef PDB_STRINGIZE_H +#define PDB_STRINGIZE_H + +//////////////////////////////// +//~ PDB Stringize Functions + +internal void pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash); + +#endif // PDB_STRINGIZE_H diff --git a/src/pe/pe.c b/src/pe/pe.c index 39447b98..f2b243f9 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -1,6 +1,54 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Basic Enum Functions + +internal U32 +pe_slot_count_from_unwind_op_code(PE_UnwindOpCode opcode) +{ + U32 result = 0; + switch(opcode) + { + case PE_UnwindOpCode_PUSH_NONVOL: result = 1; break; + case PE_UnwindOpCode_ALLOC_LARGE: result = 2; break; + case PE_UnwindOpCode_ALLOC_SMALL: result = 1; break; + case PE_UnwindOpCode_SET_FPREG: result = 1; break; + case PE_UnwindOpCode_SAVE_NONVOL: result = 2; break; + case PE_UnwindOpCode_SAVE_NONVOL_FAR: result = 3; break; + case PE_UnwindOpCode_EPILOG: result = 2; break; + case PE_UnwindOpCode_SPARE_CODE: result = 3; break; + case PE_UnwindOpCode_SAVE_XMM128: result = 2; break; + case PE_UnwindOpCode_SAVE_XMM128_FAR: result = 3; break; + case PE_UnwindOpCode_PUSH_MACHFRAME: result = 1; break; + } + return result; +} + +internal String8 +pe_string_from_windows_subsystem(PE_WindowsSubsystem subsystem) +{ + String8 result = {0}; + switch(subsystem) + { + default:{}break; + case PE_WindowsSubsystem_UNKNOWN: result = str8_lit("UNKNOWN"); break; + case PE_WindowsSubsystem_NATIVE: result = str8_lit("NATIVE"); break; + case PE_WindowsSubsystem_WINDOWS_GUI: result = str8_lit("WINDOWS_GUI"); break; + case PE_WindowsSubsystem_WINDOWS_CUI: result = str8_lit("WINDOWS_CUI"); break; + case PE_WindowsSubsystem_OS2_CUI: result = str8_lit("OS2_CUI"); break; + case PE_WindowsSubsystem_POSIX_CUI: result = str8_lit("POSIX_CUI"); break; + case PE_WindowsSubsystem_NATIVE_WINDOWS: result = str8_lit("NATIVE_WINDOWS"); break; + case PE_WindowsSubsystem_WINDOWS_CE_GUI: result = str8_lit("WINDOWS_CE_GUID"); break; + case PE_WindowsSubsystem_EFI_APPLICATION: result = str8_lit("EFI_APPLICATION"); break; + case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER: result = str8_lit("EFI_BOOT_SERVICE_DRIVER"); break; + case PE_WindowsSubsystem_EFI_ROM: result = str8_lit("EFI_ROM"); break; + case PE_WindowsSubsystem_XBOX: result = str8_lit("XBOX"); break; + case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: result = str8_lit("WINDOWS_BOOT_APPLICATION"); break; + } + return result; +} + //////////////////////////////// //~ rjf: Parser Functions @@ -535,7 +583,7 @@ pe_resource_dir_push_dir_node(Arena *arena, PE_ResourceDir *dir, COFF_ResourceID PE_Resource *res = &res_node->data; res->id = id; - res->type = PE_ResData_DIR; + res->kind = PE_ResDataKind_DIR; res->u.dir = sub_dir; return res_node; @@ -558,7 +606,7 @@ pe_resource_dir_push_entry_node(Arena *arena, PE_ResourceDir *dir, COFF_Resource PE_Resource *res = &res_node->data; res->id = id; - res->type = PE_ResData_COFF_RESOURCE; + res->kind = PE_ResDataKind_COFF_RESOURCE; res->u.coff_res.type = type; res->u.coff_res.data_version = data_version; res->u.coff_res.version = version; @@ -716,7 +764,7 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) entry->id.type = COFF_ResourceIDType_STRING; entry->id.u.string = str8_from_16(arena, name16); - entry->type = is_dir ? PE_ResData_DIR : PE_ResData_COFF_LEAF; + entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF; if (is_dir) { struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); @@ -745,7 +793,7 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) entry->id.type = COFF_ResourceIDType_NUMBER; entry->id.u.number = coff_entry.name.id; - entry->type = is_dir ? PE_ResData_DIR : PE_ResData_COFF_LEAF; + entry->kind = is_dir ? PE_ResDataKind_DIR : PE_ResDataKind_COFF_LEAF; if (is_dir) { struct stack_s *frame = push_array(scratch.arena, struct stack_s, 1); @@ -766,43 +814,3 @@ pe_resource_table_from_directory_data(Arena *arena, String8 data) scratch_end(scratch); return bottom_frame->table; } - -//////////////////////////////// - -internal String8 -pe_get_dos_program(void) -{ - // generated from pe/dos_program.asm - static U8 program[] = { - 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, - 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, - 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, - 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x24, 0x00, 0x00 - }; - return str8(program, sizeof(program)); -} - -//////////////////////////////// - -internal String8 -pe_string_from_subsystem(PE_WindowsSubsystem subsystem) -{ - switch (subsystem) { - case PE_WindowsSubsystem_UNKNOWN: return str8_lit("UNKNOWN"); - case PE_WindowsSubsystem_NATIVE: return str8_lit("NATIVE"); - case PE_WindowsSubsystem_WINDOWS_GUI: return str8_lit("WINDOWS_GUI"); - case PE_WindowsSubsystem_WINDOWS_CUI: return str8_lit("WINDOWS_CUI"); - case PE_WindowsSubsystem_OS2_CUI: return str8_lit("OS2_CUI"); - case PE_WindowsSubsystem_POSIX_CUI: return str8_lit("POSIX_CUI"); - case PE_WindowsSubsystem_NATIVE_WINDOWS: return str8_lit("NATIVE_WINDOWS"); - case PE_WindowsSubsystem_WINDOWS_CE_GUI: return str8_lit("WINDOWS_CE_GUID"); - case PE_WindowsSubsystem_EFI_APPLICATION: return str8_lit("EFI_APPLICATION"); - case PE_WindowsSubsystem_EFI_BOOT_SERVICE_DRIVER: return str8_lit("EFI_BOOT_SERVICE_DRIVER"); - case PE_WindowsSubsystem_EFI_ROM: return str8_lit("EFI_ROM"); - case PE_WindowsSubsystem_XBOX: return str8_lit("XBOX"); - case PE_WindowsSubsystem_WINDOWS_BOOT_APPLICATION: return str8_lit("WINDOWS_BOOT_APPLICATION"); - default: break; - } - return str8(0,0); -} - diff --git a/src/pe/pe.h b/src/pe/pe.h index 28635a48..ebb89f4b 100644 --- a/src/pe/pe.h +++ b/src/pe/pe.h @@ -1,13 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -/* date = September 6th 2023 8:54 am */ - #ifndef PE_H #define PE_H //////////////////////////////// -//~ rjf: PE Format Types +//~ rjf: PE Format-Defined Types/Constants #pragma pack(push,1) @@ -287,7 +285,7 @@ enum PE_GlobalFlags_HEAP_ENABLE_TAG_BY_DLL = (1 << 15), PE_GlobalFlags_DISABLE_STACK_EXTENSION = (1 << 16), PE_GlobalFlags_ENABLE_CSRDEBUG = (1 << 17), - PE_GlobalFlags_ENABLE_KDEBUG_SYMBOL_LOAD = (1 << 18), + PE_GlobalFlags_ENABLE_KDEBUG_SYMBOL_LOAD = (1 << 18), PE_GlobalFlags_DISABLE_PAGE_KERNEL_STACKS = (1 << 19), PE_GlobalFlags_ENABLE_SYSTEM_CRIT_BREAKS = (1 << 20), PE_GlobalFlags_HEAP_DISABLE_COALESCING = (1 << 21), @@ -445,11 +443,273 @@ struct PE_TLSHeader64 U32 characteristics; // COFF_SectionFlags but only align flags are used. }; +#define PE_RES_ALIGN 4u + +global read_only U8 PE_RES_MAGIC[] = +{ + 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +typedef U32 PE_ResourceKind; +enum +{ + PE_ResourceKind_CURSOR = 0x1, + PE_ResourceKind_BITMAP = 0x2, + PE_ResourceKind_ICON = 0x3, + PE_ResourceKind_MENU = 0x4, + PE_ResourceKind_DIALOG = 0x5, + PE_ResourceKind_STRING = 0x6, + PE_ResourceKind_FONTDIR = 0x7, + PE_ResourceKind_FONT = 0x8, + PE_ResourceKind_ACCELERATOR = 0x9, + PE_ResourceKind_RCDATA = 0xA, + PE_ResourceKind_MESSAGETABLE = 0xB, + PE_ResourceKind_GROUP_CURSOR = 0xC, + PE_ResourceKind_GROUP_ICON = 0xE, + PE_ResourceKind_VERSION = 0x10, + PE_ResourceKind_DLGINCLUDE = 0x11, + PE_ResourceKind_PLUGPLAY = 0x13, + PE_ResourceKind_VXD = 0x14, + PE_ResourceKind_ANICURSOR = 0x15, + PE_ResourceKind_ANIICON = 0x16, + PE_ResourceKind_HTML = 0x17, + PE_ResourceKind_MANIFEST = 0x18, + PE_ResourceKind_BITMAP_NEW = 0x2002, + PE_ResourceKind_MENU_NEW = 0x2004, + PE_ResourceKind_DIALOG_NEW = 0x2005, +}; + +typedef enum PE_ResDataKind +{ + PE_ResDataKind_NULL, + PE_ResDataKind_DIR, + PE_ResDataKind_COFF_LEAF, + PE_ResDataKind_COFF_RESOURCE, +} +PE_ResDataKind; + +typedef struct PE_ResourceHeader PE_ResourceHeader; +struct PE_ResourceHeader +{ + COFF_ResourceHeaderPrefix prefix; + U16 type; + U16 pad0; + U16 name; + U16 pad1; + U32 data_version; + COFF_ResourceMemoryFlags memory_flags; + U16 language_id; + U32 version; + U32 characteristics; +}; + +typedef U16 PE_BaseRelocKind; +enum +{ + PE_BaseRelocKind_ABSOLUTE = 0, // No reallocation is applied. Can be used as padding. + PE_BaseRelocKind_HIGH = 1, + PE_BaseRelocKind_LOW = 2, + PE_BaseRelocKind_HIGHLOW = 3, + PE_BaseRelocKind_HIGHADJ = 4, + PE_BaseRelocKind_MIPS_JMPADDR = 5, + PE_BaseRelocKind_ARM_MOV32 = 5, + PE_BaseRelocKind_RISCV_HIGH20 = 5, + // 6 is reserved + PE_BaseRelocKind_THUMB_MOV32 = 7, + PE_BaseRelocKind_RISCV_LOW12I = 7, + PE_BaseRelocKind_RISCV_LOW12S = 8, + PE_BaseRelocKind_LOONGARCH32_MARK_LA = 8, + PE_BaseRelocKind_LOONGARCH64_MARK_LA = 8, + PE_BaseRelocKind_MIPS_JMPADDR16 = 9, + PE_BaseRelocKind_DIR64 = 10, +}; +#define PE_BaseRelocOffsetFromEntry(x) ((x) & 0x1fff) +#define PE_BaseRelocKindFromEntry(x) (((x) >> 12) & 0xf) +#define PE_BaseRelocMake(k, off) ((((U16)(k) & 0xf) << 12) | (U16)((off) & 0x1fff)) + +typedef U32 PE_UnwindOpCode; +enum +{ + PE_UnwindOpCode_PUSH_NONVOL = 0, + PE_UnwindOpCode_ALLOC_LARGE = 1, + PE_UnwindOpCode_ALLOC_SMALL = 2, + PE_UnwindOpCode_SET_FPREG = 3, + PE_UnwindOpCode_SAVE_NONVOL = 4, + PE_UnwindOpCode_SAVE_NONVOL_FAR = 5, + PE_UnwindOpCode_EPILOG = 6, + PE_UnwindOpCode_SPARE_CODE = 7, + PE_UnwindOpCode_SAVE_XMM128 = 8, + PE_UnwindOpCode_SAVE_XMM128_FAR = 9, + PE_UnwindOpCode_PUSH_MACHFRAME = 10, +}; + +typedef U8 PE_UnwindGprRegX64; +enum +{ + PE_UnwindGprRegX64_RAX = 0, + PE_UnwindGprRegX64_RCX = 1, + PE_UnwindGprRegX64_RDX = 2, + PE_UnwindGprRegX64_RBX = 3, + PE_UnwindGprRegX64_RSP = 4, + PE_UnwindGprRegX64_RBP = 5, + PE_UnwindGprRegX64_RSI = 6, + PE_UnwindGprRegX64_RDI = 7, + PE_UnwindGprRegX64_R8 = 8, + PE_UnwindGprRegX64_R9 = 9, + PE_UnwindGprRegX64_R10 = 10, + PE_UnwindGprRegX64_R11 = 11, + PE_UnwindGprRegX64_R12 = 12, + PE_UnwindGprRegX64_R13 = 13, + PE_UnwindGprRegX64_R14 = 14, + PE_UnwindGprRegX64_R15 = 15, +}; + +typedef U8 PE_UnwindInfoFlags; +enum +{ + PE_UnwindInfoFlag_EHANDLER = (1<<0), + PE_UnwindInfoFlag_UHANDLER = (1<<1), + PE_UnwindInfoFlag_FHANDLER = 3, + PE_UnwindInfoFlag_CHAINED = (1<<2), +}; + +#define PE_UNWIND_OPCODE_FROM_FLAGS(f) ((f)&0xF) +#define PE_UNWIND_INFO_FROM_FLAGS(f) (((f) >> 4)&0xF) + +typedef union PE_UnwindCode PE_UnwindCode; +union PE_UnwindCode +{ + struct + { + U8 off_in_prolog; + U8 flags; + }; + U16 u16; +}; + +#define PE_UNWIND_INFO_VERSION_FROM_HDR(x) ((x)&0x7) +#define PE_UNWIND_INFO_FLAGS_FROM_HDR(x) (((x) >> 3)&0x1F) +#define PE_UNWIND_INFO_REG_FROM_FRAME(x) ((x)&0xF) +#define PE_UNWIND_INFO_OFF_FROM_FRAME(x) (((x) >> 4)&0xF) + +typedef struct PE_UnwindInfo PE_UnwindInfo; +struct PE_UnwindInfo +{ + U8 header; + U8 prolog_size; + U8 codes_num; + U8 frame; +}; + #pragma pack(pop) +//////////////////////////////// +//~ rjf: DOS Program + +// generated from pe/dos_program.asm +read_only global U8 pe_dos_program_data[] = +{ + 0x0E, 0x1F, 0xBA, 0x0E, 0x00, 0xB4, 0x09, 0xCD, 0x21, 0xB8, 0x01, 0x4C, 0xCD, 0x21, 0x54, 0x68, + 0x69, 0x73, 0x20, 0x70, 0x72, 0x6F, 0x67, 0x72, 0x61, 0x6D, 0x20, 0x63, 0x61, 0x6E, 0x6E, 0x6F, + 0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6E, 0x20, 0x69, 0x6E, 0x20, 0x44, 0x4F, 0x53, 0x20, + 0x6D, 0x6F, 0x64, 0x65, 0x2E, 0x24, 0x00, 0x00 +}; +read_only global String8 pe_dos_program = {pe_dos_program_data, sizeof(pe_dos_program_data)}; + //////////////////////////////// //~ rjf: Parsed Info Types +//- rjf: relocation blocks + +typedef struct PE_BaseRelocBlock PE_BaseRelocBlock; +struct PE_BaseRelocBlock +{ + U64 page_virt_off; + U64 entry_count; + U16 *entries; +}; + +typedef struct PE_BaseRelocBlockNode PE_BaseRelocBlockNode; +struct PE_BaseRelocBlockNode +{ + PE_BaseRelocBlockNode *next; + PE_BaseRelocBlock v; +}; + +typedef struct PE_BaseRelocBlockList PE_BaseRelocBlockList; +struct PE_BaseRelocBlockList +{ + PE_BaseRelocBlockNode *first; + PE_BaseRelocBlockNode *last; + U64 count; +}; + +//- rjf: resources + +typedef struct PE_Resource PE_Resource; +struct PE_Resource +{ + COFF_ResourceID id; + PE_ResDataKind kind; + union + { + COFF_ResourceDataEntry leaf; + struct PE_ResourceDir *dir; + struct + { + COFF_ResourceID type; + U32 data_version; + U32 version; + COFF_ResourceMemoryFlags memory_flags; + String8 data; + } + coff_res; + } + u; +}; + +typedef struct PE_ResourceNode PE_ResourceNode; +struct PE_ResourceNode +{ + PE_ResourceNode *next; + PE_Resource data; +}; + +typedef struct PE_ResourceList PE_ResourceList; +struct PE_ResourceList +{ + PE_ResourceNode *first; + PE_ResourceNode *last; + U64 count; +}; + +typedef struct PE_ResourceArray PE_ResourceArray; +struct PE_ResourceArray +{ + PE_Resource *v; + U64 count; +}; + +typedef struct PE_ResourceDir PE_ResourceDir; +struct PE_ResourceDir +{ + U32 characteristics; + COFF_TimeStamp time_stamp; + U16 major_version; + U16 minor_version; + PE_ResourceList named_list; + PE_ResourceList id_list; +}; + +//- rjf: bundle + typedef struct PE_BinInfo PE_BinInfo; struct PE_BinInfo { @@ -475,161 +735,10 @@ struct PE_BinInfo }; //////////////////////////////// -//~ rjf: Parsed Info Extraction Helper Types +//~ rjf: Basic Enum Functions -typedef U16 PE_BaseRelocKind; -enum -{ - PE_BaseRelocKind_ABSOLUTE = 0, // No reallocation is applied. Can be used as padding. - PE_BaseRelocKind_HIGH = 1, - PE_BaseRelocKind_LOW = 2, - PE_BaseRelocKind_HIGHLOW = 3, - PE_BaseRelocKind_HIGHADJ = 4, - PE_BaseRelocKind_MIPS_JMPADDR = 5, - PE_BaseRelocKind_ARM_MOV32 = 5, - PE_BaseRelocKind_RISCV_HIGH20 = 5, - // 6 is reserved - PE_BaseRelocKind_THUMB_MOV32 = 7, - PE_BaseRelocKind_RISCV_LOW12I = 7, - PE_BaseRelocKind_RISCV_LOW12S = 8, - PE_BaseRelocKind_LOONGARCH32_MARK_LA = 8, - PE_BaseRelocKind_LOONGARCH64_MARK_LA = 8, - PE_BaseRelocKind_MIPS_JMPADDR16 = 9, - PE_BaseRelocKind_DIR64 = 10, -}; -#define PE_BaseRelocOffsetFromEntry(x) ((x) & 0x1fff) -#define PE_BaseRelocKindFromEntry(x) (((x) >> 12) & 0xf) -#define PE_BaseRelocMake(k, off) ((((U16)(k) & 0xf) << 12) | (U16)((off) & 0x1fff)) - -typedef struct PE_BaseRelocBlock PE_BaseRelocBlock; -struct PE_BaseRelocBlock -{ - U64 page_virt_off; - U64 entry_count; - U16 *entries; -}; - -typedef struct PE_BaseRelocBlockNode PE_BaseRelocBlockNode; -struct PE_BaseRelocBlockNode -{ - PE_BaseRelocBlockNode *next; - PE_BaseRelocBlock v; -}; - -typedef struct PE_BaseRelocBlockList PE_BaseRelocBlockList; -struct PE_BaseRelocBlockList -{ - PE_BaseRelocBlockNode *first; - PE_BaseRelocBlockNode *last; - U64 count; -}; - -//////////////////////////////// -//~ Resources - -#define PE_RES_ALIGN 4u - -read_only U8 PE_RES_MAGIC[] = { 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - -enum -{ - PE_Resource_CURSOR = 0x1, - PE_Resource_BITMAP = 0x2, - PE_Resource_ICON = 0x3, - PE_Resource_MENU = 0x4, - PE_Resource_DIALOG = 0x5, - PE_Resource_STRING = 0x6, - PE_Resource_FONTDIR = 0x7, - PE_Resource_FONT = 0x8, - PE_Resource_ACCELERATOR = 0x9, - PE_Resource_RCDATA = 0xA, - PE_Resource_MESSAGETABLE = 0xB, - PE_Resource_GROUP_CURSOR = 0xC, - PE_Resource_GROUP_ICON = 0xE, - PE_Resource_VERSION = 0x10, - PE_Resource_DLGINCLUDE = 0x11, - PE_Resource_PLUGPLAY = 0x13, - PE_Resource_VXD = 0x14, - PE_Resource_ANICURSOR = 0x15, - PE_Resource_ANIICON = 0x16, - PE_Resource_HTML = 0x17, - PE_Resource_MANIFEST = 0x18, - PE_Resource_BITMAP_NEW = 0x2002, - PE_Resource_MENU_NEW = 0x2004, - PE_Resource_DIALOG_NEW = 0x2005, -}; -typedef U32 PE_ResourceType; - -#pragma pack(push, 1) -typedef struct PE_ResourceHeader -{ - COFF_ResourceHeaderPrefix prefix; - U16 type; - U16 pad0; - U16 name; - U16 pad1; - U32 data_version; - COFF_ResourceMemoryFlags memory_flags; - U16 language_id; - U32 version; - U32 characteristics; -} PE_ResourceHeader; -#pragma pack(pop) - -typedef enum -{ - PE_ResData_NULL, - PE_ResData_DIR, - PE_ResData_COFF_LEAF, - PE_ResData_COFF_RESOURCE, -} PE_ResDataType; - -typedef struct PE_Resource -{ - COFF_ResourceID id; - PE_ResDataType type; - union { - COFF_ResourceDataEntry leaf; - struct PE_ResourceDir *dir; - struct { - COFF_ResourceID type; - U32 data_version; - U32 version; - COFF_ResourceMemoryFlags memory_flags; - String8 data; - } coff_res; - } u; -} PE_Resource; - -typedef struct PE_ResourceNode -{ - struct PE_ResourceNode *next; - PE_Resource data; -} PE_ResourceNode; - -typedef struct PE_ResourceList -{ - U64 count; - PE_ResourceNode *first; - PE_ResourceNode *last; -} PE_ResourceList; - -typedef struct PE_ResourceArray -{ - U64 count; - PE_Resource *v; -} PE_ResourceArray; - -typedef struct PE_ResourceDir -{ - U32 characteristics; - COFF_TimeStamp time_stamp; - U16 major_version; - U16 minor_version; - PE_ResourceList named_list; - PE_ResourceList id_list; -} PE_ResourceDir; +internal U32 pe_slot_count_from_unwind_op_code(PE_UnwindOpCode opcode); +internal String8 pe_string_from_windows_subsystem(PE_WindowsSubsystem subsystem); //////////////////////////////// //~ rjf: Parser Functions @@ -661,12 +770,4 @@ internal PE_Resource * pe_resource_dir_search(PE_ResourceDir *dir, COFF_Reso internal PE_ResourceArray pe_resource_list_to_array(Arena *arena, PE_ResourceList *list); internal PE_ResourceDir * pe_resource_table_from_directory_data(Arena *arena, String8 data); -//////////////////////////////// - -internal String8 pe_get_dos_program(void); - -//////////////////////////////// - -internal String8 pe_string_from_subsystem(PE_WindowsSubsystem subsystem); - -#endif //PE_H +#endif // PE_H diff --git a/src/raddbg/raddbg.c b/src/raddbg/raddbg.c index d8414795..87425b6b 100644 --- a/src/raddbg/raddbg.c +++ b/src/raddbg/raddbg.c @@ -65,10 +65,7 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) OS_EventList events = {0}; if(os_handle_match(repaint_window_handle, os_handle_zero())) { - OS_EventList leftover_events_copy = os_event_list_copy(scratch.arena, &leftover_events); - OS_EventList new_events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0); - os_event_list_concat_in_place(&events, &leftover_events_copy); - os_event_list_concat_in_place(&events, &new_events); + events = os_get_events(scratch.arena, df_gfx_state->num_frames_requested == 0); } //- rjf: enable txti change detection @@ -321,26 +318,6 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) } } - //- rjf: gather leftover events for subsequent frame - // TODO(rjf): need to prevent spurious unconsumed events in UI layer & other event handling paths - if(events.count != 0 && 0) - { - arena_clear(leftover_events_arena); - leftover_events = os_event_list_copy(leftover_events_arena, &events); - for(OS_Event *ev = leftover_events.first, *next = 0; ev != 0; ev = next) - { - next = ev->next; - if(ev->timestamp_us+1000000 < os_now_microseconds() || - ev->kind == OS_EventKind_Text || - (ev->kind == OS_EventKind_Press && ev->key != OS_Key_LeftMouseButton && ev->key != OS_Key_RightMouseButton && ev->key != OS_Key_MiddleMouseButton) || - (ev->kind == OS_EventKind_Release && ev->key != OS_Key_LeftMouseButton && ev->key != OS_Key_RightMouseButton && ev->key != OS_Key_MiddleMouseButton) || - (ev->kind == OS_EventKind_Scroll)) - { - os_eat_event(&leftover_events, ev); - } - } - } - //- rjf: determine frame time, record into history U64 end_time_us = os_now_microseconds(); U64 frame_time_us = end_time_us-begin_time_us; @@ -355,344 +332,3 @@ internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook) { os_send_wakeup_event(); } - -internal void -entry_point(int argc, char **argv) -{ - Temp scratch = scratch_begin(0, 0); -#if PROFILE_TELEMETRY - local_persist U8 tm_data[MB(64)]; - tmLoadLibrary(TM_RELEASE); - tmSetMaxThreadCount(1024); - tmInitialize(sizeof(tm_data), (char *)tm_data); -#endif - ThreadName("[main]"); - - //- rjf: initialize basic dependencies - os_init(argc, argv); - - //- rjf: parse command line arguments - CmdLine cmdln = cmd_line_from_string_list(scratch.arena, os_get_command_line_arguments()); - ExecMode exec_mode = ExecMode_Normal; - String8 user_cfg_path = str8_lit(""); - String8 profile_cfg_path = str8_lit(""); - B32 capture = 0; - B32 auto_run = 0; - B32 auto_step = 0; - B32 jit_attach = 0; - U64 jit_pid = 0; - U64 jit_code = 0; - U64 jit_addr = 0; - { - if(cmd_line_has_flag(&cmdln, str8_lit("ipc"))) - { - exec_mode = ExecMode_IPCSender; - } - else if(cmd_line_has_flag(&cmdln, str8_lit("convert"))) - { - exec_mode = ExecMode_Converter; - } - else if(cmd_line_has_flag(&cmdln, str8_lit("?")) || - cmd_line_has_flag(&cmdln, str8_lit("help"))) - { - exec_mode = ExecMode_Help; - } - user_cfg_path = cmd_line_string(&cmdln, str8_lit("user")); - profile_cfg_path = cmd_line_string(&cmdln, str8_lit("profile")); - capture = cmd_line_has_flag(&cmdln, str8_lit("capture")); - auto_run = cmd_line_has_flag(&cmdln, str8_lit("auto_run")); - auto_step = cmd_line_has_flag(&cmdln, str8_lit("auto_step")); - String8 jit_pid_string = {0}; - String8 jit_code_string = {0}; - String8 jit_addr_string = {0}; - jit_pid_string = cmd_line_string(&cmdln, str8_lit("jit_pid")); - jit_code_string = cmd_line_string(&cmdln, str8_lit("jit_code")); - jit_addr_string = cmd_line_string(&cmdln, str8_lit("jit_addr")); - try_u64_from_str8_c_rules(jit_pid_string, &jit_pid); - try_u64_from_str8_c_rules(jit_code_string, &jit_code); - try_u64_from_str8_c_rules(jit_addr_string, &jit_addr); - jit_attach = (jit_addr != 0); - } - - //- rjf: auto-start capture - if(capture) - { - ProfBeginCapture("raddbg"); - } - - //- rjf: set default user/profile paths - { - String8 user_program_data_path = os_string_from_system_path(scratch.arena, OS_SystemPath_UserProgramData); - String8 user_data_folder = push_str8f(scratch.arena, "%S/%S", user_program_data_path, str8_lit("raddbg")); - os_make_directory(user_data_folder); - if(user_cfg_path.size == 0) - { - user_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_user", user_data_folder); - } - if(profile_cfg_path.size == 0) - { - profile_cfg_path = push_str8f(scratch.arena, "%S/default.raddbg_profile", user_data_folder); - } - } - - //- rjf: dispatch to top-level codepath based on execution mode - switch(exec_mode) - { - //- rjf: normal execution - default: - case ExecMode_Normal: - { - //- rjf: set up shared memory for ipc - OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); - void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); - OS_Handle ipc_semaphore = os_semaphore_alloc(1, 1, ipc_semaphore_name); - IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; - ipc_info->msg_size = 0; - - //- rjf: set up leftover event arena - leftover_events_arena = arena_alloc(); - - //- rjf: initialize stuff we depend on - { - hs_init(); - fs_init(); - txt_init(); - dbgi_init(); - txti_init(); - demon_init(); - ctrl_init(wakeup_hook); - dasm_init(); - os_graphical_init(); - fp_init(); - r_init(&cmdln); - tex_init(); - geo_init(); - f_init(); - DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); - df_core_init(user_cfg_path, profile_cfg_path, hist); - df_gfx_init(update_and_render, hist); - os_set_cursor(OS_Cursor_Pointer); - } - - //- rjf: setup initial target from command line args - { - String8List args = cmdln.inputs; - if(args.node_count > 0 && args.first->string.size != 0) - { - Temp scratch = scratch_begin(0, 0); - DF_Entity *target = df_entity_alloc(0, df_entity_root(), DF_EntityKind_Target); - df_entity_equip_b32(target, 1); - df_entity_equip_cfg_src(target, DF_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: equip exe - if(args.first->string.size != 0) - { - DF_Entity *exe = df_entity_alloc(0, target, DF_EntityKind_Executable); - df_entity_equip_name(0, exe, args.first->string); - } - - // rjf: equip path - 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); - DF_Entity *execution_path = df_entity_alloc(0, target, DF_EntityKind_ExecutionPath); - df_entity_equip_name(0, execution_path, path); - } - - // 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) - { - DF_Entity *args_entity = df_entity_alloc(0, target, DF_EntityKind_Arguments); - df_entity_equip_name(0, args_entity, args_str); - } - scratch_end(scratch); - } - } - - //- rjf: main application loop - { - for(;;) - { - //- rjf: get IPC messages & dispatch ui commands from them - { - if(os_semaphore_take(ipc_semaphore, max_U64)) - { - if(ipc_info->msg_size != 0) - { - U8 *buffer = (U8 *)(ipc_info+1); - U64 msg_size = ipc_info->msg_size; - String8 cmd_string = str8(buffer, msg_size); - ipc_info->msg_size = 0; - DF_Window *dst_window = df_gfx_state->first_window; - for(DF_Window *window = dst_window; window != 0; window = window->next) - { - if(os_window_is_focused(window->os)) - { - dst_window = window; - break; - } - } - if(dst_window != 0) - { - Temp scratch = scratch_begin(0, 0); - String8 cmd_spec_string = df_cmd_name_part_from_string(cmd_string); - DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(cmd_spec_string); - if(!df_cmd_spec_is_nil(cmd_spec)) - { - DF_CmdParams params = df_cmd_params_from_gfx(); - DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(dst_window); - String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, cmd_spec, df_cmd_arg_part_from_string(cmd_string)); - if(error.size == 0) - { - df_push_cmd__root(¶ms, cmd_spec); - } - else - { - DF_CmdParams params = df_cmd_params_from_window(dst_window); - params.string = error; - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); - } - } - scratch_end(scratch); - } - } - os_semaphore_drop(ipc_semaphore); - } - } - - //- rjf: update & render frame - OS_Handle repaint_window = {0}; - update_and_render(repaint_window, 0); - - //- rjf: auto run - if(auto_run) - { - auto_run = 0; - DF_CmdParams params = df_cmd_params_from_gfx(); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); - } - - //- rjf: auto step - if(auto_step) - { - auto_step = 0; - DF_CmdParams params = df_cmd_params_from_gfx(); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_StepInto)); - } - - //- rjf: jit attach - if(jit_attach) - { - jit_attach = 0; - DF_CmdParams params = df_cmd_params_from_gfx(); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_ID); - params.id = jit_pid; - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Attach)); - } - - //- rjf: quit if no windows are left - if(df_gfx_state->first_window == 0) - { - break; - } - } - } - - }break; - - //- rjf: inter-process communication message sender - case ExecMode_IPCSender: - { - Temp scratch = scratch_begin(0, 0); - - //- rjf: grab ipc shared memory - OS_Handle ipc_shared_memory = os_shared_memory_open(ipc_shared_memory_name); - void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, MB(16))); - if(ipc_shared_memory_base != 0) - { - OS_Handle ipc_semaphore = os_semaphore_open(ipc_semaphore_name); - IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; - if(os_semaphore_take(ipc_semaphore, os_now_microseconds() + Million(6))) - { - U8 *buffer = (U8 *)(ipc_info+1); - U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); - StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; - String8 msg = str8_list_join(scratch.arena, &cmdln.inputs, &join); - ipc_info->msg_size = Min(buffer_max, msg.size); - MemoryCopy(buffer, msg.str, ipc_info->msg_size); - os_semaphore_drop(ipc_semaphore); - } - } - - scratch_end(scratch); - }break; - - //- rjf: built-in pdb/dwarf -> raddbg converter mode - case ExecMode_Converter: - { - Temp scratch = scratch_begin(0, 0); - - //- rjf: parse arguments - PDBCONV_Params *params = pdb_convert_params_from_cmd_line(scratch.arena, &cmdln); - - //- rjf: open output file - String8 output_name = push_str8_copy(scratch.arena, params->output_name); - OS_Handle out_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, output_name); - B32 out_file_is_good = !os_handle_match(out_file, os_handle_zero()); - - //- rjf: convert - PDBCONV_Out *out = 0; - if(out_file_is_good) - { - out = pdbconv_convert(scratch.arena, params); - } - - //- rjf: bake file - if(out != 0 && params->output_name.size > 0) - { - String8List baked = {0}; - cons_bake_file(scratch.arena, out->root, &baked); - U64 off = 0; - for(String8Node *node = baked.first; node != 0; node = node->next) - { - os_file_write(out_file, r1u64(off, off+node->string.size), node->string.str); - off += node->string.size; - } - } - - //- rjf: close output file - os_file_close(out_file); - - scratch_end(scratch); - }break; - - //- rjf: help message box - case ExecMode_Help: - { - os_graphical_message(0, - str8_lit("The RAD Debugger - Help"), - str8_lit("The following options may be used when starting the RAD Debugger from the command line:\n\n" - "--user:\n" - "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.\n\n" - "--profile:\n" - "Use to specify the location of a profile file which should be used. Profile 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 profile-related changes are made.\n\n" - "--auto_step\n" - "This will step into all targets after the debugger initially starts.\n\n" - "--auto_run\n" - "This will run all targets after the debugger initially starts.\n\n" - "--ipc \n" - "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.\n\n")); - }break; - } - - scratch_end(scratch); -} diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 54cdf7e7..72b217cd 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -1,14 +1,23 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Demon/Cleanup Pass Tasks +// +// [ ] TLS eval -> in-process-memory EXE info +// [ ] unwinding -> in-process-memory EXE info +// [ ] "root" concept in hash store, which buckets keys & allows usage code to +// jettison a collection of keys in retained mode fashion + //////////////////////////////// //~ rjf: Frontend/UI Pass Tasks // -// [x] hover-eval when window is not focused - maybe just start directly -// using mouse-move events here -// [x] CRT asserts - stepping over int 29 should work just like stepping over -// an int3 -// [ ] committing needs to happen when navigating focus away for any reason +// [ ] n-row table selection, in watch window & other UIs, multi-selection +// ctrl+C +// [ ] UI_NavActions, OS_Event -> UI_Event (single event stream) +// +// [ ] better discoverability for view rules - have better help hover tooltip, +// info on arguments, and better autocomplete lister // // [ ] source view -> floating margin/line-nums // [ ] theme colors -> more explicit about e.g. opaque backgrounds vs. floating @@ -43,12 +52,16 @@ // start with brighter color, but sometimes with darker - shouldn't it // always have the same color ordering? // -// [ ] middle mouse button on tab should close it // [ ] pipe failure-to-launch errors back to frontend //////////////////////////////// //~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy) // +// [ ] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly +// [ ] PDB files distributed with the build are not found by DbgHelp!!! +// [ ] Jai compiler debugging crash +// [ ] raddbgi file regeneration too strict +// // [ ] Jump table thunks, on code w/o /INCREMENTAL:NO // // [ ] ** Thread/process control bullet-proofing, including solo-step mode @@ -68,16 +81,10 @@ // since that's not normally how Windows fonts work. // // [ ] ** Converter performance & heuristics for asynchronously doing it early -// -// [ ] disasm animation & go-to-address -// -// [ ] visualize remapped files (via path map) //////////////////////////////// //~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // -// [ ] Watch Window Filtering -// // [ ] investigate /DEBUG:FASTLINK - can we somehow alert that we do not // support it? // @@ -192,11 +199,8 @@ // "save" option in the menus. // // [ ] @cleanup @feature double & triple click select in source views -// [ ] @feature disasm keyboard navigation & copy/paste // [ ] @feature debug info overrides (both path-based AND module-based) // [ ] configure tab size -// [ ] run-to-line needs to work if no processes are running -// - place temp bp, attach "die on hit" flag or something like that? // [ ] auto-scroll output window // // [ ] C++ virtual inheritance member visualization in watch window @@ -222,12 +226,6 @@ // expandable? It seems like this should be consistent (one way to edit, // one way to expand/collapse, that are distinct) // -// [ ] I didn't understand the terminology "Equip With Color". Does that just -// mean specify the color used to display it? Is "Apply Color" perhaps a -// bit more user-friendly? -// -// [ ] The cursor feels a bit too huge vertically. -// // [ ] 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 @@ -396,29 +394,27 @@ // [ ] 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] solidify synchronization mechanisms for usage of demon layer +// [x] TLS eval correctness +// [x] freezing thread while running -> soft-halt +// [x] Watch Window Filtering +// [x] @feature disasm keyboard navigation & copy/paste +// [x] run-to-line needs to work if no processes are running +// - place temp bp, attach "die on hit" flag or something like that? +// [x] disasm animation & go-to-address +// [x] middle mouse button on tab should close it +// [x] I didn't understand the terminology "Equip With Color". Does that just +// mean specify the color used to display it? Is "Apply Color" perhaps a +// bit more user-friendly? +// +// [x] The cursor feels a bit too huge vertically. + #ifndef RADDBG_H #define RADDBG_H -//////////////////////////////// -//~ rjf: Build Settings - -#define RADDBG_VERSION_MAJOR 0 -#define RADDBG_VERSION_MINOR 9 -#define RADDBG_VERSION_PATCH 8 -#define RADDBG_VERSION_STRING_LITERAL Stringify(RADDBG_VERSION_MAJOR) "." Stringify(RADDBG_VERSION_MINOR) "." Stringify(RADDBG_VERSION_PATCH) -#if defined(NDEBUG) -# define RADDBG_BUILD_STR "" -#else -# define RADDBG_BUILD_STR " [Debug]" -#endif -#if defined(RADDBG_GIT) -# define RADDBG_GIT_STR " [" RADDBG_GIT "]" -#else -# define RADDBG_GIT_STR "" -#endif -#define RADDBG_TITLE_STRING_LITERAL "The RAD Debugger (" RADDBG_VERSION_STRING_LITERAL " ALPHA) - " __DATE__ "" RADDBG_GIT_STR RADDBG_BUILD_STR -#define RADDBG_GITHUB_ISSUES "https://github.com/EpicGames/raddebugger/issues" - //////////////////////////////// //~ rjf: Top-Level Execution Types @@ -446,8 +442,6 @@ read_only global String8 ipc_shared_memory_name = str8_lit_comp("_raddbg_ipc_sha read_only global String8 ipc_semaphore_name = str8_lit_comp("_raddbg_ipc_semaphore_"); global U64 frame_time_us_history[64] = {0}; global U64 frame_time_us_history_idx = 0; -global Arena *leftover_events_arena = 0; -global OS_EventList leftover_events = {0}; //////////////////////////////// //~ rjf: Frontend Entry Points diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index 922c3c2f..32b3f3df 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -1,41 +1,53 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Build Options + +#define BUILD_VERSION_MAJOR 0 +#define BUILD_VERSION_MINOR 9 +#define BUILD_VERSION_PATCH 9 +#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +#define BUILD_TITLE "The RAD Debugger" +#define OS_FEATURE_GRAPHICAL 1 + //////////////////////////////// //~ rjf: Includes +//- rjf: [lib] +#include "lib_raddbgi_format/raddbgi_format.h" +#include "lib_raddbgi_format/raddbgi_format_parse.h" +#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_raddbgi_format/raddbgi_format_parse.c" + //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" +#include "task_system/task_system.h" +#include "raddbgi_make_local/raddbgi_make_local.h" #include "mdesk/mdesk.h" #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" #include "text_cache/text_cache.h" +#include "dasm_cache/dasm_cache.h" #include "path/path.h" #include "txti/txti.h" #include "coff/coff.h" #include "pe/pe.h" -#include "raddbg_format/raddbg_format.h" -#include "raddbg_format/raddbg_format_parse.h" -#include "raddbg_cons/raddbg_cons.h" -#include "raddbg_convert/pdb/raddbg_coff.h" -#include "raddbg_convert/pdb/raddbg_codeview.h" -#include "raddbg_convert/pdb/raddbg_msf.h" -#include "raddbg_convert/pdb/raddbg_pdb.h" -#include "raddbg_convert/pdb/raddbg_coff_conversion.h" -#include "raddbg_convert/pdb/raddbg_codeview_conversion.h" -#include "raddbg_convert/pdb/raddbg_from_pdb.h" -#include "raddbg_convert/pdb/raddbg_codeview_stringize.h" -#include "raddbg_convert/pdb/raddbg_pdb_stringize.h" +#include "codeview/codeview.h" +#include "codeview/codeview_stringize.h" +#include "msf/msf.h" +#include "pdb/pdb.h" +#include "pdb/pdb_stringize.h" +#include "raddbgi_from_pdb/raddbgi_from_pdb.h" #include "regs/regs.h" -#include "regs/raddbg/regs_raddbg.h" +#include "regs/raddbgi/regs_raddbgi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" #include "unwind/unwind.h" #include "ctrl/ctrl_inc.h" -#include "dasm/dasm.h" #include "font_provider/font_provider_inc.h" #include "render/render_inc.h" #include "texture_cache/texture_cache.h" @@ -49,34 +61,31 @@ //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" +#include "task_system/task_system.c" +#include "raddbgi_make_local/raddbgi_make_local.c" #include "mdesk/mdesk.c" #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" #include "text_cache/text_cache.c" +#include "dasm_cache/dasm_cache.c" #include "path/path.c" #include "txti/txti.c" #include "coff/coff.c" #include "pe/pe.c" -#include "raddbg_format/raddbg_format.c" -#include "raddbg_format/raddbg_format_parse.c" -#include "raddbg_cons/raddbg_cons.c" -#include "raddbg_convert/pdb/raddbg_msf.c" -#include "raddbg_convert/pdb/raddbg_codeview.c" -#include "raddbg_convert/pdb/raddbg_pdb.c" -#include "raddbg_convert/pdb/raddbg_coff_conversion.c" -#include "raddbg_convert/pdb/raddbg_codeview_conversion.c" -#include "raddbg_convert/pdb/raddbg_codeview_stringize.c" -#include "raddbg_convert/pdb/raddbg_pdb_stringize.c" -#include "raddbg_convert/pdb/raddbg_from_pdb.c" +#include "codeview/codeview.c" +#include "codeview/codeview_stringize.c" +#include "msf/msf.c" +#include "pdb/pdb.c" +#include "pdb/pdb_stringize.c" +#include "raddbgi_from_pdb/raddbgi_from_pdb.c" #include "regs/regs.c" -#include "regs/raddbg/regs_raddbg.c" +#include "regs/raddbgi/regs_raddbgi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" #include "unwind/unwind.c" #include "ctrl/ctrl_inc.c" -#include "dasm/dasm.c" #include "font_provider/font_provider_inc.c" #include "render/render_inc.c" #include "texture_cache/texture_cache.c" @@ -88,213 +97,15 @@ #include "raddbg.c" //////////////////////////////// -//~ rjf: Low-Level Entry Points +//~ rjf: Entry Point -//- rjf: windows +internal void +entry_point(CmdLine *cmd_line) +{ + Temp scratch = scratch_begin(0, 0); + + //- rjf: windows -> turn off output handles, as we need to control those for target processes #if OS_WINDOWS - -#include - -#undef OS_WINDOWS // shlwapi uses its own OS_WINDOWS include inside -#include - -internal B32 g_is_quiet = 0; - -internal HRESULT WINAPI -win32_dialog_callback(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, LONG_PTR data) -{ - if(msg == TDN_HYPERLINK_CLICKED) - { - ShellExecuteW(NULL, L"open", (LPWSTR)lparam, NULL, NULL, SW_SHOWNORMAL); - } - return S_OK; -} - -internal LONG WINAPI -win32_exception_filter(EXCEPTION_POINTERS* exception_ptrs) -{ - if(g_is_quiet) - { - ExitProcess(1); - } - - static volatile LONG first = 0; - if(InterlockedCompareExchange(&first, 1, 0) != 0) - { - // prevent failures in other threads to popup same message box - // this handler just shows first thread that crashes - // we are terminating afterwards anyway - for (;;) Sleep(1000); - } - - WCHAR buffer[4096] = {0}; - int buflen = 0; - - DWORD exception_code = exception_ptrs->ExceptionRecord->ExceptionCode; - 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 - HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); - if(dbghelp) - { - DWORD (WINAPI *dbg_SymSetOptions)(DWORD SymOptions); - BOOL (WINAPI *dbg_SymInitializeW)(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess); - BOOL (WINAPI *dbg_StackWalk64)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, - LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, - PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, - PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); - PVOID (WINAPI *dbg_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase); - DWORD64 (WINAPI *dbg_SymGetModuleBase64)(HANDLE hProcess, DWORD64 qwAddr); - BOOL (WINAPI *dbg_SymFromAddrW)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFOW Symbol); - BOOL (WINAPI *dbg_SymGetLineFromAddrW64)(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line); - BOOL (WINAPI *dbg_SymGetModuleInfoW64)(HANDLE hProcess, DWORD64 qwAddr, PIMAGEHLP_MODULEW64 ModuleInfo); - - *(FARPROC*)&dbg_SymSetOptions = GetProcAddress(dbghelp, "SymSetOptions"); - *(FARPROC*)&dbg_SymInitializeW = GetProcAddress(dbghelp, "SymInitializeW"); - *(FARPROC*)&dbg_StackWalk64 = GetProcAddress(dbghelp, "StackWalk64"); - *(FARPROC*)&dbg_SymFunctionTableAccess64 = GetProcAddress(dbghelp, "SymFunctionTableAccess64"); - *(FARPROC*)&dbg_SymGetModuleBase64 = GetProcAddress(dbghelp, "SymGetModuleBase64"); - *(FARPROC*)&dbg_SymFromAddrW = GetProcAddress(dbghelp, "SymFromAddrW"); - *(FARPROC*)&dbg_SymGetLineFromAddrW64 = GetProcAddress(dbghelp, "SymGetLineFromAddrW64"); - *(FARPROC*)&dbg_SymGetModuleInfoW64 = GetProcAddress(dbghelp, "SymGetModuleInfoW64"); - - if(dbg_SymSetOptions && dbg_SymInitializeW && dbg_StackWalk64 && dbg_SymFunctionTableAccess64 && dbg_SymGetModuleBase64 && dbg_SymFromAddrW && dbg_SymGetLineFromAddrW64 && dbg_SymGetModuleInfoW64) - { - HANDLE process = GetCurrentProcess(); - HANDLE thread = GetCurrentThread(); - CONTEXT* context = exception_ptrs->ContextRecord; - - dbg_SymSetOptions(SYMOPT_EXACT_SYMBOLS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); - if(dbg_SymInitializeW(process, L"", TRUE)) - { - // check that raddbg.pdb file is good - B32 raddbg_pdb_valid = 0; - { - IMAGEHLP_MODULEW64 module = {0}; - module.SizeOfStruct = sizeof(module); - if(dbg_SymGetModuleInfoW64(process, (DWORD64)&win32_exception_filter, &module)) - { - raddbg_pdb_valid = (module.SymType == SymPdb); - } - } - - if(!raddbg_pdb_valid) - { - buflen += wnsprintfW(buffer + buflen, sizeof(buffer) - buflen, - L"\nraddbg.pdb debug file is not valid or not found. Please rebuild binary to get call stack.\n"); - } - else - { - STACKFRAME64 frame = {0}; - DWORD image_type; -#if defined(_M_AMD64) - image_type = IMAGE_FILE_MACHINE_AMD64; - frame.AddrPC.Offset = context->Rip; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context->Rbp; - frame.AddrFrame.Mode = AddrModeFlat; - frame.AddrStack.Offset = context->Rsp; - frame.AddrStack.Mode = AddrModeFlat; -#elif defined(_M_ARM64) - image_type = IMAGE_FILE_MACHINE_ARM64; - frame.AddrPC.Offset = context->Pc; - frame.AddrPC.Mode = AddrModeFlat; - frame.AddrFrame.Offset = context->Fp; - frame.AddrFrame.Mode = AddrModeFlat; - frame.AddrStack.Offset = context->Sp; - frame.AddrStack.Mode = AddrModeFlat; -#else -# error Architecture not supported! -#endif - - for(U32 idx=0; ;idx++) - { - const U32 max_frames = 32; - if(idx == max_frames) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"..."); - break; - } - - if(!dbg_StackWalk64(image_type, process, thread, &frame, context, 0, dbg_SymFunctionTableAccess64, dbg_SymGetModuleBase64, 0)) - { - break; - } - - U64 address = frame.AddrPC.Offset; - if(address == 0) - { - break; - } - - if(idx==0) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, - L"\nPress Ctrl+C to copy this text to clipboard, then create a new issue in\n" - L"%S\n\n", RADDBG_GITHUB_ISSUES, RADDBG_GITHUB_ISSUES); - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"Call stack:\n"); - } - - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"%u. [0x%I64x]", idx + 1, address); - - struct { - SYMBOL_INFOW info; - WCHAR name[MAX_SYM_NAME]; - } symbol = {0}; - - symbol.info.SizeOfStruct = sizeof(symbol.info); - symbol.info.MaxNameLen = MAX_SYM_NAME; - - DWORD64 displacement = 0; - if(dbg_SymFromAddrW(process, address, &displacement, &symbol.info)) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s +%u", symbol.info.Name, (DWORD)displacement); - - IMAGEHLP_LINEW64 line = {0}; - line.SizeOfStruct = sizeof(line); - - DWORD line_displacement = 0; - if(dbg_SymGetLineFromAddrW64(process, address, &line_displacement, &line)) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L", %s line %u", PathFindFileNameW(line.FileName), line.LineNumber); - } - } - else - { - IMAGEHLP_MODULEW64 module = {0}; - module.SizeOfStruct = sizeof(module); - if(dbg_SymGetModuleInfoW64(process, address, &module)) - { - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L" %s", module.ModuleName); - } - } - - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\n"); - } - } - } - } - } - - buflen += wnsprintfW(buffer + buflen, ArrayCount(buffer) - buflen, L"\nVersion: %S%S", RADDBG_VERSION_STRING_LITERAL, RADDBG_GIT_STR); - - TASKDIALOGCONFIG dialog = {0}; - dialog.cbSize = sizeof(dialog); - dialog.dwFlags = TDF_SIZE_TO_CONTENT | TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION; - dialog.pszMainIcon = TD_ERROR_ICON; - dialog.dwCommonButtons = TDCBF_CLOSE_BUTTON; - dialog.pszWindowTitle = L"Fatal Exception"; - dialog.pszContent = buffer; - dialog.pfCallback = &win32_dialog_callback; - TaskDialogIndirect(&dialog, 0, 0, 0); - - ExitProcess(1); -} - -int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) -{ - SetUnhandledExceptionFilter(&win32_exception_filter); - HANDLE output_handles[3] = { GetStdHandle(STD_INPUT_HANDLE), @@ -327,36 +138,295 @@ int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int n SetStdHandle(STD_INPUT_HANDLE, 0); SetStdHandle(STD_OUTPUT_HANDLE, 0); SetStdHandle(STD_ERROR_HANDLE, 0); - static TCTX main_thread_tctx = {0}; - tctx_init_and_equip(&main_thread_tctx); - Arena *perm_arena = arena_alloc(); - WCHAR *command_line = GetCommandLineW(); - int argc; - WCHAR **argv_16 = CommandLineToArgvW(command_line, &argc); - char **argv = push_array(perm_arena, char *, argc); - for(int i = 0; i < argc; i += 1) - { - String16 arg16 = str16_cstring((U16 *)argv_16[i]); - String8 arg8 = str8_from_16(perm_arena, arg16); - if(str8_match(arg8, str8_lit("--quiet"), StringMatchFlag_CaseInsensitive)) - { - g_is_quiet = 1; - } - argv[i] = (char *)arg8.str; - } - entry_point(argc, argv); - return 0; -} - -//- rjf: linux -#elif OS_LINUX - -int main(int argument_count, char **arguments) -{ - static TCTX main_thread_tctx = {0}; - tctx_init_and_equip(&main_thread_tctx); - entry_point(argument_count, arguments); - return 0; -} - #endif + + //- rjf: unpack command line arguments + ExecMode exec_mode = ExecMode_Normal; + B32 auto_run = 0; + B32 auto_step = 0; + B32 jit_attach = 0; + U64 jit_pid = 0; + U64 jit_code = 0; + U64 jit_addr = 0; + { + if(cmd_line_has_flag(cmd_line, str8_lit("ipc"))) + { + exec_mode = ExecMode_IPCSender; + } + else if(cmd_line_has_flag(cmd_line, str8_lit("convert"))) + { + exec_mode = ExecMode_Converter; + } + else if(cmd_line_has_flag(cmd_line, str8_lit("?")) || + cmd_line_has_flag(cmd_line, str8_lit("help"))) + { + exec_mode = ExecMode_Help; + } + auto_run = cmd_line_has_flag(cmd_line, str8_lit("auto_run")); + auto_step = cmd_line_has_flag(cmd_line, str8_lit("auto_step")); + String8 jit_pid_string = cmd_line_string(cmd_line, str8_lit("jit_pid")); + String8 jit_code_string = cmd_line_string(cmd_line, str8_lit("jit_code")); + String8 jit_addr_string = cmd_line_string(cmd_line, str8_lit("jit_addr")); + try_u64_from_str8_c_rules(jit_pid_string, &jit_pid); + try_u64_from_str8_c_rules(jit_code_string, &jit_code); + try_u64_from_str8_c_rules(jit_addr_string, &jit_addr); + jit_attach = (jit_addr != 0); + } + + //- rjf: set up layers + ctrl_set_wakeup_hook(wakeup_hook); + + //- rjf: dispatch to top-level codepath based on execution mode + switch(exec_mode) + { + //- rjf: normal execution + default: + case ExecMode_Normal: + { + //- rjf: set up shared memory for ipc + OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); + void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); + OS_Handle ipc_semaphore = os_semaphore_alloc(1, 1, ipc_semaphore_name); + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + ipc_info->msg_size = 0; + + //- rjf: setup initial target from command line args + { + String8List args = cmd_line->inputs; + if(args.node_count > 0 && args.first->string.size != 0) + { + Temp scratch = scratch_begin(0, 0); + DF_Entity *target = df_entity_alloc(0, df_entity_root(), DF_EntityKind_Target); + df_entity_equip_b32(target, 1); + df_entity_equip_cfg_src(target, DF_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_string_from_system_path(scratch.arena, OS_SystemPath_Current); + + // rjf: equip exe + if(args.first->string.size != 0) + { + String8 exe_name = args.first->string; + DF_Entity *exe = df_entity_alloc(0, target, DF_EntityKind_Executable); + 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); + } + df_entity_equip_name(0, exe, exe_name); + } + + // rjf: equip path + 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); + DF_Entity *execution_path = df_entity_alloc(0, target, DF_EntityKind_ExecutionPath); + df_entity_equip_name(0, execution_path, path); + } + + // 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) + { + DF_Entity *args_entity = df_entity_alloc(0, target, DF_EntityKind_Arguments); + df_entity_equip_name(0, args_entity, args_str); + } + scratch_end(scratch); + } + } + + //- rjf: main application loop + { + for(;;) + { + //- rjf: get IPC messages & dispatch ui commands from them + { + if(os_semaphore_take(ipc_semaphore, max_U64)) + { + if(ipc_info->msg_size != 0) + { + U8 *buffer = (U8 *)(ipc_info+1); + U64 msg_size = ipc_info->msg_size; + String8 cmd_string = str8(buffer, msg_size); + ipc_info->msg_size = 0; + DF_Window *dst_window = df_gfx_state->first_window; + for(DF_Window *window = dst_window; window != 0; window = window->next) + { + if(os_window_is_focused(window->os)) + { + dst_window = window; + break; + } + } + if(dst_window != 0) + { + Temp scratch = scratch_begin(0, 0); + String8 cmd_spec_string = df_cmd_name_part_from_string(cmd_string); + DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(cmd_spec_string); + if(!df_cmd_spec_is_nil(cmd_spec)) + { + DF_CmdParams params = df_cmd_params_from_gfx(); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(dst_window); + String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, cmd_spec, df_cmd_arg_part_from_string(cmd_string)); + if(error.size == 0) + { + df_push_cmd__root(¶ms, cmd_spec); + } + else + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + params.string = error; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + } + } + scratch_end(scratch); + } + } + os_semaphore_drop(ipc_semaphore); + } + } + + //- rjf: update & render frame + OS_Handle repaint_window = {0}; + update_and_render(repaint_window, 0); + + //- rjf: auto run + if(auto_run) + { + auto_run = 0; + DF_CmdParams params = df_cmd_params_from_gfx(); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_LaunchAndRun)); + } + + //- rjf: auto step + if(auto_step) + { + auto_step = 0; + DF_CmdParams params = df_cmd_params_from_gfx(); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_StepInto)); + } + + //- rjf: jit attach + if(jit_attach) + { + jit_attach = 0; + DF_CmdParams params = df_cmd_params_from_gfx(); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_ID); + params.id = jit_pid; + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Attach)); + } + + //- rjf: quit if no windows are left + if(df_gfx_state->first_window == 0) + { + break; + } + } + } + + }break; + + //- rjf: inter-process communication message sender + case ExecMode_IPCSender: + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: grab ipc shared memory + OS_Handle ipc_shared_memory = os_shared_memory_open(ipc_shared_memory_name); + void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, MB(16))); + if(ipc_shared_memory_base != 0) + { + OS_Handle ipc_semaphore = os_semaphore_open(ipc_semaphore_name); + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + if(os_semaphore_take(ipc_semaphore, os_now_microseconds() + Million(6))) + { + U8 *buffer = (U8 *)(ipc_info+1); + U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + String8 msg = str8_list_join(scratch.arena, &cmd_line->inputs, &join); + ipc_info->msg_size = Min(buffer_max, msg.size); + MemoryCopy(buffer, msg.str, ipc_info->msg_size); + os_semaphore_drop(ipc_semaphore); + } + } + + scratch_end(scratch); + }break; + + //- rjf: built-in pdb/dwarf -> raddbg converter mode + case ExecMode_Converter: + { + Temp scratch = scratch_begin(0, 0); + + //- rjf: parse arguments + P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(scratch.arena, cmd_line); + + //- rjf: open output file + String8 output_name = push_str8_copy(scratch.arena, user2convert->output_name); + OS_Handle out_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, output_name); + B32 out_file_is_good = !os_handle_match(out_file, os_handle_zero()); + + //- rjf: convert + P2R_Convert2Bake *convert2bake = 0; + if(out_file_is_good) + { + convert2bake = p2r_convert(scratch.arena, user2convert); + } + + //- rjf: bake + P2R_Bake2Serialize *bake2srlz = 0; + ProfScope("bake") + { + bake2srlz = p2r_bake(scratch.arena, convert2bake); + } + + //- rjf: serialize + String8List serialize_out = rdim_serialized_strings_from_params_bake_section_list(scratch.arena, &convert2bake->bake_params, &bake2srlz->sections); + + //- rjf: write + if(out_file_is_good) + { + U64 off = 0; + for(String8Node *n = serialize_out.first; n != 0; n = n->next) + { + os_file_write(out_file, r1u64(off, off+n->string.size), n->string.str); + off += n->string.size; + } + } + + //- rjf: close output file + os_file_close(out_file); + + scratch_end(scratch); + }break; + + //- rjf: help message box + case ExecMode_Help: + { + os_graphical_message(0, + str8_lit("The RAD Debugger - Help"), + str8_lit("The following options may be used when starting the RAD Debugger from the command line:\n\n" + "--user:\n" + "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.\n\n" + "--profile:\n" + "Use to specify the location of a profile file which should be used. Profile 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 profile-related changes are made.\n\n" + "--auto_step\n" + "This will step into all targets after the debugger initially starts.\n\n" + "--auto_run\n" + "This will run all targets after the debugger initially starts.\n\n" + "--ipc \n" + "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.\n\n")); + }break; + } + + scratch_end(scratch); +} diff --git a/src/raddbg_cons/raddbg_cons.c b/src/raddbg_cons/raddbg_cons.c deleted file mode 100644 index 6e2214db..00000000 --- a/src/raddbg_cons/raddbg_cons.c +++ /dev/null @@ -1,3378 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//- "Public Facing" Cons API - -//- init -static CONS_Root* -cons_root_new(CONS_RootParams *params){ - Arena *arena = arena_alloc__sized(GB(64), MB(256)); - CONS_Root *result = push_array(arena, CONS_Root, 1); - result->arena = arena; - - // fill in root parameters - { - result->addr_size = params->addr_size; - } - - // setup singular types - { - result->nil_type = cons__type_new(result); - result->variadic_type = cons__type_new(result); - result->variadic_type->kind = RADDBG_TypeKind_Variadic; - - // references to "handled nil type" should be emitted as - // references to nil - but should not generate error - // messages when they are detected - they are expected! - Assert(result->nil_type->idx == result->handled_nil_type.idx); - } - - // setup a null scope - { - CONS_Scope *scope = push_array(result->arena, CONS_Scope, 1); - SLLQueuePush_N(result->first_scope, result->last_scope, scope, next_order); - result->scope_count += 1; - } - - // rjf: setup null UDT - { - cons__type_udt_from_any_type(result, result->nil_type); - } - - // initialize maps - { -#define BKTCOUNT(x) ((x)?(u64_up_to_pow2(x)):(128)) - - cons__u64toptr_init(arena, &result->unit_map, BKTCOUNT(params->bucket_count_units)); - cons__u64toptr_init(arena, &result->symbol_map, BKTCOUNT(params->bucket_count_symbols)); - cons__u64toptr_init(arena, &result->scope_map, BKTCOUNT(params->bucket_count_scopes)); - cons__u64toptr_init(arena, &result->local_map, BKTCOUNT(params->bucket_count_locals)); - cons__u64toptr_init(arena, &result->type_from_id_map, BKTCOUNT(params->bucket_count_types)); - -#undef BKTCOUNT - } - - return(result); -} - -static void -cons_root_release(CONS_Root *root){ - arena_release(root->arena); -} - -//- baking -static void -cons_bake_file(Arena *arena, CONS_Root *root, String8List *out){ - ProfBegin("cons_bake_file"); - str8_serial_begin(arena, out); - - // setup cons helpers - CONS__DSections dss = {0}; - cons__dsection(arena, &dss, 0, 0, RADDBG_DataSectionTag_NULL); - - CONS__BakeCtx *bctx = cons__bake_ctx_begin(); - - //////////////////////////////// - // MAIN PART: allocating and filling out sections of the file - - // top level info - RADDBG_TopLevelInfo *tli = push_array(arena, RADDBG_TopLevelInfo, 1); - { - CONS_TopLevelInfo *cons_tli = &root->top_level_info; - tli->architecture = cons_tli->architecture; - tli->exe_name_string_idx = cons__string(bctx, cons_tli->exe_name); - tli->exe_hash = cons_tli->exe_hash; - tli->voff_max = cons_tli->voff_max; - } - cons__dsection(arena, &dss, tli, sizeof(*tli), RADDBG_DataSectionTag_TopLevelInfo); - - // binary sections array - { - U32 count = root->binary_section_count; - RADDBG_BinarySection *sections = push_array(arena, RADDBG_BinarySection, count); - RADDBG_BinarySection *dsec = sections; - for (CONS_BinarySection *ssec = root->binary_section_first; - ssec != 0; - ssec = ssec->next, dsec += 1){ - dsec->name_string_idx = cons__string(bctx, ssec->name); - dsec->flags = ssec->flags; - dsec->voff_first = ssec->voff_first; - dsec->voff_opl = ssec->voff_opl; - dsec->foff_first = ssec->foff_first; - dsec->foff_opl = ssec->foff_opl; - } - cons__dsection(arena, &dss, sections, sizeof(*sections)*count, RADDBG_DataSectionTag_BinarySections); - } - - // units array - // * pass for per-unit information including: - // * top-level unit information - // * combining line info for whole unit - { - U32 count = root->unit_count; - RADDBG_Unit *units = push_array(arena, RADDBG_Unit, count); - RADDBG_Unit *dunit = units; - for (CONS_Unit *sunit = root->unit_first; - sunit != 0; - sunit = sunit->next_order, dunit += 1){ - // strings & paths - U32 unit_name = cons__string(bctx, sunit->unit_name); - U32 cmp_name = cons__string(bctx, sunit->compiler_name); - - U32 src_path = cons__paths_idx_from_path(bctx, sunit->source_file); - U32 obj_path = cons__paths_idx_from_path(bctx, sunit->object_file); - U32 archive_path = cons__paths_idx_from_path(bctx, sunit->archive_file); - U32 build_path = cons__paths_idx_from_path(bctx, sunit->build_path); - - dunit->unit_name_string_idx = unit_name; - dunit->compiler_name_string_idx = cmp_name; - dunit->source_file_path_node = src_path; - dunit->object_file_path_node = obj_path; - dunit->archive_file_path_node = archive_path; - dunit->build_path_node = build_path; - dunit->language = sunit->language; - - // line info (voff -> file*line*col) - CONS_LineSequenceNode *first_seq = sunit->line_seq_first; - CONS__UnitLinesCombined *lines = cons__unit_combine_lines(arena, bctx, first_seq); - - U32 line_count = lines->line_count; - if (line_count > 0){ - dunit->line_info_voffs_data_idx = - cons__dsection(arena, &dss, lines->voffs, sizeof(U64)*(line_count + 1), - RADDBG_DataSectionTag_LineInfoVoffs); - dunit->line_info_data_idx = - cons__dsection(arena, &dss, lines->lines, sizeof(RADDBG_Line)*line_count, - RADDBG_DataSectionTag_LineInfoData); - if (lines->cols != 0){ - dunit->line_info_col_data_idx = - cons__dsection(arena, &dss, lines->cols, sizeof(RADDBG_Column)*line_count, - RADDBG_DataSectionTag_LineInfoColumns); - } - dunit->line_info_count = line_count; - } - } - - cons__dsection(arena, &dss, units, sizeof(*units)*count, RADDBG_DataSectionTag_Units); - } - - // source file line info baking - // * pass for "source_combine_line" for each source file - - // * can only be run after a pass that does "unit_combine_lines" for each unit. - for (CONS__SrcNode *src_node = bctx->tree->src_first; - src_node != 0; - src_node = src_node->next){ - CONS__LineMapFragment *first_fragment = src_node->first_fragment; - CONS__SrcLinesCombined *lines = cons__source_combine_lines(arena, first_fragment); - U32 line_count = lines->line_count; - - if (line_count > 0){ - src_node->line_map_count = line_count; - - src_node->line_map_nums_data_idx = - cons__dsection(arena, &dss, lines->line_nums, sizeof(*lines->line_nums)*line_count, - RADDBG_DataSectionTag_LineMapNumbers); - - src_node->line_map_range_data_idx = - cons__dsection(arena, &dss, lines->line_ranges, sizeof(*lines->line_ranges)*(line_count + 1), - RADDBG_DataSectionTag_LineMapRanges); - - src_node->line_map_voff_data_idx = - cons__dsection(arena, &dss, lines->voffs, sizeof(*lines->voffs)*lines->voff_count, - RADDBG_DataSectionTag_LineMapVoffs); - } - } - - // source file name mapping - { - CONS__NameMap* map = cons__name_map_for_kind(root, RADDBG_NameMapKind_NormalSourcePaths); - for (CONS__SrcNode *src_node = bctx->tree->src_first; - src_node != 0; - src_node = src_node->next){ - if (src_node->idx != 0){ - cons__name_map_add_pair(root, map, src_node->normal_full_path, src_node->idx); - } - } - } - - // unit vmap baking - { - CONS__VMap *vmap = cons__vmap_from_unit_ranges(arena, - root->unit_vmap_range_first, - root->unit_vmap_range_count); - - U64 vmap_size = sizeof(*vmap->vmap)*(vmap->count + 1); - cons__dsection(arena, &dss, vmap->vmap, vmap_size, RADDBG_DataSectionTag_UnitVmap); - } - - // type info baking - { - CONS__TypeData *types = cons__type_data_combine(arena, root, bctx); - - U64 type_nodes_size = sizeof(*types->type_nodes)*types->type_node_count; - cons__dsection(arena, &dss, types->type_nodes, type_nodes_size, RADDBG_DataSectionTag_TypeNodes); - - U64 udt_size = sizeof(*types->udts)*types->udt_count; - cons__dsection(arena, &dss, types->udts, udt_size, RADDBG_DataSectionTag_UDTs); - - U64 member_size = sizeof(*types->members)*types->member_count; - cons__dsection(arena, &dss, types->members, member_size, RADDBG_DataSectionTag_Members); - - U64 enum_member_size = sizeof(*types->enum_members)*types->enum_member_count; - cons__dsection(arena, &dss, types->enum_members, enum_member_size, RADDBG_DataSectionTag_EnumMembers); - } - - // symbol info baking - { - CONS__SymbolData *symbol_data = cons__symbol_data_combine(arena, root, bctx); - - U64 global_variables_size = - sizeof(*symbol_data->global_variables)*symbol_data->global_variable_count; - cons__dsection(arena, &dss, symbol_data->global_variables, global_variables_size, - RADDBG_DataSectionTag_GlobalVariables); - - CONS__VMap *global_vmap = symbol_data->global_vmap; - U64 global_vmap_size = sizeof(*global_vmap->vmap)*(global_vmap->count + 1); - cons__dsection(arena, &dss, global_vmap->vmap, global_vmap_size, - RADDBG_DataSectionTag_GlobalVmap); - - U64 thread_variables_size = - sizeof(*symbol_data->thread_variables)*symbol_data->thread_variable_count; - cons__dsection(arena, &dss, symbol_data->thread_variables, thread_variables_size, - RADDBG_DataSectionTag_ThreadVariables); - - U64 procedures_size = sizeof(*symbol_data->procedures)*symbol_data->procedure_count; - cons__dsection(arena, &dss, symbol_data->procedures, procedures_size, - RADDBG_DataSectionTag_Procedures); - - U64 scopes_size = sizeof(*symbol_data->scopes)*symbol_data->scope_count; - cons__dsection(arena, &dss, symbol_data->scopes, scopes_size, RADDBG_DataSectionTag_Scopes); - - U64 scope_voffs_size = sizeof(*symbol_data->scope_voffs)*symbol_data->scope_voff_count; - cons__dsection(arena, &dss, symbol_data->scope_voffs, scope_voffs_size, - RADDBG_DataSectionTag_ScopeVoffData); - - CONS__VMap *scope_vmap = symbol_data->scope_vmap; - U64 scope_vmap_size = sizeof(*scope_vmap->vmap)*(scope_vmap->count + 1); - cons__dsection(arena, &dss, scope_vmap->vmap, scope_vmap_size, RADDBG_DataSectionTag_ScopeVmap); - - U64 local_size = sizeof(*symbol_data->locals)*symbol_data->local_count; - cons__dsection(arena, &dss, symbol_data->locals, local_size, RADDBG_DataSectionTag_Locals); - - U64 location_blocks_size = - sizeof(*symbol_data->location_blocks)*symbol_data->location_block_count; - cons__dsection(arena, &dss, symbol_data->location_blocks, location_blocks_size, - RADDBG_DataSectionTag_LocationBlocks); - - U64 location_data_size = symbol_data->location_data_size; - cons__dsection(arena, &dss, symbol_data->location_data, location_data_size, - RADDBG_DataSectionTag_LocationData); - } - - // name map baking - { - U32 name_map_count = 0; - for (U32 i = 0; i < RADDBG_NameMapKind_COUNT; i += 1){ - if (root->name_maps[i] != 0){ - name_map_count += 1; - } - } - - RADDBG_NameMap *name_maps = push_array(arena, RADDBG_NameMap, name_map_count); - - RADDBG_NameMap *name_map_ptr = name_maps; - for (U32 i = 0; i < RADDBG_NameMapKind_COUNT; i += 1){ - CONS__NameMap *map = root->name_maps[i]; - if (map != 0){ - CONS__NameMapBaked *baked = cons__name_map_bake(arena, root, bctx, map); - - name_map_ptr->kind = i; - name_map_ptr->bucket_data_idx = - cons__dsection(arena, &dss, baked->buckets, sizeof(*baked->buckets)*baked->bucket_count, - RADDBG_DataSectionTag_NameMapBuckets); - name_map_ptr->node_data_idx = - cons__dsection(arena, &dss, baked->nodes, sizeof(*baked->nodes)*baked->node_count, - RADDBG_DataSectionTag_NameMapNodes); - name_map_ptr += 1; - } - } - - cons__dsection(arena, &dss, name_maps, sizeof(*name_maps)*name_map_count, - RADDBG_DataSectionTag_NameMaps); - } - - //////////////////////////////// - // LATE PART: baking loose structures and creating final layout - - // generate data sections for file paths - { - U32 count = bctx->tree->count; - RADDBG_FilePathNode *nodes = push_array(arena, RADDBG_FilePathNode, count); - - RADDBG_FilePathNode *out_node = nodes; - for (CONS__PathNode *node = bctx->tree->first; - node != 0; - node = node->next_order, out_node += 1){ - out_node->name_string_idx = cons__string(bctx, node->name); - if (node->parent != 0){ - out_node->parent_path_node = node->parent->idx; - } - if (node->first_child != 0){ - out_node->first_child = node->first_child->idx; - } - if (node->next_sibling != 0){ - out_node->next_sibling = node->next_sibling->idx; - } - if (node->src_file != 0){ - out_node->source_file_idx = node->src_file->idx; - } - } - - cons__dsection(arena, &dss, nodes, sizeof(*nodes)*count, RADDBG_DataSectionTag_FilePathNodes); - } - - // generate data sections for files - { - U32 count = bctx->tree->src_count; - RADDBG_SourceFile *src_files = push_array(arena, RADDBG_SourceFile, count); - - RADDBG_SourceFile *out_src_file = src_files; - for (CONS__SrcNode *node = bctx->tree->src_first; - node != 0; - node = node->next, out_src_file += 1){ - out_src_file->file_path_node_idx = node->path_node->idx; - out_src_file->normal_full_path_string_idx = cons__string(bctx, node->normal_full_path); - out_src_file->line_map_nums_data_idx = node->line_map_nums_data_idx; - out_src_file->line_map_range_data_idx = node->line_map_range_data_idx; - out_src_file->line_map_count = node->line_map_count; - out_src_file->line_map_voff_data_idx = node->line_map_voff_data_idx; - } - - cons__dsection(arena, &dss, src_files, sizeof(*src_files)*count, RADDBG_DataSectionTag_SourceFiles); - } - - // generate data sections for strings - { - U32 *str_offs = push_array_no_zero(arena, U32, bctx->strs.count + 1); - - U32 off_cursor = 0; - { - U32 *off_ptr = str_offs; - *off_ptr = 0; - off_ptr += 1; - for (CONS__StringNode *node = bctx->strs.order_first; - node != 0; - node = node->order_next){ - off_cursor += node->str.size; - *off_ptr = off_cursor; - off_ptr += 1; - } - } - - U8 *buf = push_array(arena, U8, off_cursor); - { - U8 *ptr = buf; - for (CONS__StringNode *node = bctx->strs.order_first; - node != 0; - node = node->order_next){ - MemoryCopy(ptr, node->str.str, node->str.size); - ptr += node->str.size; - } - } - - cons__dsection(arena, &dss, str_offs, sizeof(*str_offs)*(bctx->strs.count + 1), - RADDBG_DataSectionTag_StringTable); - cons__dsection(arena, &dss, buf, off_cursor, RADDBG_DataSectionTag_StringData); - } - - // generate data sections for index runs - { - U32 *idx_data = push_array_no_zero(arena, U32, bctx->idxs.idx_count); - - { - U32 *out_ptr = idx_data; - U32 *opl = out_ptr + bctx->idxs.idx_count; - CONS__IdxRunNode *node = bctx->idxs.order_first; - for (;node != 0 && out_ptr < opl; - node = node->order_next){ - MemoryCopy(out_ptr, node->idx_run, sizeof(*node->idx_run)*node->count); - out_ptr += node->count; - } - Assert(out_ptr == opl); - } - - cons__dsection(arena, &dss, idx_data, sizeof(*idx_data)*bctx->idxs.idx_count, - RADDBG_DataSectionTag_IndexRuns); - } - - // layout - // * the header and data section table have to be initialized "out of order" - // * so that the rest of the system can avoid this tricky order-layout interdependence stuff - RADDBG_Header *header = push_array(arena, RADDBG_Header, 1); - RADDBG_DataSection *dstable = push_array(arena, RADDBG_DataSection, dss.count); - str8_serial_push_align(arena, out, 8); - U64 header_off = out->total_size; - str8_list_push(arena, out, str8_struct(header)); - str8_serial_push_align(arena, out, 8); - U64 data_section_off = out->total_size; - str8_list_push(arena, out, str8((U8 *)dstable, sizeof(*dstable)*dss.count)); - { - header->magic = RADDBG_MAGIC_CONSTANT; - header->encoding_version = RADDBG_ENCODING_VERSION; - header->data_section_off = data_section_off; - header->data_section_count = dss.count; - } - { - U64 test_dss_count = 0; - for (CONS__DSectionNode *node = dss.first; - node != 0; - node = node->next){ - test_dss_count += 1; - } - Assert(test_dss_count == dss.count); - - RADDBG_DataSection *ptr = dstable; - for (CONS__DSectionNode *node = dss.first; - node != 0; - node = node->next, ptr += 1){ - U64 data_section_offset = 0; - if(node->size != 0) - { - str8_serial_push_align(arena, out, 8); - data_section_offset = out->total_size; - str8_list_push(arena, out, str8((U8 *)node->data, node->size)); - } - ptr->tag = node->tag; - ptr->encoding = RADDBG_DataSectionEncoding_Unpacked; - ptr->off = data_section_offset; - ptr->encoded_size = node->size; - ptr->unpacked_size = node->size; - } - Assert(ptr == dstable + dss.count); - } - - cons__bake_ctx_release(bctx); - ProfEnd(); -} - - -//- errors -static void -cons_errorf(CONS_Root *root, char *fmt, ...){ - ProfBeginFunction(); - CONS_Error *error = push_array(root->arena, CONS_Error, 1); - SLLQueuePush(root->errors.first, root->errors.last, error); - root->errors.count += 1; - - va_list args; - va_start(args, fmt); - String8 str = push_str8fv(root->arena, fmt, args); - va_end(args); - - error->msg = str; - ProfEnd(); -} - -static CONS_Error* -cons_get_first_error(CONS_Root *root){ - return(root->errors.first); -} - - -//- information declaration - -// top level info - -static void -cons_set_top_level_info(CONS_Root *root, CONS_TopLevelInfo *tli){ - if (root->top_level_info_is_set){ - // TODO(allen): API error - } - else{ - MemoryCopyStruct(&root->top_level_info, tli); - root->top_level_info_is_set = 1; - } -} - -// binary sections - -static void -cons_add_binary_section(CONS_Root *root, String8 name, RADDBG_BinarySectionFlags flags, - U64 voff_first, U64 voff_opl, U64 foff_first, U64 foff_opl){ - CONS_BinarySection *sec = push_array(root->arena, CONS_BinarySection, 1); - SLLQueuePush(root->binary_section_first, root->binary_section_last, sec); - root->binary_section_count += 1; - - sec->name = name; - sec->flags = flags; - sec->voff_first = voff_first; - sec->voff_opl = voff_opl; - sec->foff_first = foff_first; - sec->foff_opl = foff_opl; -} - -// units - -static CONS_Unit* -cons_unit_handle_from_user_id(CONS_Root *root, U64 unit_user_id){ - CONS__U64ToPtrLookup lookup = {0}; - cons__u64toptr_lookup(&root->unit_map, unit_user_id, &lookup); - - CONS_Unit *result = 0; - if (lookup.match != 0){ - result = (CONS_Unit*)lookup.match; - } - else{ - result = push_array(root->arena, CONS_Unit, 1); - result->idx = root->unit_count; - SLLQueuePush_N(root->unit_first, root->unit_last, result, next_order); - root->unit_count += 1; - cons__u64toptr_insert(root->arena, &root->unit_map, unit_user_id, &lookup, result); - } - - return(result); -} - -static void -cons_unit_set_info(CONS_Root *root, CONS_Unit *unit, CONS_UnitInfo *info){ - if (unit->info_is_set){ - // TODO(allen): API error - } - else{ - unit->info_is_set = 1; - unit->unit_name = push_str8_copy(root->arena, info->unit_name); - unit->compiler_name = push_str8_copy(root->arena, info->compiler_name); - unit->source_file = push_str8_copy(root->arena, info->source_file); - unit->object_file = push_str8_copy(root->arena, info->object_file); - unit->archive_file = push_str8_copy(root->arena, info->archive_file); - unit->build_path = push_str8_copy(root->arena, info->build_path); - unit->language = info->language; - } -} - -static void -cons_unit_add_line_sequence(CONS_Root *root, CONS_Unit *unit, CONS_LineSequence *line_sequence){ - CONS_LineSequenceNode *node = push_array(root->arena, CONS_LineSequenceNode, 1); - SLLQueuePush(unit->line_seq_first, unit->line_seq_last, node); - unit->line_seq_count += 1; - - node->line_seq.file_name = push_str8_copy(root->arena, line_sequence->file_name); - - node->line_seq.voffs = push_array(root->arena, U64, line_sequence->line_count + 1); - MemoryCopy(node->line_seq.voffs, line_sequence->voffs, sizeof(U64)*(line_sequence->line_count + 1)); - - node->line_seq.line_nums = push_array(root->arena, U32, line_sequence->line_count); - MemoryCopy(node->line_seq.line_nums, line_sequence->line_nums, sizeof(U32)*line_sequence->line_count); - - if (line_sequence->col_nums != 0){ - node->line_seq.col_nums = push_array(root->arena, U16, line_sequence->line_count); - MemoryCopy(node->line_seq.col_nums, line_sequence->col_nums, sizeof(U16)*line_sequence->line_count); - } - - node->line_seq.line_count = line_sequence->line_count; -} - -static void -cons_unit_vmap_add_range(CONS_Root *root, CONS_Unit *unit, U64 first, U64 opl){ - CONS_UnitVMapRange *node = push_array(root->arena, CONS_UnitVMapRange, 1); - SLLQueuePush(root->unit_vmap_range_first, root->unit_vmap_range_last, node); - root->unit_vmap_range_count += 1; - - node->unit = unit; - node->first = first; - node->opl = opl; -} - -// types - -static CONS_Type* -cons_type_from_id(CONS_Root *root, U64 type_user_id){ - CONS__U64ToPtrLookup lookup = {0}; - cons__u64toptr_lookup(&root->type_from_id_map, type_user_id, &lookup); - - CONS_Type *result = (CONS_Type*)lookup.match; - return(result); -} - -static CONS_Reservation* -cons_type_reserve_id(CONS_Root *root, U64 type_user_id){ - CONS__U64ToPtrLookup lookup = {0}; - cons__u64toptr_lookup(&root->type_from_id_map, type_user_id, &lookup); - - CONS_Reservation *result = 0; - if (lookup.match == 0){ - cons__u64toptr_insert(root->arena, &root->type_from_id_map, type_user_id, &lookup, root->nil_type); - void **slot = &lookup.fill_node->ptr[lookup.fill_k]; - result = (CONS_Reservation*)slot; - } - - return(result); -} - -static void -cons_type_fill_id(CONS_Root *root, CONS_Reservation *res, CONS_Type *type){ - if (res != 0 && type != 0){ - *(void**)res = type; - } -} - -static B32 -cons_type_is_unhandled_nil(CONS_Root *root, CONS_Type *type){ - B32 result = (type->kind == RADDBG_TypeKind_NULL && - type != &root->handled_nil_type); - return(result); -} - -static CONS_Type* -cons_type_handled_nil(CONS_Root *root){ - return(&root->handled_nil_type); -} - -static CONS_Type* -cons_type_nil(CONS_Root *root){ - return(root->nil_type); -} - -static CONS_Type* -cons_type_variadic(CONS_Root *root){ - return(root->variadic_type); -} - -static CONS_Type* -cons_type_basic(CONS_Root *root, RADDBG_TypeKind type_kind, String8 name){ - CONS_Type *result = root->nil_type; - - if (!(RADDBG_TypeKind_FirstBuiltIn <= type_kind && - type_kind <= RADDBG_TypeKind_LastBuiltIn)){ - // TODO(allen): API error - } - else{ - Temp scratch = scratch_begin(0, 0); - - // setup construct buffer - U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(type_kind) + name.size; - U8 *buf = push_array(scratch.arena, U8, buf_size); - { - U8 *ptr = buf; - // "basic" - *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Basic; - ptr += sizeof(CONS_TypeConstructKind); - // type_kind - MemoryCopy(ptr, &type_kind, sizeof(type_kind)); - ptr += sizeof(type_kind); - // name - MemoryCopy(ptr, name.str, name.size); - ptr += name.size; - } - - // check for duplicate construct - String8 blob = str8(buf, buf_size); - U64 blob_hash = raddbg_hash(buf, buf_size); - void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); - result = (CONS_Type*)lookup_ptr; - if (result == 0){ - // calculate size - U32 byte_size = raddbg_size_from_basic_type_kind(type_kind); - if (byte_size == 0xFFFFFFFF){ - byte_size = root->addr_size; - } - - // setup new node - result = cons__type_new(root); - result->kind = type_kind; - result->name = push_str8_copy(root->arena, name); - result->byte_size = byte_size; - - // save in construct map - cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); - - // save in name map - { - CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); - cons__name_map_add_pair(root, map, result->name, result->idx); - } - } - - scratch_end(scratch); - } - - Assert(result != 0); - return(result); -} - -static CONS_Type* -cons_type_modifier(CONS_Root *root, CONS_Type *direct_type, RADDBG_TypeModifierFlags flags){ - ProfBeginFunction(); - CONS_Type *result = root->nil_type; - - { - Temp scratch = scratch_begin(0, 0); - - // setup construct buffer - U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(flags) + sizeof(direct_type->idx); - U8 *buf = push_array(scratch.arena, U8, buf_size); - { - U8 *ptr = buf; - // "modifier" - *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Modifier; - ptr += sizeof(CONS_TypeConstructKind); - // flags - MemoryCopy(ptr, &flags, sizeof(flags)); - ptr += sizeof(flags); - // direct_type->idx - MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); - ptr += sizeof(direct_type->idx); - } - - // check for duplicate construct - String8 blob = str8(buf, buf_size); - U64 blob_hash = raddbg_hash(buf, buf_size); - void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); - result = (CONS_Type*)lookup_ptr; - if (result == 0){ - - // setup new node - result = cons__type_new(root); - result->kind = RADDBG_TypeKind_Modifier; - result->flags = flags; - result->byte_size = direct_type->byte_size; - result->direct_type = direct_type; - - // save in construct map - cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); - } - - scratch_end(scratch); - } - - Assert(result != 0); - ProfEnd(); - return(result); -} - -static CONS_Type* -cons_type_bitfield(CONS_Root *root, CONS_Type *direct_type, U32 bit_off, U32 bit_count){ - CONS_Type *result = root->nil_type; - - { - Temp scratch = scratch_begin(0, 0); - - // setup construct buffer - U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(direct_type->idx) + sizeof(U32)*2; - U8 *buf = push_array(scratch.arena, U8, buf_size); - { - U8 *ptr = buf; - // "bitfield" - *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Bitfield; - ptr += sizeof(CONS_TypeConstructKind); - // direct_type->idx - MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); - ptr += sizeof(direct_type->idx); - // bit_off - MemoryCopy(ptr, &bit_off, sizeof(bit_off)); - ptr += sizeof(bit_off); - // bit_count - MemoryCopy(ptr, &bit_count, sizeof(bit_count)); - ptr += sizeof(bit_count); - } - - // check for duplicate construct - String8 blob = str8(buf, buf_size); - U64 blob_hash = raddbg_hash(buf, buf_size); - void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); - result = (CONS_Type*)lookup_ptr; - if (result == 0){ - - // setup new node - result = cons__type_new(root); - result->kind = RADDBG_TypeKind_Bitfield; - result->byte_size = direct_type->byte_size; - result->off = bit_off; - result->count = bit_count; - result->direct_type = direct_type; - - // save in construct map - cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); - } - - scratch_end(scratch); - } - - Assert(result != 0); - return(result); -} - -static CONS_Type* -cons_type_pointer(CONS_Root *root, CONS_Type *direct_type, RADDBG_TypeKind ptr_type_kind){ - ProfBeginFunction(); - CONS_Type *result = root->nil_type; - - if (!(ptr_type_kind == RADDBG_TypeKind_Ptr || - ptr_type_kind == RADDBG_TypeKind_LRef || - ptr_type_kind == RADDBG_TypeKind_RRef)){ - // TODO(allen): API error - } - else{ - Temp scratch = scratch_begin(0, 0); - - // setup construct buffer - U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(ptr_type_kind) + sizeof(direct_type->idx); - U8 *buf = push_array(scratch.arena, U8, buf_size); - { - U8 *ptr = buf; - // "pointer" - *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Pointer; - ptr += sizeof(CONS_TypeConstructKind); - // type_kind - MemoryCopy(ptr, &ptr_type_kind, sizeof(ptr_type_kind)); - ptr += sizeof(ptr_type_kind); - // direct_type->idx - MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); - ptr += sizeof(direct_type->idx); - } - - // check for duplicate construct - String8 blob = str8(buf, buf_size); - U64 blob_hash = raddbg_hash(buf, buf_size); - void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); - result = (CONS_Type*)lookup_ptr; - if (result == 0){ - - // setup new node - result = cons__type_new(root); - result->kind = ptr_type_kind; - result->byte_size = root->addr_size; - result->direct_type = direct_type; - - // save in construct map - cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); - } - - scratch_end(scratch); - } - - Assert(result != 0); - ProfEnd(); - return(result); -} - -static CONS_Type* -cons_type_array(CONS_Root *root, CONS_Type *direct_type, U64 count){ - CONS_Type *result = root->nil_type; - - { - Temp scratch = scratch_begin(0, 0); - - // setup construct buffer - U64 buf_size = - sizeof(CONS_TypeConstructKind) + sizeof(direct_type->idx) + sizeof(count); - U8 *buf = push_array(scratch.arena, U8, buf_size); - { - U8 *ptr = buf; - // "array" - *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Array; - ptr += sizeof(CONS_TypeConstructKind); - // direct_type->idx - MemoryCopy(ptr, &direct_type->idx, sizeof(direct_type->idx)); - ptr += sizeof(direct_type->idx); - // count - MemoryCopy(ptr, &count, sizeof(count)); - ptr += sizeof(count); - } - - // check for duplicate construct - String8 blob = str8(buf, buf_size); - U64 blob_hash = raddbg_hash(buf, buf_size); - void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); - result = (CONS_Type*)lookup_ptr; - if (result == 0){ - - // setup new node - result = cons__type_new(root); - result->kind = RADDBG_TypeKind_Array; - result->count = count; - result->direct_type = direct_type; - result->byte_size = direct_type->byte_size*count; - - // save in construct map - cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); - } - - scratch_end(scratch); - } - - Assert(result != 0); - return(result); -} - -static CONS_Type* -cons_type_proc(CONS_Root *root, CONS_Type *return_type, CONS_TypeList *params){ - ProfBeginFunction(); - CONS_Type *result = root->nil_type; - - { - Temp scratch = scratch_begin(0, 0); - - // setup construct buffer - U64 buf_size = sizeof(CONS_TypeConstructKind) + sizeof(return_type->idx)*(1 + params->count); - U8 *buf = push_array(scratch.arena, U8, buf_size); - { - U8 *ptr = buf; - // "procedure" - *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Procedure; - ptr += sizeof(CONS_TypeConstructKind); - // ret_type->idx - MemoryCopy(ptr, &return_type->idx, sizeof(return_type->idx)); - ptr += sizeof(return_type->idx); - // (params ...)->idx - for (CONS_TypeNode *node = params->first; - node != 0; - node = node->next){ - MemoryCopy(ptr, &node->type->idx, sizeof(node->type->idx)); - ptr += sizeof(node->type->idx); - } - } - - // check for duplicate construct - String8 blob = str8(buf, buf_size); - U64 blob_hash = raddbg_hash(buf, buf_size); - void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); - result = (CONS_Type*)lookup_ptr; - if (result == 0){ - - // setup param buffer - CONS_Type **param_types = push_array(root->arena, CONS_Type*, params->count); - { - CONS_Type **ptr = param_types; - for (CONS_TypeNode *node = params->first; - node != 0; - node = node->next){ - *ptr = node->type; - ptr += 1; - } - } - - // setup new node - result = cons__type_new(root); - result->kind = RADDBG_TypeKind_Function; - result->byte_size = root->addr_size; - result->count = params->count; - result->direct_type = return_type; - result->param_types = param_types; - - // save in construct map - cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); - } - - scratch_end(scratch); - } - - Assert(result != 0); - ProfEnd(); - return(result); -} - -static CONS_Type* -cons_type_method(CONS_Root *root, CONS_Type *this_type, CONS_Type *return_type, CONS_TypeList *params){ - ProfBeginFunction(0, 0); - CONS_Type *result = root->nil_type; - - { - Temp scratch = scratch_begin(0, 0); - - // setup construct buffer - U64 buf_size = - sizeof(CONS_TypeConstructKind) + sizeof(return_type->idx)*(2 + params->count); - U8 *buf = push_array(scratch.arena, U8, buf_size); - { - U8 *ptr = buf; - // "method" - *(CONS_TypeConstructKind*)ptr = CONS_TypeConstructKind_Method; - ptr += sizeof(CONS_TypeConstructKind); - // ret_type->idx - MemoryCopy(ptr, &return_type->idx, sizeof(return_type->idx)); - ptr += sizeof(return_type->idx); - // this_type->idx - MemoryCopy(ptr, &this_type->idx, sizeof(this_type->idx)); - ptr += sizeof(this_type->idx); - // (params ...)->idx - for (CONS_TypeNode *node = params->first; - node != 0; - node = node->next){ - MemoryCopy(ptr, &node->type->idx, sizeof(node->type->idx)); - ptr += sizeof(node->type->idx); - } - } - - // check for duplicate construct - String8 blob = str8(buf, buf_size); - U64 blob_hash = raddbg_hash(buf, buf_size); - void *lookup_ptr = cons__str8toptr_lookup(&root->construct_map, blob, blob_hash); - result = (CONS_Type*)lookup_ptr; - if (result == 0){ - - // setup param buffer - CONS_Type **param_types = push_array(root->arena, CONS_Type*, params->count + 1); - { - CONS_Type **ptr = param_types; - { - *ptr = this_type; - ptr += 1; - } - for (CONS_TypeNode *node = params->first; - node != 0; - node = node->next){ - *ptr = node->type; - ptr += 1; - } - } - - // setup new node - result = cons__type_new(root); - result->kind = RADDBG_TypeKind_Method; - result->byte_size = root->addr_size; - result->count = params->count; - result->direct_type = return_type; - result->param_types = param_types; - - // save in construct map - cons__str8toptr_insert(root->arena, &root->construct_map, blob, blob_hash, result); - } - - scratch_end(scratch); - } - - Assert(result != 0); - ProfEnd(); - return(result); -} - -static CONS_Type* -cons_type_udt(CONS_Root *root, RADDBG_TypeKind record_type_kind, String8 name, U64 size){ - CONS_Type *result = root->nil_type; - - if (!(record_type_kind == RADDBG_TypeKind_Struct || - record_type_kind == RADDBG_TypeKind_Class || - record_type_kind == RADDBG_TypeKind_Union)){ - // TODO(allen): API error - } - else{ - result = cons__type_new(root); - result->kind = record_type_kind; - result->byte_size = size; - result->name = push_str8_copy(root->arena, name); - - // save in name map - { - CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); - cons__name_map_add_pair(root, map, result->name, result->idx); - } - } - - return(result); -} - -static CONS_Type* -cons_type_enum(CONS_Root *root, CONS_Type *direct_type, String8 name){ - CONS_Type *result = cons__type_new(root); - result->kind = RADDBG_TypeKind_Enum; - result->byte_size = direct_type->byte_size; - result->name = push_str8_copy(root->arena, name); - result->direct_type = direct_type; - - // save in name map - { - CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); - cons__name_map_add_pair(root, map, result->name, result->idx); - } - - return(result); -} - -static CONS_Type* -cons_type_alias(CONS_Root *root, CONS_Type *direct_type, String8 name){ - CONS_Type *result = cons__type_new(root); - result->kind = RADDBG_TypeKind_Alias; - result->byte_size = direct_type->byte_size; - result->name = push_str8_copy(root->arena, name); - result->direct_type = direct_type; - - // save in name map - { - CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); - cons__name_map_add_pair(root, map, result->name, result->idx); - } - - return(result); -} - -static CONS_Type* -cons_type_incomplete(CONS_Root *root, RADDBG_TypeKind type_kind, String8 name){ - CONS_Type *result = root->nil_type; - - if (!(type_kind == RADDBG_TypeKind_IncompleteStruct || - type_kind == RADDBG_TypeKind_IncompleteClass || - type_kind == RADDBG_TypeKind_IncompleteUnion || - type_kind == RADDBG_TypeKind_IncompleteEnum)){ - // TODO(allen): API error - } - else{ - result = cons__type_new(root); - result->kind = type_kind; - result->name = push_str8_copy(root->arena, name); - - // save in name map - { - CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Types); - cons__name_map_add_pair(root, map, result->name, result->idx); - } - } - - return(result); -} - -static void -cons_type_add_member_data_field(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type, U32 off){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_DataField; - member->name = push_str8_copy(root->arena, name); - member->type = mem_type; - member->off = off; - } -} - -static void -cons_type_add_member_static_data(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_StaticData; - member->name = push_str8_copy(root->arena, name); - member->type = mem_type; - } -} - -static void -cons_type_add_member_method(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_Method; - member->name = push_str8_copy(root->arena, name); - member->type = mem_type; - } -} - -static void -cons_type_add_member_static_method(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_StaticMethod; - member->name = push_str8_copy(root->arena, name); - member->type = mem_type; - } -} - -static void -cons_type_add_member_virtual_method(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_VirtualMethod; - member->name = push_str8_copy(root->arena, name); - member->type = mem_type; - } -} - -static void -cons_type_add_member_base(CONS_Root *root, CONS_Type *record_type, - CONS_Type *base_type, U32 off){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_Base; - member->type = base_type; - member->off = off; - } -} - -static void -cons_type_add_member_virtual_base(CONS_Root *root, CONS_Type *record_type, - CONS_Type *base_type, U32 vptr_off, U32 vtable_off){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_VirtualBase; - member->type = base_type; - // TODO(allen): what to do with the two offsets in this case? - } -} - -static void -cons_type_add_member_nested_type(CONS_Root *root, CONS_Type *record_type, - CONS_Type *nested_type){ - CONS_TypeUDT *udt = cons__type_udt_from_record_type(root, record_type); - if (udt != 0){ - CONS_TypeMember *member = push_array(root->arena, CONS_TypeMember, 1); - SLLQueuePush(udt->first_member, udt->last_member, member); - udt->member_count += 1; - - root->total_member_count += 1; - - member->kind = RADDBG_MemberKind_NestedType; - member->type = nested_type; - } -} - -static void -cons_type_add_enum_val(CONS_Root *root, CONS_Type *enum_type, String8 name, U64 val){ - if (enum_type->kind != RADDBG_TypeKind_Enum){ - // TODO(allen): API error - } - else{ - CONS_TypeUDT *udt = cons__type_udt_from_any_type(root, enum_type); - - CONS_TypeEnumVal *enum_val = push_array(root->arena, CONS_TypeEnumVal, 1); - SLLQueuePush(udt->first_enum_val, udt->last_enum_val, enum_val); - udt->enum_val_count += 1; - - root->total_enum_val_count += 1; - - enum_val->name = push_str8_copy(root->arena, name); - enum_val->val = val; - } -} - -static void -cons_type_set_source_coordinates(CONS_Root *root, CONS_Type *defined_type, - String8 source_path, U32 line, U32 col){ - if (!(RADDBG_TypeKind_FirstUserDefined <= defined_type->kind && - defined_type->kind <= RADDBG_TypeKind_LastUserDefined)){ - // TODO(allen): API error - } - else{ - CONS_TypeUDT *udt = cons__type_udt_from_any_type(root, defined_type); - - udt->source_path = push_str8_copy(root->arena, source_path); - udt->line = line; - udt->col = col; - } -} - -// type list - -static void -cons_type_list_push(Arena *arena, CONS_TypeList *list, CONS_Type *type){ - CONS_TypeNode *node = push_array(arena, CONS_TypeNode, 1); - SLLQueuePush(list->first, list->last, node); - list->count += 1; - node->type = type; -} - -// symbols - -static CONS_Symbol* -cons_symbol_handle_from_user_id(CONS_Root *root, U64 symbol_user_id){ - CONS__U64ToPtrLookup lookup = {0}; - cons__u64toptr_lookup(&root->symbol_map, symbol_user_id, &lookup); - - CONS_Symbol *result = 0; - if (lookup.match != 0){ - result = (CONS_Symbol*)lookup.match; - } - else{ - result = push_array(root->arena, CONS_Symbol, 1); - SLLQueuePush_N(root->first_symbol, root->last_symbol, result, next_order); - root->symbol_count += 1; - cons__u64toptr_insert(root->arena, &root->symbol_map, symbol_user_id, &lookup, result); - } - - return(result); -} - -static void -cons_symbol_set_info(CONS_Root *root, CONS_Symbol *symbol, CONS_SymbolInfo *info){ - CONS_SymbolKind kind = info->kind; - - if (symbol->kind != CONS_SymbolKind_NULL){ - // TODO(allen): API error - } - else if (kind == CONS_SymbolKind_NULL || kind >= CONS_SymbolKind_COUNT){ - // TODO(allen): API error - } - else if (info->type == 0){ - // TODO(allen): API error - } - else{ - CONS_Symbol *container_symbol = info->container_symbol; - CONS_Type *container_type = info->container_type; - if (info->container_symbol != 0 && info->container_type != 0){ - // TODO(allen): API error - container_type = 0; - } - - root->symbol_kind_counts[kind] += 1; - symbol->idx = root->symbol_kind_counts[kind]; - - symbol->kind = kind; - symbol->name = push_str8_copy(root->arena, info->name); - symbol->link_name = push_str8_copy(root->arena, info->link_name); - symbol->type = info->type; - symbol->is_extern = info->is_extern; - symbol->offset = info->offset; - symbol->container_symbol = container_symbol; - symbol->container_type = container_type; - - // set root scope - switch (kind){ - default:{}break; - case CONS_SymbolKind_GlobalVariable: - case CONS_SymbolKind_ThreadVariable: - { - if (info->root_scope != 0){ - // TODO(allen): API error - } - }break; - - case CONS_SymbolKind_Procedure: - { - if (info->root_scope == 0){ - // TODO(allen): API error - } - else{ - symbol->root_scope = info->root_scope; - cons__scope_recursive_set_symbol(info->root_scope, symbol); - } - }break; - } - - // save name map - { - CONS__NameMap *map = 0; - switch (kind){ - default:{}break; - case CONS_SymbolKind_GlobalVariable: - { - map = cons__name_map_for_kind(root, RADDBG_NameMapKind_GlobalVariables); - }break; - case CONS_SymbolKind_ThreadVariable: - { - map = cons__name_map_for_kind(root, RADDBG_NameMapKind_ThreadVariables); - }break; - case CONS_SymbolKind_Procedure: - { - map = cons__name_map_for_kind(root, RADDBG_NameMapKind_Procedures); - }break; - } - if (map != 0){ - cons__name_map_add_pair(root, map, symbol->name, symbol->idx); - } - } - - // save link name map - if (kind == CONS_SymbolKind_Procedure && symbol->link_name.size > 0){ - CONS__NameMap *map = cons__name_map_for_kind(root, RADDBG_NameMapKind_LinkNameProcedures); - cons__name_map_add_pair(root, map, symbol->link_name, symbol->idx); - } - } -} - -// scopes - -static CONS_Scope* -cons_scope_handle_from_user_id(CONS_Root *root, U64 scope_user_id){ - CONS__U64ToPtrLookup lookup = {0}; - cons__u64toptr_lookup(&root->scope_map, scope_user_id, &lookup); - - CONS_Scope *result = 0; - if (lookup.match != 0){ - result = (CONS_Scope*)lookup.match; - } - else{ - result = push_array(root->arena, CONS_Scope, 1); - result->idx = root->scope_count; - SLLQueuePush_N(root->first_scope, root->last_scope, result, next_order); - root->scope_count += 1; - cons__u64toptr_insert(root->arena, &root->scope_map, scope_user_id, &lookup, result); - } - - return(result); -} - -static void -cons_scope_set_parent(CONS_Root *root, CONS_Scope *scope, CONS_Scope *parent){ - if (scope->parent_scope != 0){ - // TODO(allen): API error - } - else if (parent == 0){ - // TODO(allen): API error - } - else{ - scope->symbol = parent->symbol; - scope->parent_scope = parent; - SLLQueuePush_N(parent->first_child, parent->last_child, scope, next_sibling); - } -} - -static void -cons_scope_add_voff_range(CONS_Root *root, CONS_Scope *scope, U64 voff_first, U64 voff_opl){ - CONS__VOffRange *range = push_array(root->arena, CONS__VOffRange, 1); - SLLQueuePush(scope->first_range, scope->last_range, range); - scope->range_count += 1; - range->voff_first = voff_first; - range->voff_opl = voff_opl; - scope->voff_base = Min(scope->voff_base, voff_first); - root->scope_voff_count += 2; -} - -// locals - -static CONS_Local* -cons_local_handle_from_user_id(CONS_Root *root, U64 local_user_id){ - CONS__U64ToPtrLookup lookup = {0}; - cons__u64toptr_lookup(&root->local_map, local_user_id, &lookup); - - CONS_Local *result = 0; - if (lookup.match != 0){ - result = (CONS_Local*)lookup.match; - } - else{ - result = push_array(root->arena, CONS_Local, 1); - cons__u64toptr_insert(root->arena, &root->local_map, local_user_id, &lookup, result); - } - - return(result); -} - -static void -cons_local_set_basic_info(CONS_Root *root, CONS_Local *local, CONS_LocalInfo *info){ - if (local->kind != RADDBG_LocalKind_NULL){ - // TODO(allen): API error - } - else if (info->scope == 0){ - // TODO(allen): API error - } - else if (info->kind == RADDBG_LocalKind_NULL || RADDBG_LocalKind_COUNT <= info->kind){ - // TODO(allen): API error - } - else if (info->type == 0){ - // TODO(allen): API error - } - else{ - CONS_Scope *scope = info->scope; - SLLQueuePush(scope->first_local, scope->last_local, local); - scope->local_count += 1; - root->local_count += 1; - local->kind = info->kind; - local->name = push_str8_copy(root->arena, info->name); - local->type = info->type; - } -} - -static CONS_LocationSet* -cons_location_set_from_local(CONS_Root *root, CONS_Local *local){ - CONS_LocationSet *result = local->locset; - if (result == 0){ - local->locset = push_array(root->arena, CONS_LocationSet, 1); - result = local->locset; - } - return(result); -} - -static void -cons_location_set_add_case(CONS_Root *root, CONS_LocationSet *locset, - U64 voff_first, U64 voff_opl, CONS_Location *location){ - CONS__LocationCase *location_case = push_array(root->arena, CONS__LocationCase, 1); - SLLQueuePush(locset->first_location_case, locset->last_location_case, location_case); - locset->location_case_count += 1; - root->location_count += 1; - - location_case->voff_first = voff_first; - location_case->voff_opl = voff_opl; - location_case->location = location; -} - -static CONS_Location* -cons_location_addr_bytecode_stream(CONS_Root *root, CONS_EvalBytecode *bytecode){ - CONS_Location *result = push_array(root->arena, CONS_Location, 1); - result->kind = RADDBG_LocationKind_AddrBytecodeStream; - result->bytecode = *bytecode; - return(result); -} - -static CONS_Location* -cons_location_val_bytecode_stream(CONS_Root *root, CONS_EvalBytecode *bytecode){ - CONS_Location *result = push_array(root->arena, CONS_Location, 1); - result->kind = RADDBG_LocationKind_ValBytecodeStream; - result->bytecode = *bytecode; - return(result); -} - -static CONS_Location* -cons_location_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset){ - CONS_Location *result = push_array(root->arena, CONS_Location, 1); - result->kind = RADDBG_LocationKind_AddrRegisterPlusU16; - result->register_code = reg_code; - result->offset = offset; - return(result); -} - -static CONS_Location* -cons_location_addr_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset){ - CONS_Location *result = push_array(root->arena, CONS_Location, 1); - result->kind = RADDBG_LocationKind_AddrAddrRegisterPlusU16; - result->register_code = reg_code; - result->offset = offset; - return(result); -} - -static CONS_Location* -cons_location_val_reg(CONS_Root *root, U8 reg_code){ - CONS_Location *result = push_array(root->arena, CONS_Location, 1); - result->kind = RADDBG_LocationKind_ValRegister; - result->register_code = reg_code; - return(result); -} - -// bytecode - -static void -cons_bytecode_push_op(Arena *arena, CONS_EvalBytecode *bytecode, RADDBG_EvalOp op, U64 p){ - U8 ctrlbits = raddbg_eval_opcode_ctrlbits[op]; - U32 p_size = RADDBG_DECODEN_FROM_CTRLBITS(ctrlbits); - - CONS_EvalBytecodeOp *node = push_array(arena, CONS_EvalBytecodeOp, 1); - node->op = op; - node->p_size = p_size; - node->p = p; - - SLLQueuePush(bytecode->first_op, bytecode->last_op, node); - bytecode->op_count += 1; - bytecode->encoded_size += 1 + p_size; -} - -static void -cons_bytecode_push_uconst(Arena *arena, CONS_EvalBytecode *bytecode, U64 x){ - if (x <= 0xFF){ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU8, x); - } - else if (x <= 0xFFFF){ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU16, x); - } - else if (x <= 0xFFFFFFFF){ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU32, x); - } - else{ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU64, x); - } -} - -static void -cons_bytecode_push_sconst(Arena *arena, CONS_EvalBytecode *bytecode, S64 x){ - if (-0x80 <= x && x <= 0x7F){ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU8, (U64)x); - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_TruncSigned, 8); - } - else if (-0x8000 <= x && x <= 0x7FFF){ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU16, (U64)x); - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_TruncSigned, 16); - } - else if (-0x80000000ll <= x && x <= 0x7FFFFFFFll){ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU32, (U64)x); - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_TruncSigned, 32); - } - else{ - cons_bytecode_push_op(arena, bytecode, RADDBG_EvalOp_ConstU64, (U64)x); - } -} - -static void -cons_bytecode_concat_in_place(CONS_EvalBytecode *left_dst, CONS_EvalBytecode *right_destroyed){ - if (right_destroyed->first_op != 0){ - if (left_dst->first_op == 0){ - MemoryCopyStruct(left_dst, right_destroyed); - } - 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; - } - MemoryZeroStruct(right_destroyed); - } -} - - - -//////////////////////////////// -//- Implementation Helpers - -// types - -static CONS_Type* -cons__type_new(CONS_Root *root){ - ProfBeginFunction(); - CONS_Type *result = push_array(root->arena, CONS_Type, 1); - result->idx = root->type_count; - SLLQueuePush_N(root->first_type, root->last_type, result, next_order); - root->type_count += 1; - ProfEnd(); - return(result); -} - -static CONS_TypeUDT* -cons__type_udt_from_any_type(CONS_Root *root, CONS_Type *type){ - if (type->udt == 0){ - CONS_TypeUDT *new_udt = push_array(root->arena, CONS_TypeUDT, 1); - new_udt->idx = root->type_udt_count; - SLLQueuePush_N(root->first_udt, root->last_udt, new_udt, next_order); - root->type_udt_count += 1; - new_udt->self_type = type; - type->udt = new_udt; - } - CONS_TypeUDT *result = type->udt; - return(result); -} - -static CONS_TypeUDT* -cons__type_udt_from_record_type(CONS_Root *root, CONS_Type *type){ - CONS_TypeUDT *result = 0; - - if (!(type->kind == RADDBG_TypeKind_Struct || - type->kind == RADDBG_TypeKind_Class || - type->kind == RADDBG_TypeKind_Union)){ - // TODO(allen): API error - } - else{ - result = cons__type_udt_from_any_type(root, type); - } - - return(result); -} - -// scopes - -static void -cons__scope_recursive_set_symbol(CONS_Scope *scope, CONS_Symbol *symbol){ - scope->symbol = symbol; - for (CONS_Scope *node = scope->first_child; - node != 0; - node = node->next_sibling){ - cons__scope_recursive_set_symbol(node, symbol); - } -} - -// name maps - -static CONS__NameMap* -cons__name_map_for_kind(CONS_Root *root, RADDBG_NameMapKind kind){ - CONS__NameMap *result = 0; - if (kind < RADDBG_NameMapKind_COUNT){ - if (root->name_maps[kind] == 0){ - root->name_maps[kind] = push_array(root->arena, CONS__NameMap, 1); - } - result = root->name_maps[kind]; - } - return(result); -} - -static void -cons__name_map_add_pair(CONS_Root *root, CONS__NameMap *map, String8 string, U32 idx){ - // hash - U64 hash = raddbg_hash(string.str, string.size); - U64 bucket_idx = hash%ArrayCount(map->buckets); - - // find existing name node - CONS__NameMapNode *match = 0; - for (CONS__NameMapNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->bucket_next){ - if (str8_match(string, node->string, 0)){ - match = node; - break; - } - } - - // make name node if necessary - if (match == 0){ - match = push_array(root->arena, CONS__NameMapNode, 1); - match->string = push_str8_copy(root->arena, string); - SLLStackPush_N(map->buckets[bucket_idx], match, bucket_next); - SLLQueuePush_N(map->first, map->last, match, order_next); - map->name_count += 1; - } - - // find existing idx - B32 existing_idx = 0; - for (CONS__NameMapIdxNode *node = match->idx_first; - node != 0; - node = node->next){ - for (U32 i = 0; i < ArrayCount(node->idx); i += 1){ - if (node->idx[i] == 0){ - break; - } - if (node->idx[i] == idx){ - existing_idx = 1; - break; - } - } - } - - // insert new idx if necessary - if (!existing_idx){ - CONS__NameMapIdxNode *idx_node = match->idx_last; - - U32 insert_i = match->idx_count%ArrayCount(idx_node->idx); - if (insert_i == 0){ - idx_node = push_array(root->arena, CONS__NameMapIdxNode, 1); - SLLQueuePush(match->idx_first, match->idx_last, idx_node); - } - - idx_node->idx[insert_i] = idx; - match->idx_count += 1; - } -} - -// u64 to ptr map - -static void -cons__u64toptr_init(Arena *arena, CONS__U64ToPtrMap *map, U64 bucket_count){ - Assert(IsPow2OrZero(bucket_count) && bucket_count > 0); - map->buckets = push_array(arena, CONS__U64ToPtrNode*, bucket_count); - map->bucket_count = bucket_count; -} - -static void -cons__u64toptr_lookup(CONS__U64ToPtrMap *map, U64 key, CONS__U64ToPtrLookup *lookup_out){ - ProfBeginFunction(); - U64 bucket_idx = key&(map->bucket_count - 1); - CONS__U64ToPtrNode *check_node = map->buckets[bucket_idx]; - for (;check_node != 0; check_node = check_node->next){ - for (U32 k = 0; k < ArrayCount(check_node->key); k += 1){ - if (check_node->ptr[k] == 0){ - lookup_out->fill_node = check_node; - lookup_out->fill_k = k; - break; - } - else if (check_node->key[k] == key){ - lookup_out->match = check_node->ptr[k]; - break; - } - } - } - ProfEnd(); -} - -static void -cons__u64toptr_insert(Arena *arena, CONS__U64ToPtrMap *map, U64 key, - CONS__U64ToPtrLookup *lookup, void *ptr){ - if (lookup->fill_node != 0){ - CONS__U64ToPtrNode *node = lookup->fill_node; - U32 k = lookup->fill_k; - node->key[k] = key; - node->ptr[k] = ptr; - } - else{ - U64 bucket_idx = key&(map->bucket_count - 1); - - CONS__U64ToPtrNode *node = push_array(arena, CONS__U64ToPtrNode, 1); - SLLStackPush(map->buckets[bucket_idx], node); - node->key[0] = key; - node->ptr[0] = ptr; - - lookup->fill_node = node; - lookup->fill_k = 0; - } -} - -// str8 to ptr map - -static void* -cons__str8toptr_lookup(CONS__Str8ToPtrMap *map, String8 key, U64 hash){ - ProfBeginFunction(); - void *result = 0; - U64 bucket_idx = hash%ArrayCount(map->buckets); - for (CONS__Str8ToPtrNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->hash == hash && str8_match(node->key, key, 0)){ - result = node->ptr; - break; - } - } - ProfEnd(); - return(result); -} - -static void -cons__str8toptr_insert(Arena *arena, CONS__Str8ToPtrMap *map, String8 key, U64 hash, void *ptr){ - ProfBeginFunction(); - U64 bucket_idx = hash%ArrayCount(map->buckets); - - CONS__Str8ToPtrNode *node = push_array(arena, CONS__Str8ToPtrNode, 1); - SLLStackPush(map->buckets[bucket_idx], node); - - node->key = push_str8_copy(arena, key); - node->hash = hash; - node->ptr = ptr; - ProfEnd(); -} - - -//- cons intermediate functions - -static U32 -cons__dsection(Arena *arena, CONS__DSections *dss, void *data, U64 size, RADDBG_DataSectionTag tag){ - U32 result = dss->count; - - CONS__DSectionNode *node = push_array(arena, CONS__DSectionNode, 1); - SLLQueuePush(dss->first, dss->last, node); - node->data = data; - node->size = size; - node->tag = tag; - dss->count += 1; - - return(result); -} - -static CONS__BakeCtx* -cons__bake_ctx_begin(void){ - Arena *arena = arena_alloc(); - CONS__BakeCtx *result = push_array(arena, CONS__BakeCtx, 1); - result->arena = arena; - - cons__string(result, str8_lit("")); - - cons__idx_run(result, 0, 0); - - result->tree = push_array(arena, CONS__PathTree, 1); - { - CONS__PathNode *nil_path_node = cons__paths_new_node(result); - nil_path_node->name = str8_lit(""); - CONS__SrcNode *nil_src_node = cons__paths_new_src_node(result); - nil_src_node->path_node = nil_path_node; - nil_src_node->normal_full_path = str8_lit(""); - nil_path_node->src_file = nil_src_node; - } - - return(result); -} - -static void -cons__bake_ctx_release(CONS__BakeCtx *bake_ctx){ - arena_release(bake_ctx->arena); -} - - -static U32 -cons__string(CONS__BakeCtx *bctx, String8 str){ - Arena *arena = bctx->arena; - CONS__Strings *strs = &bctx->strs; - - U64 hash = raddbg_hash(str.str, str.size); - U64 bucket_idx = hash%ArrayCount(strs->buckets); - - // look for a match - CONS__StringNode *match = 0; - for (CONS__StringNode *node = strs->buckets[bucket_idx]; - node != 0; - node = node->bucket_next){ - if (node->hash == hash && - str8_match(node->str, str, 0)){ - match = node; - break; - } - } - - // insert new node if no match - if (match == 0){ - CONS__StringNode *node = push_array_no_zero(arena, CONS__StringNode, 1); - node->str = push_str8_copy(arena, str); - node->hash = hash; - node->idx = strs->count; - strs->count += 1; - - SLLQueuePush_N(strs->order_first, strs->order_last, node, order_next); - SLLStackPush_N(strs->buckets[bucket_idx], node, bucket_next); - - match = node; - } - - // extract idx to return - Assert(match != 0); - U32 result = match->idx; - - return(result); -} - -static U64 -cons__idx_run_hash(U32 *idx_run, U32 count){ - U64 hash = 5381; - U32 *ptr = idx_run; - U32 *opl = idx_run + count; - for (; ptr < opl; ptr += 1){ - hash = ((hash << 5) + hash) + (*ptr); - } - return(hash); -} - -static U32 -cons__idx_run(CONS__BakeCtx *bctx, U32 *idx_run, U32 count){ - Arena *arena = bctx->arena; - CONS__IdxRuns *idxs = &bctx->idxs; - - U64 hash = cons__idx_run_hash(idx_run, count); - U64 bucket_idx = hash%ArrayCount(idxs->buckets); - - // look for a match - CONS__IdxRunNode *match = 0; - for (CONS__IdxRunNode *node = idxs->buckets[bucket_idx]; - node != 0; - node = node->bucket_next){ - if (node->hash == hash){ - S32 is_match = 1; - U32 *node_idx = node->idx_run; - for (U32 i = 0; i < count; i += 1){ - if (node_idx[i] != idx_run[i]){ - is_match = 0; - break; - } - } - if (is_match){ - match = node; - break; - } - } - } - - // insert new node if no match - if (match == 0){ - CONS__IdxRunNode *node = push_array_no_zero(arena, CONS__IdxRunNode, 1); - U32 *idx_run_copy = push_array_no_zero(arena, U32, count); - for (U32 i = 0; i < count; i += 1){ - idx_run_copy[i] = idx_run[i]; - } - node->idx_run = idx_run_copy; - node->hash = hash; - node->count = count; - node->first_idx = idxs->idx_count; - - idxs->count += 1; - idxs->idx_count += count; - - SLLQueuePush_N(idxs->order_first, idxs->order_last, node, order_next); - SLLStackPush_N(idxs->buckets[bucket_idx], node, bucket_next); - - match = node; - } - - // extract idx to return - Assert(match != 0); - U32 result = match->first_idx; - - return(result); -} - -static CONS__PathNode* -cons__paths_new_node(CONS__BakeCtx *bctx){ - CONS__PathTree *tree = bctx->tree; - CONS__PathNode *result = push_array(bctx->arena, CONS__PathNode, 1); - SLLQueuePush_N(tree->first, tree->last, result, next_order); - result->idx = tree->count; - tree->count += 1; - return(result); -} - -static CONS__PathNode* -cons__paths_sub_path(CONS__BakeCtx *bctx, CONS__PathNode *dir, String8 sub_dir){ - // look for existing match - CONS__PathNode *match = 0; - for (CONS__PathNode *node = dir->first_child; - node != 0; - node = node->next_sibling){ - if (str8_match(node->name, sub_dir, StringMatchFlag_CaseInsensitive)){ - match = node; - break; - } - } - - // construct new node if no match - CONS__PathNode *new_node = 0; - if (match == 0){ - new_node = cons__paths_new_node(bctx); - new_node->parent = dir; - SLLQueuePush_N(dir->first_child, dir->last_child, new_node, next_sibling); - new_node->name = push_str8_copy(bctx->arena, sub_dir); - } - - // select result from the two paths - CONS__PathNode *result = match; - if (match == 0){ - result = new_node; - } - - return(result); -} - -static CONS__PathNode* -cons__paths_node_from_path(CONS__BakeCtx *bctx, String8 path){ - CONS__PathNode *node_cursor = &bctx->tree->root; - - U8 *ptr = path.str; - U8 *opl = path.str + path.size; - for (;ptr < opl;){ - // skip past slashes - for (;ptr < opl && (*ptr == '/' || *ptr == '\\'); ptr += 1); - - // save beginning of non-slash range - U8 *range_first = ptr; - - // skip past non-slashes - for (;ptr < opl && !(*ptr == '/' || *ptr == '\\'); ptr += 1); - - // if range is non-empty advance the node cursor - if (range_first < ptr){ - String8 sub_dir = str8_range(range_first, ptr); - node_cursor = cons__paths_sub_path(bctx, node_cursor, sub_dir); - } - } - - CONS__PathNode *result = node_cursor; - return(result); -} - -static U32 -cons__paths_idx_from_path(CONS__BakeCtx *bctx, String8 path){ - CONS__PathNode *node = cons__paths_node_from_path(bctx, path); - U32 result = node->idx; - return(result); -} - -static CONS__SrcNode* -cons__paths_new_src_node(CONS__BakeCtx *bctx){ - CONS__PathTree *tree = bctx->tree; - CONS__SrcNode *result = push_array(bctx->arena, CONS__SrcNode, 1); - SLLQueuePush(tree->src_first, tree->src_last, result); - result->idx = tree->src_count; - tree->src_count += 1; - return(result); -} - -static CONS__SrcNode* -cons__paths_src_node_from_path_node(CONS__BakeCtx *bctx, CONS__PathNode *path_node){ - CONS__SrcNode *result = path_node->src_file; - if (result == 0){ - CONS__SrcNode *new_node = cons__paths_new_src_node(bctx); - new_node->path_node = path_node; - new_node->normal_full_path = cons__normal_string_from_path_node(bctx->arena, path_node); - result = path_node->src_file = new_node; - } - return(result); -} - - -//- cons path helper - -static String8 -cons__normal_string_from_path_node(Arena *arena, CONS__PathNode *node){ - Temp scratch = scratch_begin(&arena, 1); - String8List list = {0}; - if (node != 0){ - cons__normal_string_from_path_node_build(scratch.arena, node, &list); - } - StringJoin join = {0}; - join.sep = str8_lit("/"); - String8 result = str8_list_join(arena, &list, &join); - { - U8 *ptr = result.str; - U8 *opl = result.str + result.size; - for (; ptr < opl; ptr += 1){ - U8 c = *ptr; - if ('A' <= c && c <= 'Z') c += 'a' - 'A'; - *ptr = c; - } - } - scratch_end(scratch); - return(result); -} - -static void -cons__normal_string_from_path_node_build(Arena *arena, CONS__PathNode *node, String8List *out){ - if (node->parent != 0){ - cons__normal_string_from_path_node_build(arena, node->parent, out); - } - if (node->name.size > 0){ - str8_list_push(arena, out, node->name); - } -} - - -//- cons sort helper - -static CONS__SortKey* -cons__sort_key_array(Arena *arena, CONS__SortKey *keys, U64 count){ - // This sort is designed to take advantage of lots of pre-existing sorted ranges. - // Most line info is already sorted or close to already sorted. - // Similarly most vmap data has lots of pre-sorted ranges. etc. etc. - // Also - this sort should be a "stable" sort. In the use case of sorting vmap - // ranges, we want to be able to rely on order, so it needs to be preserved here. - - ProfBegin("cons__sort_key_array"); - Temp scratch = scratch_begin(&arena, 1); - - CONS__SortKey *result = 0; - - if (count <= 1){ - result = keys; - } - else{ - CONS__OrderedRange *ranges_first = 0; - CONS__OrderedRange *ranges_last = 0; - U64 range_count = 0; - { - U64 pos = 0; - for (;pos < count;){ - // identify ordered range - U64 first = pos; - U64 opl = pos + 1; - for (; opl < count && keys[opl - 1].key <= keys[opl].key; opl += 1); - - // generate an ordered range node - CONS__OrderedRange *new_range = push_array(scratch.arena, CONS__OrderedRange, 1); - SLLQueuePush(ranges_first, ranges_last, new_range); - range_count += 1; - new_range->first = first; - new_range->opl = opl; - - // update pos - pos = opl; - } - } - - if (range_count == 1){ - result = keys; - } - else{ - CONS__SortKey *keys_swap = push_array_no_zero(arena, CONS__SortKey, count); - - CONS__SortKey *src = keys; - CONS__SortKey *dst = keys_swap; - - CONS__OrderedRange *src_ranges = ranges_first; - CONS__OrderedRange *dst_ranges = 0; - CONS__OrderedRange *dst_ranges_last = 0; - - for (;;){ - // begin a pass - for (;;){ - // end pass when out of ranges - if (src_ranges == 0){ - break; - } - - // get first range - CONS__OrderedRange *range1 = src_ranges; - SLLStackPop(src_ranges); - - // if this range is the whole array, we are done - if (range1->first == 0 && range1->opl == count){ - result = src; - goto sort_done; - } - - // if there is not a second range, save this range for next time and end this pass - if (src_ranges == 0){ - U64 first = range1->first; - MemoryCopy(dst + first, src + first, sizeof(*src)*(range1->opl - first)); - SLLQueuePush(dst_ranges, dst_ranges_last, range1); - break; - } - - // get second range - CONS__OrderedRange *range2 = src_ranges; - SLLStackPop(src_ranges); - - Assert(range1->opl == range2->first); - - // merge these ranges - U64 jd = range1->first; - U64 j1 = range1->first; - U64 j1_opl = range1->opl; - U64 j2 = range2->first; - U64 j2_opl = range2->opl; - for (;;){ - if (src[j1].key <= src[j2].key){ - MemoryCopy(dst + jd, src + j1, sizeof(*src)); - j1 += 1; - jd += 1; - if (j1 >= j1_opl){ - break; - } - } - else{ - MemoryCopy(dst + jd, src + j2, sizeof(*src)); - j2 += 1; - jd += 1; - if (j2 >= j2_opl){ - break; - } - } - } - if (j1 < j1_opl){ - MemoryCopy(dst + jd, src + j1, sizeof(*src)*(j1_opl - j1)); - } - else{ - MemoryCopy(dst + jd, src + j2, sizeof(*src)*(j2_opl - j2)); - } - - // save this as one range - range1->opl = range2->opl; - SLLQueuePush(dst_ranges, dst_ranges_last, range1); - } - - // end pass by swapping buffers and range nodes - Swap(CONS__SortKey*, src, dst); - src_ranges = dst_ranges; - dst_ranges = 0; - dst_ranges_last = 0; - } - } - } - sort_done:; - -#if 0 - // assert sortedness - for (U64 i = 1; i < count; i += 1){ - Assert(result[i - 1].key <= result[i].key); - } -#endif - - scratch_end(scratch); - ProfEnd(); - - return(result); -} - - -//- cons intermediate unit line info -static CONS__UnitLinesCombined* -cons__unit_combine_lines(Arena *arena, CONS__BakeCtx *bctx, CONS_LineSequenceNode *first_seq){ - ProfBegin("cons__unit_combine_lines"); - Temp scratch = scratch_begin(&arena, 1); - - // gather up all line info into two arrays - // keys: sortable array; pairs voffs with line info records; null records are sequence enders - // recs: contains all the source coordinates for a range of voffs - U64 line_count = 0; - U64 seq_count = 0; - for (CONS_LineSequenceNode *node = first_seq; - node != 0; - node = node->next){ - seq_count += 1; - line_count += node->line_seq.line_count; - } - - U64 key_count = line_count + seq_count; - CONS__SortKey *line_keys = push_array_no_zero(scratch.arena, CONS__SortKey, key_count); - CONS__LineRec *line_recs = push_array_no_zero(scratch.arena, CONS__LineRec, line_count); - - { - CONS__SortKey *key_ptr = line_keys; - CONS__LineRec *rec_ptr = line_recs; - - for (CONS_LineSequenceNode *node = first_seq; - node != 0; - node = node->next){ - CONS__PathNode *src_path = - cons__paths_node_from_path(bctx, node->line_seq.file_name); - CONS__SrcNode *src_file = cons__paths_src_node_from_path_node(bctx, src_path); - U32 file_id = src_file->idx; - - U64 node_line_count = node->line_seq.line_count; - for (U64 i = 0; i < node_line_count; i += 1){ - key_ptr->key = node->line_seq.voffs[i]; - key_ptr->val = rec_ptr; - key_ptr += 1; - - rec_ptr->file_id = file_id; - rec_ptr->line_num = node->line_seq.line_nums[i]; - if (node->line_seq.col_nums != 0){ - rec_ptr->col_first = node->line_seq.col_nums[i*2]; - rec_ptr->col_opl = node->line_seq.col_nums[i*2 + 1]; - } - rec_ptr += 1; - } - - key_ptr->key = node->line_seq.voffs[node_line_count]; - key_ptr->val = 0; - key_ptr += 1; - - CONS__LineMapFragment *fragment = push_array(arena, CONS__LineMapFragment, 1); - SLLQueuePush(src_file->first_fragment, src_file->last_fragment, fragment); - fragment->sequence = node; - } - } - - // sort - CONS__SortKey *sorted_line_keys = cons__sort_key_array(scratch.arena, line_keys, key_count); - - // TODO(allen): do a pass over sorted keys to make sure duplicate keys are sorted with - // null record first, and no more than one null record and one non-null record - - // arrange output - U64 *arranged_voffs = push_array_no_zero(arena, U64, key_count + 1); - RADDBG_Line *arranged_lines = push_array_no_zero(arena, RADDBG_Line, key_count); - - for (U64 i = 0; i < key_count; i += 1){ - arranged_voffs[i] = sorted_line_keys[i].key; - } - arranged_voffs[key_count] = ~0ull; - for (U64 i = 0; i < key_count; i += 1){ - CONS__LineRec *rec = (CONS__LineRec*)sorted_line_keys[i].val; - if (rec != 0){ - arranged_lines[i].file_idx = rec->file_id; - arranged_lines[i].line_num = rec->line_num; - } - else{ - arranged_lines[i].file_idx = 0; - arranged_lines[i].line_num = 0; - } - } - - CONS__UnitLinesCombined *result = push_array(arena, CONS__UnitLinesCombined, 1); - result->voffs = arranged_voffs; - result->lines = arranged_lines; - result->cols = 0; - result->line_count = key_count; - - scratch_end(scratch); - ProfEnd(); - - return(result); -} - - -//- cons intermediate source line info -static CONS__SrcLinesCombined* -cons__source_combine_lines(Arena *arena, CONS__LineMapFragment *first){ - ProfBegin("cons__source_combine_lines"); - Temp scratch = scratch_begin(&arena, 1); - - // gather line number map - CONS__SrcLineMapBucket *first_bucket = 0; - CONS__SrcLineMapBucket *last_bucket = 0; - - U64 line_count = 0; - U64 voff_count = 0; - U64 max_line_num = 0; - for (CONS__LineMapFragment *map_fragment = first; - map_fragment != 0; - map_fragment = map_fragment->next){ - CONS_LineSequence *sequence = &map_fragment->sequence->line_seq; - - U64 *seq_voffs = sequence->voffs; - U32 *seq_line_nums = sequence->line_nums; - U64 seq_line_count = sequence->line_count; - for (U64 i = 0; i < seq_line_count; i += 1){ - U32 line_num = seq_line_nums[i]; - U64 voff = seq_voffs[i]; - - // update unique voff counter & max line number - voff_count += 1; - max_line_num = Max(max_line_num, line_num); - - // find match - CONS__SrcLineMapBucket *match = 0; - for (CONS__SrcLineMapBucket *node = first_bucket; - node != 0; - node = node->next){ - if (node->line_num == line_num){ - match = node; - break; - } - } - - // introduce new line if no match - if (match == 0){ - match = push_array(scratch.arena, CONS__SrcLineMapBucket, 1); - SLLQueuePush(first_bucket, last_bucket, match); - match->line_num = line_num; - line_count += 1; - } - - // insert new voff - { - CONS__SrcLineMapVoffBlock *block = push_array(scratch.arena, CONS__SrcLineMapVoffBlock, 1); - SLLQueuePush(match->first_voff_block, match->last_voff_block, block); - match->voff_count += 1; - block->voff = voff; - } - } - } - - // bake sortable keys array - CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, line_count); - { - CONS__SortKey *key_ptr = keys; - for (CONS__SrcLineMapBucket *node = first_bucket; - node != 0; - node = node->next, key_ptr += 1){ - key_ptr->key = node->line_num; - key_ptr->val = node; - } - } - - // sort - CONS__SortKey *sorted_keys = cons__sort_key_array(scratch.arena, keys, line_count); - - // bake result - U32 *line_nums = push_array_no_zero(arena, U32, line_count); - U32 *line_ranges = push_array_no_zero(arena, U32, line_count + 1); - U64 *voffs = push_array_no_zero(arena, U64, voff_count); - - { - U64 *voff_ptr = voffs; - for (U32 i = 0; i < line_count; i += 1){ - line_nums[i] = sorted_keys[i].key; - line_ranges[i] = (U32)(voff_ptr - voffs); - CONS__SrcLineMapBucket *bucket = (CONS__SrcLineMapBucket*)sorted_keys[i].val; - for (CONS__SrcLineMapVoffBlock *node = bucket->first_voff_block; - node != 0; - node = node->next){ - *voff_ptr = node->voff; - voff_ptr += 1; - } - } - line_ranges[line_count] = voff_count; - } - - CONS__SrcLinesCombined *result = push_array(arena, CONS__SrcLinesCombined, 1); - result->line_nums = line_nums; - result->line_ranges = line_ranges; - result->line_count = line_count; - result->voffs = voffs; - result->voff_count = voff_count; - - scratch_end(scratch); - ProfEnd(); - - return(result); -} - - -//- cons intermediate vmap type -static CONS__VMap* -cons__vmap_from_markers(Arena *arena, CONS__VMapMarker *markers, CONS__SortKey *keys, U64 marker_count){ - Temp scratch = scratch_begin(&arena, 1); - - // sort markers - CONS__SortKey *sorted_keys = cons__sort_key_array(scratch.arena, keys, marker_count); - - // determine if an extra vmap entry for zero is needed - U32 extra_vmap_entry = 0; - if (marker_count > 0 && sorted_keys[0].key != 0){ - extra_vmap_entry = 1; - } - - // fill output vmap entries - U32 vmap_count_raw = marker_count - 1 + extra_vmap_entry; - RADDBG_VMapEntry *vmap = push_array_no_zero(arena, RADDBG_VMapEntry, vmap_count_raw + 1); - U32 vmap_entry_count_pass_1 = 0; - - { - RADDBG_VMapEntry *vmap_ptr = vmap; - - if (extra_vmap_entry){ - vmap_ptr->voff = 0; - vmap_ptr->idx = 0; - vmap_ptr += 1; - } - - CONS__VMapRangeTracker *tracker_stack = 0; - CONS__VMapRangeTracker *tracker_free = 0; - - CONS__SortKey *key_ptr = sorted_keys; - CONS__SortKey *key_opl = sorted_keys + marker_count; - for (;key_ptr < key_opl;){ - // get initial map state from tracker stack - U32 initial_idx = max_U32; - if (tracker_stack != 0){ - initial_idx = tracker_stack->idx; - } - - // update tracker stack - // * we must process _all_ of the changes that apply at this voff before moving on - U64 voff = key_ptr->key; - - for (;key_ptr < key_opl && key_ptr->key == voff; key_ptr += 1){ - CONS__VMapMarker *marker = (CONS__VMapMarker*)key_ptr->val; - U32 idx = marker->idx; - - // push to stack - if (marker->begin_range){ - CONS__VMapRangeTracker *new_tracker = tracker_free; - if (new_tracker != 0){ - SLLStackPop(tracker_free); - } - else{ - new_tracker = push_array(scratch.arena, CONS__VMapRangeTracker, 1); - } - SLLStackPush(tracker_stack, new_tracker); - new_tracker->idx = idx; - } - - // pop matching node from stack (not always the top) - else{ - CONS__VMapRangeTracker **ptr_in = &tracker_stack; - CONS__VMapRangeTracker *match = 0; - for (CONS__VMapRangeTracker *node = tracker_stack; - node != 0;){ - if (node->idx == idx){ - match = node; - break; - } - ptr_in = &node->next; - node = node->next; - } - if (match != 0){ - *ptr_in = match->next; - SLLStackPush(tracker_free, match); - } - } - } - - // get final map state from tracker stack - U32 final_idx = 0; - if (tracker_stack != 0){ - final_idx = tracker_stack->idx; - } - - // if final is different from initial - emit new vmap entry - if (final_idx != initial_idx){ - vmap_ptr->voff = voff; - vmap_ptr->idx = final_idx; - vmap_ptr += 1; - } - } - - vmap_entry_count_pass_1 = (U32)(vmap_ptr - vmap); - } - - // replace zero unit indexes that follow a non-zero - // TODO(rjf): 0 *is* a real unit index right now - if(0) - { - // (the last entry is not replaced because it acts as a terminator) - U32 last = vmap_entry_count_pass_1 - 1; - - RADDBG_VMapEntry *vmap_ptr = vmap; - U64 real_idx = 0; - - for (U32 i = 0; i < last; i += 1, vmap_ptr += 1){ - // is this a zero after a real index? - if (vmap_ptr->idx == 0){ - vmap_ptr->idx = real_idx; - } - - // remember a real index - else{ - real_idx = vmap_ptr->idx; - } - } - } - - // combine duplicate neighbors - U32 vmap_entry_count = 0; - { - RADDBG_VMapEntry *vmap_ptr = vmap; - RADDBG_VMapEntry *vmap_opl = vmap + vmap_entry_count_pass_1; - RADDBG_VMapEntry *vmap_out = vmap; - - for (;vmap_ptr < vmap_opl;){ - RADDBG_VMapEntry *vmap_range_first = vmap_ptr; - U64 idx = vmap_ptr->idx; - vmap_ptr += 1; - for (;vmap_ptr < vmap_opl && vmap_ptr->idx == idx;) vmap_ptr += 1; - MemoryCopyStruct(vmap_out, vmap_range_first); - vmap_out += 1; - } - - vmap_entry_count = (U32)(vmap_out - vmap); - } - - // fill result - CONS__VMap *result = push_array(arena, CONS__VMap, 1); - result->vmap = vmap; - result->count = vmap_entry_count - 1; - - scratch_end(scratch); - - return(result); -} - - -//- cons intermediate unit vmap -static CONS__VMap* -cons__vmap_from_unit_ranges(Arena *arena, CONS_UnitVMapRange *first, U64 count){ - Temp scratch = scratch_begin(&arena, 1); - - // count necessary markers - U64 marker_count = count*2; - - // fill markers - CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); - CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); - - { - CONS__SortKey *key_ptr = keys; - CONS__VMapMarker *marker_ptr = markers; - for (CONS_UnitVMapRange *range = first; - range != 0; - range = range->next){ - if (range->first < range->opl){ - U32 unit_idx = range->unit->idx; - - key_ptr->key = range->first; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = range->opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = unit_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - } - - // construct vmap - CONS__VMap *result = cons__vmap_from_markers(arena, markers, keys, marker_count); - - scratch_end(scratch); - - return(result); -} - -//- cons intermediate types -static CONS__TypeData* -cons__type_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx){ - ProfBegin("cons__type_data_combine"); - Temp scratch = scratch_begin(&arena, 1); - - // fill type nodes - U32 type_count = root->type_count; - RADDBG_TypeNode *type_nodes = push_array_no_zero(arena, RADDBG_TypeNode, type_count); - - { - RADDBG_TypeNode *ptr = type_nodes; - RADDBG_TypeNode *opl = ptr + type_count; - CONS_Type *loose_type = root->first_type; - for (;loose_type != 0 && ptr < opl; - loose_type = loose_type->next_order, ptr += 1){ - - RADDBG_TypeKind kind = loose_type->kind; - - // shared - ptr->kind = kind; - ptr->flags = loose_type->flags; - ptr->byte_size = loose_type->byte_size; - - // built-in - if (RADDBG_TypeKind_FirstBuiltIn <= kind && kind <= RADDBG_TypeKind_LastBuiltIn){ - ptr->built_in.name_string_idx = cons__string(bctx, loose_type->name); - } - - // constructed - else if (RADDBG_TypeKind_FirstConstructed <= kind && kind <= RADDBG_TypeKind_LastConstructed){ - ptr->constructed.direct_type_idx = loose_type->direct_type->idx; - - switch (kind){ - case RADDBG_TypeKind_Array: - { - ptr->constructed.count = loose_type->count; - }break; - - case RADDBG_TypeKind_Function: - { - // parameters - U32 count = loose_type->count; - U32 *idx_run = cons__idx_run_from_types(scratch.arena, loose_type->param_types, count); - ptr->constructed.param_idx_run_first = cons__idx_run(bctx, idx_run, count); - ptr->constructed.count = count; - }break; - - case RADDBG_TypeKind_Method: - { - // parameters - U32 count = loose_type->count; - U32 *idx_run = cons__idx_run_from_types(scratch.arena, loose_type->param_types, count); - ptr->constructed.param_idx_run_first = cons__idx_run(bctx, idx_run, count); - ptr->constructed.count = count; - }break; - } - } - - // user-defined - else if (RADDBG_TypeKind_FirstUserDefined <= kind && kind <= RADDBG_TypeKind_LastUserDefined){ - ptr->user_defined.name_string_idx = cons__string(bctx, loose_type->name); - if (loose_type->udt != 0){ - ptr->user_defined.udt_idx = loose_type->udt->idx; - } - if (loose_type->direct_type != 0){ - ptr->user_defined.direct_type_idx = loose_type->direct_type->idx; - } - } - - // bitfield - else if (kind == RADDBG_TypeKind_Bitfield){ - ptr->bitfield.off = loose_type->off; - ptr->bitfield.size = loose_type->count; - } - - temp_end(scratch); - } - - // both iterators should end at the same time - Assert(loose_type == 0); - Assert(ptr == opl); - } - - - // fill udts - U32 udt_count = root->type_udt_count; - RADDBG_UDT *udts = push_array_no_zero(arena, RADDBG_UDT, udt_count); - - U32 member_count = root->total_member_count; - RADDBG_Member *members = push_array_no_zero(arena, RADDBG_Member, member_count); - - U32 enum_member_count = root->total_enum_val_count; - RADDBG_EnumMember *enum_members = push_array_no_zero(arena, RADDBG_EnumMember, enum_member_count); - - { - RADDBG_UDT *ptr = udts; - RADDBG_UDT *opl = ptr + udt_count; - - RADDBG_Member *member_ptr = members; - RADDBG_Member *member_opl = members + member_count; - - RADDBG_EnumMember *enum_member_ptr = enum_members; - RADDBG_EnumMember *enum_member_opl = enum_members + enum_member_count; - - CONS_TypeUDT *loose_udt = root->first_udt; - for (;loose_udt != 0 && ptr < opl; - loose_udt = loose_udt->next_order, ptr += 1){ - ptr->self_type_idx = loose_udt->self_type->idx; - - Assert(loose_udt->member_count == 0 || - loose_udt->enum_val_count == 0); - - // enum members - if (loose_udt->enum_val_count != 0){ - ptr->flags |= RADDBG_UserDefinedTypeFlag_EnumMembers; - - ptr->member_first = (U32)(enum_member_ptr - enum_members); - ptr->member_count = loose_udt->enum_val_count; - - U32 local_enum_val_count = loose_udt->enum_val_count; - CONS_TypeEnumVal *loose_enum_val = loose_udt->first_enum_val; - for (U32 i = 0; - i < local_enum_val_count; - i += 1, enum_member_ptr += 1, loose_enum_val = loose_enum_val->next){ - enum_member_ptr->name_string_idx = cons__string(bctx, loose_enum_val->name); - enum_member_ptr->val = loose_enum_val->val; - } - } - - // struct/class/union members - else{ - ptr->member_first = (U32)(member_ptr - members); - ptr->member_count = loose_udt->member_count; - - U32 local_member_count = loose_udt->member_count; - CONS_TypeMember *loose_member = loose_udt->first_member; - for (U32 i = 0; - i < local_member_count; - i += 1, member_ptr += 1, loose_member = loose_member->next){ - member_ptr->kind = loose_member->kind; - // TODO(allen): member_ptr->visibility = ; - member_ptr->name_string_idx = cons__string(bctx, loose_member->name); - member_ptr->off = loose_member->off; - member_ptr->type_idx = loose_member->type->idx; - - // TODO(allen): - if (loose_member->kind == RADDBG_MemberKind_Method){ - //loose_member_ptr->unit_idx = ; - //loose_member_ptr->proc_symbol_idx = ; - } - } - - } - - U32 file_idx = 0; - if (loose_udt->source_path.size > 0){ - CONS__PathNode *path_node = cons__paths_node_from_path(bctx, loose_udt->source_path); - CONS__SrcNode *src_node = cons__paths_src_node_from_path_node(bctx, path_node); - file_idx = src_node->idx; - } - - ptr->file_idx = file_idx; - ptr->line = loose_udt->line; - ptr->col = loose_udt->col; - } - - // all iterators should end at the same time - Assert(loose_udt == 0); - Assert(ptr == opl); - Assert(member_ptr == member_opl); - Assert(enum_member_ptr == enum_member_opl); - } - - - // fill result - CONS__TypeData *result = push_array(arena, CONS__TypeData, 1); - result->type_nodes = type_nodes; - result->type_node_count = type_count; - result->udts = udts; - result->udt_count = udt_count; - result->members = members; - result->member_count = member_count; - result->enum_members = enum_members; - result->enum_member_count = enum_member_count; - - scratch_end(scratch); - ProfEnd(); - - return(result); -} - -static U32* -cons__idx_run_from_types(Arena *arena, CONS_Type **types, U32 count){ - U32 *result = push_array(arena, U32, count); - for (U32 i = 0; i < count; i += 1){ - result[i] = types[i]->idx; - } - return(result); -} - -//- cons serializer for symbols -static CONS__SymbolData* -cons__symbol_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx){ - ProfBegin("cons__symbol_data_combine"); - Temp scratch = scratch_begin(&arena, 1); - - // count symbol kinds - U32 globalvar_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_GlobalVariable]; - U32 threadvar_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_ThreadVariable]; - U32 procedure_count = 1 + root->symbol_kind_counts[CONS_SymbolKind_Procedure]; - - // allocate symbol arrays - RADDBG_GlobalVariable *global_variables = - push_array(arena, RADDBG_GlobalVariable, globalvar_count); - - RADDBG_ThreadVariable *thread_variables = - push_array(arena, RADDBG_ThreadVariable, threadvar_count); - - RADDBG_Procedure *procedures = push_array(arena, RADDBG_Procedure, procedure_count); - - // fill symbol arrays - { - RADDBG_GlobalVariable *global_ptr = global_variables; - RADDBG_ThreadVariable *thread_local_ptr = thread_variables; - RADDBG_Procedure *procedure_ptr = procedures; - - // nils - global_ptr += 1; - thread_local_ptr += 1; - procedure_ptr += 1; - - // symbol nodes - for (CONS_Symbol *node = root->first_symbol; - node != 0; - node = node->next_order){ - U32 name_string_idx = cons__string(bctx, node->name); - U32 link_name_string_idx = cons__string(bctx, node->link_name); - U32 type_idx = node->type->idx; - - RADDBG_LinkFlags link_flags = 0; - U32 container_idx = 0; - { - if (node->is_extern){ - link_flags |= RADDBG_LinkFlag_External; - } - if (node->container_symbol != 0){ - container_idx = node->container_symbol->idx; - link_flags |= RADDBG_LinkFlag_ProcScoped; - } - else if (node->container_type != 0 && node->container_type->udt != 0){ - container_idx = node->container_type->udt->idx; - link_flags |= RADDBG_LinkFlag_TypeScoped; - } - } - - switch (node->kind){ - default:{}break; - - case CONS_SymbolKind_GlobalVariable: - { - global_ptr->name_string_idx = name_string_idx; - global_ptr->link_flags = link_flags; - global_ptr->voff = node->offset; - global_ptr->type_idx = type_idx; - global_ptr->container_idx = container_idx; - global_ptr += 1; - }break; - - case CONS_SymbolKind_ThreadVariable: - { - thread_local_ptr->name_string_idx = name_string_idx; - thread_local_ptr->link_flags = link_flags; - thread_local_ptr->tls_off = (U32)node->offset; - thread_local_ptr->type_idx = type_idx; - thread_local_ptr->container_idx = container_idx; - thread_local_ptr += 1; - }break; - - case CONS_SymbolKind_Procedure: - { - procedure_ptr->name_string_idx = name_string_idx; - procedure_ptr->link_name_string_idx = link_name_string_idx; - procedure_ptr->link_flags = link_flags; - procedure_ptr->type_idx = type_idx; - procedure_ptr->root_scope_idx = node->root_scope->idx; - procedure_ptr->container_idx = container_idx; - procedure_ptr += 1; - }break; - } - } - - Assert(global_ptr - global_variables == globalvar_count); - Assert(thread_local_ptr - thread_variables == threadvar_count); - Assert(procedure_ptr - procedures == procedure_count); - } - - // global vmap - CONS__VMap *global_vmap = 0; - { - // count necessary markers - U32 marker_count = globalvar_count*2; - - // fill markers - CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); - CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); - - CONS__SortKey *key_ptr = keys; - CONS__VMapMarker *marker_ptr = markers; - - // real globals - for (CONS_Symbol *node = root->first_symbol; - node != 0; - node = node->next_order){ - if (node->kind == CONS_SymbolKind_GlobalVariable){ - U32 global_idx = node->idx; - - U64 first = node->offset; - U64 opl = first + node->type->byte_size; - - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - // nil global - { - U32 global_idx = 0; - - U64 first = 0; - U64 opl = max_U64; - - key_ptr->key = first; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = global_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - - // assert we filled all the markers - Assert(key_ptr - keys == marker_count && - marker_ptr - markers == marker_count); - - // construct vmap - global_vmap = cons__vmap_from_markers(arena, markers, keys, marker_count); - } - - // allocate scope array - - // (assert there is a nil scope) - Assert(root->first_scope != 0 && - root->first_scope->symbol == 0 && - root->first_scope->first_child == 0 && - root->first_scope->next_sibling == 0 && - root->first_scope->range_count == 0); - - U32 scope_count = root->scope_count; - RADDBG_Scope *scopes = push_array(arena, RADDBG_Scope, scope_count); - - U32 scope_voff_count = root->scope_voff_count; - U64 *scope_voffs = push_array(arena, U64, scope_voff_count); - - U32 local_count = root->local_count; - RADDBG_Local *locals = push_array(arena, RADDBG_Local, local_count); - - U32 location_block_count = root->location_count; - RADDBG_LocationBlock *location_blocks = - push_array(arena, RADDBG_LocationBlock, location_block_count); - - String8List location_data = {0}; - - // iterate scopes, locals, and locations - // fill scope voffs, locals, and location information - { - RADDBG_Scope *scope_ptr = scopes; - U64 *scope_voff_ptr = scope_voffs; - RADDBG_Local *local_ptr = locals; - RADDBG_LocationBlock *location_block_ptr = location_blocks; - - for (CONS_Scope *node = root->first_scope; - node != 0; - node = node->next_order, scope_ptr += 1){ - - // emit voffs - U32 voff_first = (U32)(scope_voff_ptr - scope_voffs); - for (CONS__VOffRange *range = node->first_range; - range != 0; - range = range->next){ - *scope_voff_ptr = range->voff_first; - scope_voff_ptr += 1; - *scope_voff_ptr = range->voff_opl; - scope_voff_ptr += 1; - } - U32 voff_opl = (U32)(scope_voff_ptr - scope_voffs); - - // emit locals - U32 scope_local_count = node->local_count; - U32 scope_local_first = (U32)(local_ptr - locals); - for (CONS_Local *slocal = node->first_local; - slocal != 0; - slocal = slocal->next, local_ptr += 1){ - local_ptr->kind = slocal->kind; - local_ptr->name_string_idx = cons__string(bctx, slocal->name); - local_ptr->type_idx = slocal->type->idx; - - CONS_LocationSet *locset = slocal->locset; - if (locset != 0){ - U32 location_first = (U32)(location_block_ptr - location_blocks); - U32 location_opl = location_first + locset->location_case_count; - local_ptr->location_first = location_first; - local_ptr->location_opl = location_opl; - - for (CONS__LocationCase *location_case = locset->first_location_case; - location_case != 0; - location_case = location_case->next){ - location_block_ptr->scope_off_first = location_case->voff_first; - location_block_ptr->scope_off_opl = location_case->voff_opl; - location_block_ptr->location_data_off = location_data.total_size; - location_block_ptr += 1; - - CONS_Location *location = location_case->location; - if (location == 0){ - U64 data = 0; - str8_serial_push_align(scratch.arena, &location_data, 8); - str8_serial_push_data(scratch.arena, &location_data, &data, 1); - } - else{ - switch (location->kind){ - default: - { - U64 data = 0; - str8_serial_push_align(scratch.arena, &location_data, 8); - str8_serial_push_data(scratch.arena, &location_data, &data, 1); - }break; - - case RADDBG_LocationKind_AddrBytecodeStream: - case RADDBG_LocationKind_ValBytecodeStream: - { - str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&location->kind))); - for (CONS_EvalBytecodeOp *op_node = location->bytecode.first_op; - op_node != 0; - op_node = op_node->next){ - U8 op_data[9]; - op_data[0] = op_node->op; - MemoryCopy(op_data + 1, &op_node->p, op_node->p_size); - String8 op_data_str = str8(op_data, 1 + op_node->p_size); - str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, op_data_str)); - } - { - U64 data = 0; - String8 data_str = str8((U8 *)&data, 1); - str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, data_str)); - } - }break; - - case RADDBG_LocationKind_AddrRegisterPlusU16: - case RADDBG_LocationKind_AddrAddrRegisterPlusU16: - { - RADDBG_LocationRegisterPlusU16 loc = {0}; - loc.kind = location->kind; - loc.register_code = location->register_code; - loc.offset = location->offset; - str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&loc))); - }break; - - case RADDBG_LocationKind_ValRegister: - { - RADDBG_LocationRegister loc = {0}; - loc.kind = location->kind; - loc.register_code = location->register_code; - str8_list_push(scratch.arena, &location_data, push_str8_copy(scratch.arena, str8_struct(&loc))); - }break; - } - } - } - - Assert(location_block_ptr - location_blocks == location_opl); - } - } - - Assert(local_ptr - locals == scope_local_first + scope_local_count); - - // emit scope - scope_ptr->proc_idx = (node->symbol == 0)?0:node->symbol->idx; - scope_ptr->parent_scope_idx = (node->parent_scope == 0)?0:node->parent_scope->idx; - scope_ptr->first_child_scope_idx = (node->first_child == 0)?0:node->first_child->idx; - scope_ptr->next_sibling_scope_idx = (node->next_sibling == 0)?0:node->next_sibling->idx; - scope_ptr->voff_range_first = voff_first; - scope_ptr->voff_range_opl = voff_opl; - scope_ptr->local_first = scope_local_first; - scope_ptr->local_count = scope_local_count; - - // TODO(allen): - //scope_ptr->static_local_idx_run_first = ; - //scope_ptr->static_local_count = ; - } - - Assert(scope_ptr - scopes == scope_count); - Assert(local_ptr - locals == local_count); - } - - // flatten location data - String8 location_data_str = str8_list_join(arena, &location_data, 0); - - // scope vmap - CONS__VMap *scope_vmap = 0; - { - // count necessary markers - U32 marker_count = scope_voff_count; - - // fill markers - CONS__SortKey *keys = push_array_no_zero(scratch.arena, CONS__SortKey, marker_count); - CONS__VMapMarker *markers = push_array_no_zero(scratch.arena, CONS__VMapMarker, marker_count); - - CONS__SortKey *key_ptr = keys; - CONS__VMapMarker *marker_ptr = markers; - - for (CONS_Scope *node = root->first_scope; - node != 0; - node = node->next_order){ - U32 scope_idx = node->idx; - - for (CONS__VOffRange *range = node->first_range; - range != 0; - range = range->next){ - key_ptr->key = range->voff_first; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 1; - key_ptr += 1; - marker_ptr += 1; - - key_ptr->key = range->voff_opl; - key_ptr->val = marker_ptr; - marker_ptr->idx = scope_idx; - marker_ptr->begin_range = 0; - key_ptr += 1; - marker_ptr += 1; - } - } - - scope_vmap = cons__vmap_from_markers(arena, markers, keys, marker_count); - } - - // fill result - CONS__SymbolData *result = push_array(arena, CONS__SymbolData, 1); - result->global_variables = global_variables; - result->global_variable_count = globalvar_count; - result->global_vmap = global_vmap; - result->thread_variables = thread_variables; - result->thread_variable_count = threadvar_count; - result->procedures = procedures; - result->procedure_count = procedure_count; - result->scopes = scopes; - result->scope_count = scope_count; - result->scope_voffs = scope_voffs; - result->scope_voff_count = scope_voff_count; - result->scope_vmap = scope_vmap; - result->locals = locals; - result->local_count = local_count; - result->location_blocks = location_blocks; - result->location_block_count = location_block_count; - result->location_data = location_data_str.str; - result->location_data_size = location_data_str.size; - - scratch_end(scratch); - ProfEnd(); - - return(result); -} - -//- cons serializer for name maps - -static CONS__NameMapBaked* -cons__name_map_bake(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx, CONS__NameMap *map){ - Temp scratch = scratch_begin(&arena, 1); - - U32 bucket_count = map->name_count; - U32 node_count = map->name_count; - - // setup the final bucket layouts - CONS__NameMapSemiBucket *sbuckets = push_array(scratch.arena, CONS__NameMapSemiBucket, bucket_count); - for (CONS__NameMapNode *node = map->first; - node != 0; - node = node->order_next){ - U64 hash = raddbg_hash(node->string.str, node->string.size); - U64 bi = hash%bucket_count; - CONS__NameMapSemiNode *snode = push_array(scratch.arena, CONS__NameMapSemiNode, 1); - SLLQueuePush(sbuckets[bi].first, sbuckets[bi].last, snode); - snode->node = node; - sbuckets[bi].count += 1; - } - - // allocate tables - RADDBG_NameMapBucket *buckets = push_array(arena, RADDBG_NameMapBucket, bucket_count); - RADDBG_NameMapNode *nodes = push_array_no_zero(arena, RADDBG_NameMapNode, node_count); - - // convert to serialized buckets & nodes - { - RADDBG_NameMapBucket *bucket_ptr = buckets; - RADDBG_NameMapNode *node_ptr = nodes; - for (U32 i = 0; i < bucket_count; i += 1, bucket_ptr += 1){ - bucket_ptr->first_node = (U32)(node_ptr - nodes); - bucket_ptr->node_count = sbuckets[i].count; - - for (CONS__NameMapSemiNode *snode = sbuckets[i].first; - snode != 0; - snode = snode->next){ - CONS__NameMapNode *node = snode->node; - - // cons name and index(es) - U32 string_idx = cons__string(bctx, node->string); - U32 match_count = node->idx_count; - U32 idx = 0; - if (match_count == 1){ - idx = node->idx_first->idx[0]; - } - else{ - Temp temp = temp_begin(scratch.arena); - U32 *idx_run = push_array_no_zero(temp.arena, U32, match_count); - U32 *idx_ptr = idx_run; - for (CONS__NameMapIdxNode *idxnode = node->idx_first; - idxnode != 0; - idxnode = idxnode->next){ - for (U32 i = 0; i < ArrayCount(idxnode->idx); i += 1){ - if (idxnode->idx[i] == 0){ - goto dblbreak; - } - *idx_ptr = idxnode->idx[i]; - idx_ptr += 1; - } - } - dblbreak:; - Assert(idx_ptr == idx_run + match_count); - idx = cons__idx_run(bctx, idx_run, match_count); - temp_end(temp); - } - - // write to node - node_ptr->string_idx = string_idx; - node_ptr->match_count = match_count; - node_ptr->match_idx_or_idx_run_first = idx; - node_ptr += 1; - } - } - Assert(node_ptr - nodes == node_count); - } - - scratch_end(scratch); - - CONS__NameMapBaked *result = push_array(arena, CONS__NameMapBaked, 1); - result->buckets = buckets; - result->nodes = nodes; - result->bucket_count = bucket_count; - result->node_count = node_count; - return(result); -} diff --git a/src/raddbg_cons/raddbg_cons.h b/src/raddbg_cons/raddbg_cons.h deleted file mode 100644 index 3fcbca6e..00000000 --- a/src/raddbg_cons/raddbg_cons.h +++ /dev/null @@ -1,896 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_CONS_H -#define RADDBG_CONS_H - -//////////////////////////////// -//- "Public Facing" Cons API - -// frequently used opaque types -typedef struct CONS_Root CONS_Root; -typedef struct CONS_Unit CONS_Unit; -typedef struct CONS_Type CONS_Type; -typedef struct CONS_Reservation CONS_Reservation; -typedef struct CONS_Symbol CONS_Symbol; -typedef struct CONS_Scope CONS_Scope; -typedef struct CONS_Local CONS_Local; -typedef struct CONS_LocationSet CONS_LocationSet; -typedef struct CONS_Location CONS_Location; - -typedef struct CONS_TypeNode{ - struct CONS_TypeNode *next; - CONS_Type *type; -} CONS_TypeNode; - -typedef struct CONS_TypeList{ - CONS_TypeNode *first; - CONS_TypeNode *last; - U64 count; -} CONS_TypeList; - -typedef struct CONS_EvalBytecodeOp{ - struct CONS_EvalBytecodeOp *next; - RADDBG_EvalOp op; - U32 p_size; - U64 p; -} CONS_EvalBytecodeOp; - -typedef struct CONS_EvalBytecode{ - CONS_EvalBytecodeOp *first_op; - CONS_EvalBytecodeOp *last_op; - U32 op_count; - U32 encoded_size; -} CONS_EvalBytecode; - -//- init - -typedef struct CONS_RootParams{ - // important to set this correctly so pointer - // types get the correct sizes - U64 addr_size; - - // options to optimize map bucket counts - // * if these are left as zeros a modest default is used instead - U32 bucket_count_units; - U32 bucket_count_symbols; - U32 bucket_count_scopes; - U32 bucket_count_locals; - U32 bucket_count_types; -} CONS_RootParams; - -static CONS_Root* cons_root_new(CONS_RootParams *params); -static void cons_root_release(CONS_Root *root); - - -//- baking -static void cons_bake_file(Arena *arena, CONS_Root *root, String8List *out); - - -//- errors -typedef struct CONS_Error{ - struct CONS_Error *next; - String8 msg; -} CONS_Error; - -static void cons_errorf(CONS_Root *root, char *fmt, ...); - -static CONS_Error* cons_get_first_error(CONS_Root *root); - - - -//- information declaration - -// top level info -typedef struct CONS_TopLevelInfo{ - RADDBG_Arch architecture; - String8 exe_name; - U64 exe_hash; - U64 voff_max; -} CONS_TopLevelInfo; - -static void cons_set_top_level_info(CONS_Root *root, CONS_TopLevelInfo *tli); - - -// binary sections -static void cons_add_binary_section(CONS_Root *root, - String8 name, RADDBG_BinarySectionFlags flags, - U64 voff_first, U64 voff_opl, U64 foff_first, - U64 foff_opl); - - -// units -static CONS_Unit* cons_unit_handle_from_user_id(CONS_Root *root, U64 unit_user_id); - -typedef struct CONS_UnitInfo{ - String8 unit_name; - String8 compiler_name; - String8 source_file; - String8 object_file; - String8 archive_file; - String8 build_path; - RADDBG_Language language; -} CONS_UnitInfo; - -static void cons_unit_set_info(CONS_Root *root, CONS_Unit *unit, CONS_UnitInfo *info); - -typedef struct CONS_LineSequence{ - String8 file_name; - U64 *voffs; // [line_count + 1] (sorted) - U32 *line_nums; // [line_count] - U16 *col_nums; // [2*line_count] - U64 line_count; -} CONS_LineSequence; - -static void cons_unit_add_line_sequence(CONS_Root *root, CONS_Unit *unit, - CONS_LineSequence *line_sequence); - -static void cons_unit_vmap_add_range(CONS_Root *root, CONS_Unit *unit, U64 first, U64 opl); - - -// types -static CONS_Type* cons_type_from_id(CONS_Root *root, U64 type_user_id); -static CONS_Reservation* cons_type_reserve_id(CONS_Root *root, U64 type_user_id); -static void cons_type_fill_id(CONS_Root *root, CONS_Reservation *res, CONS_Type *type); - -static B32 cons_type_is_unhandled_nil(CONS_Root *root, CONS_Type *type); - -static CONS_Type* cons_type_handled_nil(CONS_Root *root); -static CONS_Type* cons_type_nil(CONS_Root *root); -static CONS_Type* cons_type_variadic(CONS_Root *root); - -static CONS_Type* cons_type_basic(CONS_Root *root, RADDBG_TypeKind type_kind, String8 name); -static CONS_Type* cons_type_modifier(CONS_Root *root, - CONS_Type *direct_type, RADDBG_TypeModifierFlags flags); -static CONS_Type* cons_type_bitfield(CONS_Root *root, - CONS_Type *direct_type, U32 bit_off, U32 bit_count); -static CONS_Type* cons_type_pointer(CONS_Root *root, - CONS_Type *direct_type, RADDBG_TypeKind ptr_type_kind); -static CONS_Type* cons_type_array(CONS_Root *root, - CONS_Type *direct_type, U64 count); -static CONS_Type* cons_type_proc(CONS_Root *root, - CONS_Type *return_type, struct CONS_TypeList *params); -static CONS_Type* cons_type_method(CONS_Root *root, - CONS_Type *this_type, CONS_Type *return_type, - struct CONS_TypeList *params); - -static CONS_Type* cons_type_udt(CONS_Root *root, - RADDBG_TypeKind record_type_kind, String8 name, U64 size); -static CONS_Type* cons_type_enum(CONS_Root *root, - CONS_Type *direct_type, String8 name); -static CONS_Type* cons_type_alias(CONS_Root *root, - CONS_Type *direct_type, String8 name); -static CONS_Type* cons_type_incomplete(CONS_Root *root, - RADDBG_TypeKind type_kind, String8 name); - -static void cons_type_add_member_data_field(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type, U32 off); -static void cons_type_add_member_static_data(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type); -static void cons_type_add_member_method(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type); -static void cons_type_add_member_static_method(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type); -static void cons_type_add_member_virtual_method(CONS_Root *root, CONS_Type *record_type, - String8 name, CONS_Type *mem_type); -static void cons_type_add_member_base(CONS_Root *root, CONS_Type *record_type, - CONS_Type *base_type, U32 off); -static void cons_type_add_member_virtual_base(CONS_Root *root, CONS_Type *record_type, - CONS_Type *base_type, U32 vptr_off, U32 vtable_off); -static void cons_type_add_member_nested_type(CONS_Root *root, CONS_Type *record_type, - CONS_Type *nested_type); - -static void cons_type_add_enum_val(CONS_Root *root, CONS_Type *enum_type, String8 name, U64 val); - -static void cons_type_set_source_coordinates(CONS_Root *root, CONS_Type *defined_type, - String8 source_path, U32 line, U32 col); - -// type list -static void cons_type_list_push(Arena *arena, CONS_TypeList *list, CONS_Type *type); - -// symbols -static CONS_Symbol* cons_symbol_handle_from_user_id(CONS_Root *root, U64 symbol_user_id); - -typedef enum{ - CONS_SymbolKind_NULL, - CONS_SymbolKind_GlobalVariable, - CONS_SymbolKind_ThreadVariable, - CONS_SymbolKind_Procedure, - CONS_SymbolKind_COUNT -} CONS_SymbolKind; - -typedef struct CONS_SymbolInfo{ - CONS_SymbolKind kind; - String8 name; - String8 link_name; - CONS_Type *type; - B32 is_extern; - U64 offset; - // TODO(allen): should this actually be "container scope"? - CONS_Symbol *container_symbol; - CONS_Type *container_type; - CONS_Scope *root_scope; -} CONS_SymbolInfo; - -static void cons_symbol_set_info(CONS_Root *root, CONS_Symbol *symbol, CONS_SymbolInfo *info); - -// scopes -static CONS_Scope *cons_scope_handle_from_user_id(CONS_Root *root, U64 scope_user_id); - -static void cons_scope_set_parent(CONS_Root *root, CONS_Scope *scope, CONS_Scope *parent); -static void cons_scope_add_voff_range(CONS_Root *root, CONS_Scope *scope, U64 voff_first, U64 voff_opl); - -// locals -static CONS_Local* cons_local_handle_from_user_id(CONS_Root *root, U64 local_user_id); - -typedef struct CONS_LocalInfo{ - RADDBG_LocalKind kind; - CONS_Scope *scope; - String8 name; - CONS_Type *type; -} CONS_LocalInfo; - -static void cons_local_set_basic_info(CONS_Root *root, CONS_Local *local, - CONS_LocalInfo *info); - -static CONS_LocationSet* cons_location_set_from_local(CONS_Root *root, CONS_Local *local); - -// locations -static void cons_location_set_add_case(CONS_Root *root, CONS_LocationSet *locset, - U64 voff_min, U64 voff_max, - CONS_Location *location); - -static CONS_Location* cons_location_addr_bytecode_stream(CONS_Root *root, - struct CONS_EvalBytecode *bytecode); -static CONS_Location* cons_location_val_bytecode_stream(CONS_Root *root, - struct CONS_EvalBytecode *bytecode); -static CONS_Location* cons_location_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset); -static CONS_Location* cons_location_addr_addr_reg_plus_u16(CONS_Root *root, U8 reg_code, U16 offset); -static CONS_Location* cons_location_val_reg(CONS_Root *root, U8 reg_code); - -// bytecode -static void cons_bytecode_push_op(Arena *arena, CONS_EvalBytecode *bytecode, RADDBG_EvalOp op, U64 p); -static void cons_bytecode_push_uconst(Arena *arena, CONS_EvalBytecode *bytecode, U64 x); -static void cons_bytecode_push_sconst(Arena *arena, CONS_EvalBytecode *bytecode, S64 x); -static void cons_bytecode_concat_in_place(CONS_EvalBytecode *left_dst, - CONS_EvalBytecode *right_destroyed); - -//////////////////////////////// -//- Concrete Types & Implementation Helpers - -// NOTE: the user should generally treat these as opaque - -// errors -typedef struct CONS_ErrorList{ - CONS_Error *first; - CONS_Error *last; - U64 count; -} CONS_ErrorList; - - -// binary sections -typedef struct CONS_BinarySection{ - struct CONS_BinarySection *next; - String8 name; - RADDBG_BinarySectionFlags flags; - U64 voff_first; - U64 voff_opl; - U64 foff_first; - U64 foff_opl; -} CONS_BinarySection; - - -// units -typedef struct CONS_LineSequenceNode{ - struct CONS_LineSequenceNode *next; - CONS_LineSequence line_seq; -} CONS_LineSequenceNode; - -typedef struct CONS_Unit{ - struct CONS_Unit *next_order; - - U32 idx; - - B32 info_is_set; - String8 unit_name; - String8 compiler_name; - String8 source_file; - String8 object_file; - String8 archive_file; - String8 build_path; - RADDBG_Language language; - - CONS_LineSequenceNode *line_seq_first; - CONS_LineSequenceNode *line_seq_last; - U64 line_seq_count; - -} CONS_Unit; - -typedef struct CONS_UnitVMapRange{ - struct CONS_UnitVMapRange *next; - CONS_Unit *unit; - U64 first; - U64 opl; -} CONS_UnitVMapRange; - - -// types -typedef struct CONS_Type{ - struct CONS_Type *next_order; - - RADDBG_TypeKind kind; - U32 idx; - U32 byte_size; - U32 flags; - U32 off; - U32 count; - - String8 name; - - struct CONS_Type *direct_type; - struct CONS_Type **param_types; - - struct CONS_TypeUDT *udt; -} CONS_Type; - -typedef struct CONS_TypeMember{ - struct CONS_TypeMember *next; - - RADDBG_MemberKind kind; - String8 name; - CONS_Type *type; - U32 off; -} CONS_TypeMember; - -typedef struct CONS_TypeEnumVal{ - struct CONS_TypeEnumVal *next; - - String8 name; - U64 val; -} CONS_TypeEnumVal; - -typedef struct CONS_TypeUDT{ - struct CONS_TypeUDT *next_order; - - U32 idx; - struct CONS_Type *self_type; - - CONS_TypeMember *first_member; - CONS_TypeMember *last_member; - U64 member_count; - - CONS_TypeEnumVal *first_enum_val; - CONS_TypeEnumVal *last_enum_val; - U64 enum_val_count; - - String8 source_path; - U32 line; - U32 col; -} CONS_TypeUDT; - -typedef U8 CONS_TypeConstructKind; -enum{ - CONS_TypeConstructKind_Basic, - CONS_TypeConstructKind_Modifier, - CONS_TypeConstructKind_Bitfield, - CONS_TypeConstructKind_Pointer, - CONS_TypeConstructKind_Array, - CONS_TypeConstructKind_Procedure, - CONS_TypeConstructKind_Method, -}; - -static CONS_Type* cons__type_new(CONS_Root *root); -static CONS_TypeUDT* cons__type_udt_from_any_type(CONS_Root *root, CONS_Type *type); -static CONS_TypeUDT* cons__type_udt_from_record_type(CONS_Root *root, CONS_Type *type); - - -// symbols -typedef struct CONS_Symbol{ - struct CONS_Symbol *next_order; - - U32 idx; - - CONS_SymbolKind kind; - String8 name; - String8 link_name; - CONS_Type *type; - B32 is_extern; - B8 offset_is_set; - U64 offset; - - CONS_Symbol *container_symbol; - CONS_Type *container_type; - - CONS_Scope *root_scope; -} CONS_Symbol; - - -// scopes -typedef struct CONS_Local{ - struct CONS_Local *next; - RADDBG_LocalKind kind; - String8 name; - CONS_Type *type; - CONS_LocationSet *locset; -} CONS_Local; - -typedef struct CONS__VOffRange{ - struct CONS__VOffRange *next; - U64 voff_first; - U64 voff_opl; -} CONS__VOffRange; - -typedef struct CONS_Scope{ - struct CONS_Scope *next_order; - - CONS_Symbol *symbol; - CONS_Scope *parent_scope; - CONS_Scope *first_child; - CONS_Scope *last_child; - CONS_Scope *next_sibling; - - U64 voff_base; - CONS__VOffRange *first_range; - CONS__VOffRange *last_range; - U32 range_count; - - U32 idx; - - CONS_Local *first_local; - CONS_Local *last_local; - U32 local_count; - -} CONS_Scope; - -static void cons__scope_recursive_set_symbol(CONS_Scope *scope, CONS_Symbol *symbol); - - -// locations -typedef struct CONS_Location{ - RADDBG_LocationKind kind; - U8 register_code; - U16 offset; - CONS_EvalBytecode bytecode; -} CONS_Location; - -typedef struct CONS__LocationCase{ - struct CONS__LocationCase *next; - U64 voff_first; - U64 voff_opl; - CONS_Location *location; -} CONS__LocationCase; - -typedef struct CONS_LocationSet{ - CONS__LocationCase *first_location_case; - CONS__LocationCase *last_location_case; - U64 location_case_count; -} CONS_LocationSet; - - -// name maps -typedef struct CONS__NameMapIdxNode{ - struct CONS__NameMapIdxNode *next; - U32 idx[8]; -} CONS__NameMapIdxNode; - -typedef struct CONS__NameMapNode{ - struct CONS__NameMapNode *bucket_next; - struct CONS__NameMapNode *order_next; - String8 string; - CONS__NameMapIdxNode *idx_first; - CONS__NameMapIdxNode *idx_last; - U64 idx_count; -} CONS__NameMapNode; - -typedef struct CONS__NameMap{ - CONS__NameMapNode *buckets[1<<24]; - CONS__NameMapNode *first; - CONS__NameMapNode *last; - U64 name_count; -} CONS__NameMap; - -static CONS__NameMap* cons__name_map_for_kind(CONS_Root *root, RADDBG_NameMapKind kind); -static void cons__name_map_add_pair(CONS_Root *root, CONS__NameMap *map, - String8 name, U32 idx); - - -// u64 to ptr map -typedef struct CONS__U64ToPtrNode{ - struct CONS__U64ToPtrNode *next; - U64 key[3]; - void *ptr[3]; -} CONS__U64ToPtrNode; - -typedef struct CONS__U64ToPtrMap{ - CONS__U64ToPtrNode **buckets; - U64 bucket_count; -} CONS__U64ToPtrMap; - -typedef struct CONS__U64ToPtrLookup{ - void *match; - CONS__U64ToPtrNode *fill_node; - U32 fill_k; -} CONS__U64ToPtrLookup; - -static void cons__u64toptr_init(Arena *arena, CONS__U64ToPtrMap *map, U64 bucket_count); - -static void cons__u64toptr_lookup(CONS__U64ToPtrMap *map, U64 key, CONS__U64ToPtrLookup *lookup_out); -static void cons__u64toptr_insert(Arena *arena, CONS__U64ToPtrMap *map, U64 key, - CONS__U64ToPtrLookup *lookup, void *ptr); - - - -// str8 to ptr map -typedef struct CONS__Str8ToPtrNode{ - struct CONS__Str8ToPtrNode *next; - String8 key; - U64 hash; - void *ptr; -} CONS__Str8ToPtrNode; - -typedef struct CONS__Str8ToPtrMap{ - CONS__Str8ToPtrNode *buckets[1<<24]; -} CONS__Str8ToPtrMap; - -static void*cons__str8toptr_lookup(CONS__Str8ToPtrMap *map, String8 key, U64 hash); -static void cons__str8toptr_insert(Arena *arena, CONS__Str8ToPtrMap *map, - String8 key, U64 hash, void *ptr); - -// root -struct CONS_Root{ - Arena *arena; - CONS_ErrorList errors; - - //////// Contextual Information - - U64 addr_size; - - //////// Info Declared By User - - // top level info - B32 top_level_info_is_set; - CONS_TopLevelInfo top_level_info; - - // binary layout - CONS_BinarySection *binary_section_first; - CONS_BinarySection *binary_section_last; - U64 binary_section_count; - - // compilation units - CONS_Unit *unit_first; - CONS_Unit *unit_last; - U64 unit_count; - - CONS_UnitVMapRange *unit_vmap_range_first; - CONS_UnitVMapRange *unit_vmap_range_last; - U64 unit_vmap_range_count; - - // types - CONS_Type *first_type; - CONS_Type *last_type; - U64 type_count; - - CONS_Type *nil_type; - CONS_Type *variadic_type; - - CONS_Type handled_nil_type; - - CONS_TypeUDT *first_udt; - CONS_TypeUDT *last_udt; - U64 type_udt_count; - - U64 total_member_count; - U64 total_enum_val_count; - - // symbols - CONS_Symbol *first_symbol; - CONS_Symbol *last_symbol; - union{ - U64 symbol_count; - U64 symbol_kind_counts[CONS_SymbolKind_COUNT]; - }; - - CONS_Scope *first_scope; - CONS_Scope *last_scope; - U64 scope_count; - U64 scope_voff_count; - - CONS_Local *first_local; - CONS_Local *last_local; - U64 local_count; - U64 location_count; - - // name maps - CONS__NameMap *name_maps[RADDBG_NameMapKind_COUNT]; - - //////// Handle Relationship Maps - - CONS__U64ToPtrMap unit_map; - CONS__U64ToPtrMap symbol_map; - CONS__U64ToPtrMap scope_map; - CONS__U64ToPtrMap local_map; - CONS__U64ToPtrMap type_from_id_map; - CONS__Str8ToPtrMap construct_map; -}; - - -//- cons intermediate data sections -typedef struct CONS__DSectionNode{ - struct CONS__DSectionNode *next; - void *data; - U64 size; - RADDBG_DataSectionTag tag; -} CONS__DSectionNode; - -typedef struct CONS__DSections{ - CONS__DSectionNode *first; - CONS__DSectionNode *last; - U32 count; -} CONS__DSections; - -//- cons intermediate strings -typedef struct CONS__StringNode{ - struct CONS__StringNode *order_next; - struct CONS__StringNode *bucket_next; - String8 str; - U64 hash; - U32 idx; -} CONS__StringNode; - -typedef struct CONS__Strings{ - CONS__StringNode *order_first; - CONS__StringNode *order_last; - CONS__StringNode *buckets[1<<24]; - U32 count; -} CONS__Strings; - -//- cons intermediate index runs -typedef struct CONS__IdxRunNode{ - struct CONS__IdxRunNode *order_next; - struct CONS__IdxRunNode *bucket_next; - U32 *idx_run; - U64 hash; - U32 count; - U32 first_idx; -} CONS__IdxRunNode; - -typedef struct CONS__IdxRuns{ - CONS__IdxRunNode *order_first; - CONS__IdxRunNode *order_last; - CONS__IdxRunNode *buckets[1<<24]; - U32 count; - U32 idx_count; -} CONS__IdxRuns; - -//- cons intermediate file path tree -typedef struct CONS__PathNode{ - struct CONS__PathNode *next_order; - struct CONS__PathNode *parent; - struct CONS__PathNode *first_child; - struct CONS__PathNode *last_child; - struct CONS__PathNode *next_sibling; - String8 name; - struct CONS__SrcNode *src_file; - U32 idx; -} CONS__PathNode; - -typedef struct CONS__LineMapFragment{ - struct CONS__LineMapFragment *next; - CONS_LineSequenceNode *sequence; -} CONS__LineMapFragment; - -typedef struct CONS__SrcNode{ - struct CONS__SrcNode *next; - CONS__PathNode *path_node; - U32 idx; - - String8 normal_full_path; - - // place to gather the line info attached to this src file - CONS__LineMapFragment *first_fragment; - CONS__LineMapFragment *last_fragment; - - // place to put the final baked version of this file's line map - U32 line_map_nums_data_idx; - U32 line_map_range_data_idx; - U32 line_map_count; - U32 line_map_voff_data_idx; -} CONS__SrcNode; - -typedef struct CONS__PathTree{ - CONS__PathNode *first; - CONS__PathNode *last; - U32 count; - CONS__PathNode root; - CONS__SrcNode *src_first; - CONS__SrcNode *src_last; - U32 src_count; -} CONS__PathTree; - -typedef struct CONS__BakeCtx{ - Arena *arena; - CONS__Strings strs; - CONS__IdxRuns idxs; - CONS__PathTree *tree; -} CONS__BakeCtx; - -//- cons intermediate functions -static U32 cons__dsection(Arena *arena, CONS__DSections *dss, - void *data, U64 size, RADDBG_DataSectionTag tag); - -static CONS__BakeCtx* cons__bake_ctx_begin(void); -static void cons__bake_ctx_release(CONS__BakeCtx *bake_ctx); - -static U32 cons__string(CONS__BakeCtx *bctx, String8 str); - -static U64 cons__idx_run_hash(U32 *idx_run, U32 count); -static U32 cons__idx_run(CONS__BakeCtx *bctx, U32 *idx_run, U32 count); - -static CONS__PathNode* cons__paths_new_node(CONS__BakeCtx *bctx); -static CONS__PathNode* cons__paths_sub_path(CONS__BakeCtx *bctx, CONS__PathNode *dir, String8 sub_dir); -static CONS__PathNode* cons__paths_node_from_path(CONS__BakeCtx *bctx, String8 path); -static U32 cons__paths_idx_from_path(CONS__BakeCtx *bctx, String8 path); - -static CONS__SrcNode* cons__paths_new_src_node(CONS__BakeCtx *bctx); -static CONS__SrcNode* cons__paths_src_node_from_path_node(CONS__BakeCtx *bctx, CONS__PathNode *path); - -//- cons path helper -static String8 cons__normal_string_from_path_node(Arena *arena, CONS__PathNode *node); -static void cons__normal_string_from_path_node_build(Arena *arena, CONS__PathNode *node, - String8List *out); - - -//- cons sort helper -typedef struct CONS__SortKey{ - U64 key; - void *val; -} CONS__SortKey; - -typedef struct CONS__OrderedRange{ - struct CONS__OrderedRange *next; - U64 first; - U64 opl; -} CONS__OrderedRange; - -static CONS__SortKey* cons__sort_key_array(Arena *arena, CONS__SortKey *keys, U64 count); - - -//- cons serializer for unit line info -typedef struct CONS__LineRec{ - U32 file_id; - U32 line_num; - U16 col_first; - U16 col_opl; -} CONS__LineRec; - -typedef struct CONS__UnitLinesCombined{ - U64 *voffs; - RADDBG_Line *lines; - U16 *cols; - U32 line_count; -} CONS__UnitLinesCombined; - -static CONS__UnitLinesCombined* cons__unit_combine_lines(Arena *arena, CONS__BakeCtx *bctx, - CONS_LineSequenceNode *first); - -//- cons serializer for source line info -typedef struct CONS__SrcLinesCombined{ - U32 *line_nums; - U32 *line_ranges; - U64 *voffs; - U32 line_count; - U32 voff_count; -} CONS__SrcLinesCombined; - -typedef struct CONS__SrcLineMapVoffBlock{ - struct CONS__SrcLineMapVoffBlock *next; - U64 voff; -} CONS__SrcLineMapVoffBlock; - -typedef struct CONS__SrcLineMapBucket{ - struct CONS__SrcLineMapBucket *next; - U32 line_num; - CONS__SrcLineMapVoffBlock *first_voff_block; - CONS__SrcLineMapVoffBlock *last_voff_block; - U64 voff_count; -} CONS__SrcLineMapBucket; - -static CONS__SrcLinesCombined* cons__source_combine_lines(Arena *arena, CONS__LineMapFragment *first); - -//- cons serializer for vmap type -typedef struct CONS__VMap{ - RADDBG_VMapEntry *vmap; // [count + 1] - U32 count; -} CONS__VMap; - -typedef struct CONS__VMapMarker{ - U32 idx; - U32 begin_range; -} CONS__VMapMarker; - -typedef struct CONS__VMapRangeTracker{ - struct CONS__VMapRangeTracker *next; - U32 idx; -} CONS__VMapRangeTracker; - -static CONS__VMap* cons__vmap_from_markers(Arena *arena, CONS__VMapMarker *markers, CONS__SortKey *keys, - U64 marker_count); - -//- cons serializer for unit vmap -static CONS__VMap* cons__vmap_from_unit_ranges(Arena *arena, CONS_UnitVMapRange *first, U64 count); - -//- cons serializer for types -typedef struct CONS__TypeData{ - RADDBG_TypeNode *type_nodes; - U32 type_node_count; - - RADDBG_UDT *udts; - U32 udt_count; - - RADDBG_Member *members; - U32 member_count; - - RADDBG_EnumMember *enum_members; - U32 enum_member_count; -} CONS__TypeData; - -static CONS__TypeData* cons__type_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx); - -static U32* cons__idx_run_from_types(Arena *arena, CONS_Type **types, U32 count); - -//- cons serializer for symbols -typedef struct CONS__SymbolData{ - RADDBG_GlobalVariable *global_variables; - U32 global_variable_count; - - CONS__VMap *global_vmap; - - RADDBG_ThreadVariable *thread_variables; - U32 thread_variable_count; - - RADDBG_Procedure *procedures; - U32 procedure_count; - - RADDBG_Scope *scopes; - U32 scope_count; - - U64 *scope_voffs; - U32 scope_voff_count; - - CONS__VMap *scope_vmap; - - RADDBG_Local *locals; - U32 local_count; - - RADDBG_LocationBlock *location_blocks; - U32 location_block_count; - - void *location_data; - U32 location_data_size; - -} CONS__SymbolData; - -static CONS__SymbolData* cons__symbol_data_combine(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx); - -//- cons serializer for name maps -typedef struct CONS__NameMapSemiNode{ - struct CONS__NameMapSemiNode *next; - CONS__NameMapNode *node; -} CONS__NameMapSemiNode; - -typedef struct CONS__NameMapSemiBucket{ - CONS__NameMapSemiNode *first; - CONS__NameMapSemiNode *last; - U64 count; -} CONS__NameMapSemiBucket; - -typedef struct CONS__NameMapBaked{ - RADDBG_NameMapBucket *buckets; - RADDBG_NameMapNode *nodes; - U32 bucket_count; - U32 node_count; -} CONS__NameMapBaked; - -static CONS__NameMapBaked* cons__name_map_bake(Arena *arena, CONS_Root *root, CONS__BakeCtx *bctx, CONS__NameMap *map); - -#endif //RADDBG_CONS_H diff --git a/src/raddbg_convert/pdb/raddbg_codeview_conversion.c b/src/raddbg_convert/pdb/raddbg_codeview_conversion.c deleted file mode 100644 index 9930b4ed..00000000 --- a/src/raddbg_convert/pdb/raddbg_codeview_conversion.c +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ CodeView Conversion Functions - -static RADDBG_Arch -raddbg_arch_from_cv_arch(CV_Arch cv_arch){ - RADDBG_Arch result = 0; - switch (cv_arch){ - case CV_Arch_8086: result = RADDBG_Arch_X86; break; - case CV_Arch_X64: result = RADDBG_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); -} - -static RADDBG_RegisterCode -raddbg_reg_code_from_cv_reg_code(RADDBG_Arch arch, CV_Reg reg_code){ - RADDBG_RegisterCode result = 0; - switch (arch){ - case RADDBG_Arch_X86: - { - switch (reg_code){ -#define X(CVN,C,RDN,BP,BZ) case C: result = RADDBG_RegisterCode_X86_##RDN; break; - CV_Reg_X86_XList(X) -#undef X - } - }break; - - case RADDBG_Arch_X64: - { - switch (reg_code){ -#define X(CVN,C,RDN,BP,BZ) case C: result = RADDBG_RegisterCode_X64_##RDN; break; - CV_Reg_X64_XList(X) -#undef X - } - }break; - } - return(result); -} - -static RADDBG_Language -raddbg_language_from_cv_language(CV_Language cv_language){ - RADDBG_Language result = 0; - switch (cv_language){ - case CV_Language_C: result = RADDBG_Language_C; break; - case CV_Language_CXX: result = RADDBG_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); -} diff --git a/src/raddbg_convert/pdb/raddbg_codeview_conversion.h b/src/raddbg_convert/pdb/raddbg_codeview_conversion.h deleted file mode 100644 index 369e0949..00000000 --- a/src/raddbg_convert/pdb/raddbg_codeview_conversion.h +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_CODEVIEW_CONVERSION_H -#define RADDBG_CODEVIEW_CONVERSION_H - -//////////////////////////////// -//~ CodeView Conversion Functions - -static RADDBG_Arch raddbg_arch_from_cv_arch(CV_Arch arch); -static RADDBG_RegisterCode raddbg_reg_code_from_cv_reg_code(RADDBG_Arch arch, CV_Reg reg_code); -static RADDBG_Language raddbg_language_from_cv_language(CV_Language language); - -#endif //RADDBG_CODEVIEW_CONVERSION_H diff --git a/src/raddbg_convert/pdb/raddbg_codeview_stringize.h b/src/raddbg_convert/pdb/raddbg_codeview_stringize.h deleted file mode 100644 index 6b59ec1f..00000000 --- a/src/raddbg_convert/pdb/raddbg_codeview_stringize.h +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_CODEVIEW_STRINGIZE_H -#define RADDBG_CODEVIEW_STRINGIZE_H - -//////////////////////////////// -//~ CodeView Stringize Helper Types - -typedef struct CV_StringizeSymParams{ - CV_Arch arch; -} CV_StringizeSymParams; - -typedef struct CV_StringizeLeafParams{ - U32 dummy; -} CV_StringizeLeafParams; - -//////////////////////////////// -//~ CodeView Common Stringize Functions - -static void cv_stringize_numeric(Arena *arena, String8List *out, CV_NumericParsed *num); - -static void cv_stringize_lvar_addr_range(Arena *arena, String8List *out, - CV_LvarAddrRange *range); -static void cv_stringize_lvar_addr_gap(Arena *arena, String8List *out, CV_LvarAddrGap *gap); -static void cv_stringize_lvar_addr_gap_list(Arena *arena, String8List *out, - void *first, void *opl); - -static String8 cv_string_from_sym_kind(CV_SymKind kind); -static String8 cv_string_from_basic_type(CV_BasicType basic_type); -static String8 cv_string_from_leaf_kind(CV_LeafKind kind); -static String8 cv_string_from_numeric_kind(CV_NumericKind kind); -static String8 cv_string_from_c13_sub_section_kind(CV_C13_SubSectionKind kind); -static String8 cv_string_from_machine(CV_Arch arch); -static String8 cv_string_from_reg(CV_Arch arch, CV_Reg reg); -static String8 cv_string_from_pointer_kind(CV_PointerKind ptr_kind); -static String8 cv_string_from_pointer_mode(CV_PointerMode ptr_mode); -static String8 cv_string_from_hfa_kind(CV_HFAKind hfa_kind); -static String8 cv_string_from_mo_com_udt_kind(CV_MoComUDTKind mo_com_udt_kind); - -//////////////////////////////// -//~ CodeView Flags Stringize Functions - -static void cv_stringize_modifier_flags(Arena *arena, String8List *out, - U32 indent, CV_ModifierFlags flags); - -static void cv_stringize_type_props(Arena *arena, String8List *out, - U32 indent, CV_TypeProps props); - -static void cv_stringize_pointer_attribs(Arena *arena, String8List *out, - U32 indent, CV_PointerAttribs attribs); - -static void cv_stringize_local_flags(Arena *arena, String8List *out, - U32 indent, CV_LocalFlags flags); - -//////////////////////////////// -//~ CodeView Sym Stringize Functions - -static void cv_stringize_sym_parsed(Arena *arena, String8List *out, CV_SymParsed *sym); - -static void cv_stringize_sym_range(Arena *arena, String8List *out, - CV_RecRange *range, String8 data, - CV_StringizeSymParams *p); -static void cv_stringize_sym_array(Arena *arena, String8List *out, - CV_RecRangeArray *ranges, String8 data, - CV_StringizeSymParams *p); - -//////////////////////////////// -//~ CodeView Leaf Stringize Functions - -static void cv_stringize_leaf_parsed(Arena *arena, String8List *out, CV_LeafParsed *leaf); - -static void cv_stringize_leaf_range(Arena *arena, String8List *out, - CV_RecRange *range, CV_TypeId itype, String8 data, - CV_StringizeLeafParams *p); -static void cv_stringize_leaf_array(Arena *arena, String8List *out, - CV_RecRangeArray *ranges, CV_TypeId itype_first, - String8 data, - CV_StringizeLeafParams *p); - -//////////////////////////////// -//~ CodeView C13 Stringize Functions - -static void cv_stringize_c13_parsed(Arena *arena, String8List *out, CV_C13Parsed *c13); - -#endif //RADDBG_CODEVIEW_STRINGIZE_H diff --git a/src/raddbg_convert/pdb/raddbg_coff.h b/src/raddbg_convert/pdb/raddbg_coff.h deleted file mode 100644 index 6078654e..00000000 --- a/src/raddbg_convert/pdb/raddbg_coff.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_COFF_H -#define RADDBG_COFF_H - -//////////////////////////////// -//~ COFF Format Types - -typedef struct COFF_Guid{ - U32 data1; - U16 data2; - U16 data3; - U32 data4; - U32 data5; -} COFF_Guid; - -#define COFF_ArchXList(X)\ -X(UNKNOWN, 0x0)\ -X(X86, 0x14c)\ -X(X64, 0x8664)\ -X(ARM33, 0x1d3)\ -X(ARM, 0x1c0)\ -X(ARM64, 0xaa64)\ -X(ARMNT, 0x1c4)\ -X(EBC, 0xebc)\ -X(IA64, 0x200)\ -X(M32R, 0x9041)\ -X(MIPS16, 0x266)\ -X(MIPSFPU, 0x366)\ -X(MIPSFPU16, 0x466)\ -X(POWERPC, 0x1f0)\ -X(POWERPCFP, 0x1f1)\ -X(R4000, 0x166)\ -X(RISCV32, 0x5032)\ -X(RISCV64, 0x5064)\ -X(RISCV128, 0x5128)\ -X(SH3, 0x1a2)\ -X(SH3DSP, 0x1a3)\ -X(SH4, 0x1a6)\ -X(SH5, 0x1a8)\ -X(THUMB, 0x1c2)\ -X(WCEMIPSV2, 0x169) - -typedef U16 COFF_Arch; -enum{ -#define X(N,c) COFF_Arch_##N = c, - COFF_ArchXList(X) -#undef X -}; - -#endif //COFF_H diff --git a/src/raddbg_convert/pdb/raddbg_coff_conversion.c b/src/raddbg_convert/pdb/raddbg_coff_conversion.c deleted file mode 100644 index f5c25c8b..00000000 --- a/src/raddbg_convert/pdb/raddbg_coff_conversion.c +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ COFF Conversion Functions - -static RADDBG_BinarySectionFlags -raddbg_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags){ - RADDBG_BinarySectionFlags result = 0; - - if (flags & COFF_SectionFlag_MEM_READ){ - result |= RADDBG_BinarySectionFlag_Read; - } - if (flags & COFF_SectionFlag_MEM_WRITE){ - result |= RADDBG_BinarySectionFlag_Write; - } - if (flags & COFF_SectionFlag_MEM_EXECUTE){ - result |= RADDBG_BinarySectionFlag_Execute; - } - - return(result); -} diff --git a/src/raddbg_convert/pdb/raddbg_coff_conversion.h b/src/raddbg_convert/pdb/raddbg_coff_conversion.h deleted file mode 100644 index 3036768c..00000000 --- a/src/raddbg_convert/pdb/raddbg_coff_conversion.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_COFF_CONVERSION_H -#define RADDBG_COFF_CONVERSION_H - -//////////////////////////////// -//~ COFF Conversion Functions - -static RADDBG_BinarySectionFlags -raddbg_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); - -#endif //RADDBG_COFF_CONVERSION_H diff --git a/src/raddbg_convert/pdb/raddbg_from_pdb.c b/src/raddbg_convert/pdb/raddbg_from_pdb.c deleted file mode 100644 index 01963467..00000000 --- a/src/raddbg_convert/pdb/raddbg_from_pdb.c +++ /dev/null @@ -1,3481 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ Program Parameters Parser - -static PDBCONV_Params* -pdb_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline){ - PDBCONV_Params *result = push_array(arena, PDBCONV_Params, 1); - - // get input pdb - { - String8 input_name = cmd_line_string(cmdline, str8_lit("pdb")); - if (input_name.size == 0){ - str8_list_push(arena, &result->errors, - str8_lit("missing required parameter '--pdb:'")); - } - - 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_pdb_name = input_name; - result->input_pdb_data = input_data; - } - } - } - - // get input exe - { - String8 input_name = cmd_line_string(cmdline, str8_lit("exe")); - 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_exe_name = input_name; - result->input_exe_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; - } - else if (str8_match(node->string, str8_lit("output"), 0)){ - result->hide_errors.output = 1; - } - else if (str8_match(node->string, str8_lit("parsing"), 0)){ - result->hide_errors.parsing = 1; - } - else if (str8_match(node->string, str8_lit("converting"), 0)){ - result->hide_errors.converting = 1; - } - } - - } - - // 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("coff_sections"), 0)){ - result->dump_coff_sections = 1; - } - else if (str8_match(node->string, str8_lit("msf"), 0)){ - result->dump_msf = 1; - } - else if (str8_match(node->string, str8_lit("sym"), 0)){ - result->dump_sym = 1; - } - else if (str8_match(node->string, str8_lit("tpi_hash"), 0)){ - result->dump_tpi_hash = 1; - } - else if (str8_match(node->string, str8_lit("leaf"), 0)){ - result->dump_leaf = 1; - } - else if (str8_match(node->string, str8_lit("c13"), 0)){ - result->dump_c13 = 1; - } - else if (str8_match(node->string, str8_lit("contributions"), 0)){ - result->dump_contributions = 1; - } - } - } - } - - return(result); -} - -//////////////////////////////// -//~ PDB Type & Symbol Info Translation Helpers - -//- pdb types and symbols - -static void -pdbconv_types_and_symbols(PDBCONV_TypesSymbolsParams *params, CONS_Root *out_root){ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - // setup a pdb conversion context - PDBCONV_Ctx *pdb_ctx = push_array(scratch.arena, PDBCONV_Ctx, 1); - pdb_ctx->arch = params->architecture; - // TODO(allen): actually infer addr_size from arch - pdb_ctx->addr_size = 8; - pdb_ctx->hash = params->tpi_hash; - pdb_ctx->leaf = params->tpi_leaf; - pdb_ctx->sections = params->sections->sections; - pdb_ctx->section_count = params->sections->count; - pdb_ctx->root = out_root; - pdb_ctx->temp_arena = arena_alloc(); - - // convert types - pdbconv_type_cons_main_passes(pdb_ctx); - if (params->sym != 0){ - pdbconv_gather_link_names(pdb_ctx, params->sym); - pdbconv_symbol_cons(pdb_ctx, params->sym, 0); - } - U64 unit_count = params->unit_count; - for (U64 i = 0; i < unit_count; i += 1){ - CV_SymParsed *unit_sym = params->sym_for_unit[i]; - pdbconv_symbol_cons(pdb_ctx, unit_sym, 1 + i); - } - - scratch_end(scratch); - ProfEnd(); -} - -//- decoding helpers - -static U32 -pdbconv_u32_from_numeric(PDBCONV_Ctx *ctx, CV_NumericParsed *num){ - U64 n_u64 = cv_u64_from_numeric(num); - U32 n_u32 = (U32)n_u64; - if (n_u64 > 0xFFFFFFFF){ - cons_errorf(ctx->root, "constant too large"); - n_u32 = 0; - } - return(n_u32); -} - -static COFF_SectionHeader* -pdbconv_sec_header_from_sec_num(PDBCONV_Ctx *ctx, U32 sec_num){ - COFF_SectionHeader *result = 0; - if (0 < sec_num && sec_num <= ctx->section_count){ - result = ctx->sections + sec_num - 1; - } - return(result); -} - -//- type info - -static void -pdbconv_type_cons_main_passes(PDBCONV_Ctx *ctx){ - ProfBeginFunction(); - CV_TypeId itype_first = ctx->leaf->itype_first; - CV_TypeId itype_opl = ctx->leaf->itype_opl; - - // setup variadic itype -> node - ProfScope("setup variadic itype -> node") - { - CONS_Type *variadic_type = cons_type_variadic(ctx->root); - CONS_Reservation *res = cons_type_reserve_id(ctx->root, CV_TypeId_Variadic); - cons_type_fill_id(ctx->root, res, variadic_type); - } - - // resolve forward references - ProfScope("resolve forward references") - { - for (CV_TypeId itype = itype_first; itype < itype_opl; itype += 1){ - pdbconv_type_resolve_fwd(ctx, itype); - } - } - - // construct type info - ProfScope("construct type info") - { - for (CV_TypeId itype = itype_first; itype < itype_opl; itype += 1){ - pdbconv_type_resolve_itype(ctx, itype); - } - } - - // construct member info - ProfScope("construct member info") - { - for (PDBCONV_TypeRev *rev = ctx->member_revisit_first; - rev != 0; - rev = rev->next){ - pdbconv_type_equip_members(ctx, rev->owner_type, rev->field_itype); - } - } - - // construct enum info - ProfScope("construct enum info") - { - for (PDBCONV_TypeRev *rev = ctx->enum_revisit_first; - rev != 0; - rev = rev->next){ - pdbconv_type_equip_enumerates(ctx, rev->owner_type, rev->field_itype); - } - } - - // TODO(allen): equip udts with location information - ProfEnd(); -} - -static CV_TypeId -pdbconv_type_resolve_fwd(PDBCONV_Ctx *ctx, CV_TypeId itype){ - Assert(ctx->leaf->itype_first <= itype && itype < ctx->leaf->itype_opl); - - CV_TypeId result = 0; - - CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[itype - ctx->leaf->itype_first]; - String8 data = ctx->leaf->data; - if (range->off + range->hdr.size <= data.size){ - U8 *first = data.str + range->off + 2; - U64 cap = range->hdr.size - 2; - - // figure out if this itype resolves to another - switch (range->hdr.kind){ - default:break; - - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - // TODO(allen): error if bad range - if (sizeof(CV_LeafStruct) <= cap){ - CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; - - // size - U8 *numeric_ptr = (U8*)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - // unique name - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, first + cap); - - if (lf_struct->props & CV_TypeProp_FwdRef){ - B32 do_unique_name_lookup = ((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0); - if (do_unique_name_lookup){ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, unique_name, 1); - } - else{ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); - } - } - } - }break; - - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - // TODO(allen): error if bad range - if (sizeof(CV_LeafStruct2) <= cap){ - CV_LeafStruct2 *lf_struct = (CV_LeafStruct2*)first; - - // size - U8 *numeric_ptr = (U8*)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - - // name - U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - // unique name - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, first + cap); - - if (lf_struct->props & CV_TypeProp_FwdRef){ - B32 do_unique_name_lookup = ((lf_struct->props & CV_TypeProp_Scoped) != 0) && - ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0); - if (do_unique_name_lookup){ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, unique_name, 1); - } - else{ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); - } - } - } - }break; - - case CV_LeafKind_UNION: - { - // TODO(allen): error if bad range - if (sizeof(CV_LeafUnion) <= cap){ - CV_LeafUnion *lf_union = (CV_LeafUnion*)first; - - // size - U8 *numeric_ptr = (U8*)(lf_union + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - // unique name - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, first + cap); - - if (lf_union->props & CV_TypeProp_FwdRef){ - B32 do_unique_name_lookup = ((lf_union->props & CV_TypeProp_Scoped) != 0) && - ((lf_union->props & CV_TypeProp_HasUniqueName) != 0); - if (do_unique_name_lookup){ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, unique_name, 1); - } - else{ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); - } - } - } - }break; - - case CV_LeafKind_ENUM: - { - // TODO(allen): error if bad range - if (sizeof(CV_LeafEnum) <= cap){ - CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; - - // name - U8 *name_ptr = (U8*)(lf_enum + 1); - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - // unique name - U8 *unique_name_ptr = name_ptr + name.size + 1; - String8 unique_name = str8_cstring_capped((char*)unique_name_ptr, first + cap); - - if (lf_enum->props & CV_TypeProp_FwdRef){ - B32 do_unique_name_lookup = ((lf_enum->props & CV_TypeProp_Scoped) != 0) && - ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0); - if (do_unique_name_lookup){ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, unique_name, 1); - } - else{ - result = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); - } - } - } - }break; - } - } - - // save in map - if (result != 0){ - pdbconv_type_fwd_map_set(ctx->temp_arena, &ctx->fwd_map, itype, result); - } - - return(result); -} - -static CONS_Type* -pdbconv_type_resolve_itype(PDBCONV_Ctx *ctx, CV_TypeId itype){ - ProfBeginFunction(); - - // convert fwd references to real types - CV_TypeId resolved_itype = pdbconv_type_fwd_map_get(&ctx->fwd_map, itype); - if (resolved_itype != 0){ - itype = resolved_itype; - } - - // type handle from id - CONS_Type *result = cons_type_from_id(ctx->root, itype); - - // basic type - if (result == 0){ - if (itype < 0x1000){ - result = pdbconv_type_cons_basic(ctx, itype); - } - } - - // leaf decode - if (result == 0){ - if (ctx->leaf->itype_first <= itype && itype < ctx->leaf->itype_opl){ - result = pdbconv_type_cons_leaf_record(ctx, itype); - } - } - - // never return null, return "nil" instead - if (result == 0){ - result = cons_type_nil(ctx->root); - } - - ProfEnd(); - return(result); -} - -static void -pdbconv_type_equip_members(PDBCONV_Ctx *ctx, CONS_Type *owner_type, CV_TypeId field_itype){ - Temp scratch = scratch_begin(0, 0); - - String8 data = ctx->leaf->data; - - // field stack - // TODO(allen): add notes about field tasks - struct FieldTask{ - struct FieldTask *next; - CV_TypeId itype; - }; - struct FieldTask *handled = 0; - struct FieldTask *todo = 0; - { - struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); - SLLStackPush(todo, task); - task->itype = field_itype; - } - - for (;;){ - // exit condition - if (todo == 0){ - break; - } - - // determine itype - CV_TypeId field_itype = todo->itype; - { - struct FieldTask *task = todo; - SLLStackPop(todo); - SLLStackPush(handled, task); - } - - // get leaf range - // TODO(allen): error if this itype is bad - U8 *first = 0; - U64 cap = 0; - if (ctx->leaf->itype_first <= field_itype && field_itype < ctx->leaf->itype_opl){ - CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[field_itype - ctx->leaf->itype_first]; - // check valid arglist - if (range->hdr.kind == CV_LeafKind_FIELDLIST && - range->off + range->hdr.size <= data.size){ - first = data.str + range->off + 2; - cap = range->hdr.size - 2; - } - } - - U64 cursor = 0; - for (;cursor + sizeof(CV_LeafKind) <= cap;){ - CV_LeafKind field_kind = *(CV_LeafKind*)(first + cursor); - - U64 list_item_off = cursor + 2; - // if we hit an error or forget to set next cursor for a case - // default to exiting the loop - U64 list_item_opl_off = cap; - - switch (field_kind){ - case CV_LeafKind_INDEX: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafIndex) <= cap){ - // compute whole layout - CV_LeafIndex *index = (CV_LeafIndex*)(first + list_item_off); - - list_item_opl_off = list_item_off + sizeof(*index); - - // create new todo task - CV_TypeId new_itype = index->itype; - B32 is_new = 1; - for (struct FieldTask *task = handled; - task != 0; - task = task->next){ - if (task->itype == new_itype){ - is_new = 0; - break; - } - } - if (is_new){ - struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); - SLLStackPush(todo, task); - task->itype = new_itype; - } - } - }break; - - case CV_LeafKind_MEMBER: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafMember) <= cap){ - // compute whole layout - CV_LeafMember *member = (CV_LeafMember*)(first + list_item_off); - - U64 offset_off = list_item_off + sizeof(*member); - CV_NumericParsed offset = cv_numeric_from_data_range(first + offset_off, first + cap); - - U64 name_off = offset_off + offset.encoded_size; - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // emit member - CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, member->itype); - U32 offset_u32 = pdbconv_u32_from_numeric(ctx, &offset); - cons_type_add_member_data_field(ctx->root, owner_type, name, mem_type, offset_u32); - } - }break; - - case CV_LeafKind_STMEMBER: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafStMember) <= cap){ - // compute whole layout - CV_LeafStMember *stmember = (CV_LeafStMember*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*stmember); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // TODO(allen): handle attribs - - // emit member - CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, stmember->itype); - cons_type_add_member_static_data(ctx->root, owner_type, name, mem_type); - } - }break; - - case CV_LeafKind_METHOD: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafMethod) <= cap){ - // compute whole layout - CV_LeafMethod *method = (CV_LeafMethod*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*method); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // extract method list - U8 *first = 0; - U64 cap = 0; - - // TODO(allen): error if bad itype - CV_TypeId methodlist_itype = method->list_itype; - if (ctx->leaf->itype_first <= methodlist_itype && - methodlist_itype < ctx->leaf->itype_opl){ - CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[methodlist_itype - ctx->leaf->itype_first]; - - // check valid methodlist - if (range->hdr.kind == CV_LeafKind_METHODLIST && - range->off + range->hdr.size <= data.size){ - first = data.str + range->off + 2; - cap = range->hdr.size - 2; - } - } - - // emit loop - U64 cursor = 0; - for (;cursor + sizeof(CV_LeafMethodListMember) <= cap;){ - CV_LeafMethodListMember *method = (CV_LeafMethodListMember*)(first + cursor); - - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(method->attribs); - - // 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. - - // extract vbaseoff - U64 next_cursor = cursor + sizeof(*method); - U32 vbaseoff = 0; - if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ - if (cursor + sizeof(*method) + 4 <= cap){ - vbaseoff = *(U32*)(method + 1); - } - next_cursor += 4; - } - - // update cursor - cursor = next_cursor; - - // TODO(allen): handle attribs - - // emit - CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, method->itype); - - switch (prop){ - default: - { - cons_type_add_member_method(ctx->root, owner_type, name, mem_type); - }break; - - case CV_MethodProp_Static: - { - cons_type_add_member_static_method(ctx->root, owner_type, name, mem_type); - }break; - - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - cons_type_add_member_virtual_method(ctx->root, owner_type, name, mem_type); - }break; - } - } - - } - }break; - - case CV_LeafKind_ONEMETHOD: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafOneMethod) <= cap){ - // compute whole layout - CV_LeafOneMethod *one_method = (CV_LeafOneMethod*)(first + list_item_off); - - CV_MethodProp prop = CV_FieldAttribs_ExtractMethodProp(one_method->attribs); - - U64 vbaseoff_off = list_item_off + sizeof(*one_method); - U64 vbaseoff_opl_off = vbaseoff_off; - U32 vbaseoff = 0; - if (prop == CV_MethodProp_Intro || prop == CV_MethodProp_PureIntro){ - vbaseoff = *(U32*)(first + vbaseoff_off); - vbaseoff_opl_off += sizeof(vbaseoff); - } - - U64 name_off = vbaseoff_opl_off; - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // TODO(allen): handle attribs - - // emit - CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, one_method->itype); - - switch (prop){ - default: - { - cons_type_add_member_method(ctx->root, owner_type, name, mem_type); - }break; - - case CV_MethodProp_Static: - { - cons_type_add_member_static_method(ctx->root, owner_type, name, mem_type); - }break; - - case CV_MethodProp_Virtual: - case CV_MethodProp_PureVirtual: - case CV_MethodProp_Intro: - case CV_MethodProp_PureIntro: - { - cons_type_add_member_virtual_method(ctx->root, owner_type, name, mem_type); - }break; - } - } - }break; - - case CV_LeafKind_NESTTYPE: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafNestType) <= cap){ - // compute whole layout - CV_LeafNestType *nest_type = (CV_LeafNestType*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*nest_type); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // emit member - CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, nest_type->itype); - cons_type_add_member_nested_type(ctx->root, owner_type, mem_type); - } - }break; - - case CV_LeafKind_NESTTYPEEX: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafNestTypeEx) <= cap){ - // compute whole layout - CV_LeafNestTypeEx *nest_type = (CV_LeafNestTypeEx*)(first + list_item_off); - - U64 name_off = list_item_off + sizeof(*nest_type); - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // TODO(allen): handle attribs - - // emit member - CONS_Type *mem_type = pdbconv_type_resolve_itype(ctx, nest_type->itype); - cons_type_add_member_nested_type(ctx->root, owner_type, mem_type); - } - }break; - - case CV_LeafKind_BCLASS: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafBClass) <= cap){ - // compute whole layout - CV_LeafBClass *bclass = (CV_LeafBClass*)(first + list_item_off); - - U64 offset_off = list_item_off + sizeof(*bclass); - CV_NumericParsed offset = cv_numeric_from_data_range(first + offset_off, first + cap); - - list_item_opl_off = offset_off + offset.encoded_size; - - // TODO(allen): handle attribs - - // emit member - CONS_Type *base_type = pdbconv_type_resolve_itype(ctx, bclass->itype); - U32 offset_u32 = pdbconv_u32_from_numeric(ctx, &offset); - cons_type_add_member_base(ctx->root, owner_type, base_type, offset_u32); - } - }break; - - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafVBClass) <= cap){ - // compute whole layout - CV_LeafVBClass *vbclass = (CV_LeafVBClass*)(first + list_item_off); - - U64 num1_off = list_item_off + sizeof(*vbclass); - CV_NumericParsed num1 = cv_numeric_from_data_range(first + num1_off, first + cap); - - U64 num2_off = num1_off + num1.encoded_size; - CV_NumericParsed num2 = cv_numeric_from_data_range(first + num2_off, first + cap); - - list_item_opl_off = num2_off + num2.encoded_size; - - // TODO(allen): handle attribs - - // emit member - CONS_Type *base_type = pdbconv_type_resolve_itype(ctx, vbclass->itype); - U32 vbptr_offset_u32 = pdbconv_u32_from_numeric(ctx, &num1); - U32 vtable_offset_u32 = pdbconv_u32_from_numeric(ctx, &num2); - cons_type_add_member_virtual_base(ctx->root, owner_type, base_type, - vbptr_offset_u32, vtable_offset_u32); - } - }break; - - // discard cases - we don't currently do anything with these - case CV_LeafKind_VFUNCTAB: - { - // TODO(rjf): error if bad range - if(list_item_off + sizeof(CV_LeafVFuncTab) <= cap) - { - list_item_opl_off = list_item_off + sizeof(CV_LeafVFuncTab); - } - }break; - - // unhandled or invalid cases - default: - { - String8 kind_str = cv_string_from_leaf_kind(field_kind); - cons_errorf(ctx->root, "unhandled/invalid case: equip_members -> %.*s", - str8_varg(kind_str)); - }break; - } - - // update cursor - U64 next_cursor = AlignPow2(list_item_opl_off, 4); - cursor = next_cursor; - } - } - - scratch_end(scratch); -} - -static void -pdbconv_type_equip_enumerates(PDBCONV_Ctx *ctx, CONS_Type *owner_type, CV_TypeId field_itype){ - Temp scratch = scratch_begin(0, 0); - - String8 data = ctx->leaf->data; - - // field stack - // TODO(allen): add notes about field tasks - struct FieldTask{ - struct FieldTask *next; - CV_TypeId itype; - }; - struct FieldTask *handled = 0; - struct FieldTask *todo = 0; - { - struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); - SLLStackPush(todo, task); - task->itype = field_itype; - } - - for (;;){ - // exit condition - if (todo == 0){ - break; - } - - // determine itype - CV_TypeId field_itype = todo->itype; - { - struct FieldTask *task = todo; - SLLStackPop(todo); - SLLStackPush(handled, task); - } - - // get leaf range - // TODO(allen): error if this itype is bad - U8 *first = 0; - U64 cap = 0; - if (ctx->leaf->itype_first <= field_itype && field_itype < ctx->leaf->itype_opl){ - CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[field_itype - ctx->leaf->itype_first]; - // check valid arglist - if (range->hdr.kind == CV_LeafKind_FIELDLIST && - range->off + range->hdr.size <= data.size){ - first = data.str + range->off + 2; - cap = range->hdr.size - 2; - } - } - - U64 cursor = 0; - for (;cursor + sizeof(CV_LeafKind) <= cap;){ - CV_LeafKind field_kind = *(CV_LeafKind*)(first + cursor); - - U64 list_item_off = cursor + 2; - // if we hit an error or forget to set next cursor for a case - // default to exiting the loop - U64 list_item_opl_off = cap; - - switch (field_kind){ - case CV_LeafKind_INDEX: - { - // TODO(allen): error if bad range - if (list_item_off + sizeof(CV_LeafIndex) <= cap){ - // compute whole layout - CV_LeafIndex *index = (CV_LeafIndex*)(first + list_item_off); - - list_item_opl_off = list_item_off + sizeof(*index); - - // create new todo task - CV_TypeId new_itype = index->itype; - B32 is_new = 1; - for (struct FieldTask *task = handled; - task != 0; - task = task->next){ - if (task->itype == new_itype){ - is_new = 0; - break; - } - } - if (is_new){ - struct FieldTask *task = push_array(scratch.arena, struct FieldTask, 1); - SLLStackPush(todo, task); - task->itype = new_itype; - } - } - }break; - - case CV_LeafKind_ENUMERATE: - { - // compute whole layout - CV_LeafEnumerate *enumerate = (CV_LeafEnumerate*)(first + list_item_off); - - U64 val_off = list_item_off + sizeof(*enumerate); - CV_NumericParsed val = cv_numeric_from_data_range(first + val_off, first + cap); - - U64 name_off = val_off + val.encoded_size; - String8 name = str8_cstring_capped(first + name_off, first + cap); - - list_item_opl_off = name_off + name.size + 1; - - // TODO(allen): handle attribs - - // emit enum val - U64 val_u64 = cv_u64_from_numeric(&val); - cons_type_add_enum_val(ctx->root, owner_type, name, val_u64); - }break; - - // unhandled or invalid cases - default: - { - String8 kind_str = cv_string_from_leaf_kind(field_kind); - cons_errorf(ctx->root, "unhandled/invalid case: equip_enumerates -> %.*s", - str8_varg(kind_str)); - }break; - } - - // update cursor - U64 next_cursor = AlignPow2(list_item_opl_off, 4); - cursor = next_cursor; - } - } - - scratch_end(scratch); -} - -static CONS_Type* -pdbconv_type_cons_basic(PDBCONV_Ctx *ctx, CV_TypeId itype){ - ProfBeginFunction(); - Assert(itype < 0x1000); - - CV_BasicPointerKind basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); - CV_BasicType basic_type_code = CV_BasicTypeFromTypeId(itype); - - CONS_Reservation *basic_res = cons_type_reserve_id(ctx->root, basic_type_code); - - CONS_Type *basic_type = 0; - switch (basic_type_code){ - case CV_BasicType_VOID: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Void, str8_lit("void")); - }break; - - case CV_BasicType_HRESULT: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Handle, str8_lit("HRESULT")); - }break; - - case CV_BasicType_RCHAR: - case CV_BasicType_CHAR: - case CV_BasicType_CHAR8: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Char8, str8_lit("char")); - }break; - - case CV_BasicType_UCHAR: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_UChar8, str8_lit("UCHAR")); - }break; - - case CV_BasicType_WCHAR: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_UChar16, str8_lit("WCHAR")); - }break; - - case CV_BasicType_CHAR16: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Char16, str8_lit("CHAR16")); - }break; - - case CV_BasicType_CHAR32: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Char32, str8_lit("CHAR32")); - }break; - - case CV_BasicType_BOOL8: - case CV_BasicType_INT8: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S8, str8_lit("S8")); - }break; - - case CV_BasicType_BOOL16: - case CV_BasicType_INT16: - case CV_BasicType_SHORT: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S16, str8_lit("S16")); - }break; - - case CV_BasicType_BOOL32: - case CV_BasicType_INT32: - case CV_BasicType_LONG: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S32, str8_lit("S32")); - }break; - - case CV_BasicType_BOOL64: - case CV_BasicType_INT64: - case CV_BasicType_QUAD: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S64, str8_lit("S64")); - }break; - - case CV_BasicType_INT128: - case CV_BasicType_OCT: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_S128, str8_lit("S128")); - }break; - - case CV_BasicType_UINT8: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U8, str8_lit("U8")); - }break; - - case CV_BasicType_UINT16: - case CV_BasicType_USHORT: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U16, str8_lit("U16")); - }break; - - case CV_BasicType_UINT32: - case CV_BasicType_ULONG: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U32, str8_lit("U32")); - }break; - - case CV_BasicType_UINT64: - case CV_BasicType_UQUAD: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U64, str8_lit("U64")); - }break; - - case CV_BasicType_UINT128: - case CV_BasicType_UOCT: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_U128, str8_lit("U128")); - }break; - - case CV_BasicType_FLOAT16: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F16, str8_lit("F16")); - }break; - - case CV_BasicType_FLOAT32: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F32, str8_lit("F32")); - }break; - - case CV_BasicType_FLOAT32PP: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F32PP, str8_lit("F32PP")); - }break; - - case CV_BasicType_FLOAT48: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F48, str8_lit("F48")); - }break; - - case CV_BasicType_FLOAT64: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F64, str8_lit("F64")); - }break; - - case CV_BasicType_FLOAT80: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F80, str8_lit("F80")); - }break; - - case CV_BasicType_FLOAT128: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_F128, str8_lit("F128")); - }break; - - case CV_BasicType_COMPLEX32: - { - basic_type = - cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF32, str8_lit("ComplexF32")); - }break; - - case CV_BasicType_COMPLEX64: - { - basic_type = - cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF64, str8_lit("ComplexF64")); - }break; - - case CV_BasicType_COMPLEX80: - { - basic_type = - cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF80, str8_lit("ComplexF80")); - }break; - - case CV_BasicType_COMPLEX128: - { - basic_type = - cons_type_basic(ctx->root, RADDBG_TypeKind_ComplexF128, str8_lit("ComplexF128")); - }break; - - case CV_BasicType_PTR: - { - basic_type = cons_type_basic(ctx->root, RADDBG_TypeKind_Handle, str8_lit("PTR")); - }break; - } - - // basic resolve - cons_type_fill_id(ctx->root, basic_res, basic_type); - - // wrap in constructed type - CONS_Type *constructed_type = 0; - if (basic_ptr_kind != 0 && basic_type != 0){ - CONS_Reservation *constructed_res = cons_type_reserve_id(ctx->root, itype); - - switch (basic_ptr_kind){ - case CV_BasicPointerKind_16BIT: - case CV_BasicPointerKind_FAR_16BIT: - case CV_BasicPointerKind_HUGE_16BIT: - case CV_BasicPointerKind_32BIT: - case CV_BasicPointerKind_16_32BIT: - case CV_BasicPointerKind_64BIT: - { - constructed_type = cons_type_pointer(ctx->root, basic_type, RADDBG_TypeKind_Ptr); - }break; - } - - // constructed resolve - cons_type_fill_id(ctx->root, constructed_res, constructed_type); - } - - // select output - CONS_Type *result = basic_type; - if (basic_ptr_kind != 0){ - result = constructed_type; - } - - ProfEnd(); - return(result); -} - -static CONS_Type* -pdbconv_type_cons_leaf_record(PDBCONV_Ctx *ctx, CV_TypeId itype){ - ProfBeginFunction(); - Assert(ctx->leaf->itype_first <= itype && itype < ctx->leaf->itype_opl); - - CONS_Reservation *res = cons_type_reserve_id(ctx->root, itype); - - CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[itype - ctx->leaf->itype_first]; - String8 data = ctx->leaf->data; - - CONS_Type *result = 0; - if (range->off + range->hdr.size <= data.size){ - U8 *first = data.str + range->off + 2; - U64 cap = range->hdr.size - 2; - - switch (range->hdr.kind){ - case CV_LeafKind_MODIFIER: - { - ProfBegin("CV_LeafKind_MODIFIER"); - - // TODO(allen): error if bad range - if (sizeof(CV_LeafModifier) <= cap){ - CV_LeafModifier *modifier = (CV_LeafModifier*)first; - - RADDBG_TypeModifierFlags flags = 0; - if (modifier->flags & CV_ModifierFlag_Const){ - flags |= RADDBG_TypeModifierFlag_Const; - } - if (modifier->flags & CV_ModifierFlag_Volatile){ - flags |= RADDBG_TypeModifierFlag_Volatile; - } - - CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, modifier->itype); - if (flags != 0){ - result = cons_type_modifier(ctx->root, direct_type, flags); - } - else{ - result = direct_type; - } - } - - ProfEnd(); - }break; - - case CV_LeafKind_POINTER: - { - ProfBegin("CV_LeafKind_POINTER"); - - // TODO(allen): error if bad range - if (sizeof(CV_LeafPointer) <= cap){ - CV_LeafPointer *pointer = (CV_LeafPointer*)first; - - CV_PointerKind ptr_kind = CV_PointerAttribs_ExtractKind(pointer->attribs); - CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(pointer->attribs); - U32 ptr_size = CV_PointerAttribs_ExtractSize(pointer->attribs); - - // TODO(allen): if ptr_mode in {PtrMem, PtrMethod} then output a member pointer instead - - // extract modifier flags - RADDBG_TypeModifierFlags modifier_flags = 0; - if (pointer->attribs & CV_PointerAttrib_Const){ - modifier_flags |= RADDBG_TypeModifierFlag_Const; - } - if (pointer->attribs & CV_PointerAttrib_Volatile){ - modifier_flags |= RADDBG_TypeModifierFlag_Volatile; - } - - // determine type kind - RADDBG_TypeKind type_kind = RADDBG_TypeKind_Ptr; - if (pointer->attribs & CV_PointerAttrib_LRef){ - type_kind = RADDBG_TypeKind_LRef; - } - else if (pointer->attribs & CV_PointerAttrib_RRef){ - type_kind = RADDBG_TypeKind_RRef; - } - if (ptr_mode == CV_PointerMode_LRef){ - type_kind = RADDBG_TypeKind_LRef; - } - else if (ptr_mode == CV_PointerMode_RRef){ - type_kind = RADDBG_TypeKind_RRef; - } - - CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, pointer->itype); - CONS_Type *ptr_type = cons_type_pointer(ctx->root, direct_type, type_kind); - - result = ptr_type; - if (modifier_flags != 0){ - result = cons_type_modifier(ctx->root, ptr_type, modifier_flags); - } - } - - ProfEnd(); - }break; - - case CV_LeafKind_PROCEDURE: - { - ProfBegin("CV_LeafKind_PROCEDURE"); - - // TODO(allen): error if bad range - if (sizeof(CV_LeafProcedure) <= cap){ - CV_LeafProcedure *procedure = (CV_LeafProcedure*)first; - - Temp scratch = scratch_begin(0, 0); - - // TODO(allen): handle call_kind & attribs - - CONS_Type *ret_type = pdbconv_type_resolve_and_check(ctx, procedure->ret_itype); - - CONS_TypeList param_list = {0}; - pdbconv_type_resolve_arglist(scratch.arena, ¶m_list, ctx, procedure->arg_itype); - - result = cons_type_proc(ctx->root, ret_type, ¶m_list); - - scratch_end(scratch); - } - - ProfEnd(); - }break; - - case CV_LeafKind_MFUNCTION: - { - ProfBegin("CV_LeafKind_MFUNCTION"); - - // TODO(allen): error if bad range - if (sizeof(CV_LeafMFunction) <= cap){ - CV_LeafMFunction *mfunction = (CV_LeafMFunction*)first; - - Temp scratch = scratch_begin(0, 0); - - // TODO(allen): handle call_kind & attribs - // TODO(allen): preserve "this_adjust" - - CONS_Type *ret_type = pdbconv_type_resolve_and_check(ctx, mfunction->ret_itype); - - CONS_TypeList param_list = {0}; - pdbconv_type_resolve_arglist(scratch.arena, ¶m_list, ctx, mfunction->arg_itype); - - CONS_Type *this_type = 0; - if (mfunction->this_itype != 0){ - this_type = pdbconv_type_resolve_and_check(ctx, mfunction->this_itype); - result = cons_type_method(ctx->root, this_type, ret_type, ¶m_list); - } - else{ - result = cons_type_proc(ctx->root, ret_type, ¶m_list); - } - - scratch_end(scratch); - } - - ProfEnd(); - }break; - - case CV_LeafKind_BITFIELD: - { - ProfBegin("CV_LeafKind_BITFIELD"); - // TODO(allen): error if bad range - if (sizeof(CV_LeafBitField) <= cap){ - CV_LeafBitField *bit_field = (CV_LeafBitField*)first; - CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, bit_field->itype); - result = cons_type_bitfield(ctx->root, direct_type, bit_field->pos, bit_field->len); - } - ProfEnd(); - }break; - - case CV_LeafKind_ARRAY: - { - ProfBegin("CV_LeafKind_ARRAY"); - // TODO(allen): error if bad range - if (sizeof(CV_LeafArray) <= cap){ - CV_LeafArray *array = (CV_LeafArray*)first; - - // parse count - U8 *numeric_ptr = (U8*)(array + 1); - CV_NumericParsed array_count = cv_numeric_from_data_range(numeric_ptr, first + cap); - - U64 full_size = cv_u64_from_numeric(&array_count); - - CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, array->entry_itype); - U64 count = full_size; - if (direct_type != 0 && direct_type->byte_size != 0){ - count /= direct_type->byte_size; - } - - // build type - result = cons_type_array(ctx->root, direct_type, count); - } - ProfEnd(); - }break; - - case CV_LeafKind_CLASS: - case CV_LeafKind_STRUCTURE: - { - ProfBegin("CV_LeafKind_CLASS/CV_LeafKind_STRUCTURE"); - - // TODO(allen): error if bad range - if (sizeof(CV_LeafStruct) <= cap){ - CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; - - // TODO(allen): handle props - - // size - U8 *numeric_ptr = (U8*)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - U64 size_u64 = cv_u64_from_numeric(&size); - - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - // incomplete type - if (lf_struct->props & CV_TypeProp_FwdRef){ - RADDBG_TypeKind type_kind = RADDBG_TypeKind_IncompleteStruct; - if (range->hdr.kind == CV_LeafKind_CLASS){ - type_kind = RADDBG_TypeKind_IncompleteClass; - } - result = cons_type_incomplete(ctx->root, type_kind, name); - } - - // complete type - else{ - RADDBG_TypeKind type_kind = RADDBG_TypeKind_Struct; - if (range->hdr.kind == CV_LeafKind_CLASS){ - type_kind = RADDBG_TypeKind_Class; - } - result = cons_type_udt(ctx->root, type_kind, name, size_u64); - - // remember to revisit this for members - { - PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); - rev->owner_type = result; - rev->field_itype = lf_struct->field_itype; - SLLQueuePush(ctx->member_revisit_first, ctx->member_revisit_last, rev); - } - } - } - ProfEnd(); - }break; - - case CV_LeafKind_CLASS2: - case CV_LeafKind_STRUCT2: - { - ProfBegin("CV_LeafKind_CLASS2/CV_LeafKind_STRUCT2"); - // TODO(allen): error if bad range - if (sizeof(CV_LeafStruct2) <= cap){ - CV_LeafStruct2 *lf_struct = (CV_LeafStruct2*)first; - - // TODO(allen): handle props - - // size - U8 *numeric_ptr = (U8*)(lf_struct + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - U64 size_u64 = cv_u64_from_numeric(&size); - - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - if(str8_match(name, str8_lit("Foo"), 0)) - { - int x = 0; - } - - // incomplete type - if (lf_struct->props & CV_TypeProp_FwdRef){ - RADDBG_TypeKind type_kind = RADDBG_TypeKind_IncompleteStruct; - if (range->hdr.kind == CV_LeafKind_CLASS2){ - type_kind = RADDBG_TypeKind_IncompleteClass; - } - result = cons_type_incomplete(ctx->root, type_kind, name); - } - - // complete type - else{ - RADDBG_TypeKind type_kind = RADDBG_TypeKind_Struct; - if (range->hdr.kind == CV_LeafKind_CLASS2){ - type_kind = RADDBG_TypeKind_Class; - } - result = cons_type_udt(ctx->root, type_kind, name, size_u64); - - // remember to revisit this for members - { - PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); - rev->owner_type = result; - rev->field_itype = lf_struct->field_itype; - SLLQueuePush(ctx->member_revisit_first, ctx->member_revisit_last, rev); - } - } - } - ProfEnd(); - }break; - - case CV_LeafKind_UNION: - { - ProfBegin("CV_LeafKind_UNION"); - // TODO(allen): error if bad range - if (sizeof(CV_LeafUnion) <= cap){ - CV_LeafUnion *lf_union = (CV_LeafUnion*)first; - - // TODO(allen): handle props - - // size - U8 *numeric_ptr = (U8*)(lf_union + 1); - CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, first + cap); - U64 size_u64 = cv_u64_from_numeric(&size); - - // name - U8 *name_ptr = numeric_ptr + size.encoded_size; - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - // incomplete type - if (lf_union->props & CV_TypeProp_FwdRef){ - result = - cons_type_incomplete(ctx->root, RADDBG_TypeKind_IncompleteUnion, name); - } - - // complete type - else{ - result = cons_type_udt(ctx->root, RADDBG_TypeKind_Union, name, size_u64); - - // remember to revisit this for members - { - PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); - rev->owner_type = result; - rev->field_itype = lf_union->field_itype; - SLLQueuePush(ctx->member_revisit_first, ctx->member_revisit_last, rev); - } - } - } - ProfEnd(); - }break; - - case CV_LeafKind_ENUM: - { - ProfBegin("CV_LeafKind_ENUM"); - // TODO(allen): error if bad range - if (sizeof(CV_LeafEnum) <= cap){ - CV_LeafEnum *lf_enum = (CV_LeafEnum*)first; - - // TODO(allen): handle props - - // name - U8 *name_ptr = (U8*)(lf_enum + 1); - String8 name = str8_cstring_capped((char*)name_ptr, first + cap); - - // incomplete type - if (lf_enum->props & CV_TypeProp_FwdRef){ - result = cons_type_incomplete(ctx->root, RADDBG_TypeKind_IncompleteEnum, name); - } - - // complete type - else{ - CONS_Type *direct_type = pdbconv_type_resolve_and_check(ctx, lf_enum->base_itype); - result = cons_type_enum(ctx->root, direct_type, name); - - // remember to revisit this for enumerates - { - PDBCONV_TypeRev *rev = push_array(ctx->temp_arena, PDBCONV_TypeRev, 1); - rev->owner_type = result; - rev->field_itype = lf_enum->field_itype; - SLLQueuePush(ctx->enum_revisit_first, ctx->enum_revisit_last, rev); - } - } - } - ProfEnd(); - }break; - - // discard cases - we currently discard these these intentionally - // so we mark them as "handled nil" - case CV_LeafKind_VTSHAPE: - case CV_LeafKind_VFTABLE: - case CV_LeafKind_LABEL: - { - result = cons_type_handled_nil(ctx->root); - }break; - - // do nothing cases - these get handled in special passes and - // they should not be appearing as direct types - // or parameter types for any other types - // so if the input data is valid we won't get - // error messages even if they resolve to nil - case CV_LeafKind_FIELDLIST: - case CV_LeafKind_ARGLIST: - case CV_LeafKind_METHODLIST: - {}break; - - // Leaf Kinds - case CV_LeafKind_MODIFIER_16t: - case CV_LeafKind_POINTER_16t: - case CV_LeafKind_ARRAY_16t: - case CV_LeafKind_CLASS_16t: - case CV_LeafKind_STRUCTURE_16t: - case CV_LeafKind_UNION_16t: - case CV_LeafKind_ENUM_16t: - case CV_LeafKind_PROCEDURE_16t: - case CV_LeafKind_MFUNCTION_16t: - //case CV_LeafKind_VTSHAPE: - case CV_LeafKind_COBOL0_16t: - case CV_LeafKind_COBOL1: - case CV_LeafKind_BARRAY_16t: - //case CV_LeafKind_LABEL: - case CV_LeafKind_NULL: - case CV_LeafKind_NOTTRAN: - case CV_LeafKind_DIMARRAY_16t: - case CV_LeafKind_VFTPATH_16t: - case CV_LeafKind_PRECOMP_16t: - case CV_LeafKind_ENDPRECOMP: - case CV_LeafKind_OEM_16t: - case CV_LeafKind_TYPESERVER_ST: - case CV_LeafKind_SKIP_16t: - case CV_LeafKind_ARGLIST_16t: - case CV_LeafKind_DEFARG_16t: - case CV_LeafKind_LIST: - case CV_LeafKind_FIELDLIST_16t: - case CV_LeafKind_DERIVED_16t: - case CV_LeafKind_BITFIELD_16t: - case CV_LeafKind_METHODLIST_16t: - case CV_LeafKind_DIMCONU_16t: - case CV_LeafKind_DIMCONLU_16t: - case CV_LeafKind_DIMVARU_16t: - case CV_LeafKind_DIMVARLU_16t: - case CV_LeafKind_REFSYM: - case CV_LeafKind_BCLASS_16t: - case CV_LeafKind_VBCLASS_16t: - case CV_LeafKind_IVBCLASS_16t: - case CV_LeafKind_ENUMERATE_ST: - case CV_LeafKind_FRIENDFCN_16t: - case CV_LeafKind_INDEX_16t: - case CV_LeafKind_MEMBER_16t: - case CV_LeafKind_STMEMBER_16t: - case CV_LeafKind_METHOD_16t: - case CV_LeafKind_NESTTYPE_16t: - case CV_LeafKind_VFUNCTAB_16t: - case CV_LeafKind_FRIENDCLS_16t: - case CV_LeafKind_ONEMETHOD_16t: - case CV_LeafKind_VFUNCOFF_16t: - case CV_LeafKind_TI16_MAX: - //case CV_LeafKind_MODIFIER: - //case CV_LeafKind_POINTER: - case CV_LeafKind_ARRAY_ST: - case CV_LeafKind_CLASS_ST: - case CV_LeafKind_STRUCTURE_ST: - case CV_LeafKind_UNION_ST: - case CV_LeafKind_ENUM_ST: - //case CV_LeafKind_PROCEDURE: - //case CV_LeafKind_MFUNCTION: - case CV_LeafKind_COBOL0: - case CV_LeafKind_BARRAY: - case CV_LeafKind_DIMARRAY_ST: - case CV_LeafKind_VFTPATH: - case CV_LeafKind_PRECOMP_ST: - case CV_LeafKind_OEM: - case CV_LeafKind_ALIAS_ST: - case CV_LeafKind_OEM2: - case CV_LeafKind_SKIP: - //case CV_LeafKind_ARGLIST: - case CV_LeafKind_DEFARG_ST: - //case CV_LeafKind_FIELDLIST: - case CV_LeafKind_DERIVED: - //case CV_LeafKind_BITFIELD: - //case CV_LeafKind_METHODLIST: - case CV_LeafKind_DIMCONU: - case CV_LeafKind_DIMCONLU: - case CV_LeafKind_DIMVARU: - case CV_LeafKind_DIMVARLU: - case CV_LeafKind_BCLASS: - case CV_LeafKind_VBCLASS: - case CV_LeafKind_IVBCLASS: - case CV_LeafKind_FRIENDFCN_ST: - case CV_LeafKind_INDEX: - case CV_LeafKind_MEMBER_ST: - case CV_LeafKind_STMEMBER_ST: - case CV_LeafKind_METHOD_ST: - case CV_LeafKind_NESTTYPE_ST: - case CV_LeafKind_VFUNCTAB: - case CV_LeafKind_FRIENDCLS: - case CV_LeafKind_ONEMETHOD_ST: - case CV_LeafKind_VFUNCOFF: - case CV_LeafKind_NESTTYPEEX_ST: - case CV_LeafKind_MEMBERMODIFY_ST: - case CV_LeafKind_MANAGED_ST: - case CV_LeafKind_ST_MAX: - case CV_LeafKind_TYPESERVER: - case CV_LeafKind_ENUMERATE: - //case CV_LeafKind_ARRAY: - //case CV_LeafKind_CLASS: - //case CV_LeafKind_STRUCTURE: - //case CV_LeafKind_UNION: - //case CV_LeafKind_ENUM: - case CV_LeafKind_DIMARRAY: - case CV_LeafKind_PRECOMP: - case CV_LeafKind_ALIAS: - case CV_LeafKind_DEFARG: - case CV_LeafKind_FRIENDFCN: - case CV_LeafKind_MEMBER: - case CV_LeafKind_STMEMBER: - case CV_LeafKind_METHOD: - case CV_LeafKind_NESTTYPE: - case CV_LeafKind_ONEMETHOD: - case CV_LeafKind_NESTTYPEEX: - case CV_LeafKind_MEMBERMODIFY: - case CV_LeafKind_MANAGED: - case CV_LeafKind_TYPESERVER2: - case CV_LeafKind_STRIDED_ARRAY: - case CV_LeafKind_HLSL: - case CV_LeafKind_MODIFIER_EX: - case CV_LeafKind_INTERFACE: - case CV_LeafKind_BINTERFACE: - case CV_LeafKind_VECTOR: - case CV_LeafKind_MATRIX: - //case CV_LeafKind_VFTABLE: - default: - { - String8 kind_str = cv_string_from_leaf_kind(range->hdr.kind); - cons_errorf(ctx->root, "pdbconv: unhandled leaf case %.*s (0x%x)", - str8_varg(kind_str), range->hdr.kind); - }break; - } - } - - cons_type_fill_id(ctx->root, res, result); - - ProfEnd(); - return(result); -} - -static CONS_Type* -pdbconv_type_resolve_and_check(PDBCONV_Ctx *ctx, CV_TypeId itype){ - CONS_Type *result = pdbconv_type_resolve_itype(ctx, itype); - if (cons_type_is_unhandled_nil(ctx->root, result)){ - cons_errorf(ctx->root, "pdbconv: could not resolve itype (itype = %u)", itype); - } - return(result); -} - -static void -pdbconv_type_resolve_arglist(Arena *arena, CONS_TypeList *out, - PDBCONV_Ctx *ctx, CV_TypeId arglist_itype){ - ProfBeginFunction(); - - // get leaf range - if (ctx->leaf->itype_first <= arglist_itype && arglist_itype < ctx->leaf->itype_opl){ - CV_RecRange *range = &ctx->leaf->leaf_ranges.ranges[arglist_itype - ctx->leaf->itype_first]; - - // check valid arglist - String8 data = ctx->leaf->data; - if (range->hdr.kind == CV_LeafKind_ARGLIST && - range->off + range->hdr.size <= data.size){ - U8 *first = data.str + range->off + 2; - U64 cap = range->hdr.size - 2; - if (sizeof(CV_LeafArgList) <= cap){ - - // resolve parameters - CV_LeafArgList *arglist = (CV_LeafArgList*)first; - CV_TypeId *itypes = (CV_TypeId*)(arglist + 1); - U32 max_count = (cap - sizeof(*arglist))/sizeof(CV_TypeId); - U32 clamped_count = ClampTop(arglist->count, max_count); - for (U32 i = 0; i < clamped_count; i += 1){ - CONS_Type *param_type = pdbconv_type_resolve_and_check(ctx, itypes[i]); - cons_type_list_push(arena, out, param_type); - } - - } - } - } - - ProfEnd(); -} - -static CONS_Type* -pdbconv_type_from_name(PDBCONV_Ctx *ctx, String8 name){ - // TODO(rjf): no idea if this is correct - CV_TypeId cv_type_id = pdb_tpi_first_itype_from_name(ctx->hash, ctx->leaf, name, 0); - CONS_Type *result = cons_type_from_id(ctx->root, cv_type_id); - return(result); -} - -static void -pdbconv_type_fwd_map_set(Arena *arena, PDBCONV_FwdMap *map, CV_TypeId key, CV_TypeId val){ - U64 bucket_idx = key%ArrayCount(map->buckets); - - // search for an existing match - PDBCONV_FwdNode *match = 0; - for (PDBCONV_FwdNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->key == key){ - match = node; - break; - } - } - - // create a new node if no match - if (match == 0){ - match = push_array(arena, PDBCONV_FwdNode, 1); - SLLStackPush(map->buckets[bucket_idx], match); - match->key = key; - } - - // set node's val - match->val = val; -} - -static CV_TypeId -pdbconv_type_fwd_map_get(PDBCONV_FwdMap *map, CV_TypeId key){ - ProfBeginFunction(); - U64 bucket_idx = key%ArrayCount(map->buckets); - - // search for an existing match - PDBCONV_FwdNode *match = 0; - for (PDBCONV_FwdNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->key == key){ - match = node; - break; - } - } - - // extract result - CV_TypeId result = 0; - if (match != 0){ - result = match->val; - } - - ProfEnd(); - return(result); -} - -//- symbols - -static void -pdbconv_symbol_cons(PDBCONV_Ctx *ctx, CV_SymParsed *sym, U32 sym_unique_id){ - ProfBeginFunction(); - Temp scratch = scratch_begin(0, 0); - - // extract important values from parameters - String8 data = sym->data; - U64 user_id_base = (((U64)sym_unique_id) << 32); - - // PASS 1: map out data associations - ProfScope("map out data associations") - { - // state variables - CONS_Symbol *current_proc = 0; - - // loop - CV_RecRange *rec_range = sym->sym_ranges.ranges; - CV_RecRange *opl = rec_range + sym->sym_ranges.count; - for (;rec_range < opl; rec_range += 1){ - // symbol data range - U64 opl_off_raw = rec_range->off + rec_range->hdr.size; - U64 opl_off = ClampTop(opl_off_raw, data.size); - - U64 off_raw = rec_range->off + 2; - U64 off = ClampTop(off_raw, opl_off); - - U8 *first = data.str + off; - U64 cap = (opl_off - off); - - CV_SymKind kind = rec_range->hdr.kind; - switch (kind){ - default: break; - - case CV_SymKind_FRAMEPROC: - { - if (sizeof(CV_SymFrameproc) > cap){ - // TODO(allen): error - } - else{ - CV_SymFrameproc *frameproc = (CV_SymFrameproc*)first; - if (current_proc == 0){ - // TODO(allen): error - } - else{ - PDBCONV_FrameProcData data = {0}; - data.frame_size = frameproc->frame_size; - data.flags = frameproc->flags; - pdbconv_symbol_frame_proc_write(ctx, current_proc, &data); - } - } - }break; - - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - U64 user_id = user_id_base + off; - current_proc = cons_symbol_handle_from_user_id(ctx->root, user_id); - }break; - } - } - } - - // PASS 2: main symbol construction pass - ProfScope("main symbol construction pass") - { - // state variables - CONS_LocationSet *defrange_target = 0; - B32 defrange_target_is_param = 0; - - // loop - CV_RecRange *rec_range = sym->sym_ranges.ranges; - CV_RecRange *opl = rec_range + sym->sym_ranges.count; - for (;rec_range < opl; rec_range += 1){ - // symbol data range - U64 opl_off_raw = rec_range->off + rec_range->hdr.size; - U64 opl_off = ClampTop(opl_off_raw, data.size); - - U64 off_raw = rec_range->off + 2; - U64 off = ClampTop(off_raw, opl_off); - - U8 *first = data.str + off; - U64 cap = (opl_off - off); - - // current state - CONS_Scope *current_scope = pdbconv_symbol_current_scope(ctx); - CONS_Symbol *current_procedure = 0; - if (current_scope != 0){ - current_procedure = current_scope->symbol; - } - - CV_SymKind kind = rec_range->hdr.kind; - switch (kind){ - default:break; - - case CV_SymKind_END: - { - // pop scope stack - pdbconv_symbol_pop_scope(ctx); - defrange_target = 0; - defrange_target_is_param = 0; - }break; - - case CV_SymKind_FRAMEPROC: - { - if (sizeof(CV_SymFrameproc) > cap){ - // TODO(allen): error - } - else{ - // do nothing (handled in 'association map' pass) - } - }break; - - case CV_SymKind_BLOCK32: - { - if (sizeof(CV_SymBlock32) > cap){ - // TODO(allen): error - } - else{ - CV_SymBlock32 *block32 = (CV_SymBlock32*)first; - - // scope - U64 user_id = user_id_base + off; - CONS_Scope *block_scope = cons_scope_handle_from_user_id(ctx->root, user_id); - cons_scope_set_parent(ctx->root, block_scope, current_scope); - pdbconv_symbol_push_scope(ctx, block_scope, current_procedure); - - // set voff range - COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, block32->sec); - if (section != 0){ - U64 voff_first = section->voff + block32->off; - U64 voff_last = voff_first + block32->len; - cons_scope_add_voff_range(ctx->root, block_scope, voff_first, voff_last); - } - } - }break; - - case CV_SymKind_LDATA32: - case CV_SymKind_GDATA32: - { - if (sizeof(CV_SymData32) > cap){ - // TODO(allen): error - } - else{ - CV_SymData32 *data32 = (CV_SymData32*)first; - - // name - String8 name = str8_cstring_capped((char*)(data32 + 1), first + cap); - - // determine voff - COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, data32->sec); - U64 voff = ((section != 0)?section->voff:0) + data32->off; - - // deduplicate global variable symbols with the same name & offset - // * PDB likes to have duplicates of these spread across - // * different symbol streams so we deduplicate across the - // * entire translation context. - if (!pdbconv_known_global_lookup(&ctx->known_globals, name, voff)){ - pdbconv_known_global_insert(ctx->temp_arena, &ctx->known_globals, name, voff); - - // type of variable - CONS_Type *type = pdbconv_type_resolve_itype(ctx, data32->itype); - - // container type - CONS_Type *container_type = 0; - U64 container_name_opl = pdbconv_end_of_cplusplus_container_name(name); - if (container_name_opl > 2){ - String8 container_name = str8(name.str, container_name_opl - 2); - container_type = pdbconv_type_from_name(ctx, container_name); - } - - // container symbol - CONS_Symbol *container_symbol = 0; - if (container_type == 0){ - container_symbol = current_procedure; - } - - // determine link kind - B32 is_extern = (kind == CV_SymKind_GDATA32); - - // cons this symbol - U64 user_id = user_id_base + off; - CONS_Symbol *symbol = cons_symbol_handle_from_user_id(ctx->root, user_id); - - CONS_SymbolInfo info = zero_struct; - info.kind = CONS_SymbolKind_GlobalVariable; - info.name = name; - info.type = type; - info.is_extern = is_extern; - info.offset = voff; - info.container_type = container_type; - info.container_symbol = container_symbol; - - cons_symbol_set_info(ctx->root, symbol, &info); - } - } - }break; - - case CV_SymKind_LPROC32: - case CV_SymKind_GPROC32: - { - if (sizeof(CV_SymProc32) > cap){ - // TODO(allen): error - } - else{ - CV_SymProc32 *proc32 = (CV_SymProc32*)first; - - // name - String8 name = str8_cstring_capped((char*)(proc32 + 1), first + cap); - - // type of procedure - CONS_Type *type = pdbconv_type_resolve_itype(ctx, proc32->itype); - - // container type - CONS_Type *container_type = 0; - U64 container_name_opl = pdbconv_end_of_cplusplus_container_name(name); - if (container_name_opl > 2){ - String8 container_name = str8(name.str, container_name_opl - 2); - container_type = pdbconv_type_from_name(ctx, container_name); - } - - // container symbol - CONS_Symbol *container_symbol = 0; - if (container_type == 0){ - container_symbol = current_procedure; - } - - // get this symbol handle - U64 user_id = user_id_base + off; - CONS_Symbol *proc_symbol = cons_symbol_handle_from_user_id(ctx->root, user_id); - - // 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 pass - // 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. - CONS_Scope *root_scope = cons_scope_handle_from_user_id(ctx->root, user_id); - pdbconv_symbol_push_scope(ctx, root_scope, proc_symbol); - - // set voff range - U64 voff = 0; - COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, proc32->sec); - if (section != 0){ - U64 voff_first = section->voff + proc32->off; - U64 voff_last = voff_first + proc32->len; - cons_scope_add_voff_range(ctx->root, root_scope, voff_first, voff_last); - - voff = voff_first; - } - - // link name - String8 link_name = {0}; - if (voff != 0){ - link_name = pdbconv_link_name_find(&ctx->link_names, voff); - } - - // determine link kind - B32 is_extern = (kind == CV_SymKind_GPROC32); - - // set symbol info - CONS_SymbolInfo info = zero_struct; - info.kind = CONS_SymbolKind_Procedure; - info.name = name; - info.link_name = link_name; - info.type = type; - info.is_extern = is_extern; - info.container_type = container_type; - info.container_symbol = container_symbol; - info.root_scope = root_scope; - - cons_symbol_set_info(ctx->root, proc_symbol, &info); - } - }break; - - case CV_SymKind_REGREL32: - { - if (sizeof(CV_SymRegrel32) > cap){ - // TODO(allen): error - } - else{ - // TODO(allen): hide this when it's redundant with better information - // from a CV_SymKind_LOCAL record. - - CV_SymRegrel32 *regrel32 = (CV_SymRegrel32*)first; - - // name - String8 name = str8_cstring_capped((char*)(regrel32 + 1), first + cap); - - // type of variable - CONS_Type *type = pdbconv_type_resolve_itype(ctx, regrel32->itype); - - // extract regrel's info - CV_Reg cv_reg = regrel32->reg; - U32 var_off = regrel32->reg_off; - - // need arch for analyzing register stuff - RADDBG_Arch arch = ctx->arch; - U64 addr_size = ctx->addr_size; - - // determine if this is a parameter - RADDBG_LocalKind local_kind = RADDBG_LocalKind_Variable; - { - B32 is_stack_reg = 0; - switch (arch){ - case RADDBG_Arch_X86: is_stack_reg = (cv_reg == CV_Regx86_ESP); break; - case RADDBG_Arch_X64: is_stack_reg = (cv_reg == CV_Regx64_RSP); break; - } - if (is_stack_reg){ - U32 frame_size = 0xFFFFFFFF; - if (current_procedure != 0){ - PDBCONV_FrameProcData *frameproc = - pdbconv_symbol_frame_proc_read(ctx, current_procedure); - frame_size = frameproc->frame_size; - } - if (var_off > frame_size){ - local_kind = RADDBG_LocalKind_Parameter; - } - } - } - - // emit local - U64 user_id = user_id_base + off; - CONS_Local *local_var = cons_local_handle_from_user_id(ctx->root, user_id); - - CONS_LocalInfo info = {0}; - info.kind = local_kind; - info.scope = current_scope; - info.name = name; - info.type = type; - - cons_local_set_basic_info(ctx->root, local_var, &info); - - // add location to local - { - // will there be an extra indirection to the value - B32 extra_indirection_to_value = 0; - switch (arch){ - case RADDBG_Arch_X86: - { - if (local_kind == RADDBG_LocalKind_Parameter && - (type->byte_size > 4 || !IsPow2OrZero(type->byte_size))){ - extra_indirection_to_value = 1; - } - }break; - - case RADDBG_Arch_X64: - { - if (local_kind == RADDBG_LocalKind_Parameter && - (type->byte_size > 8 || !IsPow2OrZero(type->byte_size))){ - extra_indirection_to_value = 1; - } - }break; - } - - // get raddbg register code - RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); - // TODO(allen): real byte_size & byte_pos from cv_reg goes here - U32 byte_size = 8; - U32 byte_pos = 0; - - // set location case - CONS_Location *loc = - pdbconv_location_from_addr_reg_off(ctx, register_code, byte_size, byte_pos, - (S64)(S32)var_off, extra_indirection_to_value); - - CONS_LocationSet *locset = cons_location_set_from_local(ctx->root, local_var); - cons_location_set_add_case(ctx->root, locset, 0, max_U64, loc); - } - } - }break; - - case CV_SymKind_LTHREAD32: - case CV_SymKind_GTHREAD32: - { - if (sizeof(CV_SymThread32) > cap){ - // TODO(allen): error - } - else{ - CV_SymThread32 *thread32 = (CV_SymThread32*)first; - - // name - String8 name = str8_cstring_capped((char*)(thread32 + 1), first + cap); - - // determine tls off - U32 tls_off = thread32->tls_off; - - // type of variable - CONS_Type *type = pdbconv_type_resolve_itype(ctx, thread32->itype); - - // container type - CONS_Type *container_type = 0; - U64 container_name_opl = pdbconv_end_of_cplusplus_container_name(name); - if (container_name_opl > 2){ - String8 container_name = str8(name.str, container_name_opl - 2); - container_type = pdbconv_type_from_name(ctx, container_name); - } - - // container symbol - CONS_Symbol *container_symbol = 0; - if (container_type == 0){ - container_symbol = current_procedure; - } - - // determine link kind - B32 is_extern = (kind == CV_SymKind_GTHREAD32); - - // setup symbol - U64 user_id = user_id_base + off; - CONS_Symbol *symbol = cons_symbol_handle_from_user_id(ctx->root, user_id); - - CONS_SymbolInfo info = zero_struct; - info.kind = CONS_SymbolKind_ThreadVariable; - info.name = name; - info.type = type; - info.is_extern = is_extern; - info.offset = tls_off; - info.container_type = container_type; - info.container_symbol = container_symbol; - - cons_symbol_set_info(ctx->root, symbol, &info); - } - }break; - - case CV_SymKind_LOCAL: - { - if (sizeof(CV_SymLocal) > cap){ - // TODO(allen): error - } - else{ - CV_SymLocal *slocal = (CV_SymLocal*)first; - - // name - String8 name = str8_cstring_capped((char*)(slocal + 1), first + cap); - - // type of variable - CONS_Type *type = pdbconv_type_resolve_itype(ctx, slocal->itype); - - // determine how to handle - B32 begin_a_global_modification = 0; - if ((slocal->flags & CV_LocalFlag_Global) || - (slocal->flags & CV_LocalFlag_Static)){ - begin_a_global_modification = 1; - } - - // emit a global modification - if (begin_a_global_modification){ - // TODO(allen): add global modification symbols - defrange_target = 0; - defrange_target_is_param = 0; - } - - // emit a local variable - else{ - // local kind - RADDBG_LocalKind local_kind = RADDBG_LocalKind_Variable; - if (slocal->flags & CV_LocalFlag_Param){ - local_kind = RADDBG_LocalKind_Parameter; - } - - // emit local - U64 user_id = user_id_base + off; - CONS_Local *local_var = cons_local_handle_from_user_id(ctx->root, user_id); - - CONS_LocalInfo info = {0}; - info.kind = local_kind; - info.scope = current_scope; - info.name = name; - info.type = type; - - cons_local_set_basic_info(ctx->root, local_var, &info); - - defrange_target = cons_location_set_from_local(ctx->root, local_var); - defrange_target_is_param = (local_kind == RADDBG_LocalKind_Parameter); - } - } - }break; - - case CV_SymKind_DEFRANGE_REGISTER: - { - if (sizeof(CV_SymDefrangeRegister) > cap){ - // TODO(allen): error - } - else{ - if (defrange_target == 0){ - // TODO(allen): error - } - else{ - CV_SymDefrangeRegister *defrange_register = (CV_SymDefrangeRegister*)first; - - // TODO(allen): offset & size from cv_reg code - RADDBG_Arch arch = ctx->arch; - CV_Reg cv_reg = defrange_register->reg; - RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); - - // setup location - CONS_Location *location = cons_location_val_reg(ctx->root, register_code); - - // extract range info - CV_LvarAddrRange *range = &defrange_register->range; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register + 1); - U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); - - // emit locations - pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, - range, gaps, gap_count); - } - } - }break; - - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL: - { - if (sizeof(CV_SymDefrangeFramepointerRel) > cap){ - // TODO(allen): error - } - else{ - if (defrange_target == 0){ - // TODO(allen): error - } - else{ - CV_SymDefrangeFramepointerRel *defrange_fprel = (CV_SymDefrangeFramepointerRel*)first; - - // select frame pointer register - CV_EncodedFramePtrReg encoded_fp_reg = - pdbconv_cv_encoded_fp_reg_from_proc(ctx, current_procedure, defrange_target_is_param); - RADDBG_RegisterCode fp_register_code = - pdbconv_reg_code_from_arch_encoded_fp_reg(ctx->arch, encoded_fp_reg); - - // setup location - B32 extra_indirection = 0; - U32 byte_size = ctx->addr_size; - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel->off; - CONS_Location *location = - pdbconv_location_from_addr_reg_off(ctx, fp_register_code, byte_size, byte_pos, - var_off, extra_indirection); - - // extract range info - CV_LvarAddrRange *range = &defrange_fprel->range; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_fprel + 1); - U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); - - // emit locations - pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, - range, gaps, gap_count); - } - } - }break; - - case CV_SymKind_DEFRANGE_SUBFIELD_REGISTER: - { - if (sizeof(CV_SymDefrangeSubfieldRegister) > cap){ - // TODO(allen): error - } - else{ - if (defrange_target == 0){ - // TODO(allen): error - } - else{ - CV_SymDefrangeSubfieldRegister *defrange_subfield_register = (CV_SymDefrangeSubfieldRegister*)first; - - // TODO(allen): full "subfield" location system - if (defrange_subfield_register->field_offset == 0){ - - // TODO(allen): offset & size from cv_reg code - RADDBG_Arch arch = ctx->arch; - CV_Reg cv_reg = defrange_subfield_register->reg; - RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); - - // setup location - CONS_Location *location = cons_location_val_reg(ctx->root, register_code); - - // extract range info - CV_LvarAddrRange *range = &defrange_subfield_register->range; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_subfield_register + 1); - U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); - - // emit locations - pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, - range, gaps, gap_count); - } - } - } - }break; - - case CV_SymKind_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE: - { - if (sizeof(CV_SymDefrangeFramepointerRelFullScope) > cap){ - // TODO(allen): error - } - else{ - if (defrange_target == 0){ - // TODO(allen): error - } - else{ - CV_SymDefrangeFramepointerRelFullScope *defrange_fprel_full_scope = - (CV_SymDefrangeFramepointerRelFullScope*)first; - - // select frame pointer register - CV_EncodedFramePtrReg encoded_fp_reg = - pdbconv_cv_encoded_fp_reg_from_proc(ctx, current_procedure, defrange_target_is_param); - RADDBG_RegisterCode fp_register_code = - pdbconv_reg_code_from_arch_encoded_fp_reg(ctx->arch, encoded_fp_reg); - - // setup location - B32 extra_indirection = 0; - U32 byte_size = ctx->addr_size; - U32 byte_pos = 0; - S64 var_off = (S64)defrange_fprel_full_scope->off; - CONS_Location *location = - pdbconv_location_from_addr_reg_off(ctx, fp_register_code, byte_size, byte_pos, - var_off, extra_indirection); - - - // emit location - cons_location_set_add_case(ctx->root, defrange_target, 0, max_U64, location); - } - } - }break; - - case CV_SymKind_DEFRANGE_REGISTER_REL: - { - if (sizeof(CV_SymDefrangeRegisterRel) > cap){ - // TODO(allen): error - } - else{ - CV_SymDefrangeRegisterRel *defrange_register_rel = (CV_SymDefrangeRegisterRel*)first; - if(defrange_target == 0) - { - // TODO(rjf): error - } - else - { - // TODO(allen): offset & size from cv_reg code - RADDBG_Arch arch = ctx->arch; - CV_Reg cv_reg = defrange_register_rel->reg; - RADDBG_RegisterCode register_code = raddbg_reg_code_from_cv_reg_code(arch, cv_reg); - U32 byte_size = ctx->addr_size; - U32 byte_pos = 0; - - B32 extra_indirection_to_value = 0; - S64 var_off = defrange_register_rel->reg_off; - - // setup location - CONS_Location *location = - pdbconv_location_from_addr_reg_off(ctx, register_code, byte_size, byte_pos, - var_off, extra_indirection_to_value); - - // extract range info - CV_LvarAddrRange *range = &defrange_register_rel->range; - CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register_rel + 1); - U64 gap_count = ((first + cap) - (U8*)gaps)/sizeof(*gaps); - - - // emit locations - pdbconv_location_over_lvar_addr_range(ctx, defrange_target, location, - range, gaps, gap_count); - } - } - }break; - - case CV_SymKind_FILESTATIC: - { - if (sizeof(CV_SymFileStatic) > cap){ - // TODO(allen): error - } - else{ - CV_SymFileStatic *file_static = (CV_SymFileStatic*)first; - - // name - String8 name = str8_cstring_capped((char*)(file_static + 1), first + cap); - - // type of variable - CONS_Type *type = pdbconv_type_resolve_itype(ctx, file_static->itype); - - // TODO(allen): emit a global modifier symbol - - // defrange records from this point attach to this location information - defrange_target = 0; - defrange_target_is_param = 0; - } - }break; - } - } - - // if scope stack isn't empty emit an error - { - CONS_Scope* scope = pdbconv_symbol_current_scope(ctx); - if (scope != 0){ - // TODO(allen): emit error - } - } - - // clear the scope stack - pdbconv_symbol_clear_scope_stack(ctx); - } - - scratch_end(scratch); - ProfEnd(); -} - -static void -pdbconv_gather_link_names(PDBCONV_Ctx *ctx, CV_SymParsed *sym){ - ProfBeginFunction(); - // extract important values from parameters - String8 data = sym->data; - - // loop - CV_RecRange *rec_range = sym->sym_ranges.ranges; - CV_RecRange *opl = rec_range + sym->sym_ranges.count; - for (;rec_range < opl; rec_range += 1){ - // symbol data range - U64 opl_off_raw = rec_range->off + rec_range->hdr.size; - U64 opl_off = ClampTop(opl_off_raw, data.size); - - U64 off_raw = rec_range->off + 2; - U64 off = ClampTop(off_raw, opl_off); - - U8 *first = data.str + off; - U64 cap = (opl_off - off); - - CV_SymKind kind = rec_range->hdr.kind; - switch (kind){ - default: break; - - case CV_SymKind_PUB32: - { - if (sizeof(CV_SymPub32) > cap){ - // TODO(allen): error - } - else{ - CV_SymPub32 *pub32 = (CV_SymPub32*)first; - - // name - String8 name = str8_cstring_capped((char*)(pub32 + 1), first + cap); - - // calculate voff - U64 voff = 0; - COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, pub32->sec); - if (section != 0){ - voff = section->voff + pub32->off; - } - - // save link name - pdbconv_link_name_save(ctx->temp_arena, &ctx->link_names, voff, name); - } - }break; - } - } - ProfEnd(); -} - -// "frameproc" map - -static void -pdbconv_symbol_frame_proc_write(PDBCONV_Ctx *ctx,CONS_Symbol *key,PDBCONV_FrameProcData *data){ - U64 key_int = IntFromPtr(key); - PDBCONV_FrameProcMap *map = &ctx->frame_proc_map; - U32 bucket_idx = key_int%ArrayCount(map->buckets); - - // find match - PDBCONV_FrameProcNode *match = 0; - for (PDBCONV_FrameProcNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->key == key){ - match = node; - break; - } - } - - // if there is already a match emit error - if (match != 0){ - // TODO(allen): error - } - - // insert new association if no match - if (match == 0){ - match = push_array(ctx->temp_arena, PDBCONV_FrameProcNode, 1); - SLLStackPush(map->buckets[bucket_idx], match); - match->key = key; - MemoryCopyStruct(&match->data, data); - } -} - -static PDBCONV_FrameProcData* -pdbconv_symbol_frame_proc_read(PDBCONV_Ctx *ctx, CONS_Symbol *key){ - U64 key_int = IntFromPtr(key); - PDBCONV_FrameProcMap *map = &ctx->frame_proc_map; - U32 bucket_idx = key_int%ArrayCount(map->buckets); - - // find match - PDBCONV_FrameProcData *result = 0; - for (PDBCONV_FrameProcNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->key == key){ - result = &node->data; - break; - } - } - - return(result); -} - -// scope stack -static void -pdbconv_symbol_push_scope(PDBCONV_Ctx *ctx, CONS_Scope *scope, CONS_Symbol *symbol){ - PDBCONV_ScopeNode *node = ctx->scope_node_free; - if (node == 0){ - node = push_array(ctx->temp_arena, PDBCONV_ScopeNode, 1); - } - else{ - SLLStackPop(ctx->scope_node_free); - } - SLLStackPush(ctx->scope_stack, node); - node->scope = scope; - node->symbol = symbol; -} - -static void -pdbconv_symbol_pop_scope(PDBCONV_Ctx *ctx){ - PDBCONV_ScopeNode *node = ctx->scope_stack; - if (node != 0){ - SLLStackPop(ctx->scope_stack); - SLLStackPush(ctx->scope_node_free, node); - } -} - -static void -pdbconv_symbol_clear_scope_stack(PDBCONV_Ctx *ctx){ - for (;;){ - PDBCONV_ScopeNode *node = ctx->scope_stack; - if (node == 0){ - break; - } - SLLStackPop(ctx->scope_stack); - SLLStackPush(ctx->scope_node_free, node); - } -} - -// PDB/C++ name parsing helper - -static U64 -pdbconv_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); -} - -// known global set - -static U64 -pdbconv_known_global_hash(String8 name, U64 voff){ - U64 result = 5381 ^ voff; - U8 *ptr = name.str; - U8 *opl = ptr + name.size; - for (; ptr < opl; ptr += 1){ - result = ((result << 5) + result) + *ptr; - } - return(result); -} - -static B32 -pdbconv_known_global_lookup(PDBCONV_KnownGlobalSet *set, String8 name, U64 voff){ - U64 hash = pdbconv_known_global_hash(name, voff); - U64 bucket_idx = hash%ArrayCount(set->buckets); - - PDBCONV_KnownGlobalNode *match = 0; - for (PDBCONV_KnownGlobalNode *node = set->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->hash == hash && - node->key_voff == voff && - str8_match(node->key_name, name, 0)){ - match = node; - break; - } - } - - B32 result = (match != 0); - return(result); -} - -static void -pdbconv_known_global_insert(Arena *arena, PDBCONV_KnownGlobalSet *set, String8 name, U64 voff){ - U64 hash = pdbconv_known_global_hash(name, voff); - U64 bucket_idx = hash%ArrayCount(set->buckets); - - PDBCONV_KnownGlobalNode *match = 0; - for (PDBCONV_KnownGlobalNode *node = set->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->hash == hash && - node->key_voff == voff && - str8_match(node->key_name, name, 0)){ - match = node; - break; - } - } - - if (match == 0){ - PDBCONV_KnownGlobalNode *node = push_array(arena, PDBCONV_KnownGlobalNode, 1); - SLLStackPush(set->buckets[bucket_idx], node); - node->key_name = push_str8_copy(arena, name); - node->key_voff = voff; - node->hash = hash; - } -} - -// location info helpers - -static CONS_Location* -pdbconv_location_from_addr_reg_off(PDBCONV_Ctx *ctx, - RADDBG_RegisterCode reg_code, - U32 reg_byte_size, - U32 reg_byte_pos, - S64 offset, - B32 extra_indirection){ - CONS_Location *result = 0; - if (0 <= offset && offset <= (S64)max_U16){ - if (extra_indirection){ - result = cons_location_addr_addr_reg_plus_u16(ctx->root, reg_code, (U16)offset); - } - else{ - result = cons_location_addr_reg_plus_u16(ctx->root, reg_code, (U16)offset); - } - } - else{ - Arena *arena = ctx->temp_arena; - - CONS_EvalBytecode bytecode = {0}; - U32 regread_param = RADDBG_EncodeRegReadParam(reg_code, reg_byte_size, reg_byte_pos); - cons_bytecode_push_op(arena, &bytecode, RADDBG_EvalOp_RegRead, regread_param); - cons_bytecode_push_sconst(arena, &bytecode, offset); - cons_bytecode_push_op(arena, &bytecode, RADDBG_EvalOp_Add, 0); - if (extra_indirection){ - cons_bytecode_push_op(arena, &bytecode, RADDBG_EvalOp_MemRead, ctx->addr_size); - } - - result = cons_location_addr_bytecode_stream(ctx->root, &bytecode); - } - - return(result); -} - -static CV_EncodedFramePtrReg -pdbconv_cv_encoded_fp_reg_from_proc(PDBCONV_Ctx *ctx, CONS_Symbol *proc, B32 param_base){ - CV_EncodedFramePtrReg result = 0; - if (proc != 0){ - PDBCONV_FrameProcData *frame_proc = pdbconv_symbol_frame_proc_read(ctx, proc); - CV_FrameprocFlags flags = frame_proc->flags; - if (param_base){ - result = CV_FrameprocFlags_ExtractParamBasePointer(flags); - } - else{ - result = CV_FrameprocFlags_ExtractLocalBasePointer(flags); - } - } - return(result); -} - -static RADDBG_RegisterCode -pdbconv_reg_code_from_arch_encoded_fp_reg(RADDBG_Arch arch, CV_EncodedFramePtrReg encoded_reg){ - RADDBG_RegisterCode result = 0; - - switch (arch){ - case RADDBG_Arch_X86: - { - switch (encoded_reg){ - case CV_EncodedFramePtrReg_StackPtr: - { - // TODO(allen): support CV_AllReg_VFRAME - // TODO(allen): error - }break; - case CV_EncodedFramePtrReg_FramePtr: - { - result = RADDBG_RegisterCode_X86_ebp; - }break; - case CV_EncodedFramePtrReg_BasePtr: - { - result = RADDBG_RegisterCode_X86_ebx; - }break; - } - }break; - - case RADDBG_Arch_X64: - { - switch (encoded_reg){ - case CV_EncodedFramePtrReg_StackPtr: - { - result = RADDBG_RegisterCode_X64_rsp; - }break; - case CV_EncodedFramePtrReg_FramePtr: - { - result = RADDBG_RegisterCode_X64_rbp; - }break; - case CV_EncodedFramePtrReg_BasePtr: - { - result = RADDBG_RegisterCode_X64_r13; - }break; - } - }break; - } - - return(result); -} - -static void -pdbconv_location_over_lvar_addr_range(PDBCONV_Ctx *ctx, - CONS_LocationSet *locset, - CONS_Location *location, - CV_LvarAddrRange *range, - CV_LvarAddrGap *gaps, U64 gap_count){ - // extract range info - U64 voff_first = 0; - U64 voff_opl = 0; - { - COFF_SectionHeader *section = pdbconv_sec_header_from_sec_num(ctx, range->sec); - if (section != 0){ - voff_first = section->voff + range->off; - voff_opl = voff_first + range->len; - } - } - - // 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){ - cons_location_set_add_case(ctx->root, locset, voff_cursor, voff_gap_first, location); - } - voff_cursor = voff_gap_opl; - } - - if (voff_cursor < voff_opl){ - cons_location_set_add_case(ctx->root, locset, voff_cursor, voff_opl, location); - } -} - -// link names - -static void -pdbconv_link_name_save(Arena *arena, PDBCONV_LinkNameMap *map, U64 voff, String8 name){ - U64 hash = (voff >> 3) ^ ((7 & voff) << 6); - U64 bucket_idx = hash%ArrayCount(map->buckets); - - PDBCONV_LinkNameNode *node = push_array(arena, PDBCONV_LinkNameNode, 1); - SLLStackPush(map->buckets[bucket_idx], node); - node->voff = voff; - node->name = push_str8_copy(arena, name); -} - -static String8 -pdbconv_link_name_find(PDBCONV_LinkNameMap *map, U64 voff){ - U64 hash = (voff >> 3) ^ ((7 & voff) << 6); - U64 bucket_idx = hash%ArrayCount(map->buckets); - - String8 result = {0}; - for (PDBCONV_LinkNameNode *node = map->buckets[bucket_idx]; - node != 0; - node = node->next){ - if (node->voff == voff){ - result = node->name; - break; - } - } - - return(result); -} - -//////////////////////////////// -//~ Conversion Path - -static PDBCONV_Out * -pdbconv_convert(Arena *arena, PDBCONV_Params *params) -{ - PDBCONV_Out *out = push_array(arena, PDBCONV_Out, 1); - out->good_parse = 1; - - // will we try to parse an input file? - B32 try_parse_input = (params->errors.node_count == 0); - -#define PARSE_CHECK_ERROR(p,fmt,...) do{ if ((p) == 0){\ -out->good_parse = 0;\ -str8_list_pushf(arena, &out->errors, fmt, __VA_ARGS__);\ -} }while(0) - - // parse msf file - MSF_Parsed *msf = 0; - if (try_parse_input) ProfScope("parse msf"){ - msf = msf_parsed_from_data(arena, params->input_pdb_data); - PARSE_CHECK_ERROR(msf, "MSF"); - } - - // parse pdb info - PDB_NamedStreamTable *named_streams = 0; - COFF_Guid auth_guid = {0}; - if (msf != 0) ProfScope("parse pdb info"){ - Temp scratch = scratch_begin(&arena, 1); - - String8 info_data = msf_data_from_stream(msf, PDB_FixedStream_PdbInfo); - 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); - - PARSE_CHECK_ERROR(named_streams, "named streams from pdb info"); - } - - // parse strtbl - PDB_Strtbl *strtbl = 0; - if (named_streams != 0) ProfScope("parse strtbl"){ - MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_STRTABLE]; - String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); - strtbl = pdb_strtbl_from_data(arena, strtbl_data); - - PARSE_CHECK_ERROR(strtbl, "string table"); - } - - // 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); - - PARSE_CHECK_ERROR(dbi, "DBI"); - } - - // 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); - - PARSE_CHECK_ERROR(tpi, "TPI"); - } - - // 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); - - PARSE_CHECK_ERROR(ipi, "IPI"); - } - - // parse coff sections - PDB_CoffSectionArray *coff_sections = 0; - U64 coff_section_count = 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); - coff_section_count = coff_sections->count; - - PARSE_CHECK_ERROR(coff_sections, "coff sections"); - } - - // 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); - - PARSE_CHECK_ERROR(gsi, "GSI"); - } - - // 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); - - PARSE_CHECK_ERROR(psi_gsi_part, "PSI"); - } - - // parse tpi hash - PDB_TpiHashParsed *tpi_hash = 0; - if (tpi != 0) ProfScope("parse tpi hash"){ - String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); - String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); - tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data); - - PARSE_CHECK_ERROR(tpi_hash, "TPI hash table"); - } - - // parse tpi leaves - CV_LeafParsed *tpi_leaf = 0; - if (tpi != 0) ProfScope("parse tpi leaves"){ - String8 leaf_data = pdb_leaf_data_from_tpi(tpi); - tpi_leaf = cv_leaf_from_data(arena, leaf_data, tpi->itype_first); - - PARSE_CHECK_ERROR(tpi_hash, "TPI leaf data"); - } - - // parse ipi hash - PDB_TpiHashParsed *ipi_hash = 0; - if (ipi != 0) ProfScope("parse ipi hash"){ - String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); - String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); - ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data); - - PARSE_CHECK_ERROR(tpi_hash, "IPI hash table"); - } - - // parse ipi leaves - CV_LeafParsed *ipi_leaf = 0; - if (ipi != 0) ProfScope("parse ipi leaves"){ - String8 leaf_data = pdb_leaf_data_from_tpi(ipi); - ipi_leaf = cv_leaf_from_data(arena, leaf_data, ipi->itype_first); - - PARSE_CHECK_ERROR(tpi_hash, "IPI leaf data"); - } - - // parse sym - CV_SymParsed *sym = 0; - if (dbi != 0) ProfScope("parse sym"){ - String8 sym_data = msf_data_from_stream(msf, dbi->sym_sn); - sym = cv_sym_from_data(arena, sym_data, 4); - - PARSE_CHECK_ERROR(tpi_hash, "public SYM data"); - } - - // parse compilation units - PDB_CompUnitArray *comp_units = 0; - U64 comp_unit_count = 0; - if (dbi != 0) ProfScope("parse compilation units"){ - String8 mod_info_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_ModuleInfo); - comp_units = pdb_comp_unit_array_from_data(arena, mod_info_data); - comp_unit_count = comp_units->count; - - PARSE_CHECK_ERROR(comp_units, "module info"); - } - - // parse dbi's section contributions - PDB_CompUnitContributionArray *comp_unit_contributions = 0; - U64 comp_unit_contribution_count = 0; - if (dbi != 0 && coff_sections != 0) ProfScope("parse dbi section contributions"){ - String8 section_contribution_data = pdb_data_from_dbi_range(dbi, PDB_DbiRange_SecCon); - comp_unit_contributions = - pdb_comp_unit_contribution_array_from_data(arena, section_contribution_data, coff_sections); - comp_unit_contribution_count = comp_unit_contributions->count; - - PARSE_CHECK_ERROR(comp_unit_contributions, "module contributions"); - } - - // parse syms for each compilation unit - CV_SymParsed **sym_for_unit = push_array(arena, CV_SymParsed*, comp_unit_count); - if (comp_units != 0) ProfScope("parse symbols"){ - PDB_CompUnit **unit_ptr = comp_units->units; - for (U64 i = 0; i < comp_unit_count; i += 1, unit_ptr += 1){ - CV_SymParsed *unit_sym = 0; - { - String8 sym_data = pdb_data_from_unit_range(msf, *unit_ptr, PDB_DbiCompUnitRange_Symbols); - unit_sym = cv_sym_from_data(arena, sym_data, 4); - } - PARSE_CHECK_ERROR(unit_sym, "module (i=%llu) SYM data", i); - - sym_for_unit[i] = unit_sym; - } - } - - // parse c13 for each compilation unit - CV_C13Parsed **c13_for_unit = push_array(arena, CV_C13Parsed*, comp_unit_count); - if (comp_units != 0) ProfScope("parse c13s"){ - PDB_CompUnit **unit_ptr = comp_units->units; - for (U64 i = 0; i < comp_unit_count; i += 1, unit_ptr += 1){ - CV_C13Parsed *unit_c13 = 0; - { - String8 c13_data = pdb_data_from_unit_range(msf, *unit_ptr, PDB_DbiCompUnitRange_C13); - unit_c13 = cv_c13_from_data(arena, c13_data, strtbl, coff_sections); - } - PARSE_CHECK_ERROR(unit_c13, "module (i=%llu) C13 line info", i); - - c13_for_unit[i] = unit_c13; - } - } - - // parsing error - if (try_parse_input && !out->good_parse && - !params->hide_errors.parsing){ - str8_list_pushf(arena, &out->errors, "error(parsing): '%S' as a PDB\n", params->input_pdb_name); - } - - // exe hash - U64 exe_hash = 0; - if (out->good_parse && params->input_exe_data.size > 0) ProfScope("hash exe"){ - exe_hash = raddbg_hash(params->input_exe_data.str, params->input_exe_data.size); - } - - // dump - if (params->dump) ProfScope("dump"){ - String8List dump = {0}; - - // EXE - if (out->good_parse){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "EXE INFO:\n")); - { - str8_list_pushf(arena, &dump, "HASH: %016llX\n", exe_hash); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // MSF - if (params->dump_msf){ - if (msf != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "MSF:\n")); - - str8_list_pushf(arena, &dump, " block_size=%llu\n", msf->block_size); - str8_list_pushf(arena, &dump, " block_count=%llu\n", msf->block_count); - str8_list_pushf(arena, &dump, " stream_count=%llu\n", msf->stream_count); - - String8 *stream_ptr = msf->streams; - U64 stream_count = msf->stream_count; - for (U64 i = 0; i < stream_count; i += 1, stream_ptr += 1){ - str8_list_pushf(arena, &dump, " stream[%u].size=%llu\n", - i, stream_ptr->size); - } - - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - - // DBI - if (params->dump_sym){ - if (sym != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "DBI SYM:\n")); - cv_stringize_sym_parsed(arena, &dump, sym); - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - - // TPI - if (params->dump_tpi_hash){ - if (tpi_hash != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "TPI HASH:\n")); - pdb_stringize_tpi_hash(arena, &dump, tpi_hash); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - if (ipi_hash != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "IPI HASH:\n")); - pdb_stringize_tpi_hash(arena, &dump, ipi_hash); - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - - // LEAF - if (params->dump_leaf){ - if (tpi_leaf != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "TPI LEAF:\n")); - cv_stringize_leaf_parsed(arena, &dump, tpi_leaf); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - if (ipi_leaf != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "IPI LEAF:\n")); - cv_stringize_leaf_parsed(arena, &dump, ipi_leaf); - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - - // BINARY SECTIONS - if (params->dump_coff_sections){ - if (coff_sections != 0){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "COFF SECTIONS:\n")); - COFF_SectionHeader *section_ptr = coff_sections->sections; - for (U64 i = 0; i < coff_section_count; i += 1, section_ptr += 1){ - // TODO(allen): probably should pull this out into a separate stringize path - // for the coff section type - char *first = (char*)section_ptr->name; - char *opl = first + sizeof(section_ptr->name); - String8 name = str8_cstring_capped(first, opl); - str8_list_pushf(arena, &dump, " %.*s:\n", str8_varg(name)); - str8_list_pushf(arena, &dump, " vsize=%u\n", section_ptr->vsize); - str8_list_pushf(arena, &dump, " voff =0x%x\n", section_ptr->voff); - str8_list_pushf(arena, &dump, " fsize=%u\n", section_ptr->fsize); - str8_list_pushf(arena, &dump, " foff =0x%x\n", section_ptr->foff); - str8_list_pushf(arena, &dump, " relocs_foff=0x%x\n", section_ptr->relocs_foff); - str8_list_pushf(arena, &dump, " lines_foff =0x%x\n", section_ptr->lines_foff); - str8_list_pushf(arena, &dump, " reloc_count=%u\n", section_ptr->reloc_count); - str8_list_pushf(arena, &dump, " line_count =%u\n", section_ptr->line_count); - // TODO(allen): better flags - str8_list_pushf(arena, &dump, " flags=%x\n", section_ptr->flags); - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - } - - // UNITS - if (comp_units != 0){ - B32 dump_sym = params->dump_sym; - B32 dump_c13 = params->dump_c13; - - B32 dump_units = (dump_sym || dump_c13); - - if (dump_units){ - PDB_CompUnit **unit_ptr = comp_units->units; - for (U64 i = 0; i < comp_unit_count; i += 1, unit_ptr += 1){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n")); - String8 name = (*unit_ptr)->obj_name; - String8 group_name = (*unit_ptr)->group_name; - str8_list_pushf(arena, &dump, "[%llu] %.*s\n(%.*s):\n", - i, str8_varg(name), str8_varg(group_name)); - if (dump_sym){ - cv_stringize_sym_parsed(arena, &dump, sym_for_unit[i]); - } - if (dump_c13){ - cv_stringize_c13_parsed(arena, &dump, c13_for_unit[i]); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - } - - // UNIT CONTRIBUTIONS - if (comp_unit_contributions != 0){ - if (params->dump_contributions){ - str8_list_push(arena, &dump, - str8_lit("################################" - "################################\n" - "UNIT CONTRIBUTIONS:\n")); - PDB_CompUnitContribution *contrib_ptr = comp_unit_contributions->contributions; - for (U64 i = 0; i < comp_unit_contribution_count; i += 1, contrib_ptr += 1){ - str8_list_pushf(arena, &dump, - " { mod = %5u; voff_first = %08llx; voff_opl = %08llx; }\n", - contrib_ptr->mod, contrib_ptr->voff_first, contrib_ptr->voff_opl); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - - out->dump = dump; - } - - // output generation - if (params->output_name.size > 0){ - - // determine arch - RADDBG_Arch architecture = RADDBG_Arch_NULL; - // TODO(rjf): in some cases, the first compilation unit has a zero - // architecture, as it's sometimes used as a "nil" unit. this causes bugs - // in later stages of conversion - particularly, this was detected via - // busted location info. so i've converted this to a scan-until-we-find-an- - // architecture. however, this is still fundamentally insufficient, because - // Nick has informed me that x86 units can be linked with x64 units, - // meaning the appropriate architecture at any point in time is not a top- - // level concept, and is rather dependent on to which compilation unit - // particular symbols belong. so in the future, to support that (odd) case, - // we'll need to not only have this be a top-level "contextual" piece of - // info, but to use the appropriate compilation unit's architecture when - // possible. - // - for(U64 comp_unit_idx = 0; comp_unit_idx < comp_unit_count; comp_unit_idx += 1) - { - if(sym_for_unit[comp_unit_idx] != 0) - { - architecture = raddbg_arch_from_cv_arch(sym_for_unit[comp_unit_idx]->info.arch); - if(architecture != 0) - { - break; - } - } - } - U64 addr_size = raddbg_addr_size_from_arch(architecture); - - - // predict symbol counts - U64 symbol_count_prediction = 0; - { - U64 rec_range_count = 0; - if (sym != 0){ - rec_range_count += sym->sym_ranges.count; - } - for (U64 i = 0; i < comp_unit_count; i += 1){ - CV_SymParsed *unit_sym = sym_for_unit[i]; - rec_range_count += unit_sym->sym_ranges.count; - } - symbol_count_prediction = rec_range_count/8; - if (symbol_count_prediction < 128){ - symbol_count_prediction = 128; - } - } - - - // setup root - CONS_RootParams root_params = {0}; - root_params.addr_size = addr_size; - - root_params.bucket_count_units = comp_unit_count; - root_params.bucket_count_symbols = symbol_count_prediction; - root_params.bucket_count_scopes = symbol_count_prediction; - root_params.bucket_count_locals = symbol_count_prediction; - root_params.bucket_count_types = tpi->itype_opl; - - CONS_Root *root = cons_root_new(&root_params); - out->root = root; - - // top level info - { - // calculate voff max - U64 voff_max = 0; - { - COFF_SectionHeader *coff_sec_ptr = coff_sections->sections; - COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_section_count; - for (;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1){ - U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; - voff_max = Max(voff_max, sec_voff_max); - } - } - - // set top level info - CONS_TopLevelInfo tli = {0}; - tli.architecture = architecture; - tli.exe_name = params->input_exe_name; - tli.exe_hash = exe_hash; - tli.voff_max = voff_max; - - cons_set_top_level_info(root, &tli); - } - - - // setup binary sections - { - COFF_SectionHeader *coff_ptr = coff_sections->sections; - COFF_SectionHeader *coff_opl = coff_ptr + coff_section_count; - for (;coff_ptr < coff_opl; coff_ptr += 1){ - char *name_first = (char*)coff_ptr->name; - char *name_opl = name_first + sizeof(coff_ptr->name); - String8 name = str8_cstring_capped(name_first, name_opl); - RADDBG_BinarySectionFlags flags = - raddbg_binary_section_flags_from_coff_section_flags(coff_ptr->flags); - cons_add_binary_section(root, name, flags, - coff_ptr->voff, coff_ptr->voff + coff_ptr->vsize, - coff_ptr->foff, coff_ptr->foff + coff_ptr->fsize); - } - } - - - // setup compilation units - { - PDB_CompUnit **units = comp_units->units; - for (U64 i = 0; i < comp_unit_count; i += 1){ - PDB_CompUnit *unit = units[i]; - CV_SymParsed *unit_sym = sym_for_unit[i]; - CV_C13Parsed *unit_c13 = c13_for_unit[i]; - - // resolve names - String8 raw_name = unit->obj_name; - - String8 unit_name = raw_name; - { - U64 first_after_slashes = 0; - for (S64 i = unit_name.size - 1; i >= 0; i -= 1){ - if (unit_name.str[i] == '/' || unit_name.str[i] == '\\'){ - first_after_slashes = i + 1; - break; - } - } - unit_name = str8_range(raw_name.str + first_after_slashes, - raw_name.str + raw_name.size); - } - - String8 obj_name = raw_name; - if (str8_match(obj_name, str8_lit("* Linker *"), 0) || - str8_match(obj_name, str8_lit("Import:"), - StringMatchFlag_RightSideSloppy)){ - MemoryZeroStruct(&obj_name); - } - - String8 compiler_name = unit_sym->info.compiler_name; - String8 archive_file = unit->group_name; - - // extract langauge - RADDBG_Language lang = raddbg_language_from_cv_language(sym->info.language); - - // basic per unit info - CONS_Unit *unit_handle = cons_unit_handle_from_user_id(root, i); - - CONS_UnitInfo info = {0}; - info.unit_name = unit_name; - info.compiler_name = compiler_name; - info.object_file = obj_name; - info.archive_file = archive_file; - info.language = lang; - - cons_unit_set_info(root, unit_handle, &info); - - // unit's line info - for (CV_C13SubSectionNode *node = unit_c13->first_sub_section; - node != 0; - node = node->next){ - if (node->kind == CV_C13_SubSectionKind_Lines){ - CV_C13LinesParsed *lines = node->lines; - if (lines != 0){ - CONS_LineSequence seq = {0}; - seq.file_name = lines->file_name; - seq.voffs = lines->voffs; - seq.line_nums = lines->line_nums; - seq.col_nums = lines->col_nums; - seq.line_count = lines->line_count; - cons_unit_add_line_sequence(root, unit_handle, &seq); - } - } - } - } - } - - - // unit vmap ranges - { - PDB_CompUnitContribution *contrib_ptr = comp_unit_contributions->contributions; - PDB_CompUnitContribution *contrib_opl = contrib_ptr + comp_unit_contribution_count; - for (;contrib_ptr < contrib_opl; contrib_ptr += 1){ - if (contrib_ptr->mod < root->unit_count){ - CONS_Unit *unit_handle = cons_unit_handle_from_user_id(root, contrib_ptr->mod); - cons_unit_vmap_add_range(root, unit_handle, - contrib_ptr->voff_first, - contrib_ptr->voff_opl); - } - } - } - - - // types & symbols - { - PDBCONV_TypesSymbolsParams pdb_params = {0}; - pdb_params.architecture = architecture; - pdb_params.sym = sym; - pdb_params.sym_for_unit = sym_for_unit; - pdb_params.unit_count = comp_unit_count; - pdb_params.tpi_hash = tpi_hash; - pdb_params.tpi_leaf = tpi_leaf; - pdb_params.sections = coff_sections; - - pdbconv_types_and_symbols(&pdb_params, root); - } - - - // conversion errors - if (!params->hide_errors.converting){ - for (CONS_Error *error = cons_get_first_error(root); - error != 0; - error = error->next){ - str8_list_push(arena, &out->errors, error->msg); - } - } - } - - return out; -} diff --git a/src/raddbg_convert/pdb/raddbg_from_pdb.h b/src/raddbg_convert/pdb/raddbg_from_pdb.h deleted file mode 100644 index c4e8e9e6..00000000 --- a/src/raddbg_convert/pdb/raddbg_from_pdb.h +++ /dev/null @@ -1,262 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_FROM_PDB_H -#define RADDBG_FROM_PDB_H - -//////////////////////////////// -//~ Program Parameters Type - -typedef struct PDBCONV_Params{ - String8 input_pdb_name; - String8 input_pdb_data; - - String8 input_exe_name; - String8 input_exe_data; - - String8 output_name; - - struct{ - B8 input; - B8 output; - B8 parsing; - B8 converting; - } hide_errors; - - B8 dump; - B8 dump__first; - B8 dump_coff_sections; - B8 dump_msf; - B8 dump_sym; - B8 dump_tpi_hash; - B8 dump_leaf; - B8 dump_c13; - B8 dump_contributions; - B8 dump__last; - - String8List errors; -} PDBCONV_Params; - -//////////////////////////////// -//~ Program Parameters Parser - -static PDBCONV_Params *pdb_convert_params_from_cmd_line(Arena *arena, CmdLine *cmdline); - -//////////////////////////////// -//~ PDB Type & Symbol Info Translation Helpers - -//- translation helper types -typedef struct PDBCONV_FwdNode{ - struct PDBCONV_FwdNode *next; - CV_TypeId key; - CV_TypeId val; -} PDBCONV_FwdNode; - -typedef struct PDBCONV_FwdMap{ - PDBCONV_FwdNode *buckets[1<<24]; -} PDBCONV_FwdMap; - -typedef struct PDBCONV_TypeRev{ - struct PDBCONV_TypeRev *next; - CONS_Type *owner_type; - CV_TypeId field_itype; -} PDBCONV_TypeRev; - -typedef struct PDBCONV_FrameProcData{ - U32 frame_size; - CV_FrameprocFlags flags; -} PDBCONV_FrameProcData; - -typedef struct PDBCONV_FrameProcNode{ - struct PDBCONV_FrameProcNode *next; - CONS_Symbol *key; - PDBCONV_FrameProcData data; -} PDBCONV_FrameProcNode; - -typedef struct PDBCONV_FrameProcMap{ - PDBCONV_FrameProcNode *buckets[1<<24]; -} PDBCONV_FrameProcMap; - -typedef struct PDBCONV_ScopeNode{ - struct PDBCONV_ScopeNode *next; - CONS_Scope *scope; - CONS_Symbol *symbol; -} PDBCONV_ScopeNode; - -typedef struct PDBCONV_KnownGlobalNode{ - struct PDBCONV_KnownGlobalNode *next; - String8 key_name; - U64 key_voff; - U64 hash; -} PDBCONV_KnownGlobalNode; - -typedef struct PDBCONV_KnownGlobalSet{ - PDBCONV_KnownGlobalNode *buckets[1<<24]; -} PDBCONV_KnownGlobalSet; - -typedef struct PDBCONV_TypesSymbolsParams{ - RADDBG_Arch architecture; - CV_SymParsed *sym; - CV_SymParsed **sym_for_unit; - U64 unit_count; - PDB_TpiHashParsed *tpi_hash; - CV_LeafParsed *tpi_leaf; - PDB_CoffSectionArray *sections; -} PDBCONV_TypesSymbolsParams; - -typedef struct PDBCONV_LinkNameNode{ - struct PDBCONV_LinkNameNode *next; - U64 voff; - String8 name; -} PDBCONV_LinkNameNode; - -typedef struct PDBCONV_LinkNameMap{ - PDBCONV_LinkNameNode *buckets[1<<24]; -} PDBCONV_LinkNameMap; - -typedef struct PDBCONV_Ctx{ - // INPUT data - RADDBG_Arch arch; - U64 addr_size; - PDB_TpiHashParsed *hash; - CV_LeafParsed *leaf; - COFF_SectionHeader *sections; - U64 section_count; - - // OUTPUT data - CONS_Root *root; - - // TEMPORARY STATE - Arena *temp_arena; - PDBCONV_FwdMap fwd_map; - PDBCONV_TypeRev *member_revisit_first; - PDBCONV_TypeRev *member_revisit_last; - PDBCONV_TypeRev *enum_revisit_first; - PDBCONV_TypeRev *enum_revisit_last; - PDBCONV_FrameProcMap frame_proc_map; - PDBCONV_ScopeNode *scope_stack; - PDBCONV_ScopeNode *scope_node_free; - PDBCONV_KnownGlobalSet known_globals; - PDBCONV_LinkNameMap link_names; -} PDBCONV_Ctx; - -//- pdb types and symbols -static void pdbconv_types_and_symbols(PDBCONV_TypesSymbolsParams *params, CONS_Root *out_root); - -//- decoding helpers -static U32 pdbconv_u32_from_numeric(PDBCONV_Ctx *ctx, CV_NumericParsed *num); -static COFF_SectionHeader* pdbconv_sec_header_from_sec_num(PDBCONV_Ctx *ctx, U32 sec_num); - -//- type info - -// TODO(allen): explain the overarching pattern of PDB type info translation here -// 1. main passes (out of order necessity) & after -// 2. resolve forward -// 3. cons type info -// 4. "resolve itype" -// 5. equipping members & enumerates -// 6. equipping source coordinates - -// type info construction passes -static void pdbconv_type_cons_main_passes(PDBCONV_Ctx *ctx); - -static CV_TypeId pdbconv_type_resolve_fwd(PDBCONV_Ctx *ctx, CV_TypeId itype); -static CONS_Type* pdbconv_type_resolve_itype(PDBCONV_Ctx *ctx, CV_TypeId itype); -static void pdbconv_type_equip_members(PDBCONV_Ctx *ctx, CONS_Type *owern_type, - CV_TypeId field_itype); -static void pdbconv_type_equip_enumerates(PDBCONV_Ctx *ctx, CONS_Type *owner_type, - CV_TypeId field_itype); - -// type info construction helpers -static CONS_Type* pdbconv_type_cons_basic(PDBCONV_Ctx *ctx, CV_TypeId itype); -static CONS_Type* pdbconv_type_cons_leaf_record(PDBCONV_Ctx *ctx, CV_TypeId itype); -static CONS_Type* pdbconv_type_resolve_and_check(PDBCONV_Ctx *ctx, CV_TypeId itype); -static void pdbconv_type_resolve_arglist(Arena *arena, CONS_TypeList *out, - PDBCONV_Ctx *ctx, CV_TypeId arglist_itype); - -// type info resolution helpers -static CONS_Type* pdbconv_type_from_name(PDBCONV_Ctx *ctx, String8 name); - -// type fwd map -static void pdbconv_type_fwd_map_set(Arena *arena, PDBCONV_FwdMap *map, - CV_TypeId key, CV_TypeId val); -static CV_TypeId pdbconv_type_fwd_map_get(PDBCONV_FwdMap *map, CV_TypeId key); - - -//- symbol info - -// symbol info construction -static void pdbconv_symbol_cons(PDBCONV_Ctx *ctx, CV_SymParsed *sym, U32 sym_unique_id); -static void pdbconv_gather_link_names(PDBCONV_Ctx *ctx, CV_SymParsed *sym); - -// "frameproc" map -static void pdbconv_symbol_frame_proc_write(PDBCONV_Ctx *ctx,CONS_Symbol *key, - PDBCONV_FrameProcData *data); -static PDBCONV_FrameProcData* pdbconv_symbol_frame_proc_read(PDBCONV_Ctx *ctx, CONS_Symbol *key); - -// scope stack -static void pdbconv_symbol_push_scope(PDBCONV_Ctx *ctx, CONS_Scope *scope, CONS_Symbol *symbol); -static void pdbconv_symbol_pop_scope(PDBCONV_Ctx *ctx); -static void pdbconv_symbol_clear_scope_stack(PDBCONV_Ctx *ctx); - -#define pdbconv_symbol_current_scope(ctx) \ -((ctx)->scope_stack == 0)?0:((ctx)->scope_stack->scope) - -#define pdbconv_symbol_current_symbol(ctx) \ -((ctx)->scope_stack == 0)?0:((ctx)->scope_stack->symbol) - -// PDB/C++ name parsing helper -static U64 pdbconv_end_of_cplusplus_container_name(String8 str); - -// global deduplication -static U64 pdbconv_known_global_hash(String8 name, U64 voff); - -static B32 pdbconv_known_global_lookup(PDBCONV_KnownGlobalSet *set, String8 name, U64 voff); -static void pdbconv_known_global_insert(Arena *arena, PDBCONV_KnownGlobalSet *set, - String8 name, U64 voff); - - -// location info helpers -static CONS_Location* pdbconv_location_from_addr_reg_off(PDBCONV_Ctx *ctx, - RADDBG_RegisterCode reg_code, - U32 reg_byte_size, - U32 reg_byte_pos, - S64 offset, - B32 extra_indirection); - -static CV_EncodedFramePtrReg pdbconv_cv_encoded_fp_reg_from_proc(PDBCONV_Ctx *ctx, - CONS_Symbol *proc, - B32 param_base); - -static RADDBG_RegisterCode pdbconv_reg_code_from_arch_encoded_fp_reg(RADDBG_Arch arch, - CV_EncodedFramePtrReg encoded_reg); - -static void pdbconv_location_over_lvar_addr_range(PDBCONV_Ctx *ctx, - CONS_LocationSet *locset, - CONS_Location *location, - CV_LvarAddrRange *range, - CV_LvarAddrGap *gaps, U64 gap_count); - -// link names -static void pdbconv_link_name_save(Arena *arena, PDBCONV_LinkNameMap *map, - U64 voff, String8 name); -static String8 pdbconv_link_name_find(PDBCONV_LinkNameMap *map, U64 voff); - -//////////////////////////////// -//~ Conversion Output Type - -typedef struct PDBCONV_Out PDBCONV_Out; -struct PDBCONV_Out -{ - B32 good_parse; - CONS_Root *root; - String8List dump; - String8List errors; -}; - -//////////////////////////////// -//~ Conversion Path - -static PDBCONV_Out *pdbconv_convert(Arena *arena, PDBCONV_Params *params); - -#endif //RADDBG_FROM_PDB_H diff --git a/src/raddbg_convert/pdb/raddbg_from_pdb_main.c b/src/raddbg_convert/pdb/raddbg_from_pdb_main.c deleted file mode 100644 index 2ce33e5c..00000000 --- a/src/raddbg_convert/pdb/raddbg_from_pdb_main.c +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "coff/coff.h" -#include "raddbg_format/raddbg_format.h" -#include "raddbg_cons/raddbg_cons.h" - -#include "raddbg_coff.h" -#include "raddbg_codeview.h" -#include "raddbg_msf.h" -#include "raddbg_pdb.h" -#include "raddbg_coff_conversion.h" -#include "raddbg_codeview_conversion.h" - -#include "raddbg_codeview_stringize.h" -#include "raddbg_pdb_stringize.h" - -#include "raddbg_from_pdb.h" - -#include "base/base_inc.c" -#include "coff/coff.c" -#include "os/os_inc.c" -#include "raddbg_format/raddbg_format.c" -#include "raddbg_cons/raddbg_cons.c" - -#include "raddbg_msf.c" -#include "raddbg_codeview.c" -#include "raddbg_pdb.c" -#include "raddbg_coff_conversion.c" -#include "raddbg_codeview_conversion.c" - -#include "raddbg_codeview_stringize.c" -#include "raddbg_pdb_stringize.c" - -#include "raddbg_from_pdb.c" - -int -main(int argc, char **argv){ - local_persist TCTX main_thread_tctx = {0}; - tctx_init_and_equip(&main_thread_tctx); -#if PROFILE_TELEMETRY - U64 tm_data_size = GB(1); - U8 *tm_data = os_reserve(tm_data_size); - os_commit(tm_data, tm_data_size); - tmLoadLibrary(TM_RELEASE); - tmSetMaxThreadCount(1024); - tmInitialize(tm_data_size, tm_data); -#endif - - ThreadName("[main]"); - - Arena *arena = arena_alloc(); - String8List args = os_string_list_from_argcv(arena, argc, argv); - CmdLine cmdline = cmd_line_from_string_list(arena, args); - - ProfBeginCapture("raddbg_from_pdb"); - - //- rjf: parse arguments - PDBCONV_Params *params = pdb_convert_params_from_cmd_line(arena, &cmdline); - - //- rjf: 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(stderr, "error(input): %.*s\n", str8_varg(node->string)); - } - } - - //- rjf: open output file - String8 output_name = push_str8_copy(arena, params->output_name); - FILE *out_file = fopen((char*)output_name.str, "wb"); - if(out_file == 0 && !params->hide_errors.output) - { - fprintf(stderr, "error(output): could not open output file\n"); - } - - //- rjf: convert - PDBCONV_Out *out = 0; - if(out_file != 0) - { - out = pdbconv_convert(arena, params); - } - - //- rjf: print dump - if(out != 0) - { - for(String8Node *node = out->dump.first; node != 0; node = node->next) - { - fwrite(node->string.str, 1, node->string.size, stdout); - } - } - - //- rjf: bake file - if(out != 0 && out->good_parse && params->output_name.size > 0 && out->good_parse) - { - String8List baked = {0}; - cons_bake_file(arena, out->root, &baked); - for(String8Node *node = baked.first; node != 0; node = node->next) - { - fwrite(node->string.str, node->string.size, 1, out_file); - } - } - - //- rjf: close output file - if(out_file != 0) - { - fclose(out_file); - } - - ProfEndCapture(); - return(0); -} diff --git a/src/raddbg_convert/pdb/raddbg_pdb_stringize.h b/src/raddbg_convert/pdb/raddbg_pdb_stringize.h deleted file mode 100644 index 6b222afa..00000000 --- a/src/raddbg_convert/pdb/raddbg_pdb_stringize.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_PDB_STRINGIZE_H -#define RADDBG_PDB_STRINGIZE_H - -//////////////////////////////// -//~ PDB Stringize Functions - -static void pdb_stringize_tpi_hash(Arena *arena, String8List *out, PDB_TpiHashParsed *hash); - -#endif //RADDBG_PDB_STRINGIZE_H diff --git a/src/raddbg_dump/raddbg_dump.c b/src/raddbg_dump/raddbg_dump.c deleted file mode 100644 index 96b42364..00000000 --- a/src/raddbg_dump/raddbg_dump.c +++ /dev/null @@ -1,428 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#include "base/base_inc.h" -#include "os/os_inc.h" -#include "raddbg_format/raddbg_format.h" -#include "raddbg_format/raddbg_format_parse.h" -#include "raddbg_stringize.h" - -#include "raddbg_dump.h" - -#include "base/base_inc.c" -#include "os/os_inc.c" -#include "raddbg_format/raddbg_format.c" -#include "raddbg_format/raddbg_format_parse.c" -#include "raddbg_stringize.c" - -//////////////////////////////// -//~ Program Parameters Parser - -static DUMP_Params* -dump_params_from_cmd_line(Arena *arena, CmdLine *cmdline){ - DUMP_Params *result = push_array(arena, DUMP_Params, 1); - - // get input raddbg - { - String8 input_name = cmd_line_string(cmdline, str8_lit("raddbg")); - if (input_name.size == 0){ - str8_list_push(arena, &result->errors, - str8_lit("missing required parameter '--raddbg:'")); - } - - 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_name = input_name; - result->input_data = input_data; - } - } - } - - // 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; - } - } - } - - // dump options - { - 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("data_sections"), 0)){ - result->dump_data_sections = 1; - } - else if (str8_match(node->string, str8_lit("top_level_info"), 0)){ - result->dump_top_level_info = 1; - } - else if (str8_match(node->string, str8_lit("binary_sections"), 0)){ - result->dump_binary_sections = 1; - } - else if (str8_match(node->string, str8_lit("file_paths"), 0)){ - result->dump_file_paths = 1; - } - else if (str8_match(node->string, str8_lit("source_files"), 0)){ - result->dump_source_files = 1; - } - else if (str8_match(node->string, str8_lit("units"), 0)){ - result->dump_units = 1; - } - else if (str8_match(node->string, str8_lit("unit_vmap"), 0)){ - result->dump_unit_vmap = 1; - } - else if (str8_match(node->string, str8_lit("type_nodes"), 0)){ - result->dump_type_nodes = 1; - } - else if (str8_match(node->string, str8_lit("udt_data"), 0)){ - result->dump_udt_data = 1; - } - else if (str8_match(node->string, str8_lit("global_variables"), 0)){ - result->dump_global_variables = 1; - } - else if (str8_match(node->string, str8_lit("global_vmap"), 0)){ - result->dump_global_vmap = 1; - } - else if (str8_match(node->string, str8_lit("thread_variables"), 0)){ - result->dump_thread_variables = 1; - } - else if (str8_match(node->string, str8_lit("procedures"), 0)){ - result->dump_procedures = 1; - } - else if (str8_match(node->string, str8_lit("scopes"), 0)){ - result->dump_scopes = 1; - } - else if (str8_match(node->string, str8_lit("scope_vmap"), 0)){ - result->dump_scope_vmap = 1; - } - } - } - } - - return(result); -} - -//////////////////////////////// -//~ Entry Point - -int -main(int argc, char **argv){ - local_persist TCTX main_thread_tctx = {0}; - tctx_init_and_equip(&main_thread_tctx); - Arena *arena = arena_alloc(); - String8List args = os_string_list_from_argcv(arena, argc, argv); - CmdLine cmdline = cmd_line_from_string_list(arena, args); - - DUMP_Params *params = dump_params_from_cmd_line(arena, &cmdline); - - // 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(stderr, "error(input): %.*s\n", str8_varg(node->string)); - } - } - - // will we try to parse an input file - B32 try_parse_input = (params->errors.node_count == 0); - - RADDBG_ParseStatus parse_status = RADDBG_ParseStatus_Good; - RADDBG_Parsed raddbg__ = {0}; - RADDBG_Parsed *raddbg = 0; - if (try_parse_input){ - parse_status = raddbg_parse(params->input_data.str, params->input_data.size, &raddbg__); - if (parse_status == RADDBG_ParseStatus_Good){ - raddbg = &raddbg__; - } - } - - if (raddbg == 0){ - // TODO(allen): improve this by looking at parse status. - fprintf(stderr, "error(parsing): error trying to parse the input file\n"); - } - - // dump - { - String8List dump = {0}; - - // DATA SECTIONS - if (raddbg->dsecs != 0 && params->dump_data_sections){ - str8_list_pushf(arena, &dump, "# DATA SECTIONS:\n"); - raddbg_stringize_data_sections(arena, &dump, raddbg, 1); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // TOP LEVEL INFO - if (raddbg->top_level_info != 0 && params->dump_top_level_info){ - str8_list_pushf(arena, &dump, "# TOP LEVEL INFO:\n"); - raddbg_stringize_top_level_info(arena, &dump, raddbg, raddbg->top_level_info, 1); - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // BINARY SECTIONS - if (raddbg->binary_sections != 0 && params->dump_binary_sections){ - str8_list_pushf(arena, &dump, "# BINARY SECTIONS:\n"); - RADDBG_BinarySection *ptr = raddbg->binary_sections; - for (U32 i = 0; i < raddbg->binary_section_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " section[%u]:\n", i); - raddbg_stringize_binary_section(arena, &dump, raddbg, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // FILE PATHS - if (raddbg->file_paths != 0 && params->dump_file_paths){ - RADDBG_FilePathBundle file_path_bundle = {0}; - { - file_path_bundle.file_paths = raddbg->file_paths; - file_path_bundle.file_path_count = raddbg->file_path_count; - } - - str8_list_pushf(arena, &dump, "# FILE PATHS\n"); - RADDBG_FilePathNode *ptr = raddbg->file_paths; - for (U32 i = 0; i < raddbg->file_path_count; i += 1, ptr += 1){ - if (ptr->parent_path_node == 0){ - raddbg_stringize_file_path(arena, &dump, raddbg, &file_path_bundle, ptr, 1); - } - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // SOURCE FILES - if (raddbg->source_files != 0 && params->dump_source_files){ - str8_list_pushf(arena, &dump, "# SOURCE FILES\n"); - RADDBG_SourceFile *ptr = raddbg->source_files; - for (U32 i = 0; i < raddbg->source_file_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " source_file[%u]:\n", i); - raddbg_stringize_source_file(arena, &dump, raddbg, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // UNITS - if (raddbg->units != 0 && params->dump_units){ - str8_list_pushf(arena, &dump, "# UNITS\n"); - RADDBG_Unit *ptr = raddbg->units; - for (U32 i = 0; i < raddbg->unit_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - raddbg_stringize_unit(arena, &dump, raddbg, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // UNIT VMAP - if (raddbg->unit_vmap != 0 && params->dump_unit_vmap){ - str8_list_pushf(arena, &dump, "# UNIT VMAP\n"); - RADDBG_VMapEntry *ptr = raddbg->unit_vmap; - for (U32 i = 0; i < raddbg->unit_vmap_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // TYPE NODES - if (raddbg->type_nodes != 0 && params->dump_type_nodes){ - str8_list_pushf(arena, &dump, "# TYPE NODES:\n"); - RADDBG_TypeNode *ptr = raddbg->type_nodes; - for (U32 i = 0; i < raddbg->type_node_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " type[%u]:\n", i); - raddbg_stringize_type_node(arena, &dump, raddbg, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // UDT DATA - if (raddbg->udts != 0 && params->dump_udt_data){ - RADDBG_UDTMemberBundle member_bundle = {0}; - { - member_bundle.members = raddbg->members; - member_bundle.enum_members = raddbg->enum_members; - member_bundle.member_count = raddbg->member_count; - member_bundle.enum_member_count = raddbg->enum_member_count; - } - - str8_list_pushf(arena, &dump, "# UDTS:\n"); - RADDBG_UDT *ptr = raddbg->udts; - for (U32 i = 0; i < raddbg->udt_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " udt[%u]:\n", i); - raddbg_stringize_udt(arena, &dump, raddbg, &member_bundle, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // GLOBAL VARIABLES - if (raddbg->global_variables != 0 && params->dump_global_variables){ - str8_list_pushf(arena, &dump, "# GLOBAL VARIABLES:\n"); - RADDBG_GlobalVariable *ptr = raddbg->global_variables; - for (U32 i = 0; i < raddbg->global_variable_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " global_variable[%u]:\n", i); - raddbg_stringize_global_variable(arena, &dump, raddbg, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // GLOBAL VMAP - if (raddbg->global_vmap != 0 && params->dump_global_vmap){ - str8_list_pushf(arena, &dump, "# GLOBAL VMAP:\n"); - RADDBG_VMapEntry *ptr = raddbg->global_vmap; - for (U32 i = 0; i < raddbg->global_vmap_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // THREAD LOCAL VARIABLES - if (raddbg->thread_variables != 0 && params->dump_thread_variables){ - str8_list_pushf(arena, &dump, "# THREAD VARIABLES:\n"); - RADDBG_ThreadVariable *ptr = raddbg->thread_variables; - for (U32 i = 0; i < raddbg->thread_variable_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " thread_variable[%u]:\n", i); - raddbg_stringize_thread_variable(arena, &dump, raddbg, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // PROCEDURES - if (raddbg->procedures != 0 && params->dump_procedures){ - str8_list_pushf(arena, &dump, "# PROCEDURES:\n"); - RADDBG_Procedure *ptr = raddbg->procedures; - for (U32 i = 0; i < raddbg->procedure_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " procedure[%u]:\n", i); - raddbg_stringize_procedure(arena, &dump, raddbg, ptr, 2); - str8_list_push(arena, &dump, str8_lit("\n")); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // SCOPES - if (raddbg->scopes != 0 && params->dump_scopes){ - RADDBG_ScopeBundle scope_bundle = {0}; - { - scope_bundle.scopes = raddbg->scopes; - scope_bundle.scope_count = raddbg->scope_count; - scope_bundle.scope_voffs = raddbg->scope_voffs; - scope_bundle.scope_voff_count = raddbg->scope_voff_count; - scope_bundle.locals = raddbg->locals; - scope_bundle.local_count = raddbg->local_count; - scope_bundle.location_blocks = raddbg->location_blocks; - scope_bundle.location_block_count = raddbg->location_block_count; - scope_bundle.location_data = raddbg->location_data; - scope_bundle.location_data_size = raddbg->location_data_size; - } - - str8_list_pushf(arena, &dump, "# SCOPES:\n"); - RADDBG_Scope *ptr = raddbg->scopes; - for (U32 i = 0; i < raddbg->scope_count; i += 1, ptr += 1){ - if (ptr->parent_scope_idx == 0){ - raddbg_stringize_scope(arena, &dump, raddbg, &scope_bundle, ptr, 1); - str8_list_push(arena, &dump, str8_lit("\n")); - } - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // SCOPE VMAP - if (raddbg->scope_vmap != 0 && params->dump_scope_vmap){ - str8_list_pushf(arena, &dump, "# SCOPE VMAP:\n"); - RADDBG_VMapEntry *ptr = raddbg->scope_vmap; - for (U32 i = 0; i < raddbg->scope_vmap_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); - } - str8_list_push(arena, &dump, str8_lit("\n")); - } - - // NAME MAPS - if (raddbg->name_maps != 0 && params->dump_name_map){ - str8_list_pushf(arena, &dump, "# NAME MAP:\n"); - RADDBG_NameMap *ptr = raddbg->name_maps; - for (U32 i = 0; i < raddbg->name_map_count; i += 1, ptr += 1){ - str8_list_pushf(arena, &dump, " name_map[%u]:\n", i); - - RADDBG_ParsedNameMap name_map = {0}; - raddbg_name_map_parse(raddbg, ptr, &name_map); - - RADDBG_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); - RADDBG_NameMapNode *node = name_map.nodes + bucket->first_node; - RADDBG_NameMapNode *node_opl = node + bucket->node_count; - for (; node < node_opl; node += 1){ - String8 string = {0}; - string.str = raddbg_string_from_idx(raddbg, 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{ - RADDBG_U32 idx_count = 0; - RADDBG_U32 *idx_run = - raddbg_idx_run_from_first_count(raddbg, node->match_idx_or_idx_run_first, - node->match_count, &idx_count); - if (idx_count > 0){ - RADDBG_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")); - } - - // print dump - for(String8Node *node = dump.first; node != 0; node = node->next) - { - fwrite(node->string.str, 1, node->string.size, stdout); - } - } - - return(0); -} diff --git a/src/raddbg_dump/raddbg_dump.h b/src/raddbg_dump/raddbg_dump.h deleted file mode 100644 index 62ca2ce4..00000000 --- a/src/raddbg_dump/raddbg_dump.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_DUMP_H -#define RADDBG_DUMP_H - -//////////////////////////////// -//~ Program Parameters Type - -typedef struct DUMP_Params{ - String8 input_name; - String8 input_data; - - struct{ - B8 input; - } hide_errors; - - B8 dump__first; - B8 dump_data_sections; - B8 dump_top_level_info; - B8 dump_binary_sections; - B8 dump_file_paths; - B8 dump_source_files; - B8 dump_units; - B8 dump_unit_vmap; - B8 dump_type_nodes; - B8 dump_udt_data; - B8 dump_global_variables; - B8 dump_global_vmap; - B8 dump_thread_variables; - B8 dump_procedures; - B8 dump_scopes; - B8 dump_scope_vmap; - B8 dump_name_map; - B8 dump__last; - - String8List errors; -} DUMP_Params; - -//////////////////////////////// -//~ Program Parameters Parser - -static DUMP_Params *dump_params_from_cmd_line(Arena *arena, CmdLine *cmdline); - -#endif //RADDBG_DUMP_H diff --git a/src/raddbg_dump/raddbg_stringize.h b/src/raddbg_dump/raddbg_stringize.h deleted file mode 100644 index 6385b156..00000000 --- a/src/raddbg_dump/raddbg_stringize.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_STRINGIZE_H -#define RADDBG_STRINGIZE_H - -// TODO(allen): this depends on types from our base layer. -// we need to decide if we want this to be included in the "format" layer -// and therefore lifted off of the base layer, or if we want to put it in -// "base" or "dump" layers or something like that so that it can -// rely on Arena, String8, and String8List from the "base" layer. - -//////////////////////////////// -//~ RADDBG Stringize Helper Types - -typedef struct RADDBG_FilePathBundle{ - RADDBG_FilePathNode *file_paths; - U32 file_path_count; -} RADDBG_FilePathBundle; - -typedef struct RADDBG_UDTMemberBundle{ - RADDBG_Member *members; - RADDBG_EnumMember *enum_members; - U32 member_count; - U32 enum_member_count; -} RADDBG_UDTMemberBundle; - -typedef struct RADDBG_ScopeBundle{ - RADDBG_Scope *scopes; - U64 *scope_voffs; - RADDBG_Local *locals; - RADDBG_LocationBlock *location_blocks; - U8 *location_data; - U32 scope_count; - U32 scope_voff_count; - U32 local_count; - U32 location_block_count; - U32 location_data_size; -} RADDBG_ScopeBundle; - -//////////////////////////////// -//~ RADDBG Common Stringize Functions - -static String8 raddbg_string_from_data_section_tag(RADDBG_DataSectionTag tag); -static String8 raddbg_string_from_arch(RADDBG_Arch arch); -static String8 raddbg_string_from_language(RADDBG_Language language); -static String8 raddbg_string_from_type_kind(RADDBG_TypeKind type_kind); -static String8 raddbg_string_from_member_kind(RADDBG_MemberKind member_kind); -static String8 raddbg_string_from_local_kind(RADDBG_LocalKind local_kind); - -//////////////////////////////// -//~ RADDBG Flags Stringize Functions - -static void raddbg_stringize_binary_section_flags(Arena *arena, String8List *out, - RADDBG_BinarySectionFlags flags); - -static void raddbg_stringize_type_modifier_flags(Arena *arena, String8List *out, - RADDBG_TypeModifierFlags flags); - -static void raddbg_stringize_user_defined_type_flags(Arena *arena, String8List *out, - RADDBG_UserDefinedTypeFlags flags); - -static void raddbg_stringize_link_flags(Arena *arena, String8List *out, - RADDBG_LinkFlags flags); - -//////////////////////////////// -//~ RADDBG Compound Stringize Functions - -static void -raddbg_stringize_data_sections(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - U32 indent_level); - -static void -raddbg_stringize_top_level_info(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_TopLevelInfo *tli, U32 indent_level); - -static void -raddbg_stringize_binary_section(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_BinarySection *bin_section, U32 indent_level); - -static void -raddbg_stringize_file_path(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_FilePathBundle *bundle, RADDBG_FilePathNode *file_path, - U32 indent_level); - -static void -raddbg_stringize_source_file(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_SourceFile *source_file, U32 indent_level); - -static void -raddbg_stringize_unit(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_Unit *unit, U32 indent_level); - -static void -raddbg_stringize_type_node(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_TypeNode *type, U32 indent_level); - -static void -raddbg_stringize_udt(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_UDTMemberBundle *bundle, RADDBG_UDT *udt, - U32 indent_level); - -static void -raddbg_stringize_global_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_GlobalVariable *global_variable, U32 indent_level); - -static void -raddbg_stringize_thread_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_ThreadVariable *thread_var, - U32 indent_level); - -static void -raddbg_stringize_procedure(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_Procedure *proc, U32 indent_level); - -static void -raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_ScopeBundle *bundle, RADDBG_Scope *scope, U32 indent_level); - -#endif //RADDBG_STRINGIZE_H diff --git a/src/raddbg_format/raddbg_format.c b/src/raddbg_format/raddbg_format.c deleted file mode 100644 index 10382bc4..00000000 --- a/src/raddbg_format/raddbg_format.c +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -// Functions - -RADDBG_PROC RADDBG_U64 -raddbg_hash(RADDBG_U8 *ptr, RADDBG_U64 size){ - RADDBG_U64 result = 5381; - RADDBG_U8 *opl = ptr + size; - for (; ptr < opl; ptr += 1){ - result = ((result << 5) + result) + *ptr; - } - return(result); -} - -RADDBG_PROC RADDBG_U32 -raddbg_size_from_basic_type_kind(RADDBG_TypeKind kind){ - RADDBG_U32 result = 0; - switch (kind){ -#define X(N,C) -#define XZ(N,C,Z) case C: result = Z; break; -#define Y(A,N) - RADDBG_TypeKindXList(X,XZ,Y) -#undef X -#undef XZ -#undef Y - } - return(result); -} - -RADDBG_PROC RADDBG_U32 -raddbg_addr_size_from_arch(RADDBG_Arch arch){ - RADDBG_U32 result = 0; - switch (arch){ -#define X(N,C,Z) case C: result = Z; break; - RADDBG_ArchXList(X) -#undef X - } - return(result); -} - -//- eval helpers - -RADDBG_PROC RADDBG_EvalConversionKind -raddbg_eval_conversion_rule(RADDBG_EvalTypeGroup in, RADDBG_EvalTypeGroup out){ - RADDBG_EvalConversionKind result = 0; - switch (in + (out << 8)){ -#define Y(i,o) case ((RADDBG_EvalTypeGroup_##i) + ((RADDBG_EvalTypeGroup_##o) << 8)): -#define Xb(c) -#define Xe(c) result = RADDBG_EvalConversionKind_##c; break; - RADDBG_EvalConversionKindFromTypeGroupPairMap(Y,Xb,Xe) -#undef Xe -#undef Xb -#undef Y - } - return(result); -} - -RADDBG_PROC RADDBG_U8* -raddbg_eval_conversion_message(RADDBG_EvalConversionKind conversion_kind, RADDBG_U64 *lenout){ - RADDBG_U8 *result = 0; - switch (conversion_kind){ -#define X(N,msg) \ -case RADDBG_EvalConversionKind_##N: result = (RADDBG_U8*)msg; *lenout = sizeof(msg) - 1; break; - RADDBG_EvalConversionKindXList(X) -#undef X - } - return(result); -} - -RADDBG_PROC RADDBG_S32 -raddbg_eval_opcode_type_compatible(RADDBG_EvalOp op, RADDBG_EvalTypeGroup group){ - RADDBG_S32 result = 0; - switch (op){ - case RADDBG_EvalOp_Neg: case RADDBG_EvalOp_Add: case RADDBG_EvalOp_Sub: - case RADDBG_EvalOp_Mul: case RADDBG_EvalOp_Div: - case RADDBG_EvalOp_EqEq:case RADDBG_EvalOp_NtEq: - case RADDBG_EvalOp_LsEq:case RADDBG_EvalOp_GrEq: - case RADDBG_EvalOp_Less:case RADDBG_EvalOp_Grtr: - { - if (group != RADDBG_EvalTypeGroup_Other){ - result = 1; - } - }break; - case RADDBG_EvalOp_Mod:case RADDBG_EvalOp_LShift:case RADDBG_EvalOp_RShift: - case RADDBG_EvalOp_BitNot:case RADDBG_EvalOp_BitAnd:case RADDBG_EvalOp_BitXor: - case RADDBG_EvalOp_BitOr:case RADDBG_EvalOp_LogNot:case RADDBG_EvalOp_LogAnd: - case RADDBG_EvalOp_LogOr: - { - if (group == RADDBG_EvalTypeGroup_S || group == RADDBG_EvalTypeGroup_U){ - result = 1; - } - }break; - } - return(result); -} diff --git a/src/raddbg_format/raddbg_format_parse.c b/src/raddbg_format/raddbg_format_parse.c deleted file mode 100644 index b29e9776..00000000 --- a/src/raddbg_format/raddbg_format_parse.c +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ RADDBG Parse API - -RADDBG_PROC RADDBG_ParseStatus -raddbg_parse(RADDBG_U8 *data, RADDBG_U64 size, RADDBG_Parsed *out){ - RADDBG_ParseStatus result = RADDBG_ParseStatus_Good; - - // out header - RADDBG_Header *hdr = 0; - { - if (sizeof(*hdr) <= size){ - hdr = (RADDBG_Header*)data; - } - - // (errors) - if (hdr == 0 || hdr->magic != RADDBG_MAGIC_CONSTANT){ - hdr = 0; - result = RADDBG_ParseStatus_HeaderDoesNotMatch; - } - if (hdr != 0 && hdr->encoding_version != 1){ - hdr = 0; - result = RADDBG_ParseStatus_UnsupportedVersionNumber; - } - } - - // out data sections - RADDBG_DataSection *dsecs = 0; - RADDBG_U32 dsec_count = 0; - if (hdr != 0){ - RADDBG_U64 opl = (RADDBG_U64)hdr->data_section_off + (RADDBG_U64)hdr->data_section_count*sizeof(*dsecs); - if (opl <= size){ - dsecs = (RADDBG_DataSection*)(data + hdr->data_section_off); - dsec_count = hdr->data_section_count; - } - - // (errors) - if (dsecs == 0){ - result = RADDBG_ParseStatus_InvalidDataSecionLayout; - } - } - - // extract primary data section indexes - RADDBG_U32 dsec_idx[RADDBG_DataSectionTag_PRIMARY_COUNT] = {0}; - if (result == RADDBG_ParseStatus_Good){ - RADDBG_DataSection *sec_ptr = dsecs; - for (RADDBG_U32 i = 0; i < dsec_count; i += 1, sec_ptr += 1){ - if (sec_ptr->tag < RADDBG_DataSectionTag_PRIMARY_COUNT){ - dsec_idx[sec_ptr->tag] = i; - } - } - } - - // fill out data block (part 1) - if (result == RADDBG_ParseStatus_Good){ - out->raw_data = data; - out->raw_data_size = size; - out->dsecs = dsecs; - out->dsec_count = dsec_count; - for (RADDBG_U32 i = 0; i < RADDBG_DataSectionTag_PRIMARY_COUNT; i += 1){ - out->dsec_idx[i] = dsec_idx[i]; - } - } - - // out string table - RADDBG_U8 *string_data = 0; - RADDBG_U64 string_opl = 0; - RADDBG_U32 *string_offs = 0; - RADDBG_U64 string_count = 0; - if (result == RADDBG_ParseStatus_Good){ - raddbg_parse__extract_primary(out, string_data, &string_opl, - RADDBG_DataSectionTag_StringData); - - RADDBG_U64 table_entry_count = 0; - raddbg_parse__extract_primary(out, string_offs, &table_entry_count, - RADDBG_DataSectionTag_StringTable); - if (table_entry_count > 0){ - string_count = table_entry_count - 1; - } - - // (errors) - if (string_data == 0){ - result = RADDBG_ParseStatus_MissingStringDataSection; - } - else if (string_offs == 0){ - result = RADDBG_ParseStatus_MissingStringTableSection; - } - } - - // out index runs - RADDBG_U32 *idx_run_data = 0; - RADDBG_U64 idx_run_count = 0; - if (result == RADDBG_ParseStatus_Good){ - raddbg_parse__extract_primary(out, idx_run_data, &idx_run_count, - RADDBG_DataSectionTag_IndexRuns); - - // (errors) - if (idx_run_data == 0){ - result = RADDBG_ParseStatus_MissingIndexRunSection; - } - } - - if (result == RADDBG_ParseStatus_Good){ - // fill out primary data structures (part 2) - out->string_data = string_data; - out->string_offs = string_offs; - out->string_data_size = string_opl; - out->string_count = string_count; - out->idx_run_data = idx_run_data; - out->idx_run_count = idx_run_count; - - { - RADDBG_TopLevelInfo *tli = 0; - RADDBG_U64 dummy = 0; - raddbg_parse__extract_primary(out, tli, &dummy, RADDBG_DataSectionTag_TopLevelInfo); - if (dummy != 1){ - tli = 0; - } - out->top_level_info = tli; - } - - raddbg_parse__extract_primary(out, out->binary_sections, &out->binary_sections_count, - RADDBG_DataSectionTag_BinarySections); - - raddbg_parse__extract_primary(out, out->file_paths, &out->file_paths_count, - RADDBG_DataSectionTag_FilePathNodes); - - raddbg_parse__extract_primary(out, out->source_files, &out->source_files_count, - RADDBG_DataSectionTag_SourceFiles); - - raddbg_parse__extract_primary(out, out->units, &out->units_count, - RADDBG_DataSectionTag_Units); - - raddbg_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, - RADDBG_DataSectionTag_UnitVmap); - - raddbg_parse__extract_primary(out, out->unit_vmap, &out->unit_vmap_count, - RADDBG_DataSectionTag_UnitVmap); - - raddbg_parse__extract_primary(out, out->type_nodes, &out->type_nodes_count, - RADDBG_DataSectionTag_TypeNodes); - - raddbg_parse__extract_primary(out, out->udts, &out->udts_count, - RADDBG_DataSectionTag_UDTs); - - raddbg_parse__extract_primary(out, out->members, &out->members_count, - RADDBG_DataSectionTag_Members); - - raddbg_parse__extract_primary(out, out->enum_members, &out->enum_members_count, - RADDBG_DataSectionTag_EnumMembers); - - raddbg_parse__extract_primary(out, out->global_variables, &out->global_variables_count, - RADDBG_DataSectionTag_GlobalVariables); - - raddbg_parse__extract_primary(out, out->global_vmap, &out->global_vmap_count, - RADDBG_DataSectionTag_GlobalVmap); - - raddbg_parse__extract_primary(out, out->thread_variables, &out->thread_variables_count, - RADDBG_DataSectionTag_ThreadVariables); - - raddbg_parse__extract_primary(out, out->procedures, &out->procedures_count, - RADDBG_DataSectionTag_Procedures); - - raddbg_parse__extract_primary(out, out->scopes, &out->scopes_count, - RADDBG_DataSectionTag_Scopes); - - raddbg_parse__extract_primary(out, out->scope_voffs, &out->scope_voffs_count, - RADDBG_DataSectionTag_ScopeVoffData); - - raddbg_parse__extract_primary(out, out->scope_vmap, &out->scope_vmap_count, - RADDBG_DataSectionTag_ScopeVmap); - - raddbg_parse__extract_primary(out, out->locals, &out->locals_count, - RADDBG_DataSectionTag_Locals); - - raddbg_parse__extract_primary(out, out->location_blocks, &out->location_blocks_count, - RADDBG_DataSectionTag_LocationBlocks); - - raddbg_parse__extract_primary(out, out->location_data, &out->location_data_size, - RADDBG_DataSectionTag_LocationData); - - { - raddbg_parse__extract_primary(out, out->name_maps, &out->name_maps_count, - RADDBG_DataSectionTag_NameMaps); - - RADDBG_NameMap *name_map_ptr = out->name_maps; - RADDBG_NameMap *name_map_opl = out->name_maps + out->name_maps_count; - for (; name_map_ptr < name_map_opl; name_map_ptr += 1){ - if (out->name_maps_by_kind[name_map_ptr->kind] == 0){ - out->name_maps_by_kind[name_map_ptr->kind] = name_map_ptr; - } - } - } - -#if !defined(RADDBG_DISABLE_NILS) - if(out->binary_sections == 0) { out->binary_sections = &raddbg_binary_section_nil; out->binary_sections_count = 1; } - if(out->file_paths == 0) { out->file_paths = &raddbg_file_path_node_nil; out->file_paths_count = 1; } - if(out->source_files == 0) { out->source_files = &raddbg_source_file_nil; out->source_files_count = 1; } - if(out->units == 0) { out->units = &raddbg_unit_nil; out->units_count = 1; } - if(out->unit_vmap == 0) { out->unit_vmap = &raddbg_vmap_entry_nil; out->unit_vmap_count = 1; } - if(out->type_nodes == 0) { out->type_nodes = &raddbg_type_node_nil; out->type_nodes_count = 1; } - if(out->udts == 0) { out->udts = &raddbg_udt_nil; out->udts_count = 1; } - if(out->members == 0) { out->members = &raddbg_member_nil; out->members_count = 1; } - if(out->enum_members == 0) { out->enum_members = &raddbg_enum_member_nil; out->enum_members_count = 1; } - if(out->global_variables == 0) { out->global_variables = &raddbg_global_variable_nil; out->global_variables_count = 1; } - if(out->global_vmap == 0) { out->global_vmap = &raddbg_vmap_entry_nil; out->global_vmap_count = 1; } - if(out->thread_variables == 0) { out->thread_variables = &raddbg_thread_variable_nil; out->thread_variables_count = 1; } - if(out->procedures == 0) { out->procedures = &raddbg_procedure_nil; out->procedures_count = 1; } - if(out->scopes == 0) { out->scopes = &raddbg_scope_nil; out->scopes_count = 1; } - if(out->scope_voffs == 0) { out->scope_voffs = &raddbg_voff_nil; out->scope_voffs_count = 1; } - if(out->scope_vmap == 0) { out->scope_vmap = &raddbg_vmap_entry_nil; out->scope_vmap_count = 1; } - if(out->locals == 0) { out->locals = &raddbg_local_nil; out->locals_count = 1; } - if(out->location_blocks == 0) { out->location_blocks = &raddbg_location_block_nil; out->location_blocks_count = 1; } -#endif - - } - - return(result); -} - -RADDBG_PROC RADDBG_U8* -raddbg_string_from_idx(RADDBG_Parsed *parsed, RADDBG_U32 idx, RADDBG_U64 *len_out){ - RADDBG_U8 *result = 0; - RADDBG_U64 len_result = 0; - if (idx < parsed->string_count){ - RADDBG_U32 off_raw = parsed->string_offs[idx]; - RADDBG_U32 opl_raw = parsed->string_offs[idx + 1]; - RADDBG_U32 opl = raddbg_parse__min(opl_raw, parsed->string_data_size); - RADDBG_U32 off = raddbg_parse__min(off_raw, opl); - result = parsed->string_data + off; - len_result = opl - off; - } - *len_out = len_result; - return(result); -} - -RADDBG_PROC RADDBG_U32* -raddbg_idx_run_from_first_count(RADDBG_Parsed *parsed, - RADDBG_U32 raw_first, RADDBG_U32 raw_count, - RADDBG_U32 *n_out){ - RADDBG_U32 raw_opl = raw_first + raw_count; - RADDBG_U32 opl = raddbg_parse__min(raw_opl, parsed->idx_run_count); - RADDBG_U32 first = raddbg_parse__min(raw_first, opl); - - RADDBG_U32 *result = 0; - if (first < parsed->idx_run_count){ - result = parsed->idx_run_data + first; - } - *n_out = opl - first; - return(result); -} - -//- line info - -RADDBG_PROC void -raddbg_line_info_from_unit(RADDBG_Parsed *p, RADDBG_Unit *unit, RADDBG_ParsedLineInfo *out){ - RADDBG_U64 line_info_voff_count = 0; - RADDBG_U64 *voffs = (RADDBG_U64*) - raddbg_data_from_dsec(p, unit->line_info_voffs_data_idx, sizeof(RADDBG_U64), - RADDBG_DataSectionTag_LineInfoVoffs, - &line_info_voff_count); - - RADDBG_U64 line_info_count_raw = 0; - RADDBG_Line *lines = (RADDBG_Line*) - raddbg_data_from_dsec(p, unit->line_info_data_idx, sizeof(RADDBG_Line), - RADDBG_DataSectionTag_LineInfoData, - &line_info_count_raw); - - RADDBG_U64 column_info_count_raw = 0; - RADDBG_Column *cols = (RADDBG_Column*) - raddbg_data_from_dsec(p, unit->line_info_col_data_idx, sizeof(RADDBG_Column), - RADDBG_DataSectionTag_LineInfoColumns, - &column_info_count_raw); - - RADDBG_U32 line_info_count_a = (line_info_voff_count > 0)?line_info_voff_count - 1:0; - RADDBG_U32 line_info_count = raddbg_parse__min(line_info_count_a, line_info_count_raw); - RADDBG_U32 column_info_count = raddbg_parse__min(column_info_count_raw, line_info_count); - - out->voffs = voffs; - out->lines = lines; - out->cols = cols; - out->count = line_info_count; - out->col_count = column_info_count; -} - -RADDBG_PROC RADDBG_U64 -raddbg_line_info_idx_from_voff(RADDBG_ParsedLineInfo *line_info, RADDBG_U64 voff) -{ - RADDBG_U64 result = 0; - if (line_info->count > 0 && line_info->voffs[0] <= voff && voff < line_info->voffs[line_info->count - 1]){ - // assuming: (i < j) -> (vmap[i].voff < vmap[j].voff) - // find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff) - RADDBG_U32 first = 0; - RADDBG_U32 opl = line_info->count; - for (;;){ - RADDBG_U32 mid = (first + opl)/2; - if (line_info->voffs[mid] < voff){ - first = mid; - } - else if (line_info->voffs[mid] > voff){ - opl = mid; - } - else{ - first = mid; - break; - } - if (opl - first <= 1){ - break; - } - } - result = (RADDBG_U64)first; - } - return(result); -} - -RADDBG_PROC void -raddbg_line_map_from_source_file(RADDBG_Parsed *p, RADDBG_SourceFile *srcfile, - RADDBG_ParsedLineMap *out){ - RADDBG_U64 num_count = 0; - RADDBG_U32 *nums = (RADDBG_U32*) - raddbg_data_from_dsec(p, srcfile->line_map_nums_data_idx, sizeof(RADDBG_U32), - RADDBG_DataSectionTag_LineMapNumbers, - &num_count); - - RADDBG_U64 range_count = 0; - RADDBG_U32 *ranges = (RADDBG_U32*) - raddbg_data_from_dsec(p, srcfile->line_map_range_data_idx, sizeof(RADDBG_U32), - RADDBG_DataSectionTag_LineMapRanges, - &range_count); - - RADDBG_U64 voff_count = 0; - RADDBG_U64 *voffs = (RADDBG_U64*) - raddbg_data_from_dsec(p, srcfile->line_map_voff_data_idx, sizeof(RADDBG_U64), - RADDBG_DataSectionTag_LineMapVoffs, - &voff_count); - - RADDBG_U32 count_a = (range_count > 0)?(range_count - 1):0; - RADDBG_U32 count_b = raddbg_parse__min(count_a, num_count); - RADDBG_U32 count = raddbg_parse__min(count_b, srcfile->line_map_count); - - out->nums = nums; - out->ranges = ranges; - out->voffs = voffs; - out->count = count; - out->voff_count = voff_count; -} - -RADDBG_PROC RADDBG_U64* -raddbg_line_voffs_from_num(RADDBG_ParsedLineMap *map, RADDBG_U32 linenum, RADDBG_U32 *n_out){ - RADDBG_U64 *result = 0; - *n_out = 0; - - RADDBG_U32 closest_i = 0; - if (map->count > 0 && map->nums[0] <= linenum){ - // assuming: (i < j) -> (nums[i] < nums[j]) - // find i such that: (nums[i] <= linenum) && (linenum < nums[i + 1]) - RADDBG_U32 *nums = map->nums; - RADDBG_U32 first = 0; - RADDBG_U32 opl = map->count; - for (;;){ - RADDBG_U32 mid = (first + opl)/2; - if (nums[mid] < linenum){ - first = mid; - } - else if (nums[mid] > linenum){ - opl = mid; - } - else{ - first = mid; - break; - } - if (opl - first <= 1){ - break; - } - } - closest_i = first; - } - - // round up instead of down if possible - if (closest_i + 1 < map->count && - map->nums[closest_i] < linenum){ - closest_i += 1; - } - - // set result if possible - if (closest_i < map->count){ - RADDBG_U32 first = map->ranges[closest_i]; - RADDBG_U32 opl = map->ranges[closest_i + 1]; - if (opl < map->voff_count){ - result = map->voffs + first; - *n_out = opl - first; - } - } - - return(result); -} - - -//- vmaps - -RADDBG_PROC RADDBG_U64 -raddbg_vmap_idx_from_voff(RADDBG_VMapEntry *vmap, RADDBG_U32 vmap_count, RADDBG_U64 voff){ - RADDBG_U64 result = 0; - if (vmap_count > 0 && vmap[0].voff <= voff && voff < vmap[vmap_count - 1].voff){ - // assuming: (i < j) -> (vmap[i].voff < vmap[j].voff) - // find i such that: (vmap[i].voff <= voff) && (voff < vmap[i + 1].voff) - RADDBG_U32 first = 0; - RADDBG_U32 opl = vmap_count; - for (;;){ - RADDBG_U32 mid = (first + opl)/2; - if (vmap[mid].voff < voff){ - first = mid; - } - else if (vmap[mid].voff > voff){ - opl = mid; - } - else{ - first = mid; - break; - } - if (opl - first <= 1){ - break; - } - } - result = (RADDBG_U64)vmap[first].idx; - } - return(result); -} - -//- name maps - -RADDBG_PROC RADDBG_NameMap* -raddbg_name_map_from_kind(RADDBG_Parsed *p, RADDBG_NameMapKind kind){ - RADDBG_NameMap *result = 0; - if (0 < kind && kind < RADDBG_NameMapKind_COUNT){ - result = p->name_maps_by_kind[kind]; - } - return(result); -} - -RADDBG_PROC void -raddbg_name_map_parse(RADDBG_Parsed *p, RADDBG_NameMap *mapptr, RADDBG_ParsedNameMap *out){ - out->buckets = 0; - out->bucket_count = 0; - if (mapptr != 0){ - out->buckets = (RADDBG_NameMapBucket*) - raddbg_data_from_dsec(p, mapptr->bucket_data_idx, sizeof(RADDBG_NameMapBucket), - RADDBG_DataSectionTag_NameMapBuckets, &out->bucket_count); - out->nodes = (RADDBG_NameMapNode*) - raddbg_data_from_dsec(p, mapptr->node_data_idx, sizeof(RADDBG_NameMapNode), - RADDBG_DataSectionTag_NameMapNodes, &out->node_count); - } -} - -RADDBG_PROC RADDBG_NameMapNode* -raddbg_name_map_lookup(RADDBG_Parsed *p, RADDBG_ParsedNameMap *map, - RADDBG_U8 *str, RADDBG_U64 len){ - RADDBG_NameMapNode *result = 0; - if (map->bucket_count > 0){ - RADDBG_NameMapBucket *buckets = map->buckets; - RADDBG_U64 bucket_count = map->bucket_count; - RADDBG_U64 hash = raddbg_hash(str, len); - RADDBG_U64 bucket_index = hash%bucket_count; - RADDBG_NameMapBucket *bucket = map->buckets + bucket_index; - - RADDBG_NameMapNode *node = map->nodes + bucket->first_node; - RADDBG_NameMapNode *node_opl = node + bucket->node_count; - for (;node < node_opl; node += 1){ - // extract a string from this node - RADDBG_U64 nlen = 0; - RADDBG_U8 *nstr = raddbg_string_from_idx(p, node->string_idx, &nlen); - - // compare this to the needle string - RADDBG_S32 match = 0; - if (nlen == len){ - RADDBG_U8 *a = str; - RADDBG_U8 *aopl = str + len; - RADDBG_U8 *b = nstr; - for (;a < aopl && *a == *b; a += 1, b += 1); - match = (a == aopl); - } - - // stop with a matching node in result - if (match){ - result = node; - break; - } - - } - } - return(result); -} - -RADDBG_PROC RADDBG_U32* -raddbg_matches_from_map_node(RADDBG_Parsed *p, RADDBG_NameMapNode *node, - RADDBG_U32 *n_out){ - RADDBG_U32 *result = 0; - *n_out = 0; - if (node != 0){ - if (node->match_count == 1){ - result = &node->match_idx_or_idx_run_first; - *n_out = 1; - } - else{ - result = raddbg_idx_run_from_first_count(p, node->match_idx_or_idx_run_first, - node->match_count, n_out); - } - } - return(result); -} - -//- common helpers - -RADDBG_PROC RADDBG_U64 -raddbg_first_voff_from_proc(RADDBG_Parsed *p, RADDBG_U32 proc_id){ - RADDBG_U64 result = 0; - if (0 < proc_id && proc_id < p->procedures_count){ - RADDBG_Procedure *proc = p->procedures + proc_id; - RADDBG_U32 scope_id = proc->root_scope_idx; - if (0 < scope_id && scope_id < p->scopes_count){ - RADDBG_Scope *scope = p->scopes + scope_id; - if (scope->voff_range_first < scope->voff_range_opl && - scope->voff_range_first < p->scope_voffs_count){ - result = p->scope_voffs[scope->voff_range_first]; - } - } - } - return(result); -} - -//////////////////////////////// -//~ RADDBG Parsing Helpers - -RADDBG_PROC void* -raddbg_data_from_dsec(RADDBG_Parsed *parsed, RADDBG_U32 idx, RADDBG_U32 item_size, - RADDBG_DataSectionTag expected_tag, - RADDBG_U64 *count_out){ - void *result = 0; - RADDBG_U32 count_result = 0; - - // TODO(allen): need a version of this that works with encodings other than "Unpacked" - - if (0 < idx && idx < parsed->dsec_count){ - RADDBG_DataSection *ds = parsed->dsecs + idx; - if (ds->tag == expected_tag){ - RADDBG_U64 opl = ds->off + ds->encoded_size; - if (opl <= parsed->raw_data_size){ - count_result = ds->encoded_size/item_size; - result = (parsed->raw_data + ds->off); - } - } - } - - *count_out = count_result; - return(result); -} diff --git a/src/raddbg_format/raddbg_format_parse.h b/src/raddbg_format/raddbg_format_parse.h deleted file mode 100644 index 5f8e0d14..00000000 --- a/src/raddbg_format/raddbg_format_parse.h +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef RADDBG_PARSE_H -#define RADDBG_PARSE_H - -//////////////////////////////// -//~ RADDBG Parsing Helpers - -typedef struct RADDBG_Parsed{ - // raw data & data sections (part 1) - RADDBG_U8 *raw_data; - RADDBG_U64 raw_data_size; - RADDBG_DataSection *dsecs; - RADDBG_U64 dsec_count; - RADDBG_U32 dsec_idx[RADDBG_DataSectionTag_PRIMARY_COUNT]; - - // primary data structures (part 2) - - // handled by helper APIs - RADDBG_U8* string_data; - RADDBG_U64 string_data_size; - RADDBG_U32* string_offs; - RADDBG_U64 string_count; - RADDBG_U32* idx_run_data; - RADDBG_U32 idx_run_count; - - // directly readable by users - // (any of these may be empty and null even in a successful parse) - RADDBG_TopLevelInfo* top_level_info; - - RADDBG_BinarySection* binary_sections; - RADDBG_U64 binary_sections_count; - RADDBG_FilePathNode* file_paths; - RADDBG_U64 file_paths_count; - RADDBG_SourceFile* source_files; - RADDBG_U64 source_files_count; - RADDBG_Unit* units; - RADDBG_U64 units_count; - RADDBG_VMapEntry* unit_vmap; - RADDBG_U64 unit_vmap_count; - RADDBG_TypeNode* type_nodes; - RADDBG_U64 type_nodes_count; - RADDBG_UDT* udts; - RADDBG_U64 udts_count; - RADDBG_Member* members; - RADDBG_U64 members_count; - RADDBG_EnumMember* enum_members; - RADDBG_U64 enum_members_count; - RADDBG_GlobalVariable* global_variables; - RADDBG_U64 global_variables_count; - RADDBG_VMapEntry* global_vmap; - RADDBG_U64 global_vmap_count; - RADDBG_ThreadVariable* thread_variables; - RADDBG_U64 thread_variables_count; - RADDBG_Procedure* procedures; - RADDBG_U64 procedures_count; - RADDBG_Scope* scopes; - RADDBG_U64 scopes_count; - RADDBG_U64* scope_voffs; - RADDBG_U64 scope_voffs_count; - RADDBG_VMapEntry* scope_vmap; - RADDBG_U64 scope_vmap_count; - RADDBG_Local* locals; - RADDBG_U64 locals_count; - RADDBG_LocationBlock* location_blocks; - RADDBG_U64 location_blocks_count; - RADDBG_U8* location_data; - RADDBG_U64 location_data_size; - RADDBG_NameMap* name_maps; - RADDBG_U64 name_maps_count; - - // other helpers - - RADDBG_NameMap* name_maps_by_kind[RADDBG_NameMapKind_COUNT]; - -} RADDBG_Parsed; - -typedef enum{ - RADDBG_ParseStatus_Good = 0, - RADDBG_ParseStatus_HeaderDoesNotMatch = 1, - RADDBG_ParseStatus_UnsupportedVersionNumber = 2, - RADDBG_ParseStatus_InvalidDataSecionLayout = 3, - RADDBG_ParseStatus_MissingStringDataSection = 4, - RADDBG_ParseStatus_MissingStringTableSection = 5, - RADDBG_ParseStatus_MissingIndexRunSection = 6, -} RADDBG_ParseStatus; - -typedef struct RADDBG_ParsedLineInfo{ - // NOTE: Mapping VOFF -> LINE_INFO - // - // * [ voff[i], voff[i + 1] ) forms the voff range - // * for the line info at lines[i] (and cols[i] if i < col_count) - - RADDBG_U64* voffs; // [count + 1] sorted - RADDBG_Line* lines; // [count] - RADDBG_Column* cols; // [col_count] - RADDBG_U64 count; - RADDBG_U64 col_count; -} RADDBG_ParsedLineInfo; - -typedef struct RADDBG_ParsedLineMap{ - // NOTE: Mapping LINE_NUMBER -> VOFFs - // - // * nums[i] gives a line number - // * that line number has one or more associated voffs - // - // * to find all associated voffs for the line number nums[i] : - // * let k span over the range [ ranges[i], ranges[i + 1] ) - // * voffs[k] gives the associated voffs - - RADDBG_U32* nums; // [count] sorted - RADDBG_U32* ranges; // [count + 1] - RADDBG_U64* voffs; // [voff_count] - RADDBG_U64 count; - RADDBG_U64 voff_count; -} RADDBG_ParsedLineMap; - - -typedef struct RADDBG_ParsedNameMap{ - RADDBG_NameMapBucket *buckets; - RADDBG_NameMapNode *nodes; - RADDBG_U64 bucket_count; - RADDBG_U64 node_count; -} RADDBG_ParsedNameMap; - -//////////////////////////////// -//~ Global Nils - -#if !defined(RADDBG_DISABLE_NILS) -static RADDBG_BinarySection raddbg_binary_section_nil = {0}; -static RADDBG_FilePathNode raddbg_file_path_node_nil = {0}; -static RADDBG_SourceFile raddbg_source_file_nil = {0}; -static RADDBG_Unit raddbg_unit_nil = {0}; -static RADDBG_VMapEntry raddbg_vmap_entry_nil = {0}; -static RADDBG_TypeNode raddbg_type_node_nil = {0}; -static RADDBG_UDT raddbg_udt_nil = {0}; -static RADDBG_Member raddbg_member_nil = {0}; -static RADDBG_EnumMember raddbg_enum_member_nil = {0}; -static RADDBG_GlobalVariable raddbg_global_variable_nil = {0}; -static RADDBG_ThreadVariable raddbg_thread_variable_nil = {0}; -static RADDBG_Procedure raddbg_procedure_nil = {0}; -static RADDBG_Scope raddbg_scope_nil = {0}; -static U64 raddbg_voff_nil = 0; -static RADDBG_LocationBlock raddbg_location_block_nil = {0}; -static RADDBG_Local raddbg_local_nil = {0}; -#endif - -//////////////////////////////// -//~ RADDBG Parse API - -RADDBG_PROC RADDBG_ParseStatus -raddbg_parse(RADDBG_U8 *data, RADDBG_U64 size, RADDBG_Parsed *out); - -RADDBG_PROC RADDBG_U8* -raddbg_string_from_idx(RADDBG_Parsed *parsed, RADDBG_U32 idx, RADDBG_U64 *len_out); - -RADDBG_PROC RADDBG_U32* -raddbg_idx_run_from_first_count(RADDBG_Parsed *parsed, RADDBG_U32 first, RADDBG_U32 raw_count, - RADDBG_U32 *n_out); - -//- table lookups -#define raddbg_element_from_idx(parsed, name, idx) ((0 <= (idx) && (idx) < (parsed)->name##_count) ? &(parsed)->name[idx] : (parsed)->name ? &(parsed)->name[0] : 0) - -//- line info -RADDBG_PROC void -raddbg_line_info_from_unit(RADDBG_Parsed *p, RADDBG_Unit *unit, RADDBG_ParsedLineInfo *out); - -RADDBG_PROC RADDBG_U64 -raddbg_line_info_idx_from_voff(RADDBG_ParsedLineInfo *line_info, RADDBG_U64 voff); - -RADDBG_PROC void -raddbg_line_map_from_source_file(RADDBG_Parsed *p, RADDBG_SourceFile *srcfile, - RADDBG_ParsedLineMap *out); - -RADDBG_PROC RADDBG_U64* -raddbg_line_voffs_from_num(RADDBG_ParsedLineMap *map, RADDBG_U32 linenum, RADDBG_U32 *n_out); - - -//- vmaps -RADDBG_PROC RADDBG_U64 -raddbg_vmap_idx_from_voff(RADDBG_VMapEntry *vmap, RADDBG_U32 vmap_count, RADDBG_U64 voff); - - -//- name maps -RADDBG_PROC RADDBG_NameMap* -raddbg_name_map_from_kind(RADDBG_Parsed *p, RADDBG_NameMapKind kind); - -RADDBG_PROC void -raddbg_name_map_parse(RADDBG_Parsed* p, RADDBG_NameMap *mapptr, RADDBG_ParsedNameMap *out); - -RADDBG_PROC RADDBG_NameMapNode* -raddbg_name_map_lookup(RADDBG_Parsed *p, RADDBG_ParsedNameMap *map, - RADDBG_U8 *str, RADDBG_U64 len); - -RADDBG_PROC RADDBG_U32* -raddbg_matches_from_map_node(RADDBG_Parsed *p, RADDBG_NameMapNode *node, RADDBG_U32 *n_out); - - -//- common helpers -RADDBG_PROC RADDBG_U64 -raddbg_first_voff_from_proc(RADDBG_Parsed *p, RADDBG_U32 proc_id); - - - -//////////////////////////////// -//~ RADDBG Parsing Helpers - -#define raddbg_parse__extract_primary(p,outptr,outn,pritag) \ -( (*(void**)&(outptr)) = \ -raddbg_data_from_dsec((p),(p)->dsec_idx[pritag],sizeof(*(outptr)),(pritag),(outn)) ) - -RADDBG_PROC void* -raddbg_data_from_dsec(RADDBG_Parsed *p, RADDBG_U32 idx, RADDBG_U32 item_size, - RADDBG_DataSectionTag expected_tag, RADDBG_U64 *n_out); - -#define raddbg_parse__min(a,b) (((a)<(b))?(a):(b)) - -#endif //RADDBG_PARSE_H diff --git a/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c b/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c new file mode 100644 index 00000000..491baf79 --- /dev/null +++ b/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c @@ -0,0 +1,337 @@ +//////////////////////////////// +//~ rjf: Build Options + +#define BUILD_VERSION_MAJOR 0 +#define BUILD_VERSION_MINOR 9 +#define BUILD_VERSION_PATCH 8 +#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +#define BUILD_TITLE "raddbgi_breakpad_from_pdb" +#define BUILD_CONSOLE_INTERFACE 1 + +//////////////////////////////// +//~ rjf: Includes + +//- rjf: [lib] +#include "lib_raddbgi_format/raddbgi_format.h" +#include "lib_raddbgi_format/raddbgi_format_parse.h" +#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_raddbgi_format/raddbgi_format_parse.c" + +//- rjf: [h] +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "task_system/task_system.h" +#include "raddbgi_make_local/raddbgi_make_local.h" +#include "coff/coff.h" +#include "codeview/codeview.h" +#include "codeview/codeview_stringize.h" +#include "msf/msf.h" +#include "pdb/pdb.h" +#include "pdb/pdb_stringize.h" +#include "raddbgi_from_pdb/raddbgi_from_pdb.h" + +//- rjf: [c] +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "task_system/task_system.c" +#include "raddbgi_make_local/raddbgi_make_local.c" +#include "coff/coff.c" +#include "codeview/codeview.c" +#include "codeview/codeview_stringize.c" +#include "msf/msf.c" +#include "pdb/pdb.c" +#include "pdb/pdb_stringize.c" +#include "raddbgi_from_pdb/raddbgi_from_pdb.c" + +//////////////////////////////// +//~ rjf: Baking Tasks + +//- rjf: unit vmap baking + +typedef struct P2B_BakeUnitVMapIn P2B_BakeUnitVMapIn; +struct P2B_BakeUnitVMapIn +{ + RDIM_BakeParams *params; +}; + +typedef struct P2B_BakeUnitVMapOut P2B_BakeUnitVMapOut; +struct P2B_BakeUnitVMapOut +{ + RDI_VMapEntry *vmap_entries; + RDI_U64 vmap_entries_count; +}; + +internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_vmap_task__entry_point) +{ + P2B_BakeUnitVMapIn *in = (P2B_BakeUnitVMapIn *)p; + P2B_BakeUnitVMapOut *out = push_array(arena, P2B_BakeUnitVMapOut, 1); + RDIM_BakeSectionList sections = rdim_bake_unit_vmap_section_list_from_params(arena, in->params); + RDIM_BakeSection *vmap_section = 0; + for(RDIM_BakeSectionNode *n = sections.first; n != 0 && vmap_section == 0; n = n->next) + { + switch(n->v.tag) + { + default:{}break; + case RDI_DataSectionTag_UnitVmap:{vmap_section = &n->v;}break; + } + } + if(vmap_section != 0) + { + out->vmap_entries = (RDI_VMapEntry *)vmap_section->data; + out->vmap_entries_count = vmap_section->size/sizeof(RDI_VMapEntry); + } + return out; +} + +//- rjf: per-unit baking + +typedef struct P2B_BakeUnitIn P2B_BakeUnitIn; +struct P2B_BakeUnitIn +{ + RDIM_Unit *unit; +}; + +typedef struct P2B_BakeUnitOut P2B_BakeUnitOut; +struct P2B_BakeUnitOut +{ + U64 unit_line_count; + U64 *unit_line_voffs; + RDI_Line *unit_lines; +}; + +internal TS_TASK_FUNCTION_DEF(p2b_bake_unit_task__entry_point) +{ + P2B_BakeUnitIn *in = (P2B_BakeUnitIn *)p; + P2B_BakeUnitOut *out = push_array(arena, P2B_BakeUnitOut, 1); + RDIM_BakeSectionList sections = rdim_bake_section_list_from_unit(arena, in->unit); + RDIM_BakeSection *voffs_section = 0; + RDIM_BakeSection *lines_section = 0; + for(RDIM_BakeSectionNode *n = sections.first; n != 0; n = n->next) + { + switch(n->v.tag) + { + default:{}break; + case RDI_DataSectionTag_LineInfoVoffs:{voffs_section = &n->v;}break; + case RDI_DataSectionTag_LineInfoData: {lines_section = &n->v;}break; + } + } + if(voffs_section != 0 && lines_section != 0) + { + out->unit_line_count = lines_section->size/sizeof(RDI_Line); + out->unit_line_voffs = (U64 *)voffs_section->data; + out->unit_lines = (RDI_Line *)lines_section->data; + } + return out; +} + +//- rjf: per-procedure chunk dumping + +typedef struct P2B_DumpProcChunkIn P2B_DumpProcChunkIn; +struct P2B_DumpProcChunkIn +{ + RDI_VMapEntry *unit_vmap; + U32 unit_vmap_count; + P2B_BakeUnitOut **bake_units_out; + U64 bake_units_out_count; + RDIM_SymbolChunkNode *chunk; +}; + +internal TS_TASK_FUNCTION_DEF(p2b_dump_proc_chunk_task__entry_point) +{ + P2B_DumpProcChunkIn *in = (P2B_DumpProcChunkIn *)p; + String8List *out = push_array(arena, String8List, 1); + for(U64 idx = 0; idx < in->chunk->count; idx += 1) + { + // NOTE(rjf): breakpad does not support multiple voff ranges per procedure. + RDIM_Symbol *proc = &in->chunk->v[idx]; + RDIM_Scope *root_scope = proc->root_scope; + if(root_scope != 0 && root_scope->voff_ranges.first != 0) + { + // rjf: dump function record + RDIM_Rng1U64 voff_range = root_scope->voff_ranges.first->v; + str8_list_pushf(arena, out, "FUNC %I64x %I64x %I64x %S\n", voff_range.min, voff_range.max-voff_range.min, 0ull, proc->name); + + // rjf: dump function lines + U64 unit_idx = rdi_vmap_idx_from_voff(in->unit_vmap, in->unit_vmap_count, voff_range.min); + if(0 < unit_idx && unit_idx <= in->bake_units_out_count) + { + // rjf: unpack unit line info + P2B_BakeUnitOut *bake_unit_out = in->bake_units_out[unit_idx]; + RDI_ParsedLineInfo line_info = {bake_unit_out->unit_line_voffs, bake_unit_out->unit_lines, 0, bake_unit_out->unit_line_count, 0}; + for(U64 voff = voff_range.min, last_voff = 0; + voff < voff_range.max && voff > last_voff;) + { + RDI_U64 line_info_idx = rdi_line_info_idx_from_voff(&line_info, voff); + if(line_info_idx < line_info.count) + { + RDI_Line *line = &line_info.lines[line_info_idx]; + U64 line_voff_min = line_info.voffs[line_info_idx]; + U64 line_voff_opl = line_info.voffs[line_info_idx+1]; + str8_list_pushf(arena, out, "%I64x %I64x %I64u %I64u\n", + line_voff_min, + line_voff_opl-line_voff_min, + (U64)line->line_num, + (U64)line->file_idx); + last_voff = voff; + voff = line_voff_opl; + } + else + { + break; + } + } + } + } + } + return out; +} + +//////////////////////////////// +//~ rjf: Entry Point + +internal void +entry_point(CmdLine *cmdline) +{ + //- rjf: initialize state, 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("?"))); + P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline); + user2convert->flags &= ~(P2R_ConvertFlag_Types|P2R_ConvertFlag_UDTs); + + //- rjf: display help + if(do_help || user2convert->errors.node_count != 0) + { + fprintf(stderr, "--- raddbgi_breakpad_from_pdb -------------------------------------------------\n\n"); + + fprintf(stderr, "This utility converts debug information from PDBs into the textual Breakpad\n"); + fprintf(stderr, "symbol information format, used for various external utilities, using the RAD\n"); + fprintf(stderr, "Debug Info conversion systems. The following arguments are accepted:\n\n"); + + fprintf(stderr, "--exe: [optional] Specifies the path of the executable file for which the\n"); + fprintf(stderr, " debug info was generated.\n"); + fprintf(stderr, "--pdb: Specifies the path of the PDB debug info file to\n"); + fprintf(stderr, " convert.\n"); + fprintf(stderr, "--out: Specifies the path at which the output Breakpad debug\n"); + fprintf(stderr, " info 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_exit_process(0); + } + + //- rjf: convert + P2R_Convert2Bake *convert2bake = 0; + ProfScope("convert") + { + convert2bake = p2r_convert(arena, user2convert); + } + + //- rjf: dump breakpad text + String8List dump = {0}; + ProfScope("dump breakpad text") + { + RDIM_BakeParams *params = &convert2bake->bake_params; + + //- rjf: kick off unit vmap baking + P2B_BakeUnitVMapIn bake_unit_vmap_in = {params}; + TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2b_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in); + + //- rjf: kick off per-unit baking + P2B_BakeUnitIn *bake_units_in = push_array(arena, P2B_BakeUnitIn, params->units.total_count+1); + TS_Ticket *bake_units_tickets = push_array(arena, TS_Ticket, params->units.total_count+1); + { + U64 idx = 1; + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + for(U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, idx += 1) + { + bake_units_in[chunk_idx].unit = &n->v[chunk_idx]; + bake_units_tickets[idx] = ts_kickoff(p2b_bake_unit_task__entry_point, 0, &bake_units_in[chunk_idx]); + } + } + } + + //- rjf: dump MODULE record + str8_list_pushf(arena, &dump, "MODULE windows x86_64 %I64x %S\n", params->top_level_info.exe_hash, params->top_level_info.exe_name); + + //- rjf: dump FILE records + ProfScope("dump FILE records") + { + for(RDIM_SrcFileChunkNode *n = params->src_files.first; n != 0; n = n->next) + { + for(U64 idx = 0; idx < n->count; idx += 1) + { + U64 file_idx = rdim_idx_from_src_file(&n->v[idx]); + String8 src_path = n->v[idx].normal_full_path; + str8_list_pushf(arena, &dump, "FILE %I64u %S\n", file_idx, src_path); + } + } + } + + //- rjf: join unit vmap + ProfBegin("join unit vmap"); + P2B_BakeUnitVMapOut *bake_unit_vmap_out = ts_join_struct(bake_unit_vmap_ticket, max_U64, P2B_BakeUnitVMapOut); + RDI_VMapEntry *unit_vmap = bake_unit_vmap_out->vmap_entries; + U32 unit_vmap_count = (U32)(bake_unit_vmap_out->vmap_entries_count); + ProfEnd(); + + //- rjf: join units + P2B_BakeUnitOut **bake_units_out = push_array(arena, P2B_BakeUnitOut*, params->units.total_count+1); + ProfScope("join units") + { + for(U64 idx = 1; idx < params->units.total_count+1; idx += 1) + { + bake_units_out[idx] = ts_join_struct(bake_units_tickets[idx], max_U64, P2B_BakeUnitOut); + } + } + + //- rjf: kick off FUNC & line record dump tasks + P2B_DumpProcChunkIn *dump_proc_chunk_in = push_array(arena, P2B_DumpProcChunkIn, params->procedures.chunk_count); + TS_Ticket *dump_proc_chunk_tickets = push_array(arena, TS_Ticket, params->procedures.chunk_count); + ProfScope("kick off FUNC & line record dump tasks") + { + U64 task_idx = 0; + for(RDIM_SymbolChunkNode *n = params->procedures.first; n != 0; n = n->next, task_idx += 1) + { + dump_proc_chunk_in[task_idx].unit_vmap = unit_vmap; + dump_proc_chunk_in[task_idx].unit_vmap_count = unit_vmap_count; + dump_proc_chunk_in[task_idx].bake_units_out = bake_units_out; + dump_proc_chunk_in[task_idx].bake_units_out_count = params->units.total_count+1; + dump_proc_chunk_in[task_idx].chunk = n; + dump_proc_chunk_tickets[task_idx] = ts_kickoff(p2b_dump_proc_chunk_task__entry_point, 0, &dump_proc_chunk_in[task_idx]); + } + } + + //- rjf: join FUNC & line record dump tasks + ProfScope("join FUNC & line record dump tasks") + { + for(U64 idx = 0; idx < params->procedures.chunk_count; idx += 1) + { + String8List *out = ts_join_struct(dump_proc_chunk_tickets[idx], max_U64, String8List); + str8_list_concat_in_place(&dump, out); + } + } + } + + //- rjf: bake + String8 baked = {0}; + ProfScope("bake") + { + baked = str8_list_join(arena, &dump, 0); + } + + //- rjf: write + ProfScope("write") + { + OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name); + os_file_write(output_file, r1u64(0, baked.size), baked.str); + os_file_close(output_file); + } +} diff --git a/src/raddbg_dump/raddbg_stringize.c b/src/raddbgi_dump/raddbgi_dump.c similarity index 51% rename from src/raddbg_dump/raddbg_stringize.c rename to src/raddbgi_dump/raddbgi_dump.c index 6bc06597..019be63b 100644 --- a/src/raddbg_dump/raddbg_stringize.c +++ b/src/raddbgi_dump/raddbgi_dump.c @@ -2,52 +2,52 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ RADDBG Common Stringize Functions +//~ rjf: RADDBGI Enum -> String Functions -static String8 -raddbg_string_from_data_section_tag(RADDBG_DataSectionTag tag){ +internal String8 +rdi_string_from_data_section_tag(RDI_DataSectionTag tag){ String8 result = {0}; switch (tag){ #define X(N,C) case C: result = str8_lit(#N); break; #define Y(N) - RADDBG_DataSectionTagXList(X,Y) + RDI_DataSectionTagXList(X,Y) #undef X #undef Y } return(result); } -static String8 -raddbg_string_from_arch(RADDBG_Arch arch){ +internal String8 +rdi_string_from_arch(RDI_Arch arch){ String8 result = {0}; switch (arch){ - default: result = str8_lit(""); break; - case RADDBG_Arch_X86: result = str8_lit("x86"); break; - case RADDBG_Arch_X64: result = str8_lit("x64"); break; + default: result = str8_lit(""); break; + case RDI_Arch_X86: result = str8_lit("x86"); break; + case RDI_Arch_X64: result = str8_lit("x64"); break; } return(result); } -static String8 -raddbg_string_from_language(RADDBG_Language language){ +internal String8 +rdi_string_from_language(RDI_Language language){ String8 result = {0}; switch (language){ #define X(name,code) case code: result = str8_lit(#name); break; - RADDBG_LanguageXList(X) + RDI_LanguageXList(X) #undef X } return(result); } -static String8 -raddbg_string_from_type_kind(RADDBG_TypeKind type_kind){ +internal String8 +rdi_string_from_type_kind(RDI_TypeKind type_kind){ String8 result = {0}; switch (type_kind){ default: result = str8_lit(""); break; #define X(name,code) case code: result = str8_lit(#name); break; #define XZ(name,code,size) X(name,code) #define Y(a,n) - RADDBG_TypeKindXList(X,XZ,Y) + RDI_TypeKindXList(X,XZ,Y) #undef X #undef XZ #undef Y @@ -55,171 +55,169 @@ raddbg_string_from_type_kind(RADDBG_TypeKind type_kind){ return(result); } -static String8 -raddbg_string_from_member_kind(RADDBG_MemberKind member_kind){ +internal String8 +rdi_string_from_member_kind(RDI_MemberKind member_kind){ String8 result = {0}; switch (member_kind){ default: result = str8_lit(""); break; #define X(N,C) case C: result = str8_lit(#N); break; - RADDBG_MemberKindXList(X) + RDI_MemberKindXList(X) #undef X } return(result); } -static String8 -raddbg_string_from_local_kind(RADDBG_LocalKind local_kind){ +internal String8 +rdi_string_from_local_kind(RDI_LocalKind local_kind){ String8 result = {0}; switch (local_kind){ default: result = str8_lit(""); break; - case RADDBG_LocalKind_Parameter: result = str8_lit("Parameter"); break; - case RADDBG_LocalKind_Variable: result = str8_lit("Variable"); break; + case RDI_LocalKind_Parameter: result = str8_lit("Parameter"); break; + case RDI_LocalKind_Variable: result = str8_lit("Variable"); break; } return(result); } - //////////////////////////////// -//~ RADDBG Flags Stringize Functions +//~ rjf: RADDBGI Flags -> String Functions -static void -raddbg_stringize_binary_section_flags(Arena *arena, String8List *out, - RADDBG_BinarySectionFlags flags){ +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")); } - if (flags & RADDBG_BinarySectionFlag_Read){ + if (flags & RDI_BinarySectionFlag_Read){ str8_list_push(arena, out, str8_lit("Read ")); } - if (flags & RADDBG_BinarySectionFlag_Write){ + if (flags & RDI_BinarySectionFlag_Write){ str8_list_push(arena, out, str8_lit("Write ")); } - if (flags & RADDBG_BinarySectionFlag_Execute){ + if (flags & RDI_BinarySectionFlag_Execute){ str8_list_push(arena, out, str8_lit("Execute ")); } } -static void -raddbg_stringize_type_modifier_flags(Arena *arena, String8List *out, - RADDBG_TypeModifierFlags flags){ +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")); } - if (flags & RADDBG_TypeModifierFlag_Const){ + if (flags & RDI_TypeModifierFlag_Const){ str8_list_push(arena, out, str8_lit("Const ")); } - if (flags & RADDBG_TypeModifierFlag_Volatile){ + if (flags & RDI_TypeModifierFlag_Volatile){ str8_list_push(arena, out, str8_lit("Volatile ")); } } -static void -raddbg_stringize_user_defined_type_flags(Arena *arena, String8List *out, - RADDBG_UserDefinedTypeFlags flags){ +internal void +rdi_stringize_user_defined_type_flags(Arena *arena, String8List *out, + RDI_UserDefinedTypeFlags flags){ if (flags == 0){ str8_list_push(arena, out, str8_lit("0")); } - if (flags & RADDBG_UserDefinedTypeFlag_EnumMembers){ + if (flags & RDI_UserDefinedTypeFlag_EnumMembers){ str8_list_push(arena, out, str8_lit("EnumMembers ")); } } -static void -raddbg_stringize_link_flags(Arena *arena, String8List *out, RADDBG_LinkFlags flags){ +internal void +rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags){ if (flags == 0){ str8_list_push(arena, out, str8_lit("0")); } - if (flags & RADDBG_LinkFlag_External){ + if (flags & RDI_LinkFlag_External){ str8_list_push(arena, out, str8_lit("External ")); } - if (flags & RADDBG_LinkFlag_TypeScoped){ + if (flags & RDI_LinkFlag_TypeScoped){ str8_list_push(arena, out, str8_lit("TypeScoped ")); } - if (flags & RADDBG_LinkFlag_ProcScoped){ + if (flags & RDI_LinkFlag_ProcScoped){ str8_list_push(arena, out, str8_lit("ProcScoped ")); } } - //////////////////////////////// -//~ RADDBG Compound Stringize Functions +//~ rjf: RADDBG Compound Stringize Functions -static char raddbg_stringize_spaces[] = " "; +global char rdi_stringize_spaces[] = " "; -static void -raddbg_stringize_data_sections(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - U32 indent_level){ +internal void +rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *parsed, + U32 indent_level){ U64 data_section_count = parsed->dsec_count; - RADDBG_DataSection *ptr = parsed->dsecs; + RDI_DataSection *ptr = parsed->dsecs; for (U64 i = 0; i < data_section_count; i += 1, ptr += 1){ - String8 tag_str = raddbg_string_from_data_section_tag(ptr->tag); + String8 tag_str = rdi_string_from_data_section_tag(ptr->tag); str8_list_pushf(arena, out, "%.*sdata_section[%5u] = {0x%08llx, %7u, %7u} %.*s\n", - indent_level, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, i, ptr->off, ptr->encoded_size, ptr->unpacked_size, str8_varg(tag_str)); } } -static void -raddbg_stringize_top_level_info(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_TopLevelInfo *tli, U32 indent_level){ - String8 arch_str = raddbg_string_from_arch(tli->architecture); +internal void +rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_TopLevelInfo *tli, U32 indent_level){ + String8 arch_str = rdi_string_from_arch(tli->architecture); String8 exe_name = {0}; - exe_name.str = raddbg_string_from_idx(parsed, tli->exe_name_string_idx, &exe_name.size); + exe_name.str = rdi_string_from_idx(parsed, tli->exe_name_string_idx, &exe_name.size); str8_list_pushf(arena, out, "%.*sarchitecture=%.*s\n", - indent_level, raddbg_stringize_spaces, str8_varg(arch_str)); + indent_level, rdi_stringize_spaces, str8_varg(arch_str)); str8_list_pushf(arena, out, "%.*sexe_name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(exe_name)); + indent_level, rdi_stringize_spaces, str8_varg(exe_name)); str8_list_pushf(arena, out, "%.*svoff_max=0x%08llx\n", - indent_level, raddbg_stringize_spaces, tli->voff_max); + indent_level, rdi_stringize_spaces, tli->voff_max); } -static void -raddbg_stringize_binary_section(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_BinarySection *bin_section, U32 indent_level){ +internal void +rdi_stringize_binary_section(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_BinarySection *bin_section, U32 indent_level){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, bin_section->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, bin_section->name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*sname='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); - str8_list_pushf(arena, out, "%.*sflags=", indent_level, raddbg_stringize_spaces); - raddbg_stringize_binary_section_flags(arena, out, bin_section->flags); + 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, raddbg_stringize_spaces, bin_section->voff_first); + indent_level, rdi_stringize_spaces, bin_section->voff_first); str8_list_pushf(arena, out, "%.*svoff_opl =0x%08x\n", - indent_level, raddbg_stringize_spaces, bin_section->voff_opl); + indent_level, rdi_stringize_spaces, bin_section->voff_opl); str8_list_pushf(arena, out, "%.*sfoff_first=0x%08x\n", - indent_level, raddbg_stringize_spaces, bin_section->foff_first); + indent_level, rdi_stringize_spaces, bin_section->foff_first); str8_list_pushf(arena, out, "%.*sfoff_opl =0x%08x\n", - indent_level, raddbg_stringize_spaces, bin_section->foff_opl); + indent_level, rdi_stringize_spaces, bin_section->foff_opl); } -static void -raddbg_stringize_file_path(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_FilePathBundle *bundle, RADDBG_FilePathNode *file_path, - U32 indent_level){ +internal void +rdi_stringize_file_path(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_FilePathBundle *bundle, RDI_FilePathNode *file_path, + U32 indent_level){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, file_path->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, 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, raddbg_stringize_spaces, + 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, raddbg_stringize_spaces, + 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 - RADDBG_FilePathNode *child_node = 0; + RDI_FilePathNode *child_node = 0; if (child < bundle->file_path_count){ child_node = bundle->file_paths + child; } @@ -228,22 +226,22 @@ raddbg_stringize_file_path(Arena *arena, String8List *out, RADDBG_Parsed *parsed } // stringize child - raddbg_stringize_file_path(arena, out, parsed, bundle, child_node, indent_level + 1); + rdi_stringize_file_path(arena, out, parsed, bundle, child_node, indent_level + 1); // increment iterator child = child_node->next_sibling; } } -static void -raddbg_stringize_source_file(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_SourceFile *source_file, U32 indent_level){ +internal void +rdi_stringize_source_file(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_SourceFile *source_file, U32 indent_level){ // extract line map data - RADDBG_ParsedLineMap line_map = {0}; - raddbg_line_map_from_source_file(parsed, source_file, &line_map); + RDI_ParsedLineMap line_map = {0}; + rdi_line_map_from_source_file(parsed, source_file, &line_map); // stringize line map data - str8_list_pushf(arena, out, "%.*slines:\n", indent_level, raddbg_stringize_spaces); + 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]; @@ -261,7 +259,7 @@ raddbg_stringize_source_file(Arena *arena, String8List *out, RADDBG_Parsed *pars } str8_list_pushf(arena, out, "%.*s %u: ", - indent_level, raddbg_stringize_spaces, line_num); + indent_level, rdi_stringize_spaces, line_num); U32 first = line_map.ranges[i]; U32 opl_raw = line_map.ranges[i + 1]; @@ -272,85 +270,85 @@ raddbg_stringize_source_file(Arena *arena, String8List *out, RADDBG_Parsed *pars } else{ str8_list_pushf(arena, out, "%.*s0x%08x\n", - indent_level + digit_count + 3, raddbg_stringize_spaces, + indent_level + digit_count + 3, rdi_stringize_spaces, line_map.voffs[j]); } } } } -static void -raddbg_stringize_unit(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_Unit *unit, U32 indent_level){ +internal void +rdi_stringize_unit(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_Unit *unit, U32 indent_level){ String8 unit_name = {0}; - unit_name.str = raddbg_string_from_idx(parsed, unit->unit_name_string_idx, &unit_name.size); + unit_name.str = rdi_string_from_idx(parsed, unit->unit_name_string_idx, &unit_name.size); String8 compiler_name = {0}; - compiler_name.str = raddbg_string_from_idx(parsed, unit->compiler_name_string_idx, - &compiler_name.size); + compiler_name.str = rdi_string_from_idx(parsed, unit->compiler_name_string_idx, + &compiler_name.size); str8_list_pushf(arena, out, "%.*sunit_name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(unit_name)); + indent_level, rdi_stringize_spaces, str8_varg(unit_name)); str8_list_pushf(arena, out, "%.*scompiler_name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(compiler_name)); + indent_level, rdi_stringize_spaces, str8_varg(compiler_name)); str8_list_pushf(arena, out, "%.*ssource_file_path=%u\n", - indent_level, raddbg_stringize_spaces, unit->source_file_path_node); + indent_level, rdi_stringize_spaces, unit->source_file_path_node); str8_list_pushf(arena, out, "%.*sobject_file_path=%u\n", - indent_level, raddbg_stringize_spaces, unit->object_file_path_node); + indent_level, rdi_stringize_spaces, unit->object_file_path_node); str8_list_pushf(arena, out, "%.*sarchive_file_path=%u\n", - indent_level, raddbg_stringize_spaces, unit->archive_file_path_node); + indent_level, rdi_stringize_spaces, unit->archive_file_path_node); str8_list_pushf(arena, out, "%.*sbuild_path=%u\n", - indent_level, raddbg_stringize_spaces, unit->build_path_node); + indent_level, rdi_stringize_spaces, unit->build_path_node); - String8 language_str = raddbg_string_from_language(unit->language); + String8 language_str = rdi_string_from_language(unit->language); str8_list_pushf(arena, out, "%.*slanguage=%.*s\n", - indent_level, raddbg_stringize_spaces, str8_varg(language_str)); + indent_level, rdi_stringize_spaces, str8_varg(language_str)); // extract line info data - RADDBG_ParsedLineInfo line_info = {0}; - raddbg_line_info_from_unit(parsed, unit, &line_info); + RDI_ParsedLineInfo line_info = {0}; + rdi_line_info_from_unit(parsed, unit, &line_info); // stringize line info - str8_list_pushf(arena, out, "%.*slines:\n", indent_level, raddbg_stringize_spaces); + str8_list_pushf(arena, out, "%.*slines:\n", indent_level, rdi_stringize_spaces); for (U32 i = 0; i < line_info.count; i += 1){ U64 first = line_info.voffs[i]; U64 opl = line_info.voffs[i + 1]; - RADDBG_Line *line = line_info.lines + i; - RADDBG_Column *col = 0; + RDI_Line *line = line_info.lines + i; + RDI_Column *col = 0; if (i < line_info.col_count){ col = line_info.cols + i; } if (col == 0){ str8_list_pushf(arena, out, "%.*s [0x%08llx,0x%08llx) file=%u; line=%u\n", - indent_level, raddbg_stringize_spaces, + 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, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, first, opl, line->file_idx, line->line_num, col->col_first, col->col_opl); } } } -static void -raddbg_stringize_type_node(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_TypeNode *type, U32 indent_level){ - RADDBG_TypeKind kind = type->kind; - String8 type_kind_str = raddbg_string_from_type_kind(kind); +internal void +rdi_stringize_type_node(Arena *arena, String8List *out, RDI_Parsed *parsed, + 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, raddbg_stringize_spaces, str8_varg(type_kind_str)); + indent_level, rdi_stringize_spaces, str8_varg(type_kind_str)); switch (type->kind){ - case RADDBG_TypeKind_Modifier: + case RDI_TypeKind_Modifier: { - str8_list_pushf(arena, out, "%.*sflags=", indent_level, raddbg_stringize_spaces); - raddbg_stringize_type_modifier_flags(arena, out, type->flags); + 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; @@ -358,42 +356,42 @@ raddbg_stringize_type_node(Arena *arena, String8List *out, RADDBG_Parsed *parsed { if (type->flags != 0){ str8_list_pushf(arena, out, "%.*sflags=%x (missing stringizer path)", - indent_level, raddbg_stringize_spaces, type->flags); + indent_level, rdi_stringize_spaces, type->flags); } }break; } str8_list_pushf(arena, out, "%.*sbyte_size=%u\n", - indent_level, raddbg_stringize_spaces, type->byte_size); + indent_level, rdi_stringize_spaces, type->byte_size); - if (RADDBG_TypeKind_FirstBuiltIn <= kind && - kind <= RADDBG_TypeKind_LastBuiltIn){ + if (RDI_TypeKind_FirstBuiltIn <= kind && + kind <= RDI_TypeKind_LastBuiltIn){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, type->built_in.name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, type->built_in.name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*sbuilt_in.name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); } - else if (RADDBG_TypeKind_FirstConstructed <= kind && - kind <= RADDBG_TypeKind_LastConstructed){ + else if (RDI_TypeKind_FirstConstructed <= kind && + kind <= RDI_TypeKind_LastConstructed){ str8_list_pushf(arena, out, "%.*sconstructed.direct_type=%u\n", - indent_level, raddbg_stringize_spaces, type->constructed.direct_type_idx); + indent_level, rdi_stringize_spaces, type->constructed.direct_type_idx); - if (type->kind == RADDBG_TypeKind_Array){ + if (type->kind == RDI_TypeKind_Array){ str8_list_pushf(arena, out, "%.*sconstructed.array_count=%u\n", - indent_level, raddbg_stringize_spaces, type->constructed.count); + indent_level, rdi_stringize_spaces, type->constructed.count); } - if (type->kind == RADDBG_TypeKind_Function || - type->kind == RADDBG_TypeKind_Method){ + 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 = raddbg_idx_run_from_first_count(parsed, run_first, run_count_raw, &run_count); + U32 *run = rdi_idx_run_from_first_count(parsed, run_first, run_count_raw, &run_count); U32 this_type_idx = 0; - if (run_count > 0 && type->kind == RADDBG_TypeKind_Method){ + if (run_count > 0 && type->kind == RDI_TypeKind_Method){ this_type_idx = run[0]; run += 1; run_count -= 1; @@ -401,11 +399,11 @@ raddbg_stringize_type_node(Arena *arena, String8List *out, RADDBG_Parsed *parsed if (this_type_idx != 0){ str8_list_pushf(arena, out, "%.*sconstructed.this_type=%u\n", - indent_level, raddbg_stringize_spaces, this_type_idx); + indent_level, rdi_stringize_spaces, this_type_idx); } str8_list_pushf(arena, out, "%.*sconstructed.params={", - indent_level, raddbg_stringize_spaces); + indent_level, rdi_stringize_spaces); if (run_count > 0){ U32 last = run_count - 1; @@ -419,63 +417,63 @@ raddbg_stringize_type_node(Arena *arena, String8List *out, RADDBG_Parsed *parsed } } - else if (RADDBG_TypeKind_FirstUserDefined <= kind && - kind <= RADDBG_TypeKind_LastUserDefined){ + else if (RDI_TypeKind_FirstUserDefined <= kind && + kind <= RDI_TypeKind_LastUserDefined){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, type->user_defined.name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, type->user_defined.name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*suser_defined.name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); str8_list_pushf(arena, out, "%.*suser_defined.direct_type=%u\n", - indent_level, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, type->user_defined.direct_type_idx); str8_list_pushf(arena, out, "%.*suser_defined.udt=%u\n", - indent_level, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, type->user_defined.udt_idx); } - else if (kind == RADDBG_TypeKind_Bitfield){ + else if (kind == RDI_TypeKind_Bitfield){ str8_list_pushf(arena, out, "%.*sbitfield.off=%u\n", - indent_level, raddbg_stringize_spaces, type->bitfield.off); + indent_level, rdi_stringize_spaces, type->bitfield.off); str8_list_pushf(arena, out, "%.*sbitfield.size=%u\n", - indent_level, raddbg_stringize_spaces, type->bitfield.size); + indent_level, rdi_stringize_spaces, type->bitfield.size); } } -static void -raddbg_stringize_udt(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_UDTMemberBundle *member_bundle, RADDBG_UDT *udt, - U32 indent_level){ +internal void +rdi_stringize_udt(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_UDTMemberBundle *member_bundle, RDI_UDT *udt, + U32 indent_level){ str8_list_pushf(arena, out, "%.*sself_type=%u\n", - indent_level, raddbg_stringize_spaces, udt->self_type_idx); + indent_level, rdi_stringize_spaces, udt->self_type_idx); - str8_list_pushf(arena, out, "%.*sflags=", indent_level, raddbg_stringize_spaces); - raddbg_stringize_user_defined_type_flags(arena, out, udt->flags); + str8_list_pushf(arena, out, "%.*sflags=", indent_level, rdi_stringize_spaces); + rdi_stringize_user_defined_type_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, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, udt->file_idx, udt->line, udt->col); } // enum members - if (udt->flags & RADDBG_UserDefinedTypeFlag_EnumMembers){ + if (udt->flags & RDI_UserDefinedTypeFlag_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, raddbg_stringize_spaces); - RADDBG_EnumMember *enum_member = member_bundle->enum_members + first; + 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 = raddbg_string_from_idx(parsed, enum_member->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, enum_member->name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*s '%.*s' %llu\n", - indent_level, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, str8_varg(name), enum_member->val); } - str8_list_pushf(arena, out, "%.*s}\n", indent_level, raddbg_stringize_spaces); + str8_list_pushf(arena, out, "%.*s}\n", indent_level, rdi_stringize_spaces); } } @@ -487,117 +485,117 @@ raddbg_stringize_udt(Arena *arena, String8List *out, RADDBG_Parsed *parsed, U32 first = ClampTop(first_raw, opl); if (first < opl){ - str8_list_pushf(arena, out, "%.*smembers={\n", indent_level, raddbg_stringize_spaces); - RADDBG_Member *member = member_bundle->members + first; + 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, raddbg_stringize_spaces); + str8_list_pushf(arena, out, "%.*s {\n", indent_level, rdi_stringize_spaces); - String8 kind_str = raddbg_string_from_member_kind(member->kind); + String8 kind_str = rdi_string_from_member_kind(member->kind); str8_list_pushf(arena, out, "%.*s kind=%.*s\n", - indent_level, raddbg_stringize_spaces, str8_varg(kind_str)); + indent_level, rdi_stringize_spaces, str8_varg(kind_str)); if (member->name_string_idx != 0){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, member->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, member->name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*s name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); } str8_list_pushf(arena, out, "%.*s type=%u\n", - indent_level, raddbg_stringize_spaces, member->type_idx); + indent_level, rdi_stringize_spaces, member->type_idx); str8_list_pushf(arena, out, "%.*s off=%u\n", - indent_level, raddbg_stringize_spaces, member->off); + indent_level, rdi_stringize_spaces, member->off); - str8_list_pushf(arena, out, "%.*s }\n", indent_level, raddbg_stringize_spaces); + str8_list_pushf(arena, out, "%.*s }\n", indent_level, rdi_stringize_spaces); } - str8_list_pushf(arena, out, "%.*s}\n", indent_level, raddbg_stringize_spaces); + str8_list_pushf(arena, out, "%.*s}\n", indent_level, rdi_stringize_spaces); } } } -static void -raddbg_stringize_global_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_GlobalVariable *global_variable, U32 indent_level){ +internal void +rdi_stringize_global_variable(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_GlobalVariable *global_variable, U32 indent_level){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, global_variable->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, global_variable->name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*sname='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); - str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, raddbg_stringize_spaces); - raddbg_stringize_link_flags(arena, out, global_variable->link_flags); + 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, raddbg_stringize_spaces, global_variable->voff); + indent_level, rdi_stringize_spaces, global_variable->voff); str8_list_pushf(arena, out, "%.*stype_idx=%u\n", - indent_level, raddbg_stringize_spaces, global_variable->type_idx); + indent_level, rdi_stringize_spaces, global_variable->type_idx); str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", - indent_level, raddbg_stringize_spaces, global_variable->container_idx); + indent_level, rdi_stringize_spaces, global_variable->container_idx); } -static void -raddbg_stringize_thread_variable(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_ThreadVariable *thread_var, - U32 indent_level){ +internal void +rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_ThreadVariable *thread_var, + U32 indent_level){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, thread_var->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, thread_var->name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*sname='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); - str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, raddbg_stringize_spaces); - raddbg_stringize_link_flags(arena, out, thread_var->link_flags); + 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, raddbg_stringize_spaces, thread_var->tls_off); + indent_level, rdi_stringize_spaces, thread_var->tls_off); str8_list_pushf(arena, out, "%.*stype_idx=%u\n", - indent_level, raddbg_stringize_spaces, thread_var->type_idx); + indent_level, rdi_stringize_spaces, thread_var->type_idx); str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", - indent_level, raddbg_stringize_spaces, thread_var->container_idx); + indent_level, rdi_stringize_spaces, thread_var->container_idx); } -static void -raddbg_stringize_procedure(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_Procedure *proc, U32 indent_level){ +internal void +rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_Procedure *proc, U32 indent_level){ String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, proc->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, proc->name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*sname='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); String8 link_name = {0}; - link_name.str = raddbg_string_from_idx(parsed, proc->link_name_string_idx, &link_name.size); + link_name.str = rdi_string_from_idx(parsed, proc->link_name_string_idx, &link_name.size); str8_list_pushf(arena, out, "%.*slink_name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(link_name)); + indent_level, rdi_stringize_spaces, str8_varg(link_name)); - str8_list_pushf(arena, out, "%.*slink_flags=", indent_level, raddbg_stringize_spaces); - raddbg_stringize_link_flags(arena, out, proc->link_flags); + 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, raddbg_stringize_spaces, proc->type_idx); + indent_level, rdi_stringize_spaces, proc->type_idx); str8_list_pushf(arena, out, "%.*sroot_scope_idx=%u\n", - indent_level, raddbg_stringize_spaces, proc->root_scope_idx); + indent_level, rdi_stringize_spaces, proc->root_scope_idx); str8_list_pushf(arena, out, "%.*scontainer_idx=%u\n", - indent_level, raddbg_stringize_spaces, proc->container_idx); + indent_level, rdi_stringize_spaces, proc->container_idx); } -static void -raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, - RADDBG_ScopeBundle *bundle, RADDBG_Scope *scope, U32 indent_level){ +internal void +rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *parsed, + RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level){ U32 this_idx = (U32)(scope - bundle->scopes); str8_list_pushf(arena, out, "%.*s[%u]\n", - indent_level, raddbg_stringize_spaces, this_idx); + indent_level, rdi_stringize_spaces, this_idx); str8_list_pushf(arena, out, "%.*s proc_idx=%u\n", - indent_level, raddbg_stringize_spaces, scope->proc_idx); + indent_level, rdi_stringize_spaces, scope->proc_idx); // voff ranges { @@ -614,18 +612,18 @@ raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, if (voff_range_opl - voff_range_first > 2){ str8_list_pushf(arena, out, "%.*s voff_ranges={\n", - indent_level, raddbg_stringize_spaces); + 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, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, voff_ptr[0], voff_ptr[1]); } str8_list_pushf(arena, out, "%.*s }\n", - indent_level, raddbg_stringize_spaces); + 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, raddbg_stringize_spaces, + indent_level, rdi_stringize_spaces, voff_ptr[0], voff_ptr[1]); } } @@ -637,60 +635,60 @@ raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, U32 local_opl = ClampTop(local_opl_raw, bundle->local_count); if (local_first < local_opl){ - RADDBG_Local *local_ptr = bundle->locals + local_first; + 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, raddbg_stringize_spaces, i); + indent_level, rdi_stringize_spaces, i); - String8 local_kind_str = raddbg_string_from_local_kind(local_ptr->kind); + String8 local_kind_str = rdi_string_from_local_kind(local_ptr->kind); str8_list_pushf(arena, out, "%.*s kind=%.*s\n", - indent_level, raddbg_stringize_spaces, str8_varg(local_kind_str)); + indent_level, rdi_stringize_spaces, str8_varg(local_kind_str)); String8 name = {0}; - name.str = raddbg_string_from_idx(parsed, local_ptr->name_string_idx, &name.size); + name.str = rdi_string_from_idx(parsed, local_ptr->name_string_idx, &name.size); str8_list_pushf(arena, out, "%.*s name='%.*s'\n", - indent_level, raddbg_stringize_spaces, str8_varg(name)); + indent_level, rdi_stringize_spaces, str8_varg(name)); str8_list_pushf(arena, out, "%.*s type_idx=%u\n", - indent_level, raddbg_stringize_spaces, local_ptr->type_idx); + 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, raddbg_stringize_spaces); - RADDBG_LocationBlock *block_ptr = bundle->location_blocks + location_first; + 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, raddbg_stringize_spaces); + 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, raddbg_stringize_spaces, + 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, raddbg_stringize_spaces); + indent_level, rdi_stringize_spaces); } else{ - str8_list_pushf(arena, out, "%.*s ", indent_level, raddbg_stringize_spaces); + 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; - RADDBG_LocationKind kind = (RADDBG_LocationKind)*loc_base_ptr; + RDI_LocationKind kind = (RDI_LocationKind)*loc_base_ptr; switch (kind){ default: { str8_list_pushf(arena, out, "\n"); }break; - case RADDBG_LocationKind_AddrBytecodeStream: + case RDI_LocationKind_AddrBytecodeStream: { str8_list_pushf(arena, out, "AddrBytecodeStream\n"); - str8_list_pushf(arena, out, "%.*s ", indent_level, raddbg_stringize_spaces); + 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); @@ -698,10 +696,10 @@ raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, str8_list_pushf(arena, out, "\n"); }break; - case RADDBG_LocationKind_ValBytecodeStream: + case RDI_LocationKind_ValBytecodeStream: { str8_list_pushf(arena, out, "ValBytecodeStream\n"); - str8_list_pushf(arena, out, "%.*s ", indent_level, raddbg_stringize_spaces); + 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); @@ -709,37 +707,37 @@ raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, str8_list_pushf(arena, out, "\n"); }break; - case RADDBG_LocationKind_AddrRegisterPlusU16: + case RDI_LocationKind_AddrRegisterPlusU16: { - if (loc_base_ptr + sizeof(RADDBG_LocationRegisterPlusU16) > loc_data_opl){ + if (loc_base_ptr + sizeof(RDI_LocationRegisterPlusU16) > loc_data_opl){ str8_list_pushf(arena, out, "AddrRegisterPlusU16( )\n"); } else{ - RADDBG_LocationRegisterPlusU16 *loc = (RADDBG_LocationRegisterPlusU16*)loc_base_ptr; + RDI_LocationRegisterPlusU16 *loc = (RDI_LocationRegisterPlusU16*)loc_base_ptr; str8_list_pushf(arena, out, "AddrRegisterPlusU16(reg: %u, off: %u)\n", loc->register_code, loc->offset); } }break; - case RADDBG_LocationKind_AddrAddrRegisterPlusU16: + case RDI_LocationKind_AddrAddrRegisterPlusU16: { - if (loc_base_ptr + sizeof(RADDBG_LocationRegisterPlusU16) > loc_data_opl){ + if (loc_base_ptr + sizeof(RDI_LocationRegisterPlusU16) > loc_data_opl){ str8_list_pushf(arena, out, "AddrAddrRegisterPlusU16( )\n"); } else{ - RADDBG_LocationRegisterPlusU16 *loc = (RADDBG_LocationRegisterPlusU16*)loc_base_ptr; + RDI_LocationRegisterPlusU16 *loc = (RDI_LocationRegisterPlusU16*)loc_base_ptr; str8_list_pushf(arena, out, "AddrAddrRegisterPlusU16(reg: %u, off: %u)\n", loc->register_code, loc->offset); } }break; - case RADDBG_LocationKind_ValRegister: + case RDI_LocationKind_ValRegister: { - if (loc_base_ptr + sizeof(RADDBG_LocationRegister) > loc_data_opl){ + if (loc_base_ptr + sizeof(RDI_LocationRegister) > loc_data_opl){ str8_list_pushf(arena, out, "ValRegister( )\n"); } else{ - RADDBG_LocationRegister *loc = (RADDBG_LocationRegister*)loc_base_ptr; + RDI_LocationRegister *loc = (RDI_LocationRegister*)loc_base_ptr; str8_list_pushf(arena, out, "ValRegister(reg: %u)\n", loc->register_code); } }break; @@ -756,7 +754,7 @@ raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, for (U32 child = scope->first_child_scope_idx; child != 0;){ // get scope for child - RADDBG_Scope *child_scope = 0; + RDI_Scope *child_scope = 0; if (child < bundle->scope_count){ child_scope = bundle->scopes + child; } @@ -765,12 +763,12 @@ raddbg_stringize_scope(Arena *arena, String8List *out, RADDBG_Parsed *parsed, } // stringize child - raddbg_stringize_scope(arena, out, parsed, bundle, child_scope, indent_level + 1); + rdi_stringize_scope(arena, out, parsed, 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, raddbg_stringize_spaces, this_idx); + indent_level, rdi_stringize_spaces, this_idx); } diff --git a/src/raddbgi_dump/raddbgi_dump.h b/src/raddbgi_dump/raddbgi_dump.h new file mode 100644 index 00000000..add5f987 --- /dev/null +++ b/src/raddbgi_dump/raddbgi_dump.h @@ -0,0 +1,75 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBGI_DUMP_H +#define RADDBGI_DUMP_H + +//////////////////////////////// +//~ rjf: RADDBG Stringize Helper Types + +typedef struct RDI_FilePathBundle RDI_FilePathBundle; +struct RDI_FilePathBundle +{ + RDI_FilePathNode *file_paths; + U32 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: RADDBGI Enum -> String Functions + +internal String8 rdi_string_from_data_section_tag(RDI_DataSectionTag tag); +internal String8 rdi_string_from_arch(RDI_Arch arch); +internal String8 rdi_string_from_language(RDI_Language language); +internal String8 rdi_string_from_type_kind(RDI_TypeKind type_kind); +internal String8 rdi_string_from_member_kind(RDI_MemberKind member_kind); +internal String8 rdi_string_from_local_kind(RDI_LocalKind local_kind); + +//////////////////////////////// +//~ rjf: RADDBGI 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_user_defined_type_flags(Arena *arena, String8List *out, RDI_UserDefinedTypeFlags flags); +internal void rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags); + +//////////////////////////////// +//~ rjf: RADDBG Compound Stringize Functions + +internal void rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *parsed, U32 indent_level); +internal void rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_TopLevelInfo *tli, U32 indent_level); +internal void rdi_stringize_binary_section(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_BinarySection *bin_section, U32 indent_level); +internal void rdi_stringize_file_path(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_FilePathBundle *bundle, RDI_FilePathNode *file_path, U32 indent_level); +internal void rdi_stringize_source_file(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_SourceFile *source_file, U32 indent_level); +internal void rdi_stringize_unit(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_Unit *unit, U32 indent_level); +internal void rdi_stringize_type_node(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_TypeNode *type, U32 indent_level); +internal void rdi_stringize_udt(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_UDTMemberBundle *bundle, RDI_UDT *udt, U32 indent_level); +internal void rdi_stringize_global_variable(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_GlobalVariable *global_variable, U32 indent_level); +internal void rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_ThreadVariable *thread_var, U32 indent_level); +internal void rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_Procedure *proc, U32 indent_level); +internal void rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level); + +#endif // RADDBGI_DUMP_H diff --git a/src/raddbgi_dump/raddbgi_dump_main.c b/src/raddbgi_dump/raddbgi_dump_main.c new file mode 100644 index 00000000..6120be19 --- /dev/null +++ b/src/raddbgi_dump/raddbgi_dump_main.c @@ -0,0 +1,431 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Build Options + +#define BUILD_VERSION_MAJOR 0 +#define BUILD_VERSION_MINOR 9 +#define BUILD_VERSION_PATCH 9 +#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +#define BUILD_TITLE "raddbgi_dump" +#define BUILD_CONSOLE_INTERFACE 1 + +//////////////////////////////// +//~ rjf: Includes + +//- rjf: [lib] +#include "lib_raddbgi_format/raddbgi_format.h" +#include "lib_raddbgi_format/raddbgi_format_parse.h" +#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_raddbgi_format/raddbgi_format_parse.c" + +//- rjf: [h] +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "raddbgi_dump.h" + +//- rjf: [c] +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "raddbgi_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_Units = (1<<5), + DumpFlag_UnitVMap = (1<<6), + DumpFlag_TypeNodes = (1<<7), + DumpFlag_UDTs = (1<<8), + DumpFlag_GlobalVariables = (1<<9), + DumpFlag_GlobalVMap = (1<<10), + DumpFlag_ThreadVariables = (1<<11), + DumpFlag_Procedures = (1<<12), + DumpFlag_Scopes = (1<<13), + DumpFlag_ScopeVMap = (1<<14), + DumpFlag_NameMaps = (1<<15), + DumpFlag_Strings = (1<<16), + }; + String8 input_name = {0}; + String8 input_data = {0}; + DumpFlags dump_flags = (U32)0xffffffff; + { + // rjf: extract input file path & load data + input_name = str8_list_first(&cmd_line->inputs); + if(input_name.size > 0) { input_data = os_data_from_file_path(arena, input_name); } + else {str8_list_pushf(arena, &errors, "error (input): No input RADDBGI file specified.");} + if(input_name.size != 0 && input_data.size == 0) { str8_list_pushf(arena, &errors, "error (input): No input RADDBGI file successfully loaded; either the path or file contents are invalid."); } + + // rjf: extract dump options + { + String8List dump_options = cmd_line_strings(cmd_line, str8_lit("dump")); + 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("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("name_maps"), StringMatchFlag_CaseInsensitive)) { dump_flags |= DumpFlag_NameMaps; } + } + } + } + } + + ////////////////////////////// + //- rjf: parse raddbg from input data + // + RDI_ParseStatus parse_status = RDI_ParseStatus_Good; + RDI_Parsed raddbg_ = {0}; + RDI_Parsed *raddbg = &raddbg_; + { + parse_status = rdi_parse(input_data.str, input_data.size, &raddbg_); + if(parse_status != RDI_ParseStatus_Good) + { + str8_list_pushf(arena, &errors, "error (parse): RADDBGI file wasn't parsed successfully. (0x%x)", parse_status); + } + } + + ////////////////////////////// + //- 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(parse_status == RDI_ParseStatus_Good) + { + //- rjf: DATA SECTIONS + if(dump_flags & DumpFlag_DataSections) + { + str8_list_pushf(arena, &dump, "# DATA SECTIONS:\n"); + rdi_stringize_data_sections(arena, &dump, raddbg, 1); + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: TOP LEVEL INFO + if(dump_flags & DumpFlag_TopLevelInfo) + { + str8_list_pushf(arena, &dump, "# TOP LEVEL INFO:\n"); + rdi_stringize_top_level_info(arena, &dump, raddbg, raddbg->top_level_info, 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"); + RDI_BinarySection *ptr = raddbg->binary_sections; + for(U32 i = 0; i < raddbg->binary_sections_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " section[%u]:\n", i); + rdi_stringize_binary_section(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + 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 = raddbg->file_paths; + file_path_bundle.file_path_count = raddbg->file_paths_count; + } + str8_list_pushf(arena, &dump, "# FILE PATHS\n"); + RDI_FilePathNode *ptr = raddbg->file_paths; + for(U32 i = 0; i < raddbg->file_paths_count; i += 1, ptr += 1) + { + if(ptr->parent_path_node == 0) + { + rdi_stringize_file_path(arena, &dump, raddbg, &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"); + RDI_SourceFile *ptr = raddbg->source_files; + for(U32 i = 0; i < raddbg->source_files_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " source_file[%u]:\n", i); + rdi_stringize_source_file(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: UNITS + if(dump_flags & DumpFlag_Units) + { + str8_list_pushf(arena, &dump, "# UNITS\n"); + RDI_Unit *ptr = raddbg->units; + for (U32 i = 0; i < raddbg->units_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " unit[%u]:\n", i); + rdi_stringize_unit(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: UNIT VMAP + if(dump_flags & DumpFlag_UnitVMap) + { + str8_list_pushf(arena, &dump, "# UNIT VMAP\n"); + RDI_VMapEntry *ptr = raddbg->unit_vmap; + for(U32 i = 0; i < raddbg->unit_vmap_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->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"); + RDI_TypeNode *ptr = raddbg->type_nodes; + for(U32 i = 0; i < raddbg->type_nodes_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " type[%u]:\n", i); + rdi_stringize_type_node(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: UDT DATA + if(dump_flags & DumpFlag_UDTs) + { + RDI_UDTMemberBundle member_bundle = {0}; + { + member_bundle.members = raddbg->members; + member_bundle.enum_members = raddbg->enum_members; + member_bundle.member_count = raddbg->members_count; + member_bundle.enum_member_count = raddbg->enum_members_count; + } + str8_list_pushf(arena, &dump, "# UDTS:\n"); + RDI_UDT *ptr = raddbg->udts; + for(U32 i = 0; i < raddbg->udts_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " udt[%u]:\n", i); + rdi_stringize_udt(arena, &dump, raddbg, &member_bundle, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + 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_GlobalVariable *ptr = raddbg->global_variables; + for(U32 i = 0; i < raddbg->global_variables_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " global_variable[%u]:\n", i); + rdi_stringize_global_variable(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: GLOBAL VMAP + if(dump_flags & DumpFlag_GlobalVMap) + { + str8_list_pushf(arena, &dump, "# GLOBAL VMAP:\n"); + RDI_VMapEntry *ptr = raddbg->global_vmap; + for(U32 i = 0; i < raddbg->global_vmap_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->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"); + RDI_ThreadVariable *ptr = raddbg->thread_variables; + for(U32 i = 0; i < raddbg->thread_variables_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " thread_variable[%u]:\n", i); + rdi_stringize_thread_variable(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: PROCEDURES + if(dump_flags & DumpFlag_Procedures) + { + str8_list_pushf(arena, &dump, "# PROCEDURES:\n"); + RDI_Procedure *ptr = raddbg->procedures; + for(U32 i = 0; i < raddbg->procedures_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " procedure[%u]:\n", i); + rdi_stringize_procedure(arena, &dump, raddbg, ptr, 2); + str8_list_push(arena, &dump, str8_lit("\n")); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: SCOPES + if(dump_flags & DumpFlag_Scopes) + { + RDI_ScopeBundle scope_bundle = {0}; + { + scope_bundle.scopes = raddbg->scopes; + scope_bundle.scope_count = raddbg->scopes_count; + scope_bundle.scope_voffs = raddbg->scope_voffs; + scope_bundle.scope_voff_count = raddbg->scope_voffs_count; + scope_bundle.locals = raddbg->locals; + scope_bundle.local_count = raddbg->locals_count; + scope_bundle.location_blocks = raddbg->location_blocks; + scope_bundle.location_block_count = raddbg->location_blocks_count; + scope_bundle.location_data = raddbg->location_data; + scope_bundle.location_data_size = raddbg->location_data_size; + } + str8_list_pushf(arena, &dump, "# SCOPES:\n"); + RDI_Scope *ptr = raddbg->scopes; + for(U32 i = 0; i < raddbg->scopes_count; i += 1, ptr += 1) + { + if(ptr->parent_scope_idx == 0) + { + rdi_stringize_scope(arena, &dump, raddbg, &scope_bundle, ptr, 1); + str8_list_push(arena, &dump, str8_lit("\n")); + } + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: SCOPE VMAP + if(dump_flags & DumpFlag_ScopeVMap) + { + str8_list_pushf(arena, &dump, "# SCOPE VMAP:\n"); + RDI_VMapEntry *ptr = raddbg->scope_vmap; + for(U32 i = 0; i < raddbg->scope_vmap_count; i += 1, ptr += 1) + { + str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); + } + str8_list_push(arena, &dump, str8_lit("\n")); + } + + //- rjf: NAME MAPS + if(dump_flags & DumpFlag_NameMaps) + { + str8_list_pushf(arena, &dump, "# NAME MAP:\n"); + RDI_NameMap *ptr = raddbg->name_maps; + for(U32 i = 0; i < raddbg->name_maps_count; i += 1, ptr += 1) + { + RDI_ParsedNameMap name_map = {0}; + rdi_name_map_parse(raddbg, ptr, &name_map); + str8_list_pushf(arena, &dump, " name_map[%u]:\n", i); + 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(raddbg, 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(raddbg, 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"); + for(U64 string_idx = 0; string_idx < raddbg->string_count; string_idx += 1) + { + String8 string = {0}; + string.str = rdi_string_from_idx(raddbg, string_idx, &string.size); + str8_list_pushf(arena, &dump, " string[%I64u]: \"%S\"\n", string_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/raddbg_convert/dwarf/raddbg_dwarf.c b/src/raddbgi_from_dwarf/raddbgi_dwarf.c similarity index 99% rename from src/raddbg_convert/dwarf/raddbg_dwarf.c rename to src/raddbgi_from_dwarf/raddbgi_dwarf.c index 06abc03c..a9f43b52 100644 --- a/src/raddbg_convert/dwarf/raddbg_dwarf.c +++ b/src/raddbgi_from_dwarf/raddbgi_dwarf.c @@ -374,7 +374,7 @@ dwarf_names_from_data(Arena *arena, String8 data){ U8 *augmentation_string = ptr; { U8 *ptr_raw = ptr + augmentation_string_size; - ptr = PtrClampTop(ptr_raw, unit_opl); + ptr = ClampTop(ptr_raw, unit_opl); } // offset size @@ -555,7 +555,7 @@ dwarf_line_from_data(Arena *arena, String8 data){ // header opl U8 *header_opl_raw = ptr + header_length; - U8 *header_opl = PtrClampTop(header_opl_raw, unit_opl); + U8 *header_opl = ClampTop(header_opl_raw, unit_opl); // minimum_instruction_length minimum_instruction_length = MemoryConsume(U8, ptr, header_opl); @@ -662,7 +662,7 @@ dwarf_line_from_data(Arena *arena, String8 data){ // header opl U8 *header_opl_raw = ptr + header_length; - U8 *header_opl = PtrClampTop(header_opl_raw, unit_opl); + U8 *header_opl = ClampTop(header_opl_raw, unit_opl); // minimum_instruction_length minimum_instruction_length = MemoryConsume(U8, ptr, header_opl); diff --git a/src/raddbg_convert/dwarf/raddbg_dwarf.h b/src/raddbgi_from_dwarf/raddbgi_dwarf.h similarity index 90% rename from src/raddbg_convert/dwarf/raddbg_dwarf.h rename to src/raddbgi_from_dwarf/raddbgi_dwarf.h index f9927685..186f0486 100644 --- a/src/raddbg_convert/dwarf/raddbg_dwarf.h +++ b/src/raddbgi_from_dwarf/raddbgi_dwarf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_DWARF_H -#define RADDBG_DWARF_H +#ifndef RADDBGI_DWARF_H +#define RADDBGI_DWARF_H // https://dwarfstd.org/doc/DWARF4.pdf // https://dwarfstd.org/doc/DWARF5.pdf @@ -1260,6 +1260,167 @@ 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 @@ -1328,5 +1489,5 @@ 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 //RADDBG_DWARF_H +#endif //RADDBGI_DWARF_H diff --git a/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.c b/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.c similarity index 100% rename from src/raddbg_convert/dwarf/raddbg_dwarf_stringize.c rename to src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.c diff --git a/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.h b/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h similarity index 87% rename from src/raddbg_convert/dwarf/raddbg_dwarf_stringize.h rename to src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h index dc322ad1..d8cd9e87 100644 --- a/src/raddbg_convert/dwarf/raddbg_dwarf_stringize.h +++ b/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_DWARF_STRINGIZE_H -#define RADDBG_DWARF_STRINGIZE_H +#ifndef RADDBGI_DWARF_STRINGIZE_H +#define RADDBGI_DWARF_STRINGIZE_H //////////////////////////////// //~ DWARF Stringize Functions @@ -25,4 +25,4 @@ dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 i -#endif //RADDBG_DWARF_STRINGIZE_H +#endif //RADDBGI_DWARF_STRINGIZE_H diff --git a/src/raddbg_convert/dwarf/raddbg_elf.c b/src/raddbgi_from_dwarf/raddbgi_elf.c similarity index 100% rename from src/raddbg_convert/dwarf/raddbg_elf.c rename to src/raddbgi_from_dwarf/raddbgi_elf.c diff --git a/src/raddbg_convert/dwarf/raddbg_elf.h b/src/raddbgi_from_dwarf/raddbgi_elf.h similarity index 99% rename from src/raddbg_convert/dwarf/raddbg_elf.h rename to src/raddbgi_from_dwarf/raddbgi_elf.h index 5b04c11e..99882ec4 100644 --- a/src/raddbg_convert/dwarf/raddbg_elf.h +++ b/src/raddbgi_from_dwarf/raddbgi_elf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_ELF_H -#define RADDBG_ELF_H +#ifndef RADDBGI_ELF_H +#define RADDBGI_ELF_H // https://refspecs.linuxfoundation.org/elf/elf.pdf @@ -514,4 +514,4 @@ 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 //RADDBG_ELF_H +#endif //RADDBGI_ELF_H diff --git a/src/raddbg_convert/dwarf/raddbg_from_dwarf.c b/src/raddbgi_from_dwarf/raddbgi_from_dwarf.c similarity index 97% rename from src/raddbg_convert/dwarf/raddbg_from_dwarf.c rename to src/raddbgi_from_dwarf/raddbgi_from_dwarf.c index 76c013bc..e8607272 100644 --- a/src/raddbg_convert/dwarf/raddbg_from_dwarf.c +++ b/src/raddbgi_from_dwarf/raddbgi_from_dwarf.c @@ -1,32 +1,31 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +#include "lib_raddbgi_format/raddbgi_format.h" #include "base/base_inc.h" #include "os/os_inc.h" -#include "raddbg_format/raddbg_format.h" -#include "raddbg_cons/raddbg_cons.h" +#include "raddbgi_make_local/raddbgi_make_local.h" -#include "raddbg_elf.h" -#include "raddbg_dwarf.h" +#include "raddbgi_elf.h" +#include "raddbgi_dwarf.h" -#include "raddbg_dwarf_stringize.h" +#include "raddbgi_dwarf_stringize.h" -#include "raddbg_from_dwarf.h" +#include "raddbgi_from_dwarf.h" +#include "lib_raddbgi_format/raddbgi_format.c" #include "base/base_inc.c" #include "os/os_inc.c" -#include "raddbg_format/raddbg_format.c" -#include "raddbg_cons/raddbg_cons.c" +#include "raddbgi_make_local/raddbgi_make_local.c" -#include "raddbg_elf.c" -#include "raddbg_dwarf.c" +#include "raddbgi_elf.c" +#include "raddbgi_dwarf.c" -#include "raddbg_dwarf_stringize.c" +#include "raddbgi_dwarf_stringize.c" // TODO(allen): // [ ] need sample data for .debug_names - //////////////////////////////// //~ Program Parameters Parser @@ -397,30 +396,13 @@ dump_entry_tree(Arena *arena, String8List *out, } #endif -int -main(int argc, char **argv){ - local_persist TCTX main_thread_tctx = {0}; - tctx_init_and_equip(&main_thread_tctx); - -#if PROFILE_TELEMETRY - U64 tm_data_size = GB(1); - U8 *tm_data = os_reserve(tm_data_size); - os_commit(tm_data, tm_data_size); - tmLoadLibrary(TM_RELEASE); - tmSetMaxThreadCount(1024); - tmInitialize(tm_data_size, tm_data); -#endif - - ThreadName("[main]"); - +internal void +entry_point(CmdLine *cmd_line) +{ Arena *arena = arena_alloc(); - String8List args = os_string_list_from_argcv(arena, argc, argv); - CmdLine cmdline = cmd_line_from_string_list(arena, args); - - ProfBeginCapture("raddbg_from_dwarf"); // parse arguments - DWARFCONV_Params *params = dwarf_convert_params_from_cmd_line(arena, &cmdline); + DWARFCONV_Params *params = dwarf_convert_params_from_cmd_line(arena, cmd_line); // show input errors if (params->errors.node_count > 0 && @@ -899,7 +881,4 @@ fprintf(stdout, "error(parsing): " fmt "\n", __VA_ARGS__); \ fwrite(node->string.str, 1, node->string.size, stdout); } } - - ProfEndCapture(); - return(0); } diff --git a/src/raddbg_convert/dwarf/raddbg_from_dwarf.h b/src/raddbgi_from_dwarf/raddbgi_from_dwarf.h similarity index 91% rename from src/raddbg_convert/dwarf/raddbg_from_dwarf.h rename to src/raddbgi_from_dwarf/raddbgi_from_dwarf.h index 46ed6616..82052c44 100644 --- a/src/raddbg_convert/dwarf/raddbg_from_dwarf.h +++ b/src/raddbgi_from_dwarf/raddbgi_from_dwarf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBG_FROM_DWARF_H -#define RADDBG_FROM_DWARF_H +#ifndef RADDBGI_FROM_DWARF_H +#define RADDBGI_FROM_DWARF_H //////////////////////////////// //~ Program Parameters Type @@ -47,4 +47,4 @@ static DWARFCONV_Params *dwarf_convert_params_from_cmd_line(Arena *arena, CmdLin -#endif //RADDBG_FROM_DWARF_H +#endif //RADDBGI_FROM_DWARF_H diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/raddbgi_from_pdb/raddbgi_from_pdb.c new file mode 100644 index 00000000..86b9cf99 --- /dev/null +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.c @@ -0,0 +1,4222 @@ +// 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) + +//////////////////////////////// +//~ 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: Command Line -> Conversion Inputs + +internal P2R_User2Convert * +p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline) +{ + P2R_User2Convert *result = push_array(arena, P2R_User2Convert, 1); + + //- rjf: get input pdb + { + String8 input_name = cmd_line_string(cmdline, str8_lit("pdb")); + if(input_name.size == 0) + { + str8_list_push(arena, &result->errors, str8_lit("Missing required parameter: '--pdb:'")); + } + 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 PDB file from '%S'", input_name); + } + if(input_data.size != 0) + { + result->input_pdb_name = input_name; + result->input_pdb_data = input_data; + } + } + } + + //- rjf: get input exe + { + String8 input_name = cmd_line_string(cmdline, str8_lit("exe")); + 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 EXE file from '%S'", input_name); + } + if(input_data.size != 0) + { + result->input_exe_name = input_name; + result->input_exe_data = input_data; + } + } + } + + //- rjf: get output name + { + result->output_name = cmd_line_string(cmdline, str8_lit("out")); + if(result->output_name.size == 0) + { + str8_list_pushf(arena, &result->errors, "Missing required parameter: '--out:'"); + } + } + + //- rjf: get flags + { + result->flags = P2R_ConvertFlag_All; + } + + return result; +} + +//////////////////////////////// +//~ rjf: COFF <-> RADDBGI Canonical Conversions + +internal RDI_BinarySectionFlags +p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) +{ + RDI_BinarySectionFlags result = 0; + if(flags & COFF_SectionFlag_MEM_READ) + { + result |= RDI_BinarySectionFlag_Read; + } + if(flags & COFF_SectionFlag_MEM_WRITE) + { + result |= RDI_BinarySectionFlag_Write; + } + if(flags & COFF_SectionFlag_MEM_EXECUTE) + { + result |= RDI_BinarySectionFlag_Execute; + } + return(result); +} + +//////////////////////////////// +//~ rjf: CodeView <-> RADDBGI Canonical Conversions + +internal RDI_Arch +p2r_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_RegisterCode +p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code) +{ + RDI_RegisterCode result = 0; + switch(arch) + { + case RDI_Arch_X86: + { + switch(reg_code) + { +#define X(CVN,C,RDN,BP,BZ) case C: result = RDI_RegisterCode_X86_##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_RegisterCode_X64_##RDN; break; + CV_Reg_X64_XList(X) +#undef X + } + }break; + } + return(result); +} + +internal RDI_Language +p2r_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_TypeKind +p2r_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_Handle;}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; +} + +//////////////////////////////// +//~ rjf: Location Info Building Helpers + +internal RDIM_Location * +p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegisterCode 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 CV_EncodedFramePtrReg +p2r_cv_encoded_fp_reg_from_frameproc(CV_SymFrameproc *frameproc, B32 param_base) +{ + CV_EncodedFramePtrReg result = 0; + CV_FrameprocFlags flags = frameproc->flags; + if(param_base) + { + result = CV_FrameprocFlags_ExtractParamBasePointer(flags); + } + else + { + result = CV_FrameprocFlags_ExtractLocalBasePointer(flags); + } + return result; +} + +internal RDI_RegisterCode +p2r_reg_code_from_arch_encoded_fp_reg(RDI_Arch arch, CV_EncodedFramePtrReg encoded_reg) +{ + RDI_RegisterCode 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_RegisterCode_X86_ebp; + }break; + case CV_EncodedFramePtrReg_BasePtr: + { + result = RDI_RegisterCode_X86_ebx; + }break; + } + }break; + case RDI_Arch_X64: + { + switch(encoded_reg) + { + case CV_EncodedFramePtrReg_StackPtr: + { + result = RDI_RegisterCode_X64_rsp; + }break; + case CV_EncodedFramePtrReg_FramePtr: + { + result = RDI_RegisterCode_X64_rbp; + }break; + case CV_EncodedFramePtrReg_BasePtr: + { + result = RDI_RegisterCode_X64_r13; + }break; + } + }break; + } + 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 + +internal TS_TASK_FUNCTION_DEF(p2r_exe_hash_task__entry_point) +{ + P2R_EXEHashIn *in = (P2R_EXEHashIn *)p; + U64 *out = push_array(arena, U64, 1); + ProfScope("hash exe") *out = rdi_hash(in->exe_data.str, in->exe_data.size); + return out; +} + +internal TS_TASK_FUNCTION_DEF(p2r_tpi_hash_parse_task__entry_point) +{ + P2R_TPIHashParseIn *in = (P2R_TPIHashParseIn *)p; + void *out = 0; + ProfScope("parse tpi hash") out = pdb_tpi_hash_from_data(arena, in->strtbl, in->tpi, in->hash_data, in->aux_data); + return out; +} + +internal TS_TASK_FUNCTION_DEF(p2r_tpi_leaf_parse_task__entry_point) +{ + P2R_TPILeafParseIn *in = (P2R_TPILeafParseIn *)p; + void *out = 0; + ProfScope("parse tpi leaf") out = cv_leaf_from_data(arena, in->leaf_data, in->itype_first); + return out; +} + +internal TS_TASK_FUNCTION_DEF(p2r_symbol_stream_parse_task__entry_point) +{ + P2R_SymbolStreamParseIn *in = (P2R_SymbolStreamParseIn *)p; + void *out = 0; + ProfScope("parse symbol stream") out = cv_sym_from_data(arena, in->data, 4); + return out; +} + +internal TS_TASK_FUNCTION_DEF(p2r_c13_stream_parse_task__entry_point) +{ + P2R_C13StreamParseIn *in = (P2R_C13StreamParseIn *)p; + void *out = 0; + ProfScope("parse c13 stream") out = cv_c13_from_data(arena, in->data, in->strtbl, in->coff_sections); + return out; +} + +internal TS_TASK_FUNCTION_DEF(p2r_comp_unit_parse_task__entry_point) +{ + P2R_CompUnitParseIn *in = (P2R_CompUnitParseIn *)p; + void *out = 0; + ProfScope("parse comp units") out = pdb_comp_unit_array_from_data(arena, in->data); + return out; +} + +internal TS_TASK_FUNCTION_DEF(p2r_comp_unit_contributions_parse_task__entry_point) +{ + P2R_CompUnitContributionsParseIn *in = (P2R_CompUnitContributionsParseIn *)p; + void *out = 0; + ProfScope("parse comp unit contributions") out = pdb_comp_unit_contribution_array_from_data(arena, in->data, in->coff_sections); + return out; +} + +//////////////////////////////// +//~ rjf: Unit Conversion Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_units_convert_task__entry_point) +{ + Temp scratch = scratch_begin(&arena, 1); + P2R_UnitConvertIn *in = (P2R_UnitConvertIn *)p; + 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: fill basic per-unit info & line info + 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 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 = p2r_rdi_language_from_cv_language(pdb_unit_sym->info.language); + + //- rjf: fill unit line info + for(CV_C13SubSectionNode *node = pdb_unit_c13->first_sub_section; + node != 0; + node = node->next) + { + if(node->kind == CV_C13_SubSectionKind_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: build sequence + RDIM_LineSequence *seq = rdim_line_sequence_list_push(arena, &dst_unit->line_sequences); + rdim_src_file_push_line_sequence(arena, &out->src_files, src_file_node->src_file, seq); + seq->src_file = src_file_node->src_file; + seq->voffs = lines->voffs; + seq->line_nums = lines->line_nums; + seq->col_nums = lines->col_nums; + seq->line_count = lines->line_count; + } + } + } + } + + //- 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; + 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); + } + } + } + scratch_end(scratch); + return out; +} + +//////////////////////////////// +//~ rjf: Link Name Map Building Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_link_name_map_build_task__entry_point) +{ + P2R_LinkNameMapBuildIn *in = (P2R_LinkNameMapBuildIn *)p; + 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->sections[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; + } + } + return 0; +} + +//////////////////////////////// +//~ rjf: Type Parsing/Conversion Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_itype_fwd_map_fill_task__entry_point) +{ + P2R_ITypeFwdMapFillIn *in = (P2R_ITypeFwdMapFillIn *)p; + ProfScope("fill itype fwd map") for(CV_TypeId itype = in->itype_first; itype < in->itype_opl; itype += 1) + { + //- rjf: skip if not in the actually stored itype range + if(itype < in->tpi_leaf->itype_first) + { + continue; + } + + //- rjf: determine if this itype resolves to another + CV_TypeId itype_fwd = 0; + 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); + 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) + { + U8 *itype_leaf_first = in->tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + default:{}break; + + //- rjf: CLASS/STRUCTURE + case CV_LeafKind_CLASS: + case CV_LeafKind_STRUCTURE: + { + // rjf: unpack leaf header + CV_LeafStruct *lf_struct = (CV_LeafStruct *)itype_leaf_first; + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_struct->props & CV_TypeProp_FwdRef) + { + // rjf: unpack rest of leaf + U8 *numeric_ptr = (U8 *)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: lookup + B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && + ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: CLASS2/STRUCT2 + case CV_LeafKind_CLASS2: + case CV_LeafKind_STRUCT2: + { + // rjf: unpack leaf header + CV_LeafStruct2 *lf_struct = (CV_LeafStruct2 *)itype_leaf_first; + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_struct->props & CV_TypeProp_FwdRef) + { + // rjf: unpack rest of leaf + U8 *numeric_ptr = (U8 *)(lf_struct + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = (U8 *)numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: lookup + B32 do_unique_name_lookup = (((lf_struct->props & CV_TypeProp_Scoped) != 0) && + ((lf_struct->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: UNION + case CV_LeafKind_UNION: + { + // rjf: unpack leaf + CV_LeafUnion *lf_union = (CV_LeafUnion *)itype_leaf_first; + U8 *numeric_ptr = (U8 *)(lf_union + 1); + CV_NumericParsed size = cv_numeric_from_data_range(numeric_ptr, itype_leaf_opl); + U8 *name_ptr = numeric_ptr + size.encoded_size; + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: has fwd ref flag -> lookup itype that this itype resolves tos + if(lf_union->props & CV_TypeProp_FwdRef) + { + B32 do_unique_name_lookup = (((lf_union->props & CV_TypeProp_Scoped) != 0) && + ((lf_union->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + // rjf: unpack leaf + CV_LeafEnum *lf_enum = (CV_LeafEnum*)itype_leaf_first; + U8 *name_ptr = (U8 *)(lf_enum + 1); + String8 name = str8_cstring_capped(name_ptr, itype_leaf_opl); + U8 *unique_name_ptr = name_ptr + name.size + 1; + String8 unique_name = str8_cstring_capped(unique_name_ptr, itype_leaf_opl); + + // rjf: has fwd ref flag -> lookup itype that this itype resolves to + if(lf_enum->props & CV_TypeProp_FwdRef) + { + B32 do_unique_name_lookup = (((lf_enum->props & CV_TypeProp_Scoped) != 0) && + ((lf_enum->props & CV_TypeProp_HasUniqueName) != 0)); + itype_fwd = pdb_tpi_first_itype_from_name(in->tpi_hash, in->tpi_leaf, do_unique_name_lookup?unique_name:name, do_unique_name_lookup); + } + }break; + } + } + + //- rjf: if the forwarded itype is nonzero & in TPI range -> save to map + if(itype_fwd != 0 && itype_fwd < in->tpi_leaf->itype_opl) + { + in->itype_fwd_map[itype] = itype_fwd; + } + } + return 0; +} + +internal TS_TASK_FUNCTION_DEF(p2r_itype_chain_build_task__entry_point) +{ + Temp scratch = scratch_begin(&arena, 1); + P2R_ITypeChainBuildIn *in = (P2R_ITypeChainBuildIn *)p; + ProfScope("dependency itype chain build") + { + for(CV_TypeId itype = in->itype_first; itype < in->itype_opl; itype += 1) + { + //- rjf: push initial itype - should be final-visited-itype for this itype + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = itype; + SLLStackPush(in->itype_chains[itype], c); + } + + //- rjf: skip basic types for dependency walk + if(itype < in->tpi_leaf->itype_first) + { + continue; + } + + //- rjf: walk dependent types, push to chain + P2R_TypeIdChain start_walk_task = {0, itype}; + P2R_TypeIdChain *first_walk_task = &start_walk_task; + P2R_TypeIdChain *last_walk_task = &start_walk_task; + for(P2R_TypeIdChain *walk_task = first_walk_task; + walk_task != 0; + walk_task = walk_task->next) + { + CV_TypeId walk_itype = in->itype_fwd_map[walk_task->itype] ? in->itype_fwd_map[walk_task->itype] : walk_task->itype; + if(walk_itype < in->tpi_leaf->itype_first) + { + continue; + } + CV_RecRange *range = &in->tpi_leaf->leaf_ranges.ranges[walk_itype-in->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 <= in->tpi_leaf->data.size && + range->off+2+header_struct_size <= in->tpi_leaf->data.size && + range->hdr.size >= 2) + { + U8 *itype_leaf_first = in->tpi_leaf->data.str + range->off+2; + U8 *itype_leaf_opl = itype_leaf_first + range->hdr.size-2; + switch(kind) + { + default:{}break; + + //- rjf: MODIFIER + case CV_LeafKind_MODIFIER: + { + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: POINTER + case CV_LeafKind_POINTER: + { + CV_LeafModifier *lf = (CV_LeafModifier *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: PROCEDURE + case CV_LeafKind_PROCEDURE: + { + CV_LeafProcedure *lf = (CV_LeafProcedure *)itype_leaf_first; + + // rjf: push return itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk return itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &in->tpi_leaf->leaf_ranges.ranges[lf->arg_itype-in->tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > in->tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = in->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: push arg types to chain + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk arg types + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: MFUNCTION + case CV_LeafKind_MFUNCTION: + { + CV_LeafMFunction *lf = (CV_LeafMFunction *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLStackPush(in->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->arg_itype; + SLLStackPush(in->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->this_itype; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->ret_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->arg_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->this_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + + // rjf: unpack arglist range + CV_RecRange *arglist_range = &in->tpi_leaf->leaf_ranges.ranges[lf->arg_itype-in->tpi_leaf->itype_first]; + if(arglist_range->hdr.kind != CV_LeafKind_ARGLIST || + arglist_range->hdr.size<2 || + arglist_range->off + arglist_range->hdr.size > in->tpi_leaf->data.size) + { + break; + } + U8 *arglist_first = in->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: push arg types to chain + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk arg types + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = arglist_itypes_base[idx]; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: BITFIELD + case CV_LeafKind_BITFIELD: + { + CV_LeafBitField *lf = (CV_LeafBitField *)itype_leaf_first; + + // rjf: push dependent itype to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itype + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: ARRAY + case CV_LeafKind_ARRAY: + { + CV_LeafArray *lf = (CV_LeafArray *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->entry_itype; + SLLStackPush(in->itype_chains[itype], c); + } + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->index_itype; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->entry_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->index_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + + //- rjf: ENUM + case CV_LeafKind_ENUM: + { + CV_LeafEnum *lf = (CV_LeafEnum *)itype_leaf_first; + + // rjf: push dependent itypes to chain + { + P2R_TypeIdChain *c = push_array(arena, P2R_TypeIdChain, 1); + c->itype = lf->base_itype; + SLLStackPush(in->itype_chains[itype], c); + } + + // rjf: push task to walk dependency itypes + { + P2R_TypeIdChain *c = push_array(scratch.arena, P2R_TypeIdChain, 1); + c->itype = lf->base_itype; + SLLQueuePush(first_walk_task, last_walk_task, c); + } + }break; + } + } + } + } + } + scratch_end(scratch); + return 0; +} + +//////////////////////////////// +//~ rjf: UDT Conversion Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_udt_convert_task__entry_point) +{ + P2R_UDTConvertIn *in = (P2R_UDTConvertIn *)p; +#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (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_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: 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_ExtractMethodProp(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_ExtractMethodProp(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: 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; + // 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 + return udts; +} + +//////////////////////////////// +//~ rjf: Symbol Stream Conversion Path & Thread + +internal TS_TASK_FUNCTION_DEF(p2r_symbol_stream_convert_task__entry_point) +{ + Temp scratch = scratch_begin(&arena, 1); + P2R_SymbolStreamConvertIn *in = (P2R_SymbolStreamConvertIn *)p; +#define p2r_type_ptr_from_itype(itype) ((in->itype_type_ptrs && (itype) < in->tpi_leaf->itype_opl) ? (in->itype_type_ptrs[(in->itype_fwd_map[(itype)] ? in->itype_fwd_map[(itype)] : (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; + RDIM_SymbolChunkList sym_procedures = {0}; + RDIM_SymbolChunkList sym_global_variables = {0}; + RDIM_SymbolChunkList sym_thread_variables = {0}; + RDIM_ScopeChunkList sym_scopes = {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_put_back(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; + 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; + 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->sections[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->sections[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, 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; + } + + // 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->offset = voff; + 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) + { + 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, 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->sections[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); + } + } + + // 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; + } + } + } + + // 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_RegisterCode register_code = p2r_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, register_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, 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; + } + + // 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->offset = tls_off; + 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->sections[range->sec-1] : 0; + CV_LvarAddrGap *gaps = (CV_LvarAddrGap*)(defrange_register+1); + U64 gap_count = ((U8*)sym_data_opl - (U8*)gaps) / sizeof(*gaps); + RDI_RegisterCode register_code = p2r_rdi_reg_code_from_cv_reg_code(in->arch, cv_reg); + + // rjf: build location + RDIM_Location *location = rdim_push_location_val_reg(arena, register_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_frameprocs[procedure_num-1] != 0 && procedure_num < procedure_frameprocs_count) + { + 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->sections[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 = p2r_cv_encoded_fp_reg_from_frameproc(frameproc, defrange_target_is_param); + RDI_RegisterCode fp_register_code = p2r_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->sections[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_RegisterCode register_code = p2r_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, register_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_frameprocs[procedure_num-1] != 0 && procedure_num < procedure_frameprocs_count) + { + 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 = p2r_cv_encoded_fp_reg_from_frameproc(frameproc, defrange_target_is_param); + RDI_RegisterCode fp_register_code = p2r_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_RegisterCode register_code = p2r_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->sections[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, register_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: 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; + } + +#undef p2r_type_ptr_from_itype + scratch_end(scratch); + return out; +} + +//////////////////////////////// +//~ rjf: Top-Level Conversion Entry Point + +internal P2R_Convert2Bake * +p2r_convert(Arena *arena, P2R_User2Convert *in) +{ + Temp scratch = scratch_begin(&arena, 1); + + ////////////////////////////////////////////////////////////// + //- rjf: parse MSF structure + // + MSF_Parsed *msf = 0; + if(in->input_pdb_data.size != 0) ProfScope("parse MSF structure") + { + msf = msf_parsed_from_data(arena, in->input_pdb_data); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse PDB auth_guid & named streams table + // + PDB_NamedStreamTable *named_streams = 0; + COFF_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_PdbInfo); + 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); + } + + ////////////////////////////////////////////////////////////// + //- rjf: parse PDB strtbl + // + PDB_Strtbl *strtbl = 0; + if(named_streams != 0) ProfScope("parse PDB strtbl") + { + MSF_StreamNumber strtbl_sn = named_streams->sn[PDB_NamedStream_STRTABLE]; + String8 strtbl_data = msf_data_from_stream(msf, strtbl_sn); + strtbl = pdb_strtbl_from_data(arena, strtbl_data); + } + + ////////////////////////////////////////////////////////////// + //- 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 + // + PDB_CoffSectionArray *coff_sections = 0; + U64 coff_section_count = 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); + coff_section_count = coff_sections->count; + } + + ////////////////////////////////////////////////////////////// + //- 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->input_exe_data}; + TS_Ticket exe_hash_ticket = ts_kickoff(p2r_exe_hash_task__entry_point, 0, &exe_hash_in); + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff TPI hash parse + // + P2R_TPIHashParseIn tpi_hash_in = {0}; + TS_Ticket tpi_hash_ticket = {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_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &tpi_hash_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff TPI leaf parse + // + P2R_TPILeafParseIn tpi_leaf_in = {0}; + TS_Ticket tpi_leaf_ticket = {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_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &tpi_leaf_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff IPI hash parse + // + P2R_TPIHashParseIn ipi_hash_in = {0}; + TS_Ticket ipi_hash_ticket = {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_ticket = ts_kickoff(p2r_tpi_hash_parse_task__entry_point, 0, &ipi_hash_in); + } + + ////////////////////////////////////////////////////////////// + //- rjf: kickoff IPI leaf parse + // + P2R_TPILeafParseIn ipi_leaf_in = {0}; + TS_Ticket ipi_leaf_ticket = {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_ticket = ts_kickoff(p2r_tpi_leaf_parse_task__entry_point, 0, &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()}; + TS_Ticket sym_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_symbol_stream_parse_task__entry_point, 0, &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}; + TS_Ticket comp_unit_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_comp_unit_parse_task__entry_point, 0, &comp_unit_parse_in); + TS_Ticket comp_unit_contributions_parse_ticket = !dbi ? ts_ticket_zero() : ts_kickoff(p2r_comp_unit_contributions_parse_task__entry_point, 0, &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 = ts_join_struct(comp_unit_parse_ticket, max_U64, PDB_CompUnitArray); + comp_unit_contributions = ts_join_struct(comp_unit_contributions_parse_ticket, max_U64, 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); + TS_Ticket *sym_tasks_tickets = push_array(scratch.arena, TS_Ticket, comp_unit_count); + P2R_C13StreamParseIn *c13_tasks_inputs = push_array(scratch.arena, P2R_C13StreamParseIn, comp_unit_count); + TS_Ticket *c13_tasks_tickets = push_array(scratch.arena, TS_Ticket, 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_tickets[idx] = ts_kickoff(p2r_symbol_stream_parse_task__entry_point, 0, &sym_tasks_inputs[idx]); + c13_tasks_inputs[idx].data = pdb_data_from_unit_range(msf, unit, PDB_DbiCompUnitRange_C13); + c13_tasks_inputs[idx].strtbl = strtbl; + c13_tasks_inputs[idx].coff_sections = coff_sections; + c13_tasks_tickets[idx] = ts_kickoff(p2r_c13_stream_parse_task__entry_point, 0, &c13_tasks_inputs[idx]); + } + + //- rjf: join tasks + for(U64 idx = 0; idx < comp_unit_count; idx += 1) + { + sym_for_unit[idx] = ts_join_struct(sym_tasks_tickets[idx], max_U64, CV_SymParsed); + c13_for_unit[idx] = ts_join_struct(c13_tasks_tickets[idx], max_U64, CV_C13Parsed); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: calculate EXE's max voff + // + U64 exe_voff_max = 0; + if(coff_sections != 0) + { + COFF_SectionHeader *coff_sec_ptr = coff_sections->sections; + COFF_SectionHeader *coff_ptr_opl = coff_sec_ptr + coff_section_count; + for(;coff_sec_ptr < coff_ptr_opl; coff_sec_ptr += 1) + { + U64 sec_voff_max = coff_sec_ptr->voff + coff_sec_ptr->vsize; + exe_voff_max = Max(exe_voff_max, sec_voff_max); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: determine architecture + // + RDI_Arch arch = RDI_Arch_NULL; + U64 arch_addr_size = 0; + { + // TODO(rjf): in some cases, the first compilation unit has a zero + // architecture, as it's sometimes used as a "nil" unit. this causes bugs + // in later stages of conversion - particularly, this was detected via + // busted location info. so i've converted this to a scan-until-we-find-an- + // architecture. however, this may still be fundamentally insufficient, + // because Nick has informed me that x86 units can be linked with x64 + // units, meaning the appropriate architecture at any point in time is not + // a top-level concept, and is rather dependent on to which compilation + // unit particular symbols belong. so in the future, to support that (odd) + // case, we'll need to not only have this be a top-level "contextual" piece + // of info, but to use the appropriate compilation unit's architecture when + // possible. assuming, of course, that we care about supporting that case. + for(U64 comp_unit_idx = 0; comp_unit_idx < comp_unit_count; comp_unit_idx += 1) + { + if(sym_for_unit[comp_unit_idx] != 0) + { + arch = p2r_rdi_arch_from_cv_arch(sym_for_unit[comp_unit_idx]->info.arch); + if(arch != RDI_Arch_NULL) + { + break; + } + } + } + arch_addr_size = rdi_addr_size_from_arch(arch); + } + + ////////////////////////////////////////////////////////////// + //- rjf: join EXE hash + // + U64 exe_hash = *ts_join_struct(exe_hash_ticket, max_U64, U64); + + ////////////////////////////////////////////////////////////// + //- rjf: produce top-level-info + // + RDIM_TopLevelInfo top_level_info = {0}; + { + top_level_info.arch = arch; + top_level_info.exe_name = in->input_exe_name; + top_level_info.exe_hash = exe_hash; + top_level_info.voff_max = exe_voff_max; + } + + ////////////////////////////////////////////////////////////// + //- rjf: build binary sections list + // + RDIM_BinarySectionList binary_sections = {0}; + if(coff_sections != 0) ProfScope("build binary section list") + { + COFF_SectionHeader *coff_ptr = coff_sections->sections; + COFF_SectionHeader *coff_opl = coff_ptr + coff_section_count; + for(;coff_ptr < coff_opl; coff_ptr += 1) + { + char *name_first = (char*)coff_ptr->name; + char *name_opl = name_first + sizeof(coff_ptr->name); + RDIM_BinarySection *sec = rdim_binary_section_list_push(arena, &binary_sections); + sec->name = str8_cstring_capped(name_first, name_opl); + sec->flags = p2r_rdi_binary_section_flags_from_coff_section_flags(coff_ptr->flags); + sec->voff_first = coff_ptr->voff; + sec->voff_opl = coff_ptr->voff+coff_ptr->vsize; + sec->foff_first = coff_ptr->foff; + sec->foff_opl = coff_ptr->foff+coff_ptr->fsize; + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: kick off unit conversion & source file collection + // + P2R_UnitConvertIn unit_convert_in = {comp_units, comp_unit_contributions, sym_for_unit, c13_for_unit}; + TS_Ticket unit_convert_ticket = ts_kickoff(p2r_units_convert_task__entry_point, 0, &unit_convert_in); + + ////////////////////////////////////////////////////////////// + //- rjf: join global sym stream parse + // + CV_SymParsed *sym = ts_join_struct(sym_parse_ticket, max_U64, 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}; + TS_Ticket link_name_map_ticket = {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_ticket = ts_kickoff(p2r_link_name_map_build_task__entry_point, 0, &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 = ts_join_struct(tpi_hash_ticket, max_U64, PDB_TpiHashParsed); + tpi_leaf = ts_join_struct(tpi_leaf_ticket, max_U64, CV_LeafParsed); + ipi_hash = ts_join_struct(ipi_hash_ticket, max_U64, PDB_TpiHashParsed); + ipi_leaf = ts_join_struct(ipi_leaf_ticket, max_U64, CV_LeafParsed); + } + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 1: produce type forward resolution map + // + // this map is used to resolve usage of "incomplete structs" in codeview's + // type info. this often happens when e.g. "struct Foo" is used to refer to + // a later-defined "Foo", which actually contains members and so on. we want + // to hook types up to their actual destination complete types wherever + // possible, and so this map can be used to do that in subsequent stages. + // + CV_TypeId *itype_fwd_map = 0; + CV_TypeId itype_first = 0; + CV_TypeId itype_opl = 0; + if(in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 1: produce type forward resolution map") + { + //- rjf: allocate forward resolution map + itype_first = tpi_leaf->itype_first; + itype_opl = tpi_leaf->itype_opl; + itype_fwd_map = push_array(arena, CV_TypeId, (U64)itype_opl); + + //- rjf: kick off tasks to fill forward resolution map + U64 task_size_itypes = 1024; + U64 tasks_count = ((U64)itype_opl+(task_size_itypes-1))/task_size_itypes; + P2R_ITypeFwdMapFillIn *tasks_inputs = push_array(scratch.arena, P2R_ITypeFwdMapFillIn, tasks_count); + TS_Ticket *tasks_tickets = push_array(scratch.arena, TS_Ticket, tasks_count); + for(U64 idx = 0; idx < tasks_count; idx += 1) + { + tasks_inputs[idx].tpi_hash = tpi_hash; + tasks_inputs[idx].tpi_leaf = tpi_leaf; + tasks_inputs[idx].itype_first = idx*task_size_itypes; + tasks_inputs[idx].itype_opl = tasks_inputs[idx].itype_first + task_size_itypes; + tasks_inputs[idx].itype_opl = ClampTop(tasks_inputs[idx].itype_opl, itype_opl); + tasks_inputs[idx].itype_fwd_map = itype_fwd_map; + tasks_tickets[idx] = ts_kickoff(p2r_itype_fwd_map_fill_task__entry_point, 0, &tasks_inputs[idx]); + } + + //- rjf: join all tasks + for(U64 idx = 0; idx < tasks_count; idx += 1) + { + ts_join(tasks_tickets[idx], max_U64); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 2: produce per-itype itype chain + // + // this pass is to ensure that subsequent passes always produce types for + // dependent itypes first - guaranteeing raddbgi's "only reference backward" + // rule (which eliminates cycles). each itype slot gets a list of itypes, + // starting with the deepest dependency - when types are produced per-itype, + // this chain is walked, so that deeper dependencies are built first, and + // as such, always show up *earlier* in the actually built types. + // + P2R_TypeIdChain **itype_chains = 0; + if(in->flags & P2R_ConvertFlag_Types) ProfScope("types pass 2: produce per-itype itype chain (for producing dependent types first)") + { + //- rjf: allocate itype chain table + itype_chains = push_array(arena, P2R_TypeIdChain *, (U64)itype_opl); + + //- rjf: kick off tasks to fill itype chain table + U64 task_size_itypes = 1024; + U64 tasks_count = ((U64)itype_opl+(task_size_itypes-1))/task_size_itypes; + P2R_ITypeChainBuildIn *tasks_inputs = push_array(scratch.arena, P2R_ITypeChainBuildIn, tasks_count); + TS_Ticket *tasks_tickets = push_array(scratch.arena, TS_Ticket, tasks_count); + for(U64 idx = 0; idx < tasks_count; idx += 1) + { + tasks_inputs[idx].tpi_leaf = tpi_leaf; + tasks_inputs[idx].itype_first = idx*task_size_itypes; + tasks_inputs[idx].itype_opl = tasks_inputs[idx].itype_first + task_size_itypes; + tasks_inputs[idx].itype_opl = ClampTop(tasks_inputs[idx].itype_opl, itype_opl); + tasks_inputs[idx].itype_chains = itype_chains; + tasks_inputs[idx].itype_fwd_map = itype_fwd_map; + tasks_tickets[idx] = ts_kickoff(p2r_itype_chain_build_task__entry_point, 0, &tasks_inputs[idx]); + } + + //- rjf: join all tasks + for(U64 idx = 0; idx < tasks_count; idx += 1) + { + ts_join(tasks_tickets[idx], max_U64); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 3: construct all types from TPI + // + // this doesn't gather struct/class/union/enum members, which is done by + // subsequent passes, to build RADDBGI "UDT" information, which is distinct + // from regular type info. + // + RDIM_Type **itype_type_ptrs = 0; + RDIM_TypeChunkList all_types = {0}; +#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)); + for(CV_TypeId root_itype = 0; root_itype < itype_opl; root_itype += 1) + { + for(P2R_TypeIdChain *itype_chain = itype_chains[root_itype]; + itype_chain != 0; + 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); + + ////////////////////////// + //- rjf: skip forward-reference itypes - all future resolutions will + // reference whatever this itype resolves to, and so there is no point + // in filling out this slot + // + if(itype_fwd_map[root_itype] != 0) + { + continue; + } + + ////////////////////////// + //- rjf: skip already produced dependencies + // + if(itype_type_ptrs[itype] != 0) + { + continue; + } + + ////////////////////////// + //- rjf: build basic type + // + if(itype_is_basic) + { + RDIM_Type *dst_type = 0; + + // rjf: unpack itype + CV_BasicPointerKind cv_basic_ptr_kind = CV_BasicPointerKindFromTypeId(itype); + CV_BasicType cv_basic_type_code = CV_BasicTypeFromTypeId(itype); + + // rjf: get basic type slot, fill if unfilled + RDIM_Type *basic_type = itype_type_ptrs[cv_basic_type_code]; + if(basic_type == 0) + { + RDI_TypeKind type_kind = p2r_rdi_type_kind_from_cv_basic_type(cv_basic_type_code); + U32 byte_size = rdi_size_from_basic_type_kind(type_kind); + basic_type = dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(byte_size == 0xffffffff) + { + byte_size = arch_addr_size; + } + basic_type->kind = type_kind; + basic_type->name = cv_type_name_from_basic_type(cv_basic_type_code); + basic_type->byte_size = byte_size; + } + + // rjf: nonzero ptr kind -> form ptr type to basic tpye + if(cv_basic_ptr_kind != 0) + { + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Ptr; + dst_type->byte_size = arch_addr_size; + dst_type->direct_type = basic_type; + } + + // rjf: fill this itype's slot with the finished type + itype_type_ptrs[itype] = dst_type; + } + + ////////////////////////// + //- rjf: build non-basic type + // + if(!itype_is_basic && itype >= itype_first) + { + RDIM_Type *dst_type = 0; + CV_RecRange *range = &tpi_leaf->leaf_ranges.ranges[itype-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 + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)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_ExtractKind(lf->attribs); + CV_PointerMode ptr_mode = CV_PointerAttribs_ExtractMode(lf->attribs); + U32 ptr_size = CV_PointerAttribs_ExtractSize(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;} + + // 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 + dst_type = rdim_type_chunk_list_push(arena, &all_types, (U64)itype_opl); + if(modifier_flags != 0) + { + RDIM_Type *pointer_type = rdim_type_chunk_list_push(arena, &all_types, (U64)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->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, (U64)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-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, (U64)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-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+1); + for(U32 idx = 0; idx < arglist_itypes_count; idx += 1) + { + params[idx+1] = p2r_type_ptr_from_itype(arglist_itypes_base[idx]); + } + params[0] = p2r_type_ptr_from_itype(lf->this_itype); + + // rjf: fill dst type + dst_type->count = arglist_itypes_count+1; + 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, (U64)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, (U64)itype_opl); + dst_type->kind = RDI_TypeKind_Array; + dst_type->direct_type = direct_type; + dst_type->byte_size = full_size; + dst_type->count = (direct_type && direct_type->byte_size) ? (dst_type->byte_size/direct_type->byte_size) : 0; + }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, (U64)itype_opl); + if(lf->props & CV_TypeProp_FwdRef) + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_IncompleteClass : RDI_TypeKind_IncompleteStruct); + dst_type->name = name; + } + else + { + dst_type->kind = (kind == CV_LeafKind_CLASS ? RDI_TypeKind_Class : RDI_TypeKind_Struct); + dst_type->byte_size = (U32)size_u64; + dst_type->name = name; + } + }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, (U64)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; + } + }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, (U64)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; + } + }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, (U64)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; + } + }break; + } + } + + //- rjf: store finalized type to this itype's slot + itype_type_ptrs[itype] = dst_type; + } + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: types pass 4: kick off UDT build + // + U64 udt_task_size_itypes = 4096; + U64 udt_tasks_count = ((U64)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); + TS_Ticket *udt_tasks_tickets = push_array(scratch.arena, TS_Ticket, udt_tasks_count); + if(in->flags & P2R_ConvertFlag_UDTs) ProfScope("types pass 4: 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, itype_opl); + udt_tasks_inputs[idx].itype_fwd_map = itype_fwd_map; + udt_tasks_inputs[idx].itype_type_ptrs = itype_type_ptrs; + udt_tasks_tickets[idx] = ts_kickoff(p2r_udt_convert_task__entry_point, 0, &udt_tasks_inputs[idx]); + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: join link name map building task + // + P2R_LinkNameMap *link_name_map = 0; + ProfScope("join link name map building task") + { + ts_join(link_name_map_ticket, max_U64); + link_name_map = &link_name_map__in_progress; + } + + ////////////////////////////////////////////////////////////// + //- 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}; + 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); + TS_Ticket *tasks_tickets = push_array(scratch.arena, TS_Ticket, 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].itype_fwd_map = itype_fwd_map; + 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_tickets[idx] = ts_kickoff(p2r_symbol_stream_convert_task__entry_point, 0, &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 = ts_join_struct(tasks_tickets[idx], max_U64, 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); + } + } + } + + ////////////////////////////////////////////////////////////// + //- rjf: join unit conversion & src file tasks + // + RDIM_UnitChunkList all_units = {0}; + RDIM_SrcFileChunkList all_src_files = {0}; + ProfScope("join unit conversion & src file tasks") + { + P2R_UnitConvertOut *out = ts_join_struct(unit_convert_ticket, max_U64, P2R_UnitConvertOut); + all_units = out->units; + all_src_files = out->src_files; + } + + ////////////////////////////////////////////////////////////// + //- 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 = ts_join_struct(udt_tasks_tickets[idx], max_U64, RDIM_UDTChunkList); + rdim_udt_chunk_list_concat_in_place(&all_udts, udts); + } + + ////////////////////////////////////////////////////////////// + //- rjf: fill output + // + P2R_Convert2Bake *out = push_array(arena, P2R_Convert2Bake, 1); + { + out->bake_params.top_level_info = top_level_info; + out->bake_params.binary_sections = binary_sections; + out->bake_params.units = all_units; + out->bake_params.types = all_types; + out->bake_params.udts = all_udts; + out->bake_params.src_files = all_src_files; + out->bake_params.global_variables = all_global_variables; + out->bake_params.thread_variables = all_thread_variables; + out->bake_params.procedures = all_procedures; + out->bake_params.scopes = all_scopes; + } + + scratch_end(scratch); + 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) + +internal TS_TASK_FUNCTION_DEF(p2r_bake_src_files_strings_task__entry_point) +{ + P2R_BakeSrcFilesStringsIn *in = (P2R_BakeSrcFilesStringsIn *)p; + 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); + return 0; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_units_strings_task__entry_point) +{ + P2R_BakeUnitsStringsIn *in = (P2R_BakeUnitsStringsIn *)p; + 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); + return 0; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_types_strings_task__entry_point) +{ + P2R_BakeTypesStringsIn *in = (P2R_BakeTypesStringsIn *)p; + 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); + } + } + return 0; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_udts_strings_task__entry_point) +{ + P2R_BakeUDTsStringsIn *in = (P2R_BakeUDTsStringsIn *)p; + 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); + } + } + return 0; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_symbols_strings_task__entry_point) +{ + P2R_BakeSymbolsStringsIn *in = (P2R_BakeSymbolsStringsIn *)p; + 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); + } + } + return 0; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_scopes_strings_task__entry_point) +{ + P2R_BakeScopesStringsIn *in = (P2R_BakeScopesStringsIn *)p; + 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); + } + } + return 0; +} + +#undef p2r_make_string_map_if_needed + +//- rjf: bake string map joining + +internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_join_task__entry_point) +{ + P2R_JoinBakeStringMapSlotsIn *in = (P2R_JoinBakeStringMapSlotsIn *)p; + 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]); + } + } + } + } + return 0; +} + +//- rjf: bake string map sorting + +internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_sort_task__entry_point) +{ + P2R_SortBakeStringMapSlotsIn *in = (P2R_SortBakeStringMapSlotsIn *)p; + 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]; + } + } + } + } + return 0; +} + +//- rjf: pass 1: interner/deduper map builds + +internal TS_TASK_FUNCTION_DEF(p2r_build_bake_name_map_task__entry_point) +{ + P2R_BuildBakeNameMapIn *in = (P2R_BuildBakeNameMapIn *)p; + 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); + return name_map; +} + +//- rjf: pass 2: string-map-dependent debug info stream builds + +internal TS_TASK_FUNCTION_DEF(p2r_bake_units_top_level_task__entry_point) +{ + P2R_BakeUnitsTopLevelIn *in = (P2R_BakeUnitsTopLevelIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake units") *s = rdim_bake_unit_top_level_section_list_from_params(arena, in->strings, in->path_tree, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_unit_task__entry_point) +{ + P2R_BakeUnitIn *in = (P2R_BakeUnitIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake unit") *s = rdim_bake_section_list_from_unit(arena, in->unit); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_unit_vmap_task__entry_point) +{ + P2R_BakeUnitVMapIn *in = (P2R_BakeUnitVMapIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake unit vmap") *s = rdim_bake_unit_vmap_section_list_from_params(arena, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_src_files_task__entry_point) +{ + P2R_BakeSrcFilesIn *in = (P2R_BakeSrcFilesIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake src files") *s = rdim_bake_src_file_section_list_from_params(arena, in->strings, in->path_tree, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_udts_task__entry_point) +{ + P2R_BakeUDTsIn *in = (P2R_BakeUDTsIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake udts") *s = rdim_bake_udt_section_list_from_params(arena, in->strings, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_global_variables_task__entry_point) +{ + P2R_BakeGlobalVariablesIn *in = (P2R_BakeGlobalVariablesIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake global variables") *s = rdim_bake_global_variable_section_list_from_params(arena, in->strings, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_global_vmap_task__entry_point) +{ + P2R_BakeGlobalVMapIn *in = (P2R_BakeGlobalVMapIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake global vmap") *s = rdim_bake_global_vmap_section_list_from_params(arena, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_thread_variables_task__entry_point) +{ + P2R_BakeThreadVariablesIn *in = (P2R_BakeThreadVariablesIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake thread variables") *s = rdim_bake_thread_variable_section_list_from_params(arena, in->strings, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_procedures_task__entry_point) +{ + P2R_BakeProceduresIn *in = (P2R_BakeProceduresIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake procedures") *s = rdim_bake_procedure_section_list_from_params(arena, in->strings, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_scopes_task__entry_point) +{ + P2R_BakeScopesIn *in = (P2R_BakeScopesIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake scopes") *s = rdim_bake_scope_section_list_from_params(arena, in->strings, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_scope_vmap_task__entry_point) +{ + P2R_BakeScopeVMapIn *in = (P2R_BakeScopeVMapIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake scope vmap") *s = rdim_bake_scope_vmap_section_list_from_params(arena, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_file_paths_task__entry_point) +{ + P2R_BakeFilePathsIn *in = (P2R_BakeFilePathsIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake file paths") *s = rdim_bake_file_path_section_list_from_path_tree(arena, in->strings, in->path_tree); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_strings_task__entry_point) +{ + P2R_BakeStringsIn *in = (P2R_BakeStringsIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake strings") *s = rdim_bake_string_section_list_from_string_map(arena, in->strings); + return s; +} + +//- rjf: pass 3: idx-run-map-dependent debug info stream builds + +internal TS_TASK_FUNCTION_DEF(p2r_bake_type_nodes_task__entry_point) +{ + P2R_BakeTypeNodesIn *in = (P2R_BakeTypeNodesIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake type nodes") *s = rdim_bake_type_node_section_list_from_params(arena, in->strings, in->idx_runs, in->params); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_name_map_task__entry_point) +{ + P2R_BakeNameMapIn *in = (P2R_BakeNameMapIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake name map %i", in->kind) *s = rdim_bake_name_map_section_list_from_params_kind_map(arena, in->strings, in->idx_runs, in->params, in->kind, in->map); + return s; +} + +internal TS_TASK_FUNCTION_DEF(p2r_bake_idx_runs_task__entry_point) +{ + P2R_BakeIdxRunsIn *in = (P2R_BakeIdxRunsIn *)p; + RDIM_BakeSectionList *s = push_array(arena, RDIM_BakeSectionList, 1); + ProfScope("bake idx runs") *s = rdim_bake_idx_run_section_list_from_idx_run_map(arena, in->idx_runs); + return s; +} + +//////////////////////////////// +//~ rjf: Top-Level Baking Entry Point + +internal P2R_Bake2Serialize * +p2r_bake(Arena *arena, P2R_Convert2Bake *in) +{ + Temp scratch = scratch_begin(&arena, 1); + RDIM_BakeParams *params = &in->bake_params; + RDIM_BakeSectionList sections = {0}; + + //- rjf: build interned path tree + RDIM_BakePathTree *path_tree = 0; + ProfScope("build interned path tree") + { + path_tree = rdim_bake_path_tree_from_params(arena, params); + } + + //- rjf: kick off per-unit baking tasks + P2R_BakeUnitIn *bake_units_in = push_array(scratch.arena, P2R_BakeUnitIn, params->units.total_count); + TS_Ticket *bake_units_tickets = push_array(scratch.arena, TS_Ticket, params->units.total_count); + { + U64 idx = 0; + for(RDIM_UnitChunkNode *n = params->units.first; n != 0; n = n->next) + { + for(U64 chunk_idx = 0; chunk_idx < n->count; chunk_idx += 1, idx += 1) + { + bake_units_in[idx].unit = &n->v[chunk_idx]; + bake_units_tickets[idx] = ts_kickoff(p2r_bake_unit_task__entry_point, 0, &bake_units_in[idx]); + } + } + } + + //- rjf: kick off string map building tasks + RDIM_BakeStringMapTopology bake_string_map_topology = {(params->procedures.total_count*1 + + params->global_variables.total_count*1 + + params->thread_variables.total_count*1 + + params->types.total_count/2)}; + RDIM_BakeStringMapLoose **bake_string_maps__in_progress = push_array(scratch.arena, RDIM_BakeStringMapLoose *, ts_thread_count()); + TS_TicketList bake_string_map_build_tickets = {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 = ¶ms->src_files; + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_src_files_strings_task__entry_point, 0, 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 = ¶ms->units; + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_units_strings_task__entry_point, 0, in)); + } + + // rjf: types + ProfScope("kick off types string map build tasks") + { + for(RDIM_TypeChunkNode *chunk = params->types.first; chunk != 0; chunk = chunk->next) + { + U64 items_per_task = Min(4096, chunk->count); + U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task; + for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; 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; + P2R_BakeTypesStringsInNode *n = push_array(scratch.arena, P2R_BakeTypesStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + task_idx*items_per_task; + n->count = Min(items_per_task, chunk->count - task_idx*items_per_task); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_types_strings_task__entry_point, 0, in)); + } + } + } + + // rjf: UDTs + ProfScope("kick off udts string map build tasks") + { + for(RDIM_UDTChunkNode *chunk = params->udts.first; chunk != 0; chunk = chunk->next) + { + U64 items_per_task = Min(4096, chunk->count); + U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task; + for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; 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; + P2R_BakeUDTsStringsInNode *n = push_array(scratch.arena, P2R_BakeUDTsStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + task_idx*items_per_task; + n->count = Min(items_per_task, chunk->count - task_idx*items_per_task); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_udts_strings_task__entry_point, 0, in)); + } + } + } + + // rjf: symbols + ProfScope("kick off symbols string map build tasks") + { + RDIM_SymbolChunkList *symbol_lists[] = + { + ¶ms->global_variables, + ¶ms->thread_variables, + ¶ms->procedures, + }; + for(U64 list_idx = 0; list_idx < ArrayCount(symbol_lists); list_idx += 1) + { + for(RDIM_SymbolChunkNode *chunk = symbol_lists[list_idx]->first; chunk != 0; chunk = chunk->next) + { + U64 items_per_task = Min(4096, chunk->count); + U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task; + for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; 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; + P2R_BakeSymbolsStringsInNode *n = push_array(scratch.arena, P2R_BakeSymbolsStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + task_idx*items_per_task; + n->count = Min(items_per_task, chunk->count - task_idx*items_per_task); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_symbols_strings_task__entry_point, 0, in)); + } + } + } + } + + // rjf: scope chunks + ProfScope("kick off scope chunks string map build tasks") + { + for(RDIM_ScopeChunkNode *chunk = params->scopes.first; chunk != 0; chunk = chunk->next) + { + U64 items_per_task = Min(4096, chunk->count); + U64 tasks_per_this_chunk = (chunk->count+items_per_task-1)/items_per_task; + for(U64 task_idx = 0; task_idx < tasks_per_this_chunk; 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; + P2R_BakeScopesStringsInNode *n = push_array(scratch.arena, P2R_BakeScopesStringsInNode, 1); + SLLQueuePush(in->first, in->last, n); + n->v = chunk->v + task_idx*items_per_task; + n->count = Min(items_per_task, chunk->count - task_idx*items_per_task); + ts_ticket_list_push(scratch.arena, &bake_string_map_build_tickets, ts_kickoff(p2r_bake_scopes_strings_task__entry_point, 0, in)); + } + } + } + } + + //- rjf: kick off name map building tasks + P2R_BuildBakeNameMapIn build_bake_name_map_in[RDI_NameMapKind_COUNT] = {0}; + TS_Ticket build_bake_name_map_ticket[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 = params; + build_bake_name_map_ticket[k] = ts_kickoff(p2r_build_bake_name_map_task__entry_point, 0, &build_bake_name_map_in[k]); + } + + //- rjf: join string map building tasks + ProfScope("join string map building tasks") + { + for(TS_TicketNode *n = bake_string_map_build_tickets.first; n != 0; n = n->next) + { + ts_join(n->v, max_U64); + } + } + + //- 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; + TS_Ticket *task_tickets = push_array(scratch.arena, TS_Ticket, 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 = ts_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); + task_tickets[task_idx] = ts_kickoff(p2r_bake_string_map_join_task__entry_point, 0, in); + } + + // rjf: join tasks + for(U64 task_idx = 0; task_idx < num_tasks; task_idx += 1) + { + ts_join(task_tickets[task_idx], max_U64); + } + + // rjf: insert small top-level stuff + rdim_bake_string_map_loose_push_top_level_info(arena, &bake_string_map_topology, unsorted_bake_string_map, ¶ms->top_level_info); + rdim_bake_string_map_loose_push_binary_sections(arena, &bake_string_map_topology, unsorted_bake_string_map, ¶ms->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 + TS_TicketList sort_bake_string_map_task_tickets = {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; + } + } + ts_ticket_list_push(scratch.arena, &sort_bake_string_map_task_tickets, ts_kickoff(p2r_bake_string_map_sort_task__entry_point, 0, in)); + } + } + + //- rjf: join string map sorting tasks + ProfScope("join string map sorting tasks") + { + for(TS_TicketNode *n = sort_bake_string_map_task_tickets.first; n != 0; n = n->next) + { + ts_join(n->v, max_U64); + } + } + 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_BakeUnitsTopLevelIn bake_units_top_level_in = {&bake_strings, path_tree, params}; + TS_Ticket bake_units_top_level_ticket = ts_kickoff(p2r_bake_units_top_level_task__entry_point, 0, &bake_units_top_level_in); + P2R_BakeUnitVMapIn bake_unit_vmap_in = {params}; + TS_Ticket bake_unit_vmap_ticket = ts_kickoff(p2r_bake_unit_vmap_task__entry_point, 0, &bake_unit_vmap_in); + P2R_BakeSrcFilesIn bake_src_files_in = {&bake_strings, path_tree, params}; + TS_Ticket bake_src_files_ticket = ts_kickoff(p2r_bake_src_files_task__entry_point, 0, &bake_src_files_in); + P2R_BakeUDTsIn bake_udts_in = {&bake_strings, params}; + TS_Ticket bake_udts_ticket = ts_kickoff(p2r_bake_udts_task__entry_point, 0, &bake_udts_in); + P2R_BakeGlobalVariablesIn bake_global_variables_in = {&bake_strings, params}; + TS_Ticket bake_global_variables_ticket = ts_kickoff(p2r_bake_global_variables_task__entry_point, 0, &bake_global_variables_in); + P2R_BakeGlobalVMapIn bake_global_vmap_in = {params}; + TS_Ticket bake_global_vmap_ticket = ts_kickoff(p2r_bake_global_vmap_task__entry_point, 0, &bake_global_vmap_in); + P2R_BakeThreadVariablesIn bake_thread_variables_in = {&bake_strings, params}; + TS_Ticket bake_thread_variables_ticket = ts_kickoff(p2r_bake_thread_variables_task__entry_point, 0, &bake_thread_variables_in); + P2R_BakeProceduresIn bake_procedures_in = {&bake_strings, params}; + TS_Ticket bake_procedures_ticket = ts_kickoff(p2r_bake_procedures_task__entry_point, 0, &bake_procedures_in); + P2R_BakeScopesIn bake_scopes_in = {&bake_strings, params}; + TS_Ticket bake_scopes_ticket = ts_kickoff(p2r_bake_scopes_task__entry_point, 0, &bake_scopes_in); + P2R_BakeScopeVMapIn bake_scope_vmap_in = {params}; + TS_Ticket bake_scope_vmap_ticket = ts_kickoff(p2r_bake_scope_vmap_task__entry_point, 0, &bake_scope_vmap_in); + P2R_BakeFilePathsIn bake_file_paths_in = {&bake_strings, path_tree}; + TS_Ticket bake_file_paths_ticket = ts_kickoff(p2r_bake_file_paths_task__entry_point, 0, &bake_file_paths_in); + P2R_BakeStringsIn bake_strings_in = {&bake_strings}; + TS_Ticket bake_strings_ticket = ts_kickoff(p2r_bake_strings_task__entry_point, 0, &bake_strings_in); + + //- rjf: top-level info + ProfScope("top level info") + { + RDIM_BakeSectionList s = rdim_bake_top_level_info_section_list_from_params(arena, &bake_strings, params); + rdim_bake_section_list_concat_in_place(§ions, &s); + } + + //- rjf: binary sections + ProfScope("binary sections") + { + RDIM_BakeSectionList s = rdim_bake_binary_section_section_list_from_params(arena, &bake_strings, params); + rdim_bake_section_list_concat_in_place(§ions, &s); + } + + //- 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] = ts_join_struct(build_bake_name_map_ticket[k], max_U64, 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, params); + } + + //- rjf: kick off pass 3 tasks + P2R_BakeTypeNodesIn bake_type_nodes_in = {&bake_strings, idx_runs, params}; + TS_Ticket bake_type_nodes_ticket = ts_kickoff(p2r_bake_type_nodes_task__entry_point, 0, &bake_type_nodes_in); + TS_TicketList bake_name_maps_tickets = {0}; + for(RDI_NameMapKind k = (RDI_NameMapKind)(RDI_NameMapKind_NULL+1); + k < RDI_NameMapKind_COUNT; + k = (RDI_NameMapKind)(k+1)) + { + 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->params = params; + in->kind = k; + in->map = name_maps[k]; + ts_ticket_list_push(scratch.arena, &bake_name_maps_tickets, ts_kickoff(p2r_bake_name_map_task__entry_point, 0, in)); + } + P2R_BakeIdxRunsIn bake_idx_runs_in = {idx_runs}; + TS_Ticket bake_idx_runs_ticket = ts_kickoff(p2r_bake_idx_runs_task__entry_point, 0, &bake_idx_runs_in); + + //- rjf: bake top-level name maps section + ProfScope("top level name maps section") + { + RDIM_BakeSectionList s = rdim_bake_top_level_name_map_section_list_from_params_maps(arena, &bake_strings, idx_runs, params, name_maps); + rdim_bake_section_list_concat_in_place(§ions, &s); + } + + //- rjf: join top-level units info + ProfScope("top-level units info") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_units_top_level_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join unit vmap + ProfScope("unit vmap") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_unit_vmap_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join source files + ProfScope("source files") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_src_files_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join UDTs + ProfScope("UDTs") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_udts_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join global variables + ProfScope("global variables") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_global_variables_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join global vmap + ProfScope("global vmap") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_global_vmap_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join thread variables + ProfScope("thread variables") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_thread_variables_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join procedures + ProfScope("procedures") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_procedures_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join scopes + ProfScope("scopes") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_scopes_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join scope vmap + ProfScope("scope vmap") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_scope_vmap_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join file paths + ProfScope("file paths") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_file_paths_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join strings + ProfScope("strings") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_strings_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join type nodes + ProfScope("type nodes") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_type_nodes_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join name maps + ProfScope("name map") + { + for(TS_TicketNode *n = bake_name_maps_tickets.first; n != 0; n = n->next) + { + RDIM_BakeSectionList *s = ts_join_struct(n->v, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + } + + //- rjf: join index runs + ProfScope("idx runs") + { + RDIM_BakeSectionList *s = ts_join_struct(bake_idx_runs_ticket, max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + + //- rjf: join per-unit bakes + ProfScope("units") + { + for(U64 idx = 0; idx < params->units.total_count; idx += 1) + { + RDIM_BakeSectionList *s = ts_join_struct(bake_units_tickets[idx], max_U64, RDIM_BakeSectionList); + rdim_bake_section_list_concat_in_place(§ions, s); + } + } + + //- rjf: fill & return + P2R_Bake2Serialize *out = push_array(arena, P2R_Bake2Serialize, 1); + out->sections = sections; + scratch_end(scratch); + return out; +} diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.h b/src/raddbgi_from_pdb/raddbgi_from_pdb.h new file mode 100644 index 00000000..7b1ae67e --- /dev/null +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb.h @@ -0,0 +1,605 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef RADDBGI_FROM_PDB_H +#define RADDBGI_FROM_PDB_H + +//////////////////////////////// +//~ rjf: Conversion Stage Inputs/Outputs + +typedef U32 P2R_ConvertFlags; +enum +{ + P2R_ConvertFlag_Types = (1<<0), + P2R_ConvertFlag_UDTs = (1<<1), + P2R_ConvertFlag_All = 0xffffffff, +}; + +typedef struct P2R_User2Convert P2R_User2Convert; +struct P2R_User2Convert +{ + String8 input_pdb_name; + String8 input_pdb_data; + String8 input_exe_name; + String8 input_exe_data; + String8 output_name; + P2R_ConvertFlags flags; + String8List errors; +}; + +typedef struct P2R_Convert2Bake P2R_Convert2Bake; +struct P2R_Convert2Bake +{ + RDIM_BakeParams bake_params; +}; + +typedef struct P2R_Bake2Serialize P2R_Bake2Serialize; +struct P2R_Bake2Serialize +{ + RDIM_BakeSectionList sections; +}; + +//////////////////////////////// +//~ 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; + PDB_Strtbl *strtbl; + PDB_CoffSectionArray *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; + PDB_CoffSectionArray *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_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; +}; + +//- rjf: link name map building tasks + +typedef struct P2R_LinkNameMapBuildIn P2R_LinkNameMapBuildIn; +struct P2R_LinkNameMapBuildIn +{ + CV_SymParsed *sym; + PDB_CoffSectionArray *coff_sections; + P2R_LinkNameMap *link_name_map; +}; + +//- rjf: type forward resolution map build + +typedef struct P2R_ITypeFwdMapFillIn P2R_ITypeFwdMapFillIn; +struct P2R_ITypeFwdMapFillIn +{ + PDB_TpiHashParsed *tpi_hash; + CV_LeafParsed *tpi_leaf; + CV_TypeId itype_first; + CV_TypeId itype_opl; + CV_TypeId *itype_fwd_map; +}; + +//- rjf: itype chain build + +typedef struct P2R_TypeIdChain P2R_TypeIdChain; +struct P2R_TypeIdChain +{ + P2R_TypeIdChain *next; + CV_TypeId itype; +}; + +typedef struct P2R_ITypeChainBuildIn P2R_ITypeChainBuildIn; +struct P2R_ITypeChainBuildIn +{ + CV_LeafParsed *tpi_leaf; + CV_TypeId itype_first; + CV_TypeId itype_opl; + CV_TypeId *itype_fwd_map; + P2R_TypeIdChain **itype_chains; +}; + +//- rjf: udt conversion + +typedef struct P2R_UDTConvertIn P2R_UDTConvertIn; +struct P2R_UDTConvertIn +{ + CV_LeafParsed *tpi_leaf; + CV_TypeId itype_first; + CV_TypeId itype_opl; + CV_TypeId *itype_fwd_map; + RDIM_Type **itype_type_ptrs; +}; + +//- rjf: symbol stream conversion + +typedef struct P2R_SymbolStreamConvertIn P2R_SymbolStreamConvertIn; +struct P2R_SymbolStreamConvertIn +{ + RDI_Arch arch; + PDB_CoffSectionArray *coff_sections; + PDB_TpiHashParsed *tpi_hash; + CV_LeafParsed *tpi_leaf; + CV_SymParsed *sym; + U64 sym_ranges_first; + U64 sym_ranges_opl; + CV_TypeId *itype_fwd_map; + RDIM_Type **itype_type_ptrs; + P2R_LinkNameMap *link_name_map; +}; + +typedef struct P2R_SymbolStreamConvertOut P2R_SymbolStreamConvertOut; +struct P2R_SymbolStreamConvertOut +{ + RDIM_SymbolChunkList procedures; + RDIM_SymbolChunkList global_variables; + RDIM_SymbolChunkList thread_variables; + RDIM_ScopeChunkList scopes; +}; + +//////////////////////////////// +//~ rjf: Baking Task Types + +//- 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_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_BakeUnitsTopLevelIn P2R_BakeUnitsTopLevelIn; +struct P2R_BakeUnitsTopLevelIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeUnitIn P2R_BakeUnitIn; +struct P2R_BakeUnitIn +{ + RDIM_Unit *unit; +}; + +typedef struct P2R_BakeUnitVMapIn P2R_BakeUnitVMapIn; +struct P2R_BakeUnitVMapIn +{ + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeSrcFilesIn P2R_BakeSrcFilesIn; +struct P2R_BakeSrcFilesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakePathTree *path_tree; + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeUDTsIn P2R_BakeUDTsIn; +struct P2R_BakeUDTsIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeGlobalVariablesIn P2R_BakeGlobalVariablesIn; +struct P2R_BakeGlobalVariablesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeGlobalVMapIn P2R_BakeGlobalVMapIn; +struct P2R_BakeGlobalVMapIn +{ + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeThreadVariablesIn P2R_BakeThreadVariablesIn; +struct P2R_BakeThreadVariablesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeProceduresIn P2R_BakeProceduresIn; +struct P2R_BakeProceduresIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeScopesIn P2R_BakeScopesIn; +struct P2R_BakeScopesIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeParams *params; +}; + +typedef struct P2R_BakeScopeVMapIn P2R_BakeScopeVMapIn; +struct P2R_BakeScopeVMapIn +{ + RDIM_BakeParams *params; +}; + +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_BakeParams *params; +}; + +typedef struct P2R_BakeNameMapIn P2R_BakeNameMapIn; +struct P2R_BakeNameMapIn +{ + RDIM_BakeStringMapTight *strings; + RDIM_BakeIdxRunMap *idx_runs; + RDIM_BakeParams *params; + RDI_NameMapKind kind; + RDIM_BakeNameMap *map; +}; + +typedef struct P2R_BakeIdxRunsIn P2R_BakeIdxRunsIn; +struct P2R_BakeIdxRunsIn +{ + RDIM_BakeIdxRunMap *idx_runs; +}; + +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 p2r_end_of_cplusplus_container_name(String8 str); +internal U64 p2r_hash_from_voff(U64 voff); + +//////////////////////////////// +//~ rjf: Command Line -> Conversion Inputs + +internal P2R_User2Convert *p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline); + +//////////////////////////////// +//~ rjf: COFF => RADDBGI Canonical Conversions + +internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); + +//////////////////////////////// +//~ rjf: CodeView => RADDBGI Canonical Conversions + +internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch arch); +internal RDI_RegisterCode p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code); +internal RDI_Language p2r_rdi_language_from_cv_language(CV_Language language); +internal RDI_TypeKind p2r_rdi_type_kind_from_cv_basic_type(CV_BasicType basic_type); + +//////////////////////////////// +//~ rjf: Location Info Building Helpers + +internal RDIM_Location *p2r_location_from_addr_reg_off(Arena *arena, RDI_Arch arch, RDI_RegisterCode reg_code, U32 reg_byte_size, U32 reg_byte_pos, S64 offset, B32 extra_indirection); +internal CV_EncodedFramePtrReg p2r_cv_encoded_fp_reg_from_frameproc(CV_SymFrameproc *frameproc, B32 param_base); +internal RDI_RegisterCode 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 + +internal TS_TASK_FUNCTION_DEF(p2r_exe_hash_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_tpi_hash_parse_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_tpi_leaf_parse_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_symbol_stream_parse_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_c13_stream_parse_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_comp_unit_parse_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_comp_unit_contributions_parse_task__entry_point); + +//////////////////////////////// +//~ rjf: Unit Conversion Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_units_convert_task__entry_point); + +//////////////////////////////// +//~ rjf: Link Name Map Building Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_link_name_map_build_task__entry_point); + +//////////////////////////////// +//~ rjf: Type Parsing/Conversion Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_itype_fwd_map_fill_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_itype_chain_build_task__entry_point); + +//////////////////////////////// +//~ rjf: UDT Conversion Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_udt_convert_task__entry_point); + +//////////////////////////////// +//~ rjf: Symbol Stream Conversion Tasks + +internal TS_TASK_FUNCTION_DEF(p2r_symbol_stream_convert_task__entry_point); + +//////////////////////////////// +//~ rjf: Top-Level Conversion Entry Point + +internal P2R_Convert2Bake *p2r_convert(Arena *arena, P2R_User2Convert *in); + +//////////////////////////////// +//~ rjf: Baking Stage Tasks + +//- rjf: unsorted bake string map building +internal TS_TASK_FUNCTION_DEF(p2r_bake_src_files_strings_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_units_strings_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_types_strings_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_udts_strings_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_symbols_strings_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_scopes_strings_task__entry_point); + +//- rjf: bake string map joining +internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_join_task__entry_point); + +//- rjf: bake string map sorting +internal TS_TASK_FUNCTION_DEF(p2r_bake_string_map_sort_task__entry_point); + +//- rjf: pass 1: interner/deduper map builds +internal TS_TASK_FUNCTION_DEF(p2r_build_bake_name_map_task__entry_point); + +//- rjf: pass 2: string-map-dependent debug info stream builds +internal TS_TASK_FUNCTION_DEF(p2r_bake_units_top_level_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_unit_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_unit_vmap_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_src_files_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_udts_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_global_variables_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_global_vmap_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_thread_variables_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_procedures_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_scopes_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_scope_vmap_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_file_paths_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_strings_task__entry_point); + +//- rjf: pass 3: idx-run-map-dependent debug info stream builds +internal TS_TASK_FUNCTION_DEF(p2r_bake_type_nodes_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_name_map_task__entry_point); +internal TS_TASK_FUNCTION_DEF(p2r_bake_idx_runs_task__entry_point); + +//////////////////////////////// +//~ rjf: Top-Level Baking Entry Point + +internal P2R_Bake2Serialize *p2r_bake(Arena *arena, P2R_Convert2Bake *in); + +#endif // RADDBGI_FROM_PDB_H diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c b/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c new file mode 100644 index 00000000..bc0ef474 --- /dev/null +++ b/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c @@ -0,0 +1,114 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Build Options + +#define BUILD_VERSION_MAJOR 0 +#define BUILD_VERSION_MINOR 9 +#define BUILD_VERSION_PATCH 9 +#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +#define BUILD_TITLE "raddbgi_from_pdb" +#define BUILD_CONSOLE_INTERFACE 1 + +//////////////////////////////// +//~ rjf: Includes + +//- rjf: [lib] +#include "lib_raddbgi_format/raddbgi_format.h" +#include "lib_raddbgi_format/raddbgi_format.c" + +//- rjf: [h] +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "task_system/task_system.h" +#include "raddbgi_make_local/raddbgi_make_local.h" +#include "coff/coff.h" +#include "codeview/codeview.h" +#include "codeview/codeview_stringize.h" +#include "msf/msf.h" +#include "pdb/pdb.h" +#include "pdb/pdb_stringize.h" +#include "raddbgi_from_pdb.h" + +//- rjf: [c] +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "task_system/task_system.c" +#include "raddbgi_make_local/raddbgi_make_local.c" +#include "coff/coff.c" +#include "codeview/codeview.c" +#include "codeview/codeview_stringize.c" +#include "msf/msf.c" +#include "pdb/pdb.c" +#include "pdb/pdb_stringize.c" +#include "raddbgi_from_pdb.c" + +//////////////////////////////// +//~ rjf: Entry Point + +internal void +entry_point(CmdLine *cmdline) +{ + //- rjf: initialize state, 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("?"))); + P2R_User2Convert *user2convert = p2r_user2convert_from_cmdln(arena, cmdline); + + //- rjf: display help + if(do_help || user2convert->errors.node_count != 0) + { + fprintf(stderr, "--- raddbgi_from_pdb ----------------------------------------------------------\n\n"); + + fprintf(stderr, "This utility converts debug information from PDBs 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 file for which the\n"); + fprintf(stderr, " debug info was generated.\n"); + fprintf(stderr, "--pdb: Specifies the path of the PDB debug info file to\n"); + fprintf(stderr, " convert.\n"); + fprintf(stderr, "--out: Specifies the path at which the output Breakpad debug\n"); + fprintf(stderr, " info 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_exit_process(0); + } + + //- rjf: convert + P2R_Convert2Bake *convert2bake = 0; + ProfScope("convert") + { + convert2bake = p2r_convert(arena, user2convert); + } + + //- rjf: bake + P2R_Bake2Serialize *bake2srlz = 0; + ProfScope("bake") + { + bake2srlz = p2r_bake(arena, convert2bake); + } + + //- rjf: serialize + String8List serialize_out = rdim_serialized_strings_from_params_bake_section_list(arena, &convert2bake->bake_params, &bake2srlz->sections); + + //- rjf: write + ProfScope("write") + { + OS_Handle output_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_Write, user2convert->output_name); + U64 off = 0; + for(String8Node *n = serialize_out.first; n != 0; n = n->next) + { + os_file_write(output_file, r1u64(off, off+n->string.size), n->string.str); + off += n->string.size; + } + os_file_close(output_file); + } +} diff --git a/src/raddbgi_make_local/raddbgi_make_local.c b/src/raddbgi_make_local/raddbgi_make_local.c new file mode 100644 index 00000000..7e476d6c --- /dev/null +++ b/src/raddbgi_make_local/raddbgi_make_local.c @@ -0,0 +1,4 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "lib_raddbgi_make/raddbgi_make.c" diff --git a/src/raddbgi_make_local/raddbgi_make_local.h b/src/raddbgi_make_local/raddbgi_make_local.h new file mode 100644 index 00000000..d4201e24 --- /dev/null +++ b/src/raddbgi_make_local/raddbgi_make_local.h @@ -0,0 +1,50 @@ +// 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 + +// rjf: base layer memory ops +#define RDIM_MEMSET_OVERRIDE +#define RDIM_MEMCPY_OVERRIDE +#define rdim_memset MemorySet +#define rdim_memcpy MemoryCopy + +// rjf: base layer string overrides +#define RDI_STRING8_OVERRIDE +#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_String8List_NodeCountMember node_count +#define RDIM_String8List_TotalSizeMember total_size + +// rjf: base layer arena overrides +#define RDIM_ARENA_OVERRIDE +#define RDIM_Arena Arena +#define rdim_arena_alloc arena_alloc +#define rdim_arena_release arena_release +#define rdim_arena_pos arena_pos +#define rdim_arena_push arena_push +#define rdim_arena_pop_to arena_pop_to + +// rjf: base layer scratch arena overrides +#define RDIM_SCRATCH_OVERRIDE +#define RDIM_Temp Temp +#define rdim_temp_arena(t) ((t).arena) +#define rdim_scratch_begin scratch_begin +#define rdim_scratch_end scratch_end + +// rjf: base layer profiling markup overrides +#define RDIM_ProfBegin(...) ProfBeginDynamic(__VA_ARGS__) +#define RDIM_ProfEnd(...) ProfEnd() + +#include "lib_raddbgi_make/raddbgi_make.h" + +#endif // RDI_CONS_LOCAL_H diff --git a/src/regs/generated/regs.meta.c b/src/regs/generated/regs.meta.c index ee37e616..213acb9b 100644 --- a/src/regs/generated/regs.meta.c +++ b/src/regs/generated/regs.meta.c @@ -5,7 +5,7 @@ internal U64 regs_block_size_from_architecture(Architecture arch) { -U64 result = 0; +U64 result = 8; switch(arch) { default:{}break; @@ -102,3 +102,816 @@ case Architecture_x86:{result = regs_g_alias_code_x86_usage_kind_table;}break; } return result; } +C_LINKAGE_BEGIN +REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[77] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +REGS_UsageKind regs_g_alias_code_x64_usage_kind_table[80] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +String8 regs_g_reg_code_x64_string_table[77] = +{ +str8_lit_comp(""), +str8_lit_comp("rax"), +str8_lit_comp("rcx"), +str8_lit_comp("rdx"), +str8_lit_comp("rbx"), +str8_lit_comp("rsp"), +str8_lit_comp("rbp"), +str8_lit_comp("rsi"), +str8_lit_comp("rdi"), +str8_lit_comp("r8"), +str8_lit_comp("r9"), +str8_lit_comp("r10"), +str8_lit_comp("r11"), +str8_lit_comp("r12"), +str8_lit_comp("r13"), +str8_lit_comp("r14"), +str8_lit_comp("r15"), +str8_lit_comp("fsbase"), +str8_lit_comp("gsbase"), +str8_lit_comp("rip"), +str8_lit_comp("rflags"), +str8_lit_comp("dr0"), +str8_lit_comp("dr1"), +str8_lit_comp("dr2"), +str8_lit_comp("dr3"), +str8_lit_comp("dr4"), +str8_lit_comp("dr5"), +str8_lit_comp("dr6"), +str8_lit_comp("dr7"), +str8_lit_comp("fpr0"), +str8_lit_comp("fpr1"), +str8_lit_comp("fpr2"), +str8_lit_comp("fpr3"), +str8_lit_comp("fpr4"), +str8_lit_comp("fpr5"), +str8_lit_comp("fpr6"), +str8_lit_comp("fpr7"), +str8_lit_comp("st0"), +str8_lit_comp("st1"), +str8_lit_comp("st2"), +str8_lit_comp("st3"), +str8_lit_comp("st4"), +str8_lit_comp("st5"), +str8_lit_comp("st6"), +str8_lit_comp("st7"), +str8_lit_comp("fcw"), +str8_lit_comp("fsw"), +str8_lit_comp("ftw"), +str8_lit_comp("fop"), +str8_lit_comp("fcs"), +str8_lit_comp("fds"), +str8_lit_comp("fip"), +str8_lit_comp("fdp"), +str8_lit_comp("mxcsr"), +str8_lit_comp("mxcsr_mask"), +str8_lit_comp("ss"), +str8_lit_comp("cs"), +str8_lit_comp("ds"), +str8_lit_comp("es"), +str8_lit_comp("fs"), +str8_lit_comp("gs"), +str8_lit_comp("ymm0"), +str8_lit_comp("ymm1"), +str8_lit_comp("ymm2"), +str8_lit_comp("ymm3"), +str8_lit_comp("ymm4"), +str8_lit_comp("ymm5"), +str8_lit_comp("ymm6"), +str8_lit_comp("ymm7"), +str8_lit_comp("ymm8"), +str8_lit_comp("ymm9"), +str8_lit_comp("ymm10"), +str8_lit_comp("ymm11"), +str8_lit_comp("ymm12"), +str8_lit_comp("ymm13"), +str8_lit_comp("ymm14"), +str8_lit_comp("ymm15"), +}; + +String8 regs_g_alias_code_x64_string_table[80] = +{ +str8_lit_comp(""), +str8_lit_comp("eax"), +str8_lit_comp("ecx"), +str8_lit_comp("edx"), +str8_lit_comp("ebx"), +str8_lit_comp("esp"), +str8_lit_comp("ebp"), +str8_lit_comp("esi"), +str8_lit_comp("edi"), +str8_lit_comp("r8d"), +str8_lit_comp("r9d"), +str8_lit_comp("r10d"), +str8_lit_comp("r11d"), +str8_lit_comp("r12d"), +str8_lit_comp("r13d"), +str8_lit_comp("r14d"), +str8_lit_comp("r15d"), +str8_lit_comp("eip"), +str8_lit_comp("eflags"), +str8_lit_comp("ax"), +str8_lit_comp("cx"), +str8_lit_comp("dx"), +str8_lit_comp("bx"), +str8_lit_comp("si"), +str8_lit_comp("di"), +str8_lit_comp("sp"), +str8_lit_comp("bp"), +str8_lit_comp("ip"), +str8_lit_comp("r8w"), +str8_lit_comp("r9w"), +str8_lit_comp("r10w"), +str8_lit_comp("r11w"), +str8_lit_comp("r12w"), +str8_lit_comp("r13w"), +str8_lit_comp("r14w"), +str8_lit_comp("r15w"), +str8_lit_comp("al"), +str8_lit_comp("cl"), +str8_lit_comp("dl"), +str8_lit_comp("bl"), +str8_lit_comp("sil"), +str8_lit_comp("dil"), +str8_lit_comp("bpl"), +str8_lit_comp("spl"), +str8_lit_comp("r8b"), +str8_lit_comp("r9b"), +str8_lit_comp("r10b"), +str8_lit_comp("r11b"), +str8_lit_comp("r12b"), +str8_lit_comp("r13b"), +str8_lit_comp("r14b"), +str8_lit_comp("r15b"), +str8_lit_comp("ah"), +str8_lit_comp("ch"), +str8_lit_comp("dh"), +str8_lit_comp("bh"), +str8_lit_comp("xmm0"), +str8_lit_comp("xmm1"), +str8_lit_comp("xmm2"), +str8_lit_comp("xmm3"), +str8_lit_comp("xmm4"), +str8_lit_comp("xmm5"), +str8_lit_comp("xmm6"), +str8_lit_comp("xmm7"), +str8_lit_comp("xmm8"), +str8_lit_comp("xmm9"), +str8_lit_comp("xmm10"), +str8_lit_comp("xmm11"), +str8_lit_comp("xmm12"), +str8_lit_comp("xmm13"), +str8_lit_comp("xmm14"), +str8_lit_comp("xmm15"), +str8_lit_comp("mm0"), +str8_lit_comp("mm1"), +str8_lit_comp("mm2"), +str8_lit_comp("mm3"), +str8_lit_comp("mm4"), +str8_lit_comp("mm5"), +str8_lit_comp("mm6"), +str8_lit_comp("mm7"), +}; + +REGS_Rng regs_g_reg_code_x64_rng_table[77] = +{ +{0}, +{(U16)OffsetOf(REGS_RegBlockX64, rax), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rcx), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rdx), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rbx), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rsp), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rbp), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rsi), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, rdi), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r8), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r9), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r10), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r11), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r12), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r13), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r14), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, r15), 8}, +{(U16)OffsetOf(REGS_RegBlockX64, fsbase), 8}, +{(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, fpr0), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr1), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr2), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr3), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr4), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr5), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr6), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fpr7), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st0), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st1), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st2), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st3), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st4), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st5), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st6), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, st7), 10}, +{(U16)OffsetOf(REGS_RegBlockX64, fcw), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fsw), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, ftw), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fop), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fcs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fds), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fip), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, fdp), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, mxcsr), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, mxcsr_mask), 4}, +{(U16)OffsetOf(REGS_RegBlockX64, ss), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, cs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, ds), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, es), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, fs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, gs), 2}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm0), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm1), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm2), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm3), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm4), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm5), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm6), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm7), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm8), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm9), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm10), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm11), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm12), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm13), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm14), 32}, +{(U16)OffsetOf(REGS_RegBlockX64, ymm15), 32}, +}; + +REGS_Slice regs_g_alias_code_x64_slice_table[80] = +{ +{0}, +{REGS_RegCodeX64_rax, 0, 4}, +{REGS_RegCodeX64_rcx, 0, 4}, +{REGS_RegCodeX64_rdx, 0, 4}, +{REGS_RegCodeX64_rbx, 0, 4}, +{REGS_RegCodeX64_rsp, 0, 4}, +{REGS_RegCodeX64_rbp, 0, 4}, +{REGS_RegCodeX64_rsi, 0, 4}, +{REGS_RegCodeX64_rdi, 0, 4}, +{REGS_RegCodeX64_r8, 0, 4}, +{REGS_RegCodeX64_r9, 0, 4}, +{REGS_RegCodeX64_r10, 0, 4}, +{REGS_RegCodeX64_r11, 0, 4}, +{REGS_RegCodeX64_r12, 0, 4}, +{REGS_RegCodeX64_r13, 0, 4}, +{REGS_RegCodeX64_r14, 0, 4}, +{REGS_RegCodeX64_r15, 0, 4}, +{REGS_RegCodeX64_rip, 0, 4}, +{REGS_RegCodeX64_rflags, 0, 4}, +{REGS_RegCodeX64_rax, 0, 2}, +{REGS_RegCodeX64_rcx, 0, 2}, +{REGS_RegCodeX64_rdx, 0, 2}, +{REGS_RegCodeX64_rbx, 0, 2}, +{REGS_RegCodeX64_rsi, 0, 2}, +{REGS_RegCodeX64_rdi, 0, 2}, +{REGS_RegCodeX64_rsp, 0, 2}, +{REGS_RegCodeX64_rbp, 0, 2}, +{REGS_RegCodeX64_rip, 0, 2}, +{REGS_RegCodeX64_r8, 0, 2}, +{REGS_RegCodeX64_r9, 0, 2}, +{REGS_RegCodeX64_r10, 0, 2}, +{REGS_RegCodeX64_r11, 0, 2}, +{REGS_RegCodeX64_r12, 0, 2}, +{REGS_RegCodeX64_r13, 0, 2}, +{REGS_RegCodeX64_r14, 0, 2}, +{REGS_RegCodeX64_r15, 0, 2}, +{REGS_RegCodeX64_rax, 0, 1}, +{REGS_RegCodeX64_rcx, 0, 1}, +{REGS_RegCodeX64_rdx, 0, 1}, +{REGS_RegCodeX64_rbx, 0, 1}, +{REGS_RegCodeX64_rsi, 0, 1}, +{REGS_RegCodeX64_rdi, 0, 1}, +{REGS_RegCodeX64_rbp, 0, 1}, +{REGS_RegCodeX64_rsp, 0, 1}, +{REGS_RegCodeX64_r8, 0, 1}, +{REGS_RegCodeX64_r9, 0, 1}, +{REGS_RegCodeX64_r10, 0, 1}, +{REGS_RegCodeX64_r11, 0, 1}, +{REGS_RegCodeX64_r12, 0, 1}, +{REGS_RegCodeX64_r13, 0, 1}, +{REGS_RegCodeX64_r14, 0, 1}, +{REGS_RegCodeX64_r15, 0, 1}, +{REGS_RegCodeX64_rax, 1, 1}, +{REGS_RegCodeX64_rcx, 1, 1}, +{REGS_RegCodeX64_rdx, 1, 1}, +{REGS_RegCodeX64_rbx, 1, 1}, +{REGS_RegCodeX64_ymm0, 0, 16}, +{REGS_RegCodeX64_ymm1, 0, 16}, +{REGS_RegCodeX64_ymm2, 0, 16}, +{REGS_RegCodeX64_ymm3, 0, 16}, +{REGS_RegCodeX64_ymm4, 0, 16}, +{REGS_RegCodeX64_ymm5, 0, 16}, +{REGS_RegCodeX64_ymm6, 0, 16}, +{REGS_RegCodeX64_ymm7, 0, 16}, +{REGS_RegCodeX64_ymm8, 0, 16}, +{REGS_RegCodeX64_ymm9, 0, 16}, +{REGS_RegCodeX64_ymm10, 0, 16}, +{REGS_RegCodeX64_ymm11, 0, 16}, +{REGS_RegCodeX64_ymm12, 0, 16}, +{REGS_RegCodeX64_ymm13, 0, 16}, +{REGS_RegCodeX64_ymm14, 0, 16}, +{REGS_RegCodeX64_ymm15, 0, 16}, +{REGS_RegCodeX64_fpr0, 0, 8}, +{REGS_RegCodeX64_fpr1, 0, 8}, +{REGS_RegCodeX64_fpr2, 0, 8}, +{REGS_RegCodeX64_fpr3, 0, 8}, +{REGS_RegCodeX64_fpr4, 0, 8}, +{REGS_RegCodeX64_fpr5, 0, 8}, +{REGS_RegCodeX64_fpr6, 0, 8}, +{REGS_RegCodeX64_fpr7, 0, 8}, +}; + +REGS_UsageKind regs_g_reg_code_x86_usage_kind_table[61] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +REGS_UsageKind regs_g_alias_code_x86_usage_kind_table[36] = +{ +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +REGS_UsageKind_Normal, +}; + +String8 regs_g_reg_code_x86_string_table[61] = +{ +str8_lit_comp(""), +str8_lit_comp("eax"), +str8_lit_comp("ecx"), +str8_lit_comp("edx"), +str8_lit_comp("ebx"), +str8_lit_comp("esp"), +str8_lit_comp("ebp"), +str8_lit_comp("esi"), +str8_lit_comp("edi"), +str8_lit_comp("fsbase"), +str8_lit_comp("gsbase"), +str8_lit_comp("eflags"), +str8_lit_comp("eip"), +str8_lit_comp("dr0"), +str8_lit_comp("dr1"), +str8_lit_comp("dr2"), +str8_lit_comp("dr3"), +str8_lit_comp("dr4"), +str8_lit_comp("dr5"), +str8_lit_comp("dr6"), +str8_lit_comp("dr7"), +str8_lit_comp("fpr0"), +str8_lit_comp("fpr1"), +str8_lit_comp("fpr2"), +str8_lit_comp("fpr3"), +str8_lit_comp("fpr4"), +str8_lit_comp("fpr5"), +str8_lit_comp("fpr6"), +str8_lit_comp("fpr7"), +str8_lit_comp("st0"), +str8_lit_comp("st1"), +str8_lit_comp("st2"), +str8_lit_comp("st3"), +str8_lit_comp("st4"), +str8_lit_comp("st5"), +str8_lit_comp("st6"), +str8_lit_comp("st7"), +str8_lit_comp("fcw"), +str8_lit_comp("fsw"), +str8_lit_comp("ftw"), +str8_lit_comp("fop"), +str8_lit_comp("fcs"), +str8_lit_comp("fds"), +str8_lit_comp("fip"), +str8_lit_comp("fdp"), +str8_lit_comp("mxcsr"), +str8_lit_comp("mxcsr_mask"), +str8_lit_comp("ss"), +str8_lit_comp("cs"), +str8_lit_comp("ds"), +str8_lit_comp("es"), +str8_lit_comp("fs"), +str8_lit_comp("gs"), +str8_lit_comp("ymm0"), +str8_lit_comp("ymm1"), +str8_lit_comp("ymm2"), +str8_lit_comp("ymm3"), +str8_lit_comp("ymm4"), +str8_lit_comp("ymm5"), +str8_lit_comp("ymm6"), +str8_lit_comp("ymm7"), +}; + +String8 regs_g_alias_code_x86_string_table[36] = +{ +str8_lit_comp(""), +str8_lit_comp("ax"), +str8_lit_comp("cx"), +str8_lit_comp("bx"), +str8_lit_comp("dx"), +str8_lit_comp("sp"), +str8_lit_comp("bp"), +str8_lit_comp("si"), +str8_lit_comp("di"), +str8_lit_comp("ip"), +str8_lit_comp("ah"), +str8_lit_comp("ch"), +str8_lit_comp("dh"), +str8_lit_comp("bh"), +str8_lit_comp("al"), +str8_lit_comp("cl"), +str8_lit_comp("dl"), +str8_lit_comp("bl"), +str8_lit_comp("bpl"), +str8_lit_comp("spl"), +str8_lit_comp("xmm0"), +str8_lit_comp("xmm1"), +str8_lit_comp("xmm2"), +str8_lit_comp("xmm3"), +str8_lit_comp("xmm4"), +str8_lit_comp("xmm5"), +str8_lit_comp("xmm6"), +str8_lit_comp("xmm7"), +str8_lit_comp("mm0"), +str8_lit_comp("mm1"), +str8_lit_comp("mm2"), +str8_lit_comp("mm3"), +str8_lit_comp("mm4"), +str8_lit_comp("mm5"), +str8_lit_comp("mm6"), +str8_lit_comp("mm7"), +}; + +REGS_Rng regs_g_reg_code_x86_rng_table[61] = +{ +{0}, +{(U16)OffsetOf(REGS_RegBlockX86, eax), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ecx), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, edx), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ebx), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, esp), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ebp), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, esi), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, edi), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, fsbase), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, gsbase), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, eflags), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, eip), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr0), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr1), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr2), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr3), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr4), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr5), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr6), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, dr7), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr0), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr1), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr2), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr3), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr4), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr5), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr6), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fpr7), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st0), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st1), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st2), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st3), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st4), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st5), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st6), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, st7), 10}, +{(U16)OffsetOf(REGS_RegBlockX86, fcw), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fsw), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, ftw), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fop), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fcs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fds), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fip), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, fdp), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, mxcsr), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, mxcsr_mask), 4}, +{(U16)OffsetOf(REGS_RegBlockX86, ss), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, cs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, ds), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, es), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, fs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, gs), 2}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm0), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm1), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm2), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm3), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm4), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm5), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm6), 32}, +{(U16)OffsetOf(REGS_RegBlockX86, ymm7), 32}, +}; + +REGS_Slice regs_g_alias_code_x86_slice_table[36] = +{ +{0}, +{REGS_RegCodeX86_eax, 0, 2}, +{REGS_RegCodeX86_ecx, 0, 2}, +{REGS_RegCodeX86_ebx, 0, 2}, +{REGS_RegCodeX86_edx, 0, 2}, +{REGS_RegCodeX86_esp, 0, 2}, +{REGS_RegCodeX86_ebp, 0, 2}, +{REGS_RegCodeX86_esi, 0, 2}, +{REGS_RegCodeX86_edi, 0, 2}, +{REGS_RegCodeX86_eip, 0, 2}, +{REGS_RegCodeX86_eax, 1, 1}, +{REGS_RegCodeX86_ecx, 1, 1}, +{REGS_RegCodeX86_edx, 1, 1}, +{REGS_RegCodeX86_ebx, 1, 1}, +{REGS_RegCodeX86_eax, 0, 1}, +{REGS_RegCodeX86_ecx, 0, 1}, +{REGS_RegCodeX86_edx, 0, 1}, +{REGS_RegCodeX86_ebx, 0, 1}, +{REGS_RegCodeX86_ebp, 0, 1}, +{REGS_RegCodeX86_esp, 0, 1}, +{REGS_RegCodeX86_ymm0, 0, 16}, +{REGS_RegCodeX86_ymm1, 0, 16}, +{REGS_RegCodeX86_ymm2, 0, 16}, +{REGS_RegCodeX86_ymm3, 0, 16}, +{REGS_RegCodeX86_ymm4, 0, 16}, +{REGS_RegCodeX86_ymm5, 0, 16}, +{REGS_RegCodeX86_ymm6, 0, 16}, +{REGS_RegCodeX86_ymm7, 0, 16}, +{REGS_RegCodeX86_fpr0, 0, 8}, +{REGS_RegCodeX86_fpr1, 0, 8}, +{REGS_RegCodeX86_fpr2, 0, 8}, +{REGS_RegCodeX86_fpr3, 0, 8}, +{REGS_RegCodeX86_fpr4, 0, 8}, +{REGS_RegCodeX86_fpr5, 0, 8}, +{REGS_RegCodeX86_fpr6, 0, 8}, +{REGS_RegCodeX86_fpr7, 0, 8}, +}; + +C_LINKAGE_END + diff --git a/src/regs/generated/regs.meta.h b/src/regs/generated/regs.meta.h index f1661343..88eb256a 100644 --- a/src/regs/generated/regs.meta.h +++ b/src/regs/generated/regs.meta.h @@ -85,7 +85,7 @@ REGS_RegCodeX64_ymm12, REGS_RegCodeX64_ymm13, REGS_RegCodeX64_ymm14, REGS_RegCodeX64_ymm15, -REGS_RegCodeX64_COUNT +REGS_RegCodeX64_COUNT, } REGS_RegCodeX64; typedef enum REGS_AliasCodeX64 @@ -170,7 +170,7 @@ REGS_AliasCodeX64_mm4, REGS_AliasCodeX64_mm5, REGS_AliasCodeX64_mm6, REGS_AliasCodeX64_mm7, -REGS_AliasCodeX64_COUNT +REGS_AliasCodeX64_COUNT, } REGS_AliasCodeX64; typedef enum REGS_RegCodeX86 @@ -236,7 +236,7 @@ REGS_RegCodeX86_ymm4, REGS_RegCodeX86_ymm5, REGS_RegCodeX86_ymm6, REGS_RegCodeX86_ymm7, -REGS_RegCodeX86_COUNT +REGS_RegCodeX86_COUNT, } REGS_RegCodeX86; typedef enum REGS_AliasCodeX86 @@ -277,7 +277,7 @@ REGS_AliasCodeX86_mm4, REGS_AliasCodeX86_mm5, REGS_AliasCodeX86_mm6, REGS_AliasCodeX86_mm7, -REGS_AliasCodeX86_COUNT +REGS_AliasCodeX86_COUNT, } REGS_AliasCodeX86; typedef struct REGS_RegBlockX64 REGS_RegBlockX64; @@ -426,815 +426,19 @@ REGS_Reg256 ymm6; REGS_Reg256 ymm7; }; -REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[] = -{ -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -}; - -REGS_UsageKind regs_g_alias_code_x64_usage_kind_table[] = -{ -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -}; - -String8 regs_g_reg_code_x64_string_table[] = -{ -str8_lit_comp(""), -str8_lit_comp("rax"), -str8_lit_comp("rcx"), -str8_lit_comp("rdx"), -str8_lit_comp("rbx"), -str8_lit_comp("rsp"), -str8_lit_comp("rbp"), -str8_lit_comp("rsi"), -str8_lit_comp("rdi"), -str8_lit_comp("r8"), -str8_lit_comp("r9"), -str8_lit_comp("r10"), -str8_lit_comp("r11"), -str8_lit_comp("r12"), -str8_lit_comp("r13"), -str8_lit_comp("r14"), -str8_lit_comp("r15"), -str8_lit_comp("fsbase"), -str8_lit_comp("gsbase"), -str8_lit_comp("rip"), -str8_lit_comp("rflags"), -str8_lit_comp("dr0"), -str8_lit_comp("dr1"), -str8_lit_comp("dr2"), -str8_lit_comp("dr3"), -str8_lit_comp("dr4"), -str8_lit_comp("dr5"), -str8_lit_comp("dr6"), -str8_lit_comp("dr7"), -str8_lit_comp("fpr0"), -str8_lit_comp("fpr1"), -str8_lit_comp("fpr2"), -str8_lit_comp("fpr3"), -str8_lit_comp("fpr4"), -str8_lit_comp("fpr5"), -str8_lit_comp("fpr6"), -str8_lit_comp("fpr7"), -str8_lit_comp("st0"), -str8_lit_comp("st1"), -str8_lit_comp("st2"), -str8_lit_comp("st3"), -str8_lit_comp("st4"), -str8_lit_comp("st5"), -str8_lit_comp("st6"), -str8_lit_comp("st7"), -str8_lit_comp("fcw"), -str8_lit_comp("fsw"), -str8_lit_comp("ftw"), -str8_lit_comp("fop"), -str8_lit_comp("fcs"), -str8_lit_comp("fds"), -str8_lit_comp("fip"), -str8_lit_comp("fdp"), -str8_lit_comp("mxcsr"), -str8_lit_comp("mxcsr_mask"), -str8_lit_comp("ss"), -str8_lit_comp("cs"), -str8_lit_comp("ds"), -str8_lit_comp("es"), -str8_lit_comp("fs"), -str8_lit_comp("gs"), -str8_lit_comp("ymm0"), -str8_lit_comp("ymm1"), -str8_lit_comp("ymm2"), -str8_lit_comp("ymm3"), -str8_lit_comp("ymm4"), -str8_lit_comp("ymm5"), -str8_lit_comp("ymm6"), -str8_lit_comp("ymm7"), -str8_lit_comp("ymm8"), -str8_lit_comp("ymm9"), -str8_lit_comp("ymm10"), -str8_lit_comp("ymm11"), -str8_lit_comp("ymm12"), -str8_lit_comp("ymm13"), -str8_lit_comp("ymm14"), -str8_lit_comp("ymm15"), -}; - -String8 regs_g_alias_code_x64_string_table[] = -{ -str8_lit_comp(""), -str8_lit_comp("eax"), -str8_lit_comp("ecx"), -str8_lit_comp("edx"), -str8_lit_comp("ebx"), -str8_lit_comp("esp"), -str8_lit_comp("ebp"), -str8_lit_comp("esi"), -str8_lit_comp("edi"), -str8_lit_comp("r8d"), -str8_lit_comp("r9d"), -str8_lit_comp("r10d"), -str8_lit_comp("r11d"), -str8_lit_comp("r12d"), -str8_lit_comp("r13d"), -str8_lit_comp("r14d"), -str8_lit_comp("r15d"), -str8_lit_comp("eip"), -str8_lit_comp("eflags"), -str8_lit_comp("ax"), -str8_lit_comp("cx"), -str8_lit_comp("dx"), -str8_lit_comp("bx"), -str8_lit_comp("si"), -str8_lit_comp("di"), -str8_lit_comp("sp"), -str8_lit_comp("bp"), -str8_lit_comp("ip"), -str8_lit_comp("r8w"), -str8_lit_comp("r9w"), -str8_lit_comp("r10w"), -str8_lit_comp("r11w"), -str8_lit_comp("r12w"), -str8_lit_comp("r13w"), -str8_lit_comp("r14w"), -str8_lit_comp("r15w"), -str8_lit_comp("al"), -str8_lit_comp("cl"), -str8_lit_comp("dl"), -str8_lit_comp("bl"), -str8_lit_comp("sil"), -str8_lit_comp("dil"), -str8_lit_comp("bpl"), -str8_lit_comp("spl"), -str8_lit_comp("r8b"), -str8_lit_comp("r9b"), -str8_lit_comp("r10b"), -str8_lit_comp("r11b"), -str8_lit_comp("r12b"), -str8_lit_comp("r13b"), -str8_lit_comp("r14b"), -str8_lit_comp("r15b"), -str8_lit_comp("ah"), -str8_lit_comp("ch"), -str8_lit_comp("dh"), -str8_lit_comp("bh"), -str8_lit_comp("xmm0"), -str8_lit_comp("xmm1"), -str8_lit_comp("xmm2"), -str8_lit_comp("xmm3"), -str8_lit_comp("xmm4"), -str8_lit_comp("xmm5"), -str8_lit_comp("xmm6"), -str8_lit_comp("xmm7"), -str8_lit_comp("xmm8"), -str8_lit_comp("xmm9"), -str8_lit_comp("xmm10"), -str8_lit_comp("xmm11"), -str8_lit_comp("xmm12"), -str8_lit_comp("xmm13"), -str8_lit_comp("xmm14"), -str8_lit_comp("xmm15"), -str8_lit_comp("mm0"), -str8_lit_comp("mm1"), -str8_lit_comp("mm2"), -str8_lit_comp("mm3"), -str8_lit_comp("mm4"), -str8_lit_comp("mm5"), -str8_lit_comp("mm6"), -str8_lit_comp("mm7"), -}; - -REGS_Rng regs_g_reg_code_x64_rng_table[] = -{ -{0}, -{(U16)OffsetOf(REGS_RegBlockX64, rax), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, rcx), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, rdx), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, rbx), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, rsp), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, rbp), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, rsi), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, rdi), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r8), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r9), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r10), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r11), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r12), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r13), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r14), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, r15), 8}, -{(U16)OffsetOf(REGS_RegBlockX64, fsbase), 8}, -{(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, fpr0), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fpr1), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fpr2), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fpr3), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fpr4), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fpr5), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fpr6), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fpr7), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st0), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st1), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st2), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st3), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st4), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st5), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st6), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, st7), 10}, -{(U16)OffsetOf(REGS_RegBlockX64, fcw), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, fsw), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, ftw), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, fop), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, fcs), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, fds), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, fip), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, fdp), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, mxcsr), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, mxcsr_mask), 4}, -{(U16)OffsetOf(REGS_RegBlockX64, ss), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, cs), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, ds), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, es), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, fs), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, gs), 2}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm0), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm1), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm2), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm3), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm4), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm5), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm6), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm7), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm8), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm9), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm10), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm11), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm12), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm13), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm14), 32}, -{(U16)OffsetOf(REGS_RegBlockX64, ymm15), 32}, -}; - -REGS_Slice regs_g_alias_code_x64_slice_table[] = -{ -{0}, -{REGS_RegCodeX64_rax, 0, 4}, -{REGS_RegCodeX64_rcx, 0, 4}, -{REGS_RegCodeX64_rdx, 0, 4}, -{REGS_RegCodeX64_rbx, 0, 4}, -{REGS_RegCodeX64_rsp, 0, 4}, -{REGS_RegCodeX64_rbp, 0, 4}, -{REGS_RegCodeX64_rsi, 0, 4}, -{REGS_RegCodeX64_rdi, 0, 4}, -{REGS_RegCodeX64_r8, 0, 4}, -{REGS_RegCodeX64_r9, 0, 4}, -{REGS_RegCodeX64_r10, 0, 4}, -{REGS_RegCodeX64_r11, 0, 4}, -{REGS_RegCodeX64_r12, 0, 4}, -{REGS_RegCodeX64_r13, 0, 4}, -{REGS_RegCodeX64_r14, 0, 4}, -{REGS_RegCodeX64_r15, 0, 4}, -{REGS_RegCodeX64_rip, 0, 4}, -{REGS_RegCodeX64_rflags, 0, 4}, -{REGS_RegCodeX64_rax, 0, 2}, -{REGS_RegCodeX64_rcx, 0, 2}, -{REGS_RegCodeX64_rdx, 0, 2}, -{REGS_RegCodeX64_rbx, 0, 2}, -{REGS_RegCodeX64_rsi, 0, 2}, -{REGS_RegCodeX64_rdi, 0, 2}, -{REGS_RegCodeX64_rsp, 0, 2}, -{REGS_RegCodeX64_rbp, 0, 2}, -{REGS_RegCodeX64_rip, 0, 2}, -{REGS_RegCodeX64_r8, 0, 2}, -{REGS_RegCodeX64_r9, 0, 2}, -{REGS_RegCodeX64_r10, 0, 2}, -{REGS_RegCodeX64_r11, 0, 2}, -{REGS_RegCodeX64_r12, 0, 2}, -{REGS_RegCodeX64_r13, 0, 2}, -{REGS_RegCodeX64_r14, 0, 2}, -{REGS_RegCodeX64_r15, 0, 2}, -{REGS_RegCodeX64_rax, 0, 1}, -{REGS_RegCodeX64_rcx, 0, 1}, -{REGS_RegCodeX64_rdx, 0, 1}, -{REGS_RegCodeX64_rbx, 0, 1}, -{REGS_RegCodeX64_rsi, 0, 1}, -{REGS_RegCodeX64_rdi, 0, 1}, -{REGS_RegCodeX64_rbp, 0, 1}, -{REGS_RegCodeX64_rsp, 0, 1}, -{REGS_RegCodeX64_r8, 0, 1}, -{REGS_RegCodeX64_r9, 0, 1}, -{REGS_RegCodeX64_r10, 0, 1}, -{REGS_RegCodeX64_r11, 0, 1}, -{REGS_RegCodeX64_r12, 0, 1}, -{REGS_RegCodeX64_r13, 0, 1}, -{REGS_RegCodeX64_r14, 0, 1}, -{REGS_RegCodeX64_r15, 0, 1}, -{REGS_RegCodeX64_rax, 1, 1}, -{REGS_RegCodeX64_rcx, 1, 1}, -{REGS_RegCodeX64_rdx, 1, 1}, -{REGS_RegCodeX64_rbx, 1, 1}, -{REGS_RegCodeX64_ymm0, 0, 16}, -{REGS_RegCodeX64_ymm1, 0, 16}, -{REGS_RegCodeX64_ymm2, 0, 16}, -{REGS_RegCodeX64_ymm3, 0, 16}, -{REGS_RegCodeX64_ymm4, 0, 16}, -{REGS_RegCodeX64_ymm5, 0, 16}, -{REGS_RegCodeX64_ymm6, 0, 16}, -{REGS_RegCodeX64_ymm7, 0, 16}, -{REGS_RegCodeX64_ymm8, 0, 16}, -{REGS_RegCodeX64_ymm9, 0, 16}, -{REGS_RegCodeX64_ymm10, 0, 16}, -{REGS_RegCodeX64_ymm11, 0, 16}, -{REGS_RegCodeX64_ymm12, 0, 16}, -{REGS_RegCodeX64_ymm13, 0, 16}, -{REGS_RegCodeX64_ymm14, 0, 16}, -{REGS_RegCodeX64_ymm15, 0, 16}, -{REGS_RegCodeX64_fpr0, 0, 8}, -{REGS_RegCodeX64_fpr1, 0, 8}, -{REGS_RegCodeX64_fpr2, 0, 8}, -{REGS_RegCodeX64_fpr3, 0, 8}, -{REGS_RegCodeX64_fpr4, 0, 8}, -{REGS_RegCodeX64_fpr5, 0, 8}, -{REGS_RegCodeX64_fpr6, 0, 8}, -{REGS_RegCodeX64_fpr7, 0, 8}, -}; - -REGS_UsageKind regs_g_reg_code_x86_usage_kind_table[] = -{ -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -}; - -REGS_UsageKind regs_g_alias_code_x86_usage_kind_table[] = -{ -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -REGS_UsageKind_Normal, -}; - -String8 regs_g_reg_code_x86_string_table[] = -{ -str8_lit_comp(""), -str8_lit_comp("eax"), -str8_lit_comp("ecx"), -str8_lit_comp("edx"), -str8_lit_comp("ebx"), -str8_lit_comp("esp"), -str8_lit_comp("ebp"), -str8_lit_comp("esi"), -str8_lit_comp("edi"), -str8_lit_comp("fsbase"), -str8_lit_comp("gsbase"), -str8_lit_comp("eflags"), -str8_lit_comp("eip"), -str8_lit_comp("dr0"), -str8_lit_comp("dr1"), -str8_lit_comp("dr2"), -str8_lit_comp("dr3"), -str8_lit_comp("dr4"), -str8_lit_comp("dr5"), -str8_lit_comp("dr6"), -str8_lit_comp("dr7"), -str8_lit_comp("fpr0"), -str8_lit_comp("fpr1"), -str8_lit_comp("fpr2"), -str8_lit_comp("fpr3"), -str8_lit_comp("fpr4"), -str8_lit_comp("fpr5"), -str8_lit_comp("fpr6"), -str8_lit_comp("fpr7"), -str8_lit_comp("st0"), -str8_lit_comp("st1"), -str8_lit_comp("st2"), -str8_lit_comp("st3"), -str8_lit_comp("st4"), -str8_lit_comp("st5"), -str8_lit_comp("st6"), -str8_lit_comp("st7"), -str8_lit_comp("fcw"), -str8_lit_comp("fsw"), -str8_lit_comp("ftw"), -str8_lit_comp("fop"), -str8_lit_comp("fcs"), -str8_lit_comp("fds"), -str8_lit_comp("fip"), -str8_lit_comp("fdp"), -str8_lit_comp("mxcsr"), -str8_lit_comp("mxcsr_mask"), -str8_lit_comp("ss"), -str8_lit_comp("cs"), -str8_lit_comp("ds"), -str8_lit_comp("es"), -str8_lit_comp("fs"), -str8_lit_comp("gs"), -str8_lit_comp("ymm0"), -str8_lit_comp("ymm1"), -str8_lit_comp("ymm2"), -str8_lit_comp("ymm3"), -str8_lit_comp("ymm4"), -str8_lit_comp("ymm5"), -str8_lit_comp("ymm6"), -str8_lit_comp("ymm7"), -}; - -String8 regs_g_alias_code_x86_string_table[] = -{ -str8_lit_comp(""), -str8_lit_comp("ax"), -str8_lit_comp("cx"), -str8_lit_comp("bx"), -str8_lit_comp("dx"), -str8_lit_comp("sp"), -str8_lit_comp("bp"), -str8_lit_comp("si"), -str8_lit_comp("di"), -str8_lit_comp("ip"), -str8_lit_comp("ah"), -str8_lit_comp("ch"), -str8_lit_comp("dh"), -str8_lit_comp("bh"), -str8_lit_comp("al"), -str8_lit_comp("cl"), -str8_lit_comp("dl"), -str8_lit_comp("bl"), -str8_lit_comp("bpl"), -str8_lit_comp("spl"), -str8_lit_comp("xmm0"), -str8_lit_comp("xmm1"), -str8_lit_comp("xmm2"), -str8_lit_comp("xmm3"), -str8_lit_comp("xmm4"), -str8_lit_comp("xmm5"), -str8_lit_comp("xmm6"), -str8_lit_comp("xmm7"), -str8_lit_comp("mm0"), -str8_lit_comp("mm1"), -str8_lit_comp("mm2"), -str8_lit_comp("mm3"), -str8_lit_comp("mm4"), -str8_lit_comp("mm5"), -str8_lit_comp("mm6"), -str8_lit_comp("mm7"), -}; - -REGS_Rng regs_g_reg_code_x86_rng_table[] = -{ -{0}, -{(U16)OffsetOf(REGS_RegBlockX86, eax), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, ecx), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, edx), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, ebx), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, esp), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, ebp), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, esi), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, edi), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, fsbase), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, gsbase), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, eflags), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, eip), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr0), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr1), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr2), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr3), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr4), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr5), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr6), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, dr7), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr0), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr1), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr2), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr3), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr4), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr5), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr6), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fpr7), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st0), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st1), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st2), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st3), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st4), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st5), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st6), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, st7), 10}, -{(U16)OffsetOf(REGS_RegBlockX86, fcw), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, fsw), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, ftw), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, fop), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, fcs), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, fds), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, fip), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, fdp), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, mxcsr), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, mxcsr_mask), 4}, -{(U16)OffsetOf(REGS_RegBlockX86, ss), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, cs), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, ds), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, es), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, fs), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, gs), 2}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm0), 32}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm1), 32}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm2), 32}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm3), 32}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm4), 32}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm5), 32}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm6), 32}, -{(U16)OffsetOf(REGS_RegBlockX86, ymm7), 32}, -}; - -REGS_Slice regs_g_alias_code_x86_slice_table[] = -{ -{0}, -{REGS_RegCodeX86_eax, 0, 2}, -{REGS_RegCodeX86_ecx, 0, 2}, -{REGS_RegCodeX86_ebx, 0, 2}, -{REGS_RegCodeX86_edx, 0, 2}, -{REGS_RegCodeX86_esp, 0, 2}, -{REGS_RegCodeX86_ebp, 0, 2}, -{REGS_RegCodeX86_esi, 0, 2}, -{REGS_RegCodeX86_edi, 0, 2}, -{REGS_RegCodeX86_eip, 0, 2}, -{REGS_RegCodeX86_eax, 1, 1}, -{REGS_RegCodeX86_ecx, 1, 1}, -{REGS_RegCodeX86_edx, 1, 1}, -{REGS_RegCodeX86_ebx, 1, 1}, -{REGS_RegCodeX86_eax, 0, 1}, -{REGS_RegCodeX86_ecx, 0, 1}, -{REGS_RegCodeX86_edx, 0, 1}, -{REGS_RegCodeX86_ebx, 0, 1}, -{REGS_RegCodeX86_ebp, 0, 1}, -{REGS_RegCodeX86_esp, 0, 1}, -{REGS_RegCodeX86_ymm0, 0, 16}, -{REGS_RegCodeX86_ymm1, 0, 16}, -{REGS_RegCodeX86_ymm2, 0, 16}, -{REGS_RegCodeX86_ymm3, 0, 16}, -{REGS_RegCodeX86_ymm4, 0, 16}, -{REGS_RegCodeX86_ymm5, 0, 16}, -{REGS_RegCodeX86_ymm6, 0, 16}, -{REGS_RegCodeX86_ymm7, 0, 16}, -{REGS_RegCodeX86_fpr0, 0, 8}, -{REGS_RegCodeX86_fpr1, 0, 8}, -{REGS_RegCodeX86_fpr2, 0, 8}, -{REGS_RegCodeX86_fpr3, 0, 8}, -{REGS_RegCodeX86_fpr4, 0, 8}, -{REGS_RegCodeX86_fpr5, 0, 8}, -{REGS_RegCodeX86_fpr6, 0, 8}, -{REGS_RegCodeX86_fpr7, 0, 8}, -}; - +C_LINKAGE_BEGIN +extern REGS_UsageKind regs_g_reg_code_x64_usage_kind_table[77]; +extern REGS_UsageKind regs_g_alias_code_x64_usage_kind_table[80]; +extern String8 regs_g_reg_code_x64_string_table[77]; +extern String8 regs_g_alias_code_x64_string_table[80]; +extern REGS_Rng regs_g_reg_code_x64_rng_table[77]; +extern REGS_Slice regs_g_alias_code_x64_slice_table[80]; +extern REGS_UsageKind regs_g_reg_code_x86_usage_kind_table[61]; +extern REGS_UsageKind regs_g_alias_code_x86_usage_kind_table[36]; +extern String8 regs_g_reg_code_x86_string_table[61]; +extern String8 regs_g_alias_code_x86_string_table[36]; +extern REGS_Rng regs_g_reg_code_x86_rng_table[61]; +extern REGS_Slice regs_g_alias_code_x86_slice_table[36]; +C_LINKAGE_END #endif // REGS_META_H diff --git a/src/regs/generated/regs_raddbg.meta.c b/src/regs/generated/regs_raddbg.meta.c deleted file mode 100644 index 8b322f55..00000000 --- a/src/regs/generated/regs_raddbg.meta.c +++ /dev/null @@ -1,322 +0,0 @@ -// generated -#ifndef _REGS_RADDBG_META_C -#define _REGS_RADDBG_META_C - -internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code) -{ -RADDBG_RegisterCode result = 0; -switch(arch) -{ -case Architecture_x64: -{ -switch(code) -{ -default:{}break; -case REGS_RegCodeX64_rax:{result = RADDBG_RegisterCode_X64_rax;}break; -case REGS_RegCodeX64_rcx:{result = RADDBG_RegisterCode_X64_rcx;}break; -case REGS_RegCodeX64_rdx:{result = RADDBG_RegisterCode_X64_rdx;}break; -case REGS_RegCodeX64_rbx:{result = RADDBG_RegisterCode_X64_rbx;}break; -case REGS_RegCodeX64_rsp:{result = RADDBG_RegisterCode_X64_rsp;}break; -case REGS_RegCodeX64_rbp:{result = RADDBG_RegisterCode_X64_rbp;}break; -case REGS_RegCodeX64_rsi:{result = RADDBG_RegisterCode_X64_rsi;}break; -case REGS_RegCodeX64_rdi:{result = RADDBG_RegisterCode_X64_rdi;}break; -case REGS_RegCodeX64_r8:{result = RADDBG_RegisterCode_X64_r8;}break; -case REGS_RegCodeX64_r9:{result = RADDBG_RegisterCode_X64_r9;}break; -case REGS_RegCodeX64_r10:{result = RADDBG_RegisterCode_X64_r10;}break; -case REGS_RegCodeX64_r11:{result = RADDBG_RegisterCode_X64_r11;}break; -case REGS_RegCodeX64_r12:{result = RADDBG_RegisterCode_X64_r12;}break; -case REGS_RegCodeX64_r13:{result = RADDBG_RegisterCode_X64_r13;}break; -case REGS_RegCodeX64_r14:{result = RADDBG_RegisterCode_X64_r14;}break; -case REGS_RegCodeX64_r15:{result = RADDBG_RegisterCode_X64_r15;}break; -case REGS_RegCodeX64_fsbase:{result = RADDBG_RegisterCode_X64_fsbase;}break; -case REGS_RegCodeX64_gsbase:{result = RADDBG_RegisterCode_X64_gsbase;}break; -case REGS_RegCodeX64_rip:{result = RADDBG_RegisterCode_X64_rip;}break; -case REGS_RegCodeX64_rflags:{result = RADDBG_RegisterCode_X64_rflags;}break; -case REGS_RegCodeX64_dr0:{result = RADDBG_RegisterCode_X64_dr0;}break; -case REGS_RegCodeX64_dr1:{result = RADDBG_RegisterCode_X64_dr1;}break; -case REGS_RegCodeX64_dr2:{result = RADDBG_RegisterCode_X64_dr2;}break; -case REGS_RegCodeX64_dr3:{result = RADDBG_RegisterCode_X64_dr3;}break; -case REGS_RegCodeX64_dr4:{result = RADDBG_RegisterCode_X64_dr4;}break; -case REGS_RegCodeX64_dr5:{result = RADDBG_RegisterCode_X64_dr5;}break; -case REGS_RegCodeX64_dr6:{result = RADDBG_RegisterCode_X64_dr6;}break; -case REGS_RegCodeX64_dr7:{result = RADDBG_RegisterCode_X64_dr7;}break; -case REGS_RegCodeX64_fpr0:{result = RADDBG_RegisterCode_X64_fpr0;}break; -case REGS_RegCodeX64_fpr1:{result = RADDBG_RegisterCode_X64_fpr1;}break; -case REGS_RegCodeX64_fpr2:{result = RADDBG_RegisterCode_X64_fpr2;}break; -case REGS_RegCodeX64_fpr3:{result = RADDBG_RegisterCode_X64_fpr3;}break; -case REGS_RegCodeX64_fpr4:{result = RADDBG_RegisterCode_X64_fpr4;}break; -case REGS_RegCodeX64_fpr5:{result = RADDBG_RegisterCode_X64_fpr5;}break; -case REGS_RegCodeX64_fpr6:{result = RADDBG_RegisterCode_X64_fpr6;}break; -case REGS_RegCodeX64_fpr7:{result = RADDBG_RegisterCode_X64_fpr7;}break; -case REGS_RegCodeX64_st0:{result = RADDBG_RegisterCode_X64_st0;}break; -case REGS_RegCodeX64_st1:{result = RADDBG_RegisterCode_X64_st1;}break; -case REGS_RegCodeX64_st2:{result = RADDBG_RegisterCode_X64_st2;}break; -case REGS_RegCodeX64_st3:{result = RADDBG_RegisterCode_X64_st3;}break; -case REGS_RegCodeX64_st4:{result = RADDBG_RegisterCode_X64_st4;}break; -case REGS_RegCodeX64_st5:{result = RADDBG_RegisterCode_X64_st5;}break; -case REGS_RegCodeX64_st6:{result = RADDBG_RegisterCode_X64_st6;}break; -case REGS_RegCodeX64_st7:{result = RADDBG_RegisterCode_X64_st7;}break; -case REGS_RegCodeX64_fcw:{result = RADDBG_RegisterCode_X64_fcw;}break; -case REGS_RegCodeX64_fsw:{result = RADDBG_RegisterCode_X64_fsw;}break; -case REGS_RegCodeX64_ftw:{result = RADDBG_RegisterCode_X64_ftw;}break; -case REGS_RegCodeX64_fop:{result = RADDBG_RegisterCode_X64_fop;}break; -case REGS_RegCodeX64_fcs:{result = RADDBG_RegisterCode_X64_fcs;}break; -case REGS_RegCodeX64_fds:{result = RADDBG_RegisterCode_X64_fds;}break; -case REGS_RegCodeX64_fip:{result = RADDBG_RegisterCode_X64_fip;}break; -case REGS_RegCodeX64_fdp:{result = RADDBG_RegisterCode_X64_fdp;}break; -case REGS_RegCodeX64_mxcsr:{result = RADDBG_RegisterCode_X64_mxcsr;}break; -case REGS_RegCodeX64_mxcsr_mask:{result = RADDBG_RegisterCode_X64_mxcsr_mask;}break; -case REGS_RegCodeX64_ss:{result = RADDBG_RegisterCode_X64_ss;}break; -case REGS_RegCodeX64_cs:{result = RADDBG_RegisterCode_X64_cs;}break; -case REGS_RegCodeX64_ds:{result = RADDBG_RegisterCode_X64_ds;}break; -case REGS_RegCodeX64_es:{result = RADDBG_RegisterCode_X64_es;}break; -case REGS_RegCodeX64_fs:{result = RADDBG_RegisterCode_X64_fs;}break; -case REGS_RegCodeX64_gs:{result = RADDBG_RegisterCode_X64_gs;}break; -case REGS_RegCodeX64_ymm0:{result = RADDBG_RegisterCode_X64_ymm0;}break; -case REGS_RegCodeX64_ymm1:{result = RADDBG_RegisterCode_X64_ymm1;}break; -case REGS_RegCodeX64_ymm2:{result = RADDBG_RegisterCode_X64_ymm2;}break; -case REGS_RegCodeX64_ymm3:{result = RADDBG_RegisterCode_X64_ymm3;}break; -case REGS_RegCodeX64_ymm4:{result = RADDBG_RegisterCode_X64_ymm4;}break; -case REGS_RegCodeX64_ymm5:{result = RADDBG_RegisterCode_X64_ymm5;}break; -case REGS_RegCodeX64_ymm6:{result = RADDBG_RegisterCode_X64_ymm6;}break; -case REGS_RegCodeX64_ymm7:{result = RADDBG_RegisterCode_X64_ymm7;}break; -case REGS_RegCodeX64_ymm8:{result = RADDBG_RegisterCode_X64_ymm8;}break; -case REGS_RegCodeX64_ymm9:{result = RADDBG_RegisterCode_X64_ymm9;}break; -case REGS_RegCodeX64_ymm10:{result = RADDBG_RegisterCode_X64_ymm10;}break; -case REGS_RegCodeX64_ymm11:{result = RADDBG_RegisterCode_X64_ymm11;}break; -case REGS_RegCodeX64_ymm12:{result = RADDBG_RegisterCode_X64_ymm12;}break; -case REGS_RegCodeX64_ymm13:{result = RADDBG_RegisterCode_X64_ymm13;}break; -case REGS_RegCodeX64_ymm14:{result = RADDBG_RegisterCode_X64_ymm14;}break; -case REGS_RegCodeX64_ymm15:{result = RADDBG_RegisterCode_X64_ymm15;}break; -} -}break; -case Architecture_x86: -{ -switch(code) -{ -default:{}break; -case REGS_RegCodeX86_eax:{result = RADDBG_RegisterCode_X86_eax;}break; -case REGS_RegCodeX86_ecx:{result = RADDBG_RegisterCode_X86_ecx;}break; -case REGS_RegCodeX86_edx:{result = RADDBG_RegisterCode_X86_edx;}break; -case REGS_RegCodeX86_ebx:{result = RADDBG_RegisterCode_X86_ebx;}break; -case REGS_RegCodeX86_esp:{result = RADDBG_RegisterCode_X86_esp;}break; -case REGS_RegCodeX86_ebp:{result = RADDBG_RegisterCode_X86_ebp;}break; -case REGS_RegCodeX86_esi:{result = RADDBG_RegisterCode_X86_esi;}break; -case REGS_RegCodeX86_edi:{result = RADDBG_RegisterCode_X86_edi;}break; -case REGS_RegCodeX86_fsbase:{result = RADDBG_RegisterCode_X86_fsbase;}break; -case REGS_RegCodeX86_gsbase:{result = RADDBG_RegisterCode_X86_gsbase;}break; -case REGS_RegCodeX86_eflags:{result = RADDBG_RegisterCode_X86_eflags;}break; -case REGS_RegCodeX86_eip:{result = RADDBG_RegisterCode_X86_eip;}break; -case REGS_RegCodeX86_dr0:{result = RADDBG_RegisterCode_X86_dr0;}break; -case REGS_RegCodeX86_dr1:{result = RADDBG_RegisterCode_X86_dr1;}break; -case REGS_RegCodeX86_dr2:{result = RADDBG_RegisterCode_X86_dr2;}break; -case REGS_RegCodeX86_dr3:{result = RADDBG_RegisterCode_X86_dr3;}break; -case REGS_RegCodeX86_dr4:{result = RADDBG_RegisterCode_X86_dr4;}break; -case REGS_RegCodeX86_dr5:{result = RADDBG_RegisterCode_X86_dr5;}break; -case REGS_RegCodeX86_dr6:{result = RADDBG_RegisterCode_X86_dr6;}break; -case REGS_RegCodeX86_dr7:{result = RADDBG_RegisterCode_X86_dr7;}break; -case REGS_RegCodeX86_fpr0:{result = RADDBG_RegisterCode_X86_fpr0;}break; -case REGS_RegCodeX86_fpr1:{result = RADDBG_RegisterCode_X86_fpr1;}break; -case REGS_RegCodeX86_fpr2:{result = RADDBG_RegisterCode_X86_fpr2;}break; -case REGS_RegCodeX86_fpr3:{result = RADDBG_RegisterCode_X86_fpr3;}break; -case REGS_RegCodeX86_fpr4:{result = RADDBG_RegisterCode_X86_fpr4;}break; -case REGS_RegCodeX86_fpr5:{result = RADDBG_RegisterCode_X86_fpr5;}break; -case REGS_RegCodeX86_fpr6:{result = RADDBG_RegisterCode_X86_fpr6;}break; -case REGS_RegCodeX86_fpr7:{result = RADDBG_RegisterCode_X86_fpr7;}break; -case REGS_RegCodeX86_st0:{result = RADDBG_RegisterCode_X86_st0;}break; -case REGS_RegCodeX86_st1:{result = RADDBG_RegisterCode_X86_st1;}break; -case REGS_RegCodeX86_st2:{result = RADDBG_RegisterCode_X86_st2;}break; -case REGS_RegCodeX86_st3:{result = RADDBG_RegisterCode_X86_st3;}break; -case REGS_RegCodeX86_st4:{result = RADDBG_RegisterCode_X86_st4;}break; -case REGS_RegCodeX86_st5:{result = RADDBG_RegisterCode_X86_st5;}break; -case REGS_RegCodeX86_st6:{result = RADDBG_RegisterCode_X86_st6;}break; -case REGS_RegCodeX86_st7:{result = RADDBG_RegisterCode_X86_st7;}break; -case REGS_RegCodeX86_fcw:{result = RADDBG_RegisterCode_X86_fcw;}break; -case REGS_RegCodeX86_fsw:{result = RADDBG_RegisterCode_X86_fsw;}break; -case REGS_RegCodeX86_ftw:{result = RADDBG_RegisterCode_X86_ftw;}break; -case REGS_RegCodeX86_fop:{result = RADDBG_RegisterCode_X86_fop;}break; -case REGS_RegCodeX86_fcs:{result = RADDBG_RegisterCode_X86_fcs;}break; -case REGS_RegCodeX86_fds:{result = RADDBG_RegisterCode_X86_fds;}break; -case REGS_RegCodeX86_fip:{result = RADDBG_RegisterCode_X86_fip;}break; -case REGS_RegCodeX86_fdp:{result = RADDBG_RegisterCode_X86_fdp;}break; -case REGS_RegCodeX86_mxcsr:{result = RADDBG_RegisterCode_X86_mxcsr;}break; -case REGS_RegCodeX86_mxcsr_mask:{result = RADDBG_RegisterCode_X86_mxcsr_mask;}break; -case REGS_RegCodeX86_ss:{result = RADDBG_RegisterCode_X86_ss;}break; -case REGS_RegCodeX86_cs:{result = RADDBG_RegisterCode_X86_cs;}break; -case REGS_RegCodeX86_ds:{result = RADDBG_RegisterCode_X86_ds;}break; -case REGS_RegCodeX86_es:{result = RADDBG_RegisterCode_X86_es;}break; -case REGS_RegCodeX86_fs:{result = RADDBG_RegisterCode_X86_fs;}break; -case REGS_RegCodeX86_gs:{result = RADDBG_RegisterCode_X86_gs;}break; -case REGS_RegCodeX86_ymm0:{result = RADDBG_RegisterCode_X86_ymm0;}break; -case REGS_RegCodeX86_ymm1:{result = RADDBG_RegisterCode_X86_ymm1;}break; -case REGS_RegCodeX86_ymm2:{result = RADDBG_RegisterCode_X86_ymm2;}break; -case REGS_RegCodeX86_ymm3:{result = RADDBG_RegisterCode_X86_ymm3;}break; -case REGS_RegCodeX86_ymm4:{result = RADDBG_RegisterCode_X86_ymm4;}break; -case REGS_RegCodeX86_ymm5:{result = RADDBG_RegisterCode_X86_ymm5;}break; -case REGS_RegCodeX86_ymm6:{result = RADDBG_RegisterCode_X86_ymm6;}break; -case REGS_RegCodeX86_ymm7:{result = RADDBG_RegisterCode_X86_ymm7;}break; -} -}break; -} -return result; -} -internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode code) -{ -REGS_RegCode result = 0; -switch(arch) -{ -case Architecture_x64: -{ -switch(code) -{ -default:{}break; -case RADDBG_RegisterCode_X64_rax:{result = REGS_RegCodeX64_rax;}break; -case RADDBG_RegisterCode_X64_rcx:{result = REGS_RegCodeX64_rcx;}break; -case RADDBG_RegisterCode_X64_rdx:{result = REGS_RegCodeX64_rdx;}break; -case RADDBG_RegisterCode_X64_rbx:{result = REGS_RegCodeX64_rbx;}break; -case RADDBG_RegisterCode_X64_rsp:{result = REGS_RegCodeX64_rsp;}break; -case RADDBG_RegisterCode_X64_rbp:{result = REGS_RegCodeX64_rbp;}break; -case RADDBG_RegisterCode_X64_rsi:{result = REGS_RegCodeX64_rsi;}break; -case RADDBG_RegisterCode_X64_rdi:{result = REGS_RegCodeX64_rdi;}break; -case RADDBG_RegisterCode_X64_r8:{result = REGS_RegCodeX64_r8;}break; -case RADDBG_RegisterCode_X64_r9:{result = REGS_RegCodeX64_r9;}break; -case RADDBG_RegisterCode_X64_r10:{result = REGS_RegCodeX64_r10;}break; -case RADDBG_RegisterCode_X64_r11:{result = REGS_RegCodeX64_r11;}break; -case RADDBG_RegisterCode_X64_r12:{result = REGS_RegCodeX64_r12;}break; -case RADDBG_RegisterCode_X64_r13:{result = REGS_RegCodeX64_r13;}break; -case RADDBG_RegisterCode_X64_r14:{result = REGS_RegCodeX64_r14;}break; -case RADDBG_RegisterCode_X64_r15:{result = REGS_RegCodeX64_r15;}break; -case RADDBG_RegisterCode_X64_fsbase:{result = REGS_RegCodeX64_fsbase;}break; -case RADDBG_RegisterCode_X64_gsbase:{result = REGS_RegCodeX64_gsbase;}break; -case RADDBG_RegisterCode_X64_rip:{result = REGS_RegCodeX64_rip;}break; -case RADDBG_RegisterCode_X64_rflags:{result = REGS_RegCodeX64_rflags;}break; -case RADDBG_RegisterCode_X64_dr0:{result = REGS_RegCodeX64_dr0;}break; -case RADDBG_RegisterCode_X64_dr1:{result = REGS_RegCodeX64_dr1;}break; -case RADDBG_RegisterCode_X64_dr2:{result = REGS_RegCodeX64_dr2;}break; -case RADDBG_RegisterCode_X64_dr3:{result = REGS_RegCodeX64_dr3;}break; -case RADDBG_RegisterCode_X64_dr4:{result = REGS_RegCodeX64_dr4;}break; -case RADDBG_RegisterCode_X64_dr5:{result = REGS_RegCodeX64_dr5;}break; -case RADDBG_RegisterCode_X64_dr6:{result = REGS_RegCodeX64_dr6;}break; -case RADDBG_RegisterCode_X64_dr7:{result = REGS_RegCodeX64_dr7;}break; -case RADDBG_RegisterCode_X64_fpr0:{result = REGS_RegCodeX64_fpr0;}break; -case RADDBG_RegisterCode_X64_fpr1:{result = REGS_RegCodeX64_fpr1;}break; -case RADDBG_RegisterCode_X64_fpr2:{result = REGS_RegCodeX64_fpr2;}break; -case RADDBG_RegisterCode_X64_fpr3:{result = REGS_RegCodeX64_fpr3;}break; -case RADDBG_RegisterCode_X64_fpr4:{result = REGS_RegCodeX64_fpr4;}break; -case RADDBG_RegisterCode_X64_fpr5:{result = REGS_RegCodeX64_fpr5;}break; -case RADDBG_RegisterCode_X64_fpr6:{result = REGS_RegCodeX64_fpr6;}break; -case RADDBG_RegisterCode_X64_fpr7:{result = REGS_RegCodeX64_fpr7;}break; -case RADDBG_RegisterCode_X64_st0:{result = REGS_RegCodeX64_st0;}break; -case RADDBG_RegisterCode_X64_st1:{result = REGS_RegCodeX64_st1;}break; -case RADDBG_RegisterCode_X64_st2:{result = REGS_RegCodeX64_st2;}break; -case RADDBG_RegisterCode_X64_st3:{result = REGS_RegCodeX64_st3;}break; -case RADDBG_RegisterCode_X64_st4:{result = REGS_RegCodeX64_st4;}break; -case RADDBG_RegisterCode_X64_st5:{result = REGS_RegCodeX64_st5;}break; -case RADDBG_RegisterCode_X64_st6:{result = REGS_RegCodeX64_st6;}break; -case RADDBG_RegisterCode_X64_st7:{result = REGS_RegCodeX64_st7;}break; -case RADDBG_RegisterCode_X64_fcw:{result = REGS_RegCodeX64_fcw;}break; -case RADDBG_RegisterCode_X64_fsw:{result = REGS_RegCodeX64_fsw;}break; -case RADDBG_RegisterCode_X64_ftw:{result = REGS_RegCodeX64_ftw;}break; -case RADDBG_RegisterCode_X64_fop:{result = REGS_RegCodeX64_fop;}break; -case RADDBG_RegisterCode_X64_fcs:{result = REGS_RegCodeX64_fcs;}break; -case RADDBG_RegisterCode_X64_fds:{result = REGS_RegCodeX64_fds;}break; -case RADDBG_RegisterCode_X64_fip:{result = REGS_RegCodeX64_fip;}break; -case RADDBG_RegisterCode_X64_fdp:{result = REGS_RegCodeX64_fdp;}break; -case RADDBG_RegisterCode_X64_mxcsr:{result = REGS_RegCodeX64_mxcsr;}break; -case RADDBG_RegisterCode_X64_mxcsr_mask:{result = REGS_RegCodeX64_mxcsr_mask;}break; -case RADDBG_RegisterCode_X64_ss:{result = REGS_RegCodeX64_ss;}break; -case RADDBG_RegisterCode_X64_cs:{result = REGS_RegCodeX64_cs;}break; -case RADDBG_RegisterCode_X64_ds:{result = REGS_RegCodeX64_ds;}break; -case RADDBG_RegisterCode_X64_es:{result = REGS_RegCodeX64_es;}break; -case RADDBG_RegisterCode_X64_fs:{result = REGS_RegCodeX64_fs;}break; -case RADDBG_RegisterCode_X64_gs:{result = REGS_RegCodeX64_gs;}break; -case RADDBG_RegisterCode_X64_ymm0:{result = REGS_RegCodeX64_ymm0;}break; -case RADDBG_RegisterCode_X64_ymm1:{result = REGS_RegCodeX64_ymm1;}break; -case RADDBG_RegisterCode_X64_ymm2:{result = REGS_RegCodeX64_ymm2;}break; -case RADDBG_RegisterCode_X64_ymm3:{result = REGS_RegCodeX64_ymm3;}break; -case RADDBG_RegisterCode_X64_ymm4:{result = REGS_RegCodeX64_ymm4;}break; -case RADDBG_RegisterCode_X64_ymm5:{result = REGS_RegCodeX64_ymm5;}break; -case RADDBG_RegisterCode_X64_ymm6:{result = REGS_RegCodeX64_ymm6;}break; -case RADDBG_RegisterCode_X64_ymm7:{result = REGS_RegCodeX64_ymm7;}break; -case RADDBG_RegisterCode_X64_ymm8:{result = REGS_RegCodeX64_ymm8;}break; -case RADDBG_RegisterCode_X64_ymm9:{result = REGS_RegCodeX64_ymm9;}break; -case RADDBG_RegisterCode_X64_ymm10:{result = REGS_RegCodeX64_ymm10;}break; -case RADDBG_RegisterCode_X64_ymm11:{result = REGS_RegCodeX64_ymm11;}break; -case RADDBG_RegisterCode_X64_ymm12:{result = REGS_RegCodeX64_ymm12;}break; -case RADDBG_RegisterCode_X64_ymm13:{result = REGS_RegCodeX64_ymm13;}break; -case RADDBG_RegisterCode_X64_ymm14:{result = REGS_RegCodeX64_ymm14;}break; -case RADDBG_RegisterCode_X64_ymm15:{result = REGS_RegCodeX64_ymm15;}break; -} -}break; -case Architecture_x86: -{ -switch(code) -{ -default:{}break; -case RADDBG_RegisterCode_X86_eax:{result = REGS_RegCodeX86_eax;}break; -case RADDBG_RegisterCode_X86_ecx:{result = REGS_RegCodeX86_ecx;}break; -case RADDBG_RegisterCode_X86_edx:{result = REGS_RegCodeX86_edx;}break; -case RADDBG_RegisterCode_X86_ebx:{result = REGS_RegCodeX86_ebx;}break; -case RADDBG_RegisterCode_X86_esp:{result = REGS_RegCodeX86_esp;}break; -case RADDBG_RegisterCode_X86_ebp:{result = REGS_RegCodeX86_ebp;}break; -case RADDBG_RegisterCode_X86_esi:{result = REGS_RegCodeX86_esi;}break; -case RADDBG_RegisterCode_X86_edi:{result = REGS_RegCodeX86_edi;}break; -case RADDBG_RegisterCode_X86_fsbase:{result = REGS_RegCodeX86_fsbase;}break; -case RADDBG_RegisterCode_X86_gsbase:{result = REGS_RegCodeX86_gsbase;}break; -case RADDBG_RegisterCode_X86_eflags:{result = REGS_RegCodeX86_eflags;}break; -case RADDBG_RegisterCode_X86_eip:{result = REGS_RegCodeX86_eip;}break; -case RADDBG_RegisterCode_X86_dr0:{result = REGS_RegCodeX86_dr0;}break; -case RADDBG_RegisterCode_X86_dr1:{result = REGS_RegCodeX86_dr1;}break; -case RADDBG_RegisterCode_X86_dr2:{result = REGS_RegCodeX86_dr2;}break; -case RADDBG_RegisterCode_X86_dr3:{result = REGS_RegCodeX86_dr3;}break; -case RADDBG_RegisterCode_X86_dr4:{result = REGS_RegCodeX86_dr4;}break; -case RADDBG_RegisterCode_X86_dr5:{result = REGS_RegCodeX86_dr5;}break; -case RADDBG_RegisterCode_X86_dr6:{result = REGS_RegCodeX86_dr6;}break; -case RADDBG_RegisterCode_X86_dr7:{result = REGS_RegCodeX86_dr7;}break; -case RADDBG_RegisterCode_X86_fpr0:{result = REGS_RegCodeX86_fpr0;}break; -case RADDBG_RegisterCode_X86_fpr1:{result = REGS_RegCodeX86_fpr1;}break; -case RADDBG_RegisterCode_X86_fpr2:{result = REGS_RegCodeX86_fpr2;}break; -case RADDBG_RegisterCode_X86_fpr3:{result = REGS_RegCodeX86_fpr3;}break; -case RADDBG_RegisterCode_X86_fpr4:{result = REGS_RegCodeX86_fpr4;}break; -case RADDBG_RegisterCode_X86_fpr5:{result = REGS_RegCodeX86_fpr5;}break; -case RADDBG_RegisterCode_X86_fpr6:{result = REGS_RegCodeX86_fpr6;}break; -case RADDBG_RegisterCode_X86_fpr7:{result = REGS_RegCodeX86_fpr7;}break; -case RADDBG_RegisterCode_X86_st0:{result = REGS_RegCodeX86_st0;}break; -case RADDBG_RegisterCode_X86_st1:{result = REGS_RegCodeX86_st1;}break; -case RADDBG_RegisterCode_X86_st2:{result = REGS_RegCodeX86_st2;}break; -case RADDBG_RegisterCode_X86_st3:{result = REGS_RegCodeX86_st3;}break; -case RADDBG_RegisterCode_X86_st4:{result = REGS_RegCodeX86_st4;}break; -case RADDBG_RegisterCode_X86_st5:{result = REGS_RegCodeX86_st5;}break; -case RADDBG_RegisterCode_X86_st6:{result = REGS_RegCodeX86_st6;}break; -case RADDBG_RegisterCode_X86_st7:{result = REGS_RegCodeX86_st7;}break; -case RADDBG_RegisterCode_X86_fcw:{result = REGS_RegCodeX86_fcw;}break; -case RADDBG_RegisterCode_X86_fsw:{result = REGS_RegCodeX86_fsw;}break; -case RADDBG_RegisterCode_X86_ftw:{result = REGS_RegCodeX86_ftw;}break; -case RADDBG_RegisterCode_X86_fop:{result = REGS_RegCodeX86_fop;}break; -case RADDBG_RegisterCode_X86_fcs:{result = REGS_RegCodeX86_fcs;}break; -case RADDBG_RegisterCode_X86_fds:{result = REGS_RegCodeX86_fds;}break; -case RADDBG_RegisterCode_X86_fip:{result = REGS_RegCodeX86_fip;}break; -case RADDBG_RegisterCode_X86_fdp:{result = REGS_RegCodeX86_fdp;}break; -case RADDBG_RegisterCode_X86_mxcsr:{result = REGS_RegCodeX86_mxcsr;}break; -case RADDBG_RegisterCode_X86_mxcsr_mask:{result = REGS_RegCodeX86_mxcsr_mask;}break; -case RADDBG_RegisterCode_X86_ss:{result = REGS_RegCodeX86_ss;}break; -case RADDBG_RegisterCode_X86_cs:{result = REGS_RegCodeX86_cs;}break; -case RADDBG_RegisterCode_X86_ds:{result = REGS_RegCodeX86_ds;}break; -case RADDBG_RegisterCode_X86_es:{result = REGS_RegCodeX86_es;}break; -case RADDBG_RegisterCode_X86_fs:{result = REGS_RegCodeX86_fs;}break; -case RADDBG_RegisterCode_X86_gs:{result = REGS_RegCodeX86_gs;}break; -case RADDBG_RegisterCode_X86_ymm0:{result = REGS_RegCodeX86_ymm0;}break; -case RADDBG_RegisterCode_X86_ymm1:{result = REGS_RegCodeX86_ymm1;}break; -case RADDBG_RegisterCode_X86_ymm2:{result = REGS_RegCodeX86_ymm2;}break; -case RADDBG_RegisterCode_X86_ymm3:{result = REGS_RegCodeX86_ymm3;}break; -case RADDBG_RegisterCode_X86_ymm4:{result = REGS_RegCodeX86_ymm4;}break; -case RADDBG_RegisterCode_X86_ymm5:{result = REGS_RegCodeX86_ymm5;}break; -case RADDBG_RegisterCode_X86_ymm6:{result = REGS_RegCodeX86_ymm6;}break; -case RADDBG_RegisterCode_X86_ymm7:{result = REGS_RegCodeX86_ymm7;}break; -} -}break; -} -return result; -} - -#endif diff --git a/src/regs/raddbg/generated/regs_raddbg.meta.c b/src/regs/raddbg/generated/regs_raddbg.meta.c deleted file mode 100644 index c52e08b2..00000000 --- a/src/regs/raddbg/generated/regs_raddbg.meta.c +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//- GENERATED CODE - -internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code) -{ -RADDBG_RegisterCode result = 0; -switch(arch) -{ -default:{}break; -case Architecture_x64: -{ -switch(code) -{ -default:{}break; -case REGS_RegCodeX64_rax:{result = RADDBG_RegisterCode_X64_rax;}break; -case REGS_RegCodeX64_rcx:{result = RADDBG_RegisterCode_X64_rcx;}break; -case REGS_RegCodeX64_rdx:{result = RADDBG_RegisterCode_X64_rdx;}break; -case REGS_RegCodeX64_rbx:{result = RADDBG_RegisterCode_X64_rbx;}break; -case REGS_RegCodeX64_rsp:{result = RADDBG_RegisterCode_X64_rsp;}break; -case REGS_RegCodeX64_rbp:{result = RADDBG_RegisterCode_X64_rbp;}break; -case REGS_RegCodeX64_rsi:{result = RADDBG_RegisterCode_X64_rsi;}break; -case REGS_RegCodeX64_rdi:{result = RADDBG_RegisterCode_X64_rdi;}break; -case REGS_RegCodeX64_r8:{result = RADDBG_RegisterCode_X64_r8;}break; -case REGS_RegCodeX64_r9:{result = RADDBG_RegisterCode_X64_r9;}break; -case REGS_RegCodeX64_r10:{result = RADDBG_RegisterCode_X64_r10;}break; -case REGS_RegCodeX64_r11:{result = RADDBG_RegisterCode_X64_r11;}break; -case REGS_RegCodeX64_r12:{result = RADDBG_RegisterCode_X64_r12;}break; -case REGS_RegCodeX64_r13:{result = RADDBG_RegisterCode_X64_r13;}break; -case REGS_RegCodeX64_r14:{result = RADDBG_RegisterCode_X64_r14;}break; -case REGS_RegCodeX64_r15:{result = RADDBG_RegisterCode_X64_r15;}break; -case REGS_RegCodeX64_fsbase:{result = RADDBG_RegisterCode_X64_fsbase;}break; -case REGS_RegCodeX64_gsbase:{result = RADDBG_RegisterCode_X64_gsbase;}break; -case REGS_RegCodeX64_rip:{result = RADDBG_RegisterCode_X64_rip;}break; -case REGS_RegCodeX64_rflags:{result = RADDBG_RegisterCode_X64_rflags;}break; -case REGS_RegCodeX64_dr0:{result = RADDBG_RegisterCode_X64_dr0;}break; -case REGS_RegCodeX64_dr1:{result = RADDBG_RegisterCode_X64_dr1;}break; -case REGS_RegCodeX64_dr2:{result = RADDBG_RegisterCode_X64_dr2;}break; -case REGS_RegCodeX64_dr3:{result = RADDBG_RegisterCode_X64_dr3;}break; -case REGS_RegCodeX64_dr4:{result = RADDBG_RegisterCode_X64_dr4;}break; -case REGS_RegCodeX64_dr5:{result = RADDBG_RegisterCode_X64_dr5;}break; -case REGS_RegCodeX64_dr6:{result = RADDBG_RegisterCode_X64_dr6;}break; -case REGS_RegCodeX64_dr7:{result = RADDBG_RegisterCode_X64_dr7;}break; -case REGS_RegCodeX64_fpr0:{result = RADDBG_RegisterCode_X64_fpr0;}break; -case REGS_RegCodeX64_fpr1:{result = RADDBG_RegisterCode_X64_fpr1;}break; -case REGS_RegCodeX64_fpr2:{result = RADDBG_RegisterCode_X64_fpr2;}break; -case REGS_RegCodeX64_fpr3:{result = RADDBG_RegisterCode_X64_fpr3;}break; -case REGS_RegCodeX64_fpr4:{result = RADDBG_RegisterCode_X64_fpr4;}break; -case REGS_RegCodeX64_fpr5:{result = RADDBG_RegisterCode_X64_fpr5;}break; -case REGS_RegCodeX64_fpr6:{result = RADDBG_RegisterCode_X64_fpr6;}break; -case REGS_RegCodeX64_fpr7:{result = RADDBG_RegisterCode_X64_fpr7;}break; -case REGS_RegCodeX64_st0:{result = RADDBG_RegisterCode_X64_st0;}break; -case REGS_RegCodeX64_st1:{result = RADDBG_RegisterCode_X64_st1;}break; -case REGS_RegCodeX64_st2:{result = RADDBG_RegisterCode_X64_st2;}break; -case REGS_RegCodeX64_st3:{result = RADDBG_RegisterCode_X64_st3;}break; -case REGS_RegCodeX64_st4:{result = RADDBG_RegisterCode_X64_st4;}break; -case REGS_RegCodeX64_st5:{result = RADDBG_RegisterCode_X64_st5;}break; -case REGS_RegCodeX64_st6:{result = RADDBG_RegisterCode_X64_st6;}break; -case REGS_RegCodeX64_st7:{result = RADDBG_RegisterCode_X64_st7;}break; -case REGS_RegCodeX64_fcw:{result = RADDBG_RegisterCode_X64_fcw;}break; -case REGS_RegCodeX64_fsw:{result = RADDBG_RegisterCode_X64_fsw;}break; -case REGS_RegCodeX64_ftw:{result = RADDBG_RegisterCode_X64_ftw;}break; -case REGS_RegCodeX64_fop:{result = RADDBG_RegisterCode_X64_fop;}break; -case REGS_RegCodeX64_fcs:{result = RADDBG_RegisterCode_X64_fcs;}break; -case REGS_RegCodeX64_fds:{result = RADDBG_RegisterCode_X64_fds;}break; -case REGS_RegCodeX64_fip:{result = RADDBG_RegisterCode_X64_fip;}break; -case REGS_RegCodeX64_fdp:{result = RADDBG_RegisterCode_X64_fdp;}break; -case REGS_RegCodeX64_mxcsr:{result = RADDBG_RegisterCode_X64_mxcsr;}break; -case REGS_RegCodeX64_mxcsr_mask:{result = RADDBG_RegisterCode_X64_mxcsr_mask;}break; -case REGS_RegCodeX64_ss:{result = RADDBG_RegisterCode_X64_ss;}break; -case REGS_RegCodeX64_cs:{result = RADDBG_RegisterCode_X64_cs;}break; -case REGS_RegCodeX64_ds:{result = RADDBG_RegisterCode_X64_ds;}break; -case REGS_RegCodeX64_es:{result = RADDBG_RegisterCode_X64_es;}break; -case REGS_RegCodeX64_fs:{result = RADDBG_RegisterCode_X64_fs;}break; -case REGS_RegCodeX64_gs:{result = RADDBG_RegisterCode_X64_gs;}break; -case REGS_RegCodeX64_ymm0:{result = RADDBG_RegisterCode_X64_ymm0;}break; -case REGS_RegCodeX64_ymm1:{result = RADDBG_RegisterCode_X64_ymm1;}break; -case REGS_RegCodeX64_ymm2:{result = RADDBG_RegisterCode_X64_ymm2;}break; -case REGS_RegCodeX64_ymm3:{result = RADDBG_RegisterCode_X64_ymm3;}break; -case REGS_RegCodeX64_ymm4:{result = RADDBG_RegisterCode_X64_ymm4;}break; -case REGS_RegCodeX64_ymm5:{result = RADDBG_RegisterCode_X64_ymm5;}break; -case REGS_RegCodeX64_ymm6:{result = RADDBG_RegisterCode_X64_ymm6;}break; -case REGS_RegCodeX64_ymm7:{result = RADDBG_RegisterCode_X64_ymm7;}break; -case REGS_RegCodeX64_ymm8:{result = RADDBG_RegisterCode_X64_ymm8;}break; -case REGS_RegCodeX64_ymm9:{result = RADDBG_RegisterCode_X64_ymm9;}break; -case REGS_RegCodeX64_ymm10:{result = RADDBG_RegisterCode_X64_ymm10;}break; -case REGS_RegCodeX64_ymm11:{result = RADDBG_RegisterCode_X64_ymm11;}break; -case REGS_RegCodeX64_ymm12:{result = RADDBG_RegisterCode_X64_ymm12;}break; -case REGS_RegCodeX64_ymm13:{result = RADDBG_RegisterCode_X64_ymm13;}break; -case REGS_RegCodeX64_ymm14:{result = RADDBG_RegisterCode_X64_ymm14;}break; -case REGS_RegCodeX64_ymm15:{result = RADDBG_RegisterCode_X64_ymm15;}break; -} -}break; -case Architecture_x86: -{ -switch(code) -{ -default:{}break; -case REGS_RegCodeX86_eax:{result = RADDBG_RegisterCode_X86_eax;}break; -case REGS_RegCodeX86_ecx:{result = RADDBG_RegisterCode_X86_ecx;}break; -case REGS_RegCodeX86_edx:{result = RADDBG_RegisterCode_X86_edx;}break; -case REGS_RegCodeX86_ebx:{result = RADDBG_RegisterCode_X86_ebx;}break; -case REGS_RegCodeX86_esp:{result = RADDBG_RegisterCode_X86_esp;}break; -case REGS_RegCodeX86_ebp:{result = RADDBG_RegisterCode_X86_ebp;}break; -case REGS_RegCodeX86_esi:{result = RADDBG_RegisterCode_X86_esi;}break; -case REGS_RegCodeX86_edi:{result = RADDBG_RegisterCode_X86_edi;}break; -case REGS_RegCodeX86_fsbase:{result = RADDBG_RegisterCode_X86_fsbase;}break; -case REGS_RegCodeX86_gsbase:{result = RADDBG_RegisterCode_X86_gsbase;}break; -case REGS_RegCodeX86_eflags:{result = RADDBG_RegisterCode_X86_eflags;}break; -case REGS_RegCodeX86_eip:{result = RADDBG_RegisterCode_X86_eip;}break; -case REGS_RegCodeX86_dr0:{result = RADDBG_RegisterCode_X86_dr0;}break; -case REGS_RegCodeX86_dr1:{result = RADDBG_RegisterCode_X86_dr1;}break; -case REGS_RegCodeX86_dr2:{result = RADDBG_RegisterCode_X86_dr2;}break; -case REGS_RegCodeX86_dr3:{result = RADDBG_RegisterCode_X86_dr3;}break; -case REGS_RegCodeX86_dr4:{result = RADDBG_RegisterCode_X86_dr4;}break; -case REGS_RegCodeX86_dr5:{result = RADDBG_RegisterCode_X86_dr5;}break; -case REGS_RegCodeX86_dr6:{result = RADDBG_RegisterCode_X86_dr6;}break; -case REGS_RegCodeX86_dr7:{result = RADDBG_RegisterCode_X86_dr7;}break; -case REGS_RegCodeX86_fpr0:{result = RADDBG_RegisterCode_X86_fpr0;}break; -case REGS_RegCodeX86_fpr1:{result = RADDBG_RegisterCode_X86_fpr1;}break; -case REGS_RegCodeX86_fpr2:{result = RADDBG_RegisterCode_X86_fpr2;}break; -case REGS_RegCodeX86_fpr3:{result = RADDBG_RegisterCode_X86_fpr3;}break; -case REGS_RegCodeX86_fpr4:{result = RADDBG_RegisterCode_X86_fpr4;}break; -case REGS_RegCodeX86_fpr5:{result = RADDBG_RegisterCode_X86_fpr5;}break; -case REGS_RegCodeX86_fpr6:{result = RADDBG_RegisterCode_X86_fpr6;}break; -case REGS_RegCodeX86_fpr7:{result = RADDBG_RegisterCode_X86_fpr7;}break; -case REGS_RegCodeX86_st0:{result = RADDBG_RegisterCode_X86_st0;}break; -case REGS_RegCodeX86_st1:{result = RADDBG_RegisterCode_X86_st1;}break; -case REGS_RegCodeX86_st2:{result = RADDBG_RegisterCode_X86_st2;}break; -case REGS_RegCodeX86_st3:{result = RADDBG_RegisterCode_X86_st3;}break; -case REGS_RegCodeX86_st4:{result = RADDBG_RegisterCode_X86_st4;}break; -case REGS_RegCodeX86_st5:{result = RADDBG_RegisterCode_X86_st5;}break; -case REGS_RegCodeX86_st6:{result = RADDBG_RegisterCode_X86_st6;}break; -case REGS_RegCodeX86_st7:{result = RADDBG_RegisterCode_X86_st7;}break; -case REGS_RegCodeX86_fcw:{result = RADDBG_RegisterCode_X86_fcw;}break; -case REGS_RegCodeX86_fsw:{result = RADDBG_RegisterCode_X86_fsw;}break; -case REGS_RegCodeX86_ftw:{result = RADDBG_RegisterCode_X86_ftw;}break; -case REGS_RegCodeX86_fop:{result = RADDBG_RegisterCode_X86_fop;}break; -case REGS_RegCodeX86_fcs:{result = RADDBG_RegisterCode_X86_fcs;}break; -case REGS_RegCodeX86_fds:{result = RADDBG_RegisterCode_X86_fds;}break; -case REGS_RegCodeX86_fip:{result = RADDBG_RegisterCode_X86_fip;}break; -case REGS_RegCodeX86_fdp:{result = RADDBG_RegisterCode_X86_fdp;}break; -case REGS_RegCodeX86_mxcsr:{result = RADDBG_RegisterCode_X86_mxcsr;}break; -case REGS_RegCodeX86_mxcsr_mask:{result = RADDBG_RegisterCode_X86_mxcsr_mask;}break; -case REGS_RegCodeX86_ss:{result = RADDBG_RegisterCode_X86_ss;}break; -case REGS_RegCodeX86_cs:{result = RADDBG_RegisterCode_X86_cs;}break; -case REGS_RegCodeX86_ds:{result = RADDBG_RegisterCode_X86_ds;}break; -case REGS_RegCodeX86_es:{result = RADDBG_RegisterCode_X86_es;}break; -case REGS_RegCodeX86_fs:{result = RADDBG_RegisterCode_X86_fs;}break; -case REGS_RegCodeX86_gs:{result = RADDBG_RegisterCode_X86_gs;}break; -case REGS_RegCodeX86_ymm0:{result = RADDBG_RegisterCode_X86_ymm0;}break; -case REGS_RegCodeX86_ymm1:{result = RADDBG_RegisterCode_X86_ymm1;}break; -case REGS_RegCodeX86_ymm2:{result = RADDBG_RegisterCode_X86_ymm2;}break; -case REGS_RegCodeX86_ymm3:{result = RADDBG_RegisterCode_X86_ymm3;}break; -case REGS_RegCodeX86_ymm4:{result = RADDBG_RegisterCode_X86_ymm4;}break; -case REGS_RegCodeX86_ymm5:{result = RADDBG_RegisterCode_X86_ymm5;}break; -case REGS_RegCodeX86_ymm6:{result = RADDBG_RegisterCode_X86_ymm6;}break; -case REGS_RegCodeX86_ymm7:{result = RADDBG_RegisterCode_X86_ymm7;}break; -} -}break; -} -return result; -} -internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode code) -{ -REGS_RegCode result = 0; -switch(arch) -{ -default:{}break; -case Architecture_x64: -{ -switch(code) -{ -default:{}break; -case RADDBG_RegisterCode_X64_rax:{result = REGS_RegCodeX64_rax;}break; -case RADDBG_RegisterCode_X64_rcx:{result = REGS_RegCodeX64_rcx;}break; -case RADDBG_RegisterCode_X64_rdx:{result = REGS_RegCodeX64_rdx;}break; -case RADDBG_RegisterCode_X64_rbx:{result = REGS_RegCodeX64_rbx;}break; -case RADDBG_RegisterCode_X64_rsp:{result = REGS_RegCodeX64_rsp;}break; -case RADDBG_RegisterCode_X64_rbp:{result = REGS_RegCodeX64_rbp;}break; -case RADDBG_RegisterCode_X64_rsi:{result = REGS_RegCodeX64_rsi;}break; -case RADDBG_RegisterCode_X64_rdi:{result = REGS_RegCodeX64_rdi;}break; -case RADDBG_RegisterCode_X64_r8:{result = REGS_RegCodeX64_r8;}break; -case RADDBG_RegisterCode_X64_r9:{result = REGS_RegCodeX64_r9;}break; -case RADDBG_RegisterCode_X64_r10:{result = REGS_RegCodeX64_r10;}break; -case RADDBG_RegisterCode_X64_r11:{result = REGS_RegCodeX64_r11;}break; -case RADDBG_RegisterCode_X64_r12:{result = REGS_RegCodeX64_r12;}break; -case RADDBG_RegisterCode_X64_r13:{result = REGS_RegCodeX64_r13;}break; -case RADDBG_RegisterCode_X64_r14:{result = REGS_RegCodeX64_r14;}break; -case RADDBG_RegisterCode_X64_r15:{result = REGS_RegCodeX64_r15;}break; -case RADDBG_RegisterCode_X64_fsbase:{result = REGS_RegCodeX64_fsbase;}break; -case RADDBG_RegisterCode_X64_gsbase:{result = REGS_RegCodeX64_gsbase;}break; -case RADDBG_RegisterCode_X64_rip:{result = REGS_RegCodeX64_rip;}break; -case RADDBG_RegisterCode_X64_rflags:{result = REGS_RegCodeX64_rflags;}break; -case RADDBG_RegisterCode_X64_dr0:{result = REGS_RegCodeX64_dr0;}break; -case RADDBG_RegisterCode_X64_dr1:{result = REGS_RegCodeX64_dr1;}break; -case RADDBG_RegisterCode_X64_dr2:{result = REGS_RegCodeX64_dr2;}break; -case RADDBG_RegisterCode_X64_dr3:{result = REGS_RegCodeX64_dr3;}break; -case RADDBG_RegisterCode_X64_dr4:{result = REGS_RegCodeX64_dr4;}break; -case RADDBG_RegisterCode_X64_dr5:{result = REGS_RegCodeX64_dr5;}break; -case RADDBG_RegisterCode_X64_dr6:{result = REGS_RegCodeX64_dr6;}break; -case RADDBG_RegisterCode_X64_dr7:{result = REGS_RegCodeX64_dr7;}break; -case RADDBG_RegisterCode_X64_fpr0:{result = REGS_RegCodeX64_fpr0;}break; -case RADDBG_RegisterCode_X64_fpr1:{result = REGS_RegCodeX64_fpr1;}break; -case RADDBG_RegisterCode_X64_fpr2:{result = REGS_RegCodeX64_fpr2;}break; -case RADDBG_RegisterCode_X64_fpr3:{result = REGS_RegCodeX64_fpr3;}break; -case RADDBG_RegisterCode_X64_fpr4:{result = REGS_RegCodeX64_fpr4;}break; -case RADDBG_RegisterCode_X64_fpr5:{result = REGS_RegCodeX64_fpr5;}break; -case RADDBG_RegisterCode_X64_fpr6:{result = REGS_RegCodeX64_fpr6;}break; -case RADDBG_RegisterCode_X64_fpr7:{result = REGS_RegCodeX64_fpr7;}break; -case RADDBG_RegisterCode_X64_st0:{result = REGS_RegCodeX64_st0;}break; -case RADDBG_RegisterCode_X64_st1:{result = REGS_RegCodeX64_st1;}break; -case RADDBG_RegisterCode_X64_st2:{result = REGS_RegCodeX64_st2;}break; -case RADDBG_RegisterCode_X64_st3:{result = REGS_RegCodeX64_st3;}break; -case RADDBG_RegisterCode_X64_st4:{result = REGS_RegCodeX64_st4;}break; -case RADDBG_RegisterCode_X64_st5:{result = REGS_RegCodeX64_st5;}break; -case RADDBG_RegisterCode_X64_st6:{result = REGS_RegCodeX64_st6;}break; -case RADDBG_RegisterCode_X64_st7:{result = REGS_RegCodeX64_st7;}break; -case RADDBG_RegisterCode_X64_fcw:{result = REGS_RegCodeX64_fcw;}break; -case RADDBG_RegisterCode_X64_fsw:{result = REGS_RegCodeX64_fsw;}break; -case RADDBG_RegisterCode_X64_ftw:{result = REGS_RegCodeX64_ftw;}break; -case RADDBG_RegisterCode_X64_fop:{result = REGS_RegCodeX64_fop;}break; -case RADDBG_RegisterCode_X64_fcs:{result = REGS_RegCodeX64_fcs;}break; -case RADDBG_RegisterCode_X64_fds:{result = REGS_RegCodeX64_fds;}break; -case RADDBG_RegisterCode_X64_fip:{result = REGS_RegCodeX64_fip;}break; -case RADDBG_RegisterCode_X64_fdp:{result = REGS_RegCodeX64_fdp;}break; -case RADDBG_RegisterCode_X64_mxcsr:{result = REGS_RegCodeX64_mxcsr;}break; -case RADDBG_RegisterCode_X64_mxcsr_mask:{result = REGS_RegCodeX64_mxcsr_mask;}break; -case RADDBG_RegisterCode_X64_ss:{result = REGS_RegCodeX64_ss;}break; -case RADDBG_RegisterCode_X64_cs:{result = REGS_RegCodeX64_cs;}break; -case RADDBG_RegisterCode_X64_ds:{result = REGS_RegCodeX64_ds;}break; -case RADDBG_RegisterCode_X64_es:{result = REGS_RegCodeX64_es;}break; -case RADDBG_RegisterCode_X64_fs:{result = REGS_RegCodeX64_fs;}break; -case RADDBG_RegisterCode_X64_gs:{result = REGS_RegCodeX64_gs;}break; -case RADDBG_RegisterCode_X64_ymm0:{result = REGS_RegCodeX64_ymm0;}break; -case RADDBG_RegisterCode_X64_ymm1:{result = REGS_RegCodeX64_ymm1;}break; -case RADDBG_RegisterCode_X64_ymm2:{result = REGS_RegCodeX64_ymm2;}break; -case RADDBG_RegisterCode_X64_ymm3:{result = REGS_RegCodeX64_ymm3;}break; -case RADDBG_RegisterCode_X64_ymm4:{result = REGS_RegCodeX64_ymm4;}break; -case RADDBG_RegisterCode_X64_ymm5:{result = REGS_RegCodeX64_ymm5;}break; -case RADDBG_RegisterCode_X64_ymm6:{result = REGS_RegCodeX64_ymm6;}break; -case RADDBG_RegisterCode_X64_ymm7:{result = REGS_RegCodeX64_ymm7;}break; -case RADDBG_RegisterCode_X64_ymm8:{result = REGS_RegCodeX64_ymm8;}break; -case RADDBG_RegisterCode_X64_ymm9:{result = REGS_RegCodeX64_ymm9;}break; -case RADDBG_RegisterCode_X64_ymm10:{result = REGS_RegCodeX64_ymm10;}break; -case RADDBG_RegisterCode_X64_ymm11:{result = REGS_RegCodeX64_ymm11;}break; -case RADDBG_RegisterCode_X64_ymm12:{result = REGS_RegCodeX64_ymm12;}break; -case RADDBG_RegisterCode_X64_ymm13:{result = REGS_RegCodeX64_ymm13;}break; -case RADDBG_RegisterCode_X64_ymm14:{result = REGS_RegCodeX64_ymm14;}break; -case RADDBG_RegisterCode_X64_ymm15:{result = REGS_RegCodeX64_ymm15;}break; -} -}break; -case Architecture_x86: -{ -switch(code) -{ -default:{}break; -case RADDBG_RegisterCode_X86_eax:{result = REGS_RegCodeX86_eax;}break; -case RADDBG_RegisterCode_X86_ecx:{result = REGS_RegCodeX86_ecx;}break; -case RADDBG_RegisterCode_X86_edx:{result = REGS_RegCodeX86_edx;}break; -case RADDBG_RegisterCode_X86_ebx:{result = REGS_RegCodeX86_ebx;}break; -case RADDBG_RegisterCode_X86_esp:{result = REGS_RegCodeX86_esp;}break; -case RADDBG_RegisterCode_X86_ebp:{result = REGS_RegCodeX86_ebp;}break; -case RADDBG_RegisterCode_X86_esi:{result = REGS_RegCodeX86_esi;}break; -case RADDBG_RegisterCode_X86_edi:{result = REGS_RegCodeX86_edi;}break; -case RADDBG_RegisterCode_X86_fsbase:{result = REGS_RegCodeX86_fsbase;}break; -case RADDBG_RegisterCode_X86_gsbase:{result = REGS_RegCodeX86_gsbase;}break; -case RADDBG_RegisterCode_X86_eflags:{result = REGS_RegCodeX86_eflags;}break; -case RADDBG_RegisterCode_X86_eip:{result = REGS_RegCodeX86_eip;}break; -case RADDBG_RegisterCode_X86_dr0:{result = REGS_RegCodeX86_dr0;}break; -case RADDBG_RegisterCode_X86_dr1:{result = REGS_RegCodeX86_dr1;}break; -case RADDBG_RegisterCode_X86_dr2:{result = REGS_RegCodeX86_dr2;}break; -case RADDBG_RegisterCode_X86_dr3:{result = REGS_RegCodeX86_dr3;}break; -case RADDBG_RegisterCode_X86_dr4:{result = REGS_RegCodeX86_dr4;}break; -case RADDBG_RegisterCode_X86_dr5:{result = REGS_RegCodeX86_dr5;}break; -case RADDBG_RegisterCode_X86_dr6:{result = REGS_RegCodeX86_dr6;}break; -case RADDBG_RegisterCode_X86_dr7:{result = REGS_RegCodeX86_dr7;}break; -case RADDBG_RegisterCode_X86_fpr0:{result = REGS_RegCodeX86_fpr0;}break; -case RADDBG_RegisterCode_X86_fpr1:{result = REGS_RegCodeX86_fpr1;}break; -case RADDBG_RegisterCode_X86_fpr2:{result = REGS_RegCodeX86_fpr2;}break; -case RADDBG_RegisterCode_X86_fpr3:{result = REGS_RegCodeX86_fpr3;}break; -case RADDBG_RegisterCode_X86_fpr4:{result = REGS_RegCodeX86_fpr4;}break; -case RADDBG_RegisterCode_X86_fpr5:{result = REGS_RegCodeX86_fpr5;}break; -case RADDBG_RegisterCode_X86_fpr6:{result = REGS_RegCodeX86_fpr6;}break; -case RADDBG_RegisterCode_X86_fpr7:{result = REGS_RegCodeX86_fpr7;}break; -case RADDBG_RegisterCode_X86_st0:{result = REGS_RegCodeX86_st0;}break; -case RADDBG_RegisterCode_X86_st1:{result = REGS_RegCodeX86_st1;}break; -case RADDBG_RegisterCode_X86_st2:{result = REGS_RegCodeX86_st2;}break; -case RADDBG_RegisterCode_X86_st3:{result = REGS_RegCodeX86_st3;}break; -case RADDBG_RegisterCode_X86_st4:{result = REGS_RegCodeX86_st4;}break; -case RADDBG_RegisterCode_X86_st5:{result = REGS_RegCodeX86_st5;}break; -case RADDBG_RegisterCode_X86_st6:{result = REGS_RegCodeX86_st6;}break; -case RADDBG_RegisterCode_X86_st7:{result = REGS_RegCodeX86_st7;}break; -case RADDBG_RegisterCode_X86_fcw:{result = REGS_RegCodeX86_fcw;}break; -case RADDBG_RegisterCode_X86_fsw:{result = REGS_RegCodeX86_fsw;}break; -case RADDBG_RegisterCode_X86_ftw:{result = REGS_RegCodeX86_ftw;}break; -case RADDBG_RegisterCode_X86_fop:{result = REGS_RegCodeX86_fop;}break; -case RADDBG_RegisterCode_X86_fcs:{result = REGS_RegCodeX86_fcs;}break; -case RADDBG_RegisterCode_X86_fds:{result = REGS_RegCodeX86_fds;}break; -case RADDBG_RegisterCode_X86_fip:{result = REGS_RegCodeX86_fip;}break; -case RADDBG_RegisterCode_X86_fdp:{result = REGS_RegCodeX86_fdp;}break; -case RADDBG_RegisterCode_X86_mxcsr:{result = REGS_RegCodeX86_mxcsr;}break; -case RADDBG_RegisterCode_X86_mxcsr_mask:{result = REGS_RegCodeX86_mxcsr_mask;}break; -case RADDBG_RegisterCode_X86_ss:{result = REGS_RegCodeX86_ss;}break; -case RADDBG_RegisterCode_X86_cs:{result = REGS_RegCodeX86_cs;}break; -case RADDBG_RegisterCode_X86_ds:{result = REGS_RegCodeX86_ds;}break; -case RADDBG_RegisterCode_X86_es:{result = REGS_RegCodeX86_es;}break; -case RADDBG_RegisterCode_X86_fs:{result = REGS_RegCodeX86_fs;}break; -case RADDBG_RegisterCode_X86_gs:{result = REGS_RegCodeX86_gs;}break; -case RADDBG_RegisterCode_X86_ymm0:{result = REGS_RegCodeX86_ymm0;}break; -case RADDBG_RegisterCode_X86_ymm1:{result = REGS_RegCodeX86_ymm1;}break; -case RADDBG_RegisterCode_X86_ymm2:{result = REGS_RegCodeX86_ymm2;}break; -case RADDBG_RegisterCode_X86_ymm3:{result = REGS_RegCodeX86_ymm3;}break; -case RADDBG_RegisterCode_X86_ymm4:{result = REGS_RegCodeX86_ymm4;}break; -case RADDBG_RegisterCode_X86_ymm5:{result = REGS_RegCodeX86_ymm5;}break; -case RADDBG_RegisterCode_X86_ymm6:{result = REGS_RegCodeX86_ymm6;}break; -case RADDBG_RegisterCode_X86_ymm7:{result = REGS_RegCodeX86_ymm7;}break; -} -}break; -} -return result; -} diff --git a/src/regs/raddbg/regs_raddbg.h b/src/regs/raddbg/regs_raddbg.h deleted file mode 100644 index 77f9a25d..00000000 --- a/src/regs/raddbg/regs_raddbg.h +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef REGS_RADDBG_H -#define REGS_RADDBG_H - -internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code); -internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode reg); - -#endif //REGS_RADDBG_H diff --git a/src/regs/raddbgi/generated/regs_raddbgi.meta.c b/src/regs/raddbgi/generated/regs_raddbgi.meta.c new file mode 100644 index 00000000..763da2aa --- /dev/null +++ b/src/regs/raddbgi/generated/regs_raddbgi.meta.c @@ -0,0 +1,326 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//- GENERATED CODE + +internal RDI_RegisterCode regs_rdi_code_from_arch_reg_code(Architecture arch, REGS_RegCode code) +{ +RDI_RegisterCode result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64: +{ +switch(code) +{ +default:{}break; +case REGS_RegCodeX64_rax:{result = RDI_RegisterCode_X64_rax;}break; +case REGS_RegCodeX64_rcx:{result = RDI_RegisterCode_X64_rcx;}break; +case REGS_RegCodeX64_rdx:{result = RDI_RegisterCode_X64_rdx;}break; +case REGS_RegCodeX64_rbx:{result = RDI_RegisterCode_X64_rbx;}break; +case REGS_RegCodeX64_rsp:{result = RDI_RegisterCode_X64_rsp;}break; +case REGS_RegCodeX64_rbp:{result = RDI_RegisterCode_X64_rbp;}break; +case REGS_RegCodeX64_rsi:{result = RDI_RegisterCode_X64_rsi;}break; +case REGS_RegCodeX64_rdi:{result = RDI_RegisterCode_X64_rdi;}break; +case REGS_RegCodeX64_r8:{result = RDI_RegisterCode_X64_r8;}break; +case REGS_RegCodeX64_r9:{result = RDI_RegisterCode_X64_r9;}break; +case REGS_RegCodeX64_r10:{result = RDI_RegisterCode_X64_r10;}break; +case REGS_RegCodeX64_r11:{result = RDI_RegisterCode_X64_r11;}break; +case REGS_RegCodeX64_r12:{result = RDI_RegisterCode_X64_r12;}break; +case REGS_RegCodeX64_r13:{result = RDI_RegisterCode_X64_r13;}break; +case REGS_RegCodeX64_r14:{result = RDI_RegisterCode_X64_r14;}break; +case REGS_RegCodeX64_r15:{result = RDI_RegisterCode_X64_r15;}break; +case REGS_RegCodeX64_fsbase:{result = RDI_RegisterCode_X64_fsbase;}break; +case REGS_RegCodeX64_gsbase:{result = RDI_RegisterCode_X64_gsbase;}break; +case REGS_RegCodeX64_rip:{result = RDI_RegisterCode_X64_rip;}break; +case REGS_RegCodeX64_rflags:{result = RDI_RegisterCode_X64_rflags;}break; +case REGS_RegCodeX64_dr0:{result = RDI_RegisterCode_X64_dr0;}break; +case REGS_RegCodeX64_dr1:{result = RDI_RegisterCode_X64_dr1;}break; +case REGS_RegCodeX64_dr2:{result = RDI_RegisterCode_X64_dr2;}break; +case REGS_RegCodeX64_dr3:{result = RDI_RegisterCode_X64_dr3;}break; +case REGS_RegCodeX64_dr4:{result = RDI_RegisterCode_X64_dr4;}break; +case REGS_RegCodeX64_dr5:{result = RDI_RegisterCode_X64_dr5;}break; +case REGS_RegCodeX64_dr6:{result = RDI_RegisterCode_X64_dr6;}break; +case REGS_RegCodeX64_dr7:{result = RDI_RegisterCode_X64_dr7;}break; +case REGS_RegCodeX64_fpr0:{result = RDI_RegisterCode_X64_fpr0;}break; +case REGS_RegCodeX64_fpr1:{result = RDI_RegisterCode_X64_fpr1;}break; +case REGS_RegCodeX64_fpr2:{result = RDI_RegisterCode_X64_fpr2;}break; +case REGS_RegCodeX64_fpr3:{result = RDI_RegisterCode_X64_fpr3;}break; +case REGS_RegCodeX64_fpr4:{result = RDI_RegisterCode_X64_fpr4;}break; +case REGS_RegCodeX64_fpr5:{result = RDI_RegisterCode_X64_fpr5;}break; +case REGS_RegCodeX64_fpr6:{result = RDI_RegisterCode_X64_fpr6;}break; +case REGS_RegCodeX64_fpr7:{result = RDI_RegisterCode_X64_fpr7;}break; +case REGS_RegCodeX64_st0:{result = RDI_RegisterCode_X64_st0;}break; +case REGS_RegCodeX64_st1:{result = RDI_RegisterCode_X64_st1;}break; +case REGS_RegCodeX64_st2:{result = RDI_RegisterCode_X64_st2;}break; +case REGS_RegCodeX64_st3:{result = RDI_RegisterCode_X64_st3;}break; +case REGS_RegCodeX64_st4:{result = RDI_RegisterCode_X64_st4;}break; +case REGS_RegCodeX64_st5:{result = RDI_RegisterCode_X64_st5;}break; +case REGS_RegCodeX64_st6:{result = RDI_RegisterCode_X64_st6;}break; +case REGS_RegCodeX64_st7:{result = RDI_RegisterCode_X64_st7;}break; +case REGS_RegCodeX64_fcw:{result = RDI_RegisterCode_X64_fcw;}break; +case REGS_RegCodeX64_fsw:{result = RDI_RegisterCode_X64_fsw;}break; +case REGS_RegCodeX64_ftw:{result = RDI_RegisterCode_X64_ftw;}break; +case REGS_RegCodeX64_fop:{result = RDI_RegisterCode_X64_fop;}break; +case REGS_RegCodeX64_fcs:{result = RDI_RegisterCode_X64_fcs;}break; +case REGS_RegCodeX64_fds:{result = RDI_RegisterCode_X64_fds;}break; +case REGS_RegCodeX64_fip:{result = RDI_RegisterCode_X64_fip;}break; +case REGS_RegCodeX64_fdp:{result = RDI_RegisterCode_X64_fdp;}break; +case REGS_RegCodeX64_mxcsr:{result = RDI_RegisterCode_X64_mxcsr;}break; +case REGS_RegCodeX64_mxcsr_mask:{result = RDI_RegisterCode_X64_mxcsr_mask;}break; +case REGS_RegCodeX64_ss:{result = RDI_RegisterCode_X64_ss;}break; +case REGS_RegCodeX64_cs:{result = RDI_RegisterCode_X64_cs;}break; +case REGS_RegCodeX64_ds:{result = RDI_RegisterCode_X64_ds;}break; +case REGS_RegCodeX64_es:{result = RDI_RegisterCode_X64_es;}break; +case REGS_RegCodeX64_fs:{result = RDI_RegisterCode_X64_fs;}break; +case REGS_RegCodeX64_gs:{result = RDI_RegisterCode_X64_gs;}break; +case REGS_RegCodeX64_ymm0:{result = RDI_RegisterCode_X64_ymm0;}break; +case REGS_RegCodeX64_ymm1:{result = RDI_RegisterCode_X64_ymm1;}break; +case REGS_RegCodeX64_ymm2:{result = RDI_RegisterCode_X64_ymm2;}break; +case REGS_RegCodeX64_ymm3:{result = RDI_RegisterCode_X64_ymm3;}break; +case REGS_RegCodeX64_ymm4:{result = RDI_RegisterCode_X64_ymm4;}break; +case REGS_RegCodeX64_ymm5:{result = RDI_RegisterCode_X64_ymm5;}break; +case REGS_RegCodeX64_ymm6:{result = RDI_RegisterCode_X64_ymm6;}break; +case REGS_RegCodeX64_ymm7:{result = RDI_RegisterCode_X64_ymm7;}break; +case REGS_RegCodeX64_ymm8:{result = RDI_RegisterCode_X64_ymm8;}break; +case REGS_RegCodeX64_ymm9:{result = RDI_RegisterCode_X64_ymm9;}break; +case REGS_RegCodeX64_ymm10:{result = RDI_RegisterCode_X64_ymm10;}break; +case REGS_RegCodeX64_ymm11:{result = RDI_RegisterCode_X64_ymm11;}break; +case REGS_RegCodeX64_ymm12:{result = RDI_RegisterCode_X64_ymm12;}break; +case REGS_RegCodeX64_ymm13:{result = RDI_RegisterCode_X64_ymm13;}break; +case REGS_RegCodeX64_ymm14:{result = RDI_RegisterCode_X64_ymm14;}break; +case REGS_RegCodeX64_ymm15:{result = RDI_RegisterCode_X64_ymm15;}break; +} +}break; +case Architecture_x86: +{ +switch(code) +{ +default:{}break; +case REGS_RegCodeX86_eax:{result = RDI_RegisterCode_X86_eax;}break; +case REGS_RegCodeX86_ecx:{result = RDI_RegisterCode_X86_ecx;}break; +case REGS_RegCodeX86_edx:{result = RDI_RegisterCode_X86_edx;}break; +case REGS_RegCodeX86_ebx:{result = RDI_RegisterCode_X86_ebx;}break; +case REGS_RegCodeX86_esp:{result = RDI_RegisterCode_X86_esp;}break; +case REGS_RegCodeX86_ebp:{result = RDI_RegisterCode_X86_ebp;}break; +case REGS_RegCodeX86_esi:{result = RDI_RegisterCode_X86_esi;}break; +case REGS_RegCodeX86_edi:{result = RDI_RegisterCode_X86_edi;}break; +case REGS_RegCodeX86_fsbase:{result = RDI_RegisterCode_X86_fsbase;}break; +case REGS_RegCodeX86_gsbase:{result = RDI_RegisterCode_X86_gsbase;}break; +case REGS_RegCodeX86_eflags:{result = RDI_RegisterCode_X86_eflags;}break; +case REGS_RegCodeX86_eip:{result = RDI_RegisterCode_X86_eip;}break; +case REGS_RegCodeX86_dr0:{result = RDI_RegisterCode_X86_dr0;}break; +case REGS_RegCodeX86_dr1:{result = RDI_RegisterCode_X86_dr1;}break; +case REGS_RegCodeX86_dr2:{result = RDI_RegisterCode_X86_dr2;}break; +case REGS_RegCodeX86_dr3:{result = RDI_RegisterCode_X86_dr3;}break; +case REGS_RegCodeX86_dr4:{result = RDI_RegisterCode_X86_dr4;}break; +case REGS_RegCodeX86_dr5:{result = RDI_RegisterCode_X86_dr5;}break; +case REGS_RegCodeX86_dr6:{result = RDI_RegisterCode_X86_dr6;}break; +case REGS_RegCodeX86_dr7:{result = RDI_RegisterCode_X86_dr7;}break; +case REGS_RegCodeX86_fpr0:{result = RDI_RegisterCode_X86_fpr0;}break; +case REGS_RegCodeX86_fpr1:{result = RDI_RegisterCode_X86_fpr1;}break; +case REGS_RegCodeX86_fpr2:{result = RDI_RegisterCode_X86_fpr2;}break; +case REGS_RegCodeX86_fpr3:{result = RDI_RegisterCode_X86_fpr3;}break; +case REGS_RegCodeX86_fpr4:{result = RDI_RegisterCode_X86_fpr4;}break; +case REGS_RegCodeX86_fpr5:{result = RDI_RegisterCode_X86_fpr5;}break; +case REGS_RegCodeX86_fpr6:{result = RDI_RegisterCode_X86_fpr6;}break; +case REGS_RegCodeX86_fpr7:{result = RDI_RegisterCode_X86_fpr7;}break; +case REGS_RegCodeX86_st0:{result = RDI_RegisterCode_X86_st0;}break; +case REGS_RegCodeX86_st1:{result = RDI_RegisterCode_X86_st1;}break; +case REGS_RegCodeX86_st2:{result = RDI_RegisterCode_X86_st2;}break; +case REGS_RegCodeX86_st3:{result = RDI_RegisterCode_X86_st3;}break; +case REGS_RegCodeX86_st4:{result = RDI_RegisterCode_X86_st4;}break; +case REGS_RegCodeX86_st5:{result = RDI_RegisterCode_X86_st5;}break; +case REGS_RegCodeX86_st6:{result = RDI_RegisterCode_X86_st6;}break; +case REGS_RegCodeX86_st7:{result = RDI_RegisterCode_X86_st7;}break; +case REGS_RegCodeX86_fcw:{result = RDI_RegisterCode_X86_fcw;}break; +case REGS_RegCodeX86_fsw:{result = RDI_RegisterCode_X86_fsw;}break; +case REGS_RegCodeX86_ftw:{result = RDI_RegisterCode_X86_ftw;}break; +case REGS_RegCodeX86_fop:{result = RDI_RegisterCode_X86_fop;}break; +case REGS_RegCodeX86_fcs:{result = RDI_RegisterCode_X86_fcs;}break; +case REGS_RegCodeX86_fds:{result = RDI_RegisterCode_X86_fds;}break; +case REGS_RegCodeX86_fip:{result = RDI_RegisterCode_X86_fip;}break; +case REGS_RegCodeX86_fdp:{result = RDI_RegisterCode_X86_fdp;}break; +case REGS_RegCodeX86_mxcsr:{result = RDI_RegisterCode_X86_mxcsr;}break; +case REGS_RegCodeX86_mxcsr_mask:{result = RDI_RegisterCode_X86_mxcsr_mask;}break; +case REGS_RegCodeX86_ss:{result = RDI_RegisterCode_X86_ss;}break; +case REGS_RegCodeX86_cs:{result = RDI_RegisterCode_X86_cs;}break; +case REGS_RegCodeX86_ds:{result = RDI_RegisterCode_X86_ds;}break; +case REGS_RegCodeX86_es:{result = RDI_RegisterCode_X86_es;}break; +case REGS_RegCodeX86_fs:{result = RDI_RegisterCode_X86_fs;}break; +case REGS_RegCodeX86_gs:{result = RDI_RegisterCode_X86_gs;}break; +case REGS_RegCodeX86_ymm0:{result = RDI_RegisterCode_X86_ymm0;}break; +case REGS_RegCodeX86_ymm1:{result = RDI_RegisterCode_X86_ymm1;}break; +case REGS_RegCodeX86_ymm2:{result = RDI_RegisterCode_X86_ymm2;}break; +case REGS_RegCodeX86_ymm3:{result = RDI_RegisterCode_X86_ymm3;}break; +case REGS_RegCodeX86_ymm4:{result = RDI_RegisterCode_X86_ymm4;}break; +case REGS_RegCodeX86_ymm5:{result = RDI_RegisterCode_X86_ymm5;}break; +case REGS_RegCodeX86_ymm6:{result = RDI_RegisterCode_X86_ymm6;}break; +case REGS_RegCodeX86_ymm7:{result = RDI_RegisterCode_X86_ymm7;}break; +} +}break; +} +return result; +} +internal REGS_RegCode regs_reg_code_from_arch_rdi_code(Architecture arch, RDI_RegisterCode code) +{ +REGS_RegCode result = 0; +switch(arch) +{ +default:{}break; +case Architecture_x64: +{ +switch(code) +{ +default:{}break; +case RDI_RegisterCode_X64_rax:{result = REGS_RegCodeX64_rax;}break; +case RDI_RegisterCode_X64_rcx:{result = REGS_RegCodeX64_rcx;}break; +case RDI_RegisterCode_X64_rdx:{result = REGS_RegCodeX64_rdx;}break; +case RDI_RegisterCode_X64_rbx:{result = REGS_RegCodeX64_rbx;}break; +case RDI_RegisterCode_X64_rsp:{result = REGS_RegCodeX64_rsp;}break; +case RDI_RegisterCode_X64_rbp:{result = REGS_RegCodeX64_rbp;}break; +case RDI_RegisterCode_X64_rsi:{result = REGS_RegCodeX64_rsi;}break; +case RDI_RegisterCode_X64_rdi:{result = REGS_RegCodeX64_rdi;}break; +case RDI_RegisterCode_X64_r8:{result = REGS_RegCodeX64_r8;}break; +case RDI_RegisterCode_X64_r9:{result = REGS_RegCodeX64_r9;}break; +case RDI_RegisterCode_X64_r10:{result = REGS_RegCodeX64_r10;}break; +case RDI_RegisterCode_X64_r11:{result = REGS_RegCodeX64_r11;}break; +case RDI_RegisterCode_X64_r12:{result = REGS_RegCodeX64_r12;}break; +case RDI_RegisterCode_X64_r13:{result = REGS_RegCodeX64_r13;}break; +case RDI_RegisterCode_X64_r14:{result = REGS_RegCodeX64_r14;}break; +case RDI_RegisterCode_X64_r15:{result = REGS_RegCodeX64_r15;}break; +case RDI_RegisterCode_X64_fsbase:{result = REGS_RegCodeX64_fsbase;}break; +case RDI_RegisterCode_X64_gsbase:{result = REGS_RegCodeX64_gsbase;}break; +case RDI_RegisterCode_X64_rip:{result = REGS_RegCodeX64_rip;}break; +case RDI_RegisterCode_X64_rflags:{result = REGS_RegCodeX64_rflags;}break; +case RDI_RegisterCode_X64_dr0:{result = REGS_RegCodeX64_dr0;}break; +case RDI_RegisterCode_X64_dr1:{result = REGS_RegCodeX64_dr1;}break; +case RDI_RegisterCode_X64_dr2:{result = REGS_RegCodeX64_dr2;}break; +case RDI_RegisterCode_X64_dr3:{result = REGS_RegCodeX64_dr3;}break; +case RDI_RegisterCode_X64_dr4:{result = REGS_RegCodeX64_dr4;}break; +case RDI_RegisterCode_X64_dr5:{result = REGS_RegCodeX64_dr5;}break; +case RDI_RegisterCode_X64_dr6:{result = REGS_RegCodeX64_dr6;}break; +case RDI_RegisterCode_X64_dr7:{result = REGS_RegCodeX64_dr7;}break; +case RDI_RegisterCode_X64_fpr0:{result = REGS_RegCodeX64_fpr0;}break; +case RDI_RegisterCode_X64_fpr1:{result = REGS_RegCodeX64_fpr1;}break; +case RDI_RegisterCode_X64_fpr2:{result = REGS_RegCodeX64_fpr2;}break; +case RDI_RegisterCode_X64_fpr3:{result = REGS_RegCodeX64_fpr3;}break; +case RDI_RegisterCode_X64_fpr4:{result = REGS_RegCodeX64_fpr4;}break; +case RDI_RegisterCode_X64_fpr5:{result = REGS_RegCodeX64_fpr5;}break; +case RDI_RegisterCode_X64_fpr6:{result = REGS_RegCodeX64_fpr6;}break; +case RDI_RegisterCode_X64_fpr7:{result = REGS_RegCodeX64_fpr7;}break; +case RDI_RegisterCode_X64_st0:{result = REGS_RegCodeX64_st0;}break; +case RDI_RegisterCode_X64_st1:{result = REGS_RegCodeX64_st1;}break; +case RDI_RegisterCode_X64_st2:{result = REGS_RegCodeX64_st2;}break; +case RDI_RegisterCode_X64_st3:{result = REGS_RegCodeX64_st3;}break; +case RDI_RegisterCode_X64_st4:{result = REGS_RegCodeX64_st4;}break; +case RDI_RegisterCode_X64_st5:{result = REGS_RegCodeX64_st5;}break; +case RDI_RegisterCode_X64_st6:{result = REGS_RegCodeX64_st6;}break; +case RDI_RegisterCode_X64_st7:{result = REGS_RegCodeX64_st7;}break; +case RDI_RegisterCode_X64_fcw:{result = REGS_RegCodeX64_fcw;}break; +case RDI_RegisterCode_X64_fsw:{result = REGS_RegCodeX64_fsw;}break; +case RDI_RegisterCode_X64_ftw:{result = REGS_RegCodeX64_ftw;}break; +case RDI_RegisterCode_X64_fop:{result = REGS_RegCodeX64_fop;}break; +case RDI_RegisterCode_X64_fcs:{result = REGS_RegCodeX64_fcs;}break; +case RDI_RegisterCode_X64_fds:{result = REGS_RegCodeX64_fds;}break; +case RDI_RegisterCode_X64_fip:{result = REGS_RegCodeX64_fip;}break; +case RDI_RegisterCode_X64_fdp:{result = REGS_RegCodeX64_fdp;}break; +case RDI_RegisterCode_X64_mxcsr:{result = REGS_RegCodeX64_mxcsr;}break; +case RDI_RegisterCode_X64_mxcsr_mask:{result = REGS_RegCodeX64_mxcsr_mask;}break; +case RDI_RegisterCode_X64_ss:{result = REGS_RegCodeX64_ss;}break; +case RDI_RegisterCode_X64_cs:{result = REGS_RegCodeX64_cs;}break; +case RDI_RegisterCode_X64_ds:{result = REGS_RegCodeX64_ds;}break; +case RDI_RegisterCode_X64_es:{result = REGS_RegCodeX64_es;}break; +case RDI_RegisterCode_X64_fs:{result = REGS_RegCodeX64_fs;}break; +case RDI_RegisterCode_X64_gs:{result = REGS_RegCodeX64_gs;}break; +case RDI_RegisterCode_X64_ymm0:{result = REGS_RegCodeX64_ymm0;}break; +case RDI_RegisterCode_X64_ymm1:{result = REGS_RegCodeX64_ymm1;}break; +case RDI_RegisterCode_X64_ymm2:{result = REGS_RegCodeX64_ymm2;}break; +case RDI_RegisterCode_X64_ymm3:{result = REGS_RegCodeX64_ymm3;}break; +case RDI_RegisterCode_X64_ymm4:{result = REGS_RegCodeX64_ymm4;}break; +case RDI_RegisterCode_X64_ymm5:{result = REGS_RegCodeX64_ymm5;}break; +case RDI_RegisterCode_X64_ymm6:{result = REGS_RegCodeX64_ymm6;}break; +case RDI_RegisterCode_X64_ymm7:{result = REGS_RegCodeX64_ymm7;}break; +case RDI_RegisterCode_X64_ymm8:{result = REGS_RegCodeX64_ymm8;}break; +case RDI_RegisterCode_X64_ymm9:{result = REGS_RegCodeX64_ymm9;}break; +case RDI_RegisterCode_X64_ymm10:{result = REGS_RegCodeX64_ymm10;}break; +case RDI_RegisterCode_X64_ymm11:{result = REGS_RegCodeX64_ymm11;}break; +case RDI_RegisterCode_X64_ymm12:{result = REGS_RegCodeX64_ymm12;}break; +case RDI_RegisterCode_X64_ymm13:{result = REGS_RegCodeX64_ymm13;}break; +case RDI_RegisterCode_X64_ymm14:{result = REGS_RegCodeX64_ymm14;}break; +case RDI_RegisterCode_X64_ymm15:{result = REGS_RegCodeX64_ymm15;}break; +} +}break; +case Architecture_x86: +{ +switch(code) +{ +default:{}break; +case RDI_RegisterCode_X86_eax:{result = REGS_RegCodeX86_eax;}break; +case RDI_RegisterCode_X86_ecx:{result = REGS_RegCodeX86_ecx;}break; +case RDI_RegisterCode_X86_edx:{result = REGS_RegCodeX86_edx;}break; +case RDI_RegisterCode_X86_ebx:{result = REGS_RegCodeX86_ebx;}break; +case RDI_RegisterCode_X86_esp:{result = REGS_RegCodeX86_esp;}break; +case RDI_RegisterCode_X86_ebp:{result = REGS_RegCodeX86_ebp;}break; +case RDI_RegisterCode_X86_esi:{result = REGS_RegCodeX86_esi;}break; +case RDI_RegisterCode_X86_edi:{result = REGS_RegCodeX86_edi;}break; +case RDI_RegisterCode_X86_fsbase:{result = REGS_RegCodeX86_fsbase;}break; +case RDI_RegisterCode_X86_gsbase:{result = REGS_RegCodeX86_gsbase;}break; +case RDI_RegisterCode_X86_eflags:{result = REGS_RegCodeX86_eflags;}break; +case RDI_RegisterCode_X86_eip:{result = REGS_RegCodeX86_eip;}break; +case RDI_RegisterCode_X86_dr0:{result = REGS_RegCodeX86_dr0;}break; +case RDI_RegisterCode_X86_dr1:{result = REGS_RegCodeX86_dr1;}break; +case RDI_RegisterCode_X86_dr2:{result = REGS_RegCodeX86_dr2;}break; +case RDI_RegisterCode_X86_dr3:{result = REGS_RegCodeX86_dr3;}break; +case RDI_RegisterCode_X86_dr4:{result = REGS_RegCodeX86_dr4;}break; +case RDI_RegisterCode_X86_dr5:{result = REGS_RegCodeX86_dr5;}break; +case RDI_RegisterCode_X86_dr6:{result = REGS_RegCodeX86_dr6;}break; +case RDI_RegisterCode_X86_dr7:{result = REGS_RegCodeX86_dr7;}break; +case RDI_RegisterCode_X86_fpr0:{result = REGS_RegCodeX86_fpr0;}break; +case RDI_RegisterCode_X86_fpr1:{result = REGS_RegCodeX86_fpr1;}break; +case RDI_RegisterCode_X86_fpr2:{result = REGS_RegCodeX86_fpr2;}break; +case RDI_RegisterCode_X86_fpr3:{result = REGS_RegCodeX86_fpr3;}break; +case RDI_RegisterCode_X86_fpr4:{result = REGS_RegCodeX86_fpr4;}break; +case RDI_RegisterCode_X86_fpr5:{result = REGS_RegCodeX86_fpr5;}break; +case RDI_RegisterCode_X86_fpr6:{result = REGS_RegCodeX86_fpr6;}break; +case RDI_RegisterCode_X86_fpr7:{result = REGS_RegCodeX86_fpr7;}break; +case RDI_RegisterCode_X86_st0:{result = REGS_RegCodeX86_st0;}break; +case RDI_RegisterCode_X86_st1:{result = REGS_RegCodeX86_st1;}break; +case RDI_RegisterCode_X86_st2:{result = REGS_RegCodeX86_st2;}break; +case RDI_RegisterCode_X86_st3:{result = REGS_RegCodeX86_st3;}break; +case RDI_RegisterCode_X86_st4:{result = REGS_RegCodeX86_st4;}break; +case RDI_RegisterCode_X86_st5:{result = REGS_RegCodeX86_st5;}break; +case RDI_RegisterCode_X86_st6:{result = REGS_RegCodeX86_st6;}break; +case RDI_RegisterCode_X86_st7:{result = REGS_RegCodeX86_st7;}break; +case RDI_RegisterCode_X86_fcw:{result = REGS_RegCodeX86_fcw;}break; +case RDI_RegisterCode_X86_fsw:{result = REGS_RegCodeX86_fsw;}break; +case RDI_RegisterCode_X86_ftw:{result = REGS_RegCodeX86_ftw;}break; +case RDI_RegisterCode_X86_fop:{result = REGS_RegCodeX86_fop;}break; +case RDI_RegisterCode_X86_fcs:{result = REGS_RegCodeX86_fcs;}break; +case RDI_RegisterCode_X86_fds:{result = REGS_RegCodeX86_fds;}break; +case RDI_RegisterCode_X86_fip:{result = REGS_RegCodeX86_fip;}break; +case RDI_RegisterCode_X86_fdp:{result = REGS_RegCodeX86_fdp;}break; +case RDI_RegisterCode_X86_mxcsr:{result = REGS_RegCodeX86_mxcsr;}break; +case RDI_RegisterCode_X86_mxcsr_mask:{result = REGS_RegCodeX86_mxcsr_mask;}break; +case RDI_RegisterCode_X86_ss:{result = REGS_RegCodeX86_ss;}break; +case RDI_RegisterCode_X86_cs:{result = REGS_RegCodeX86_cs;}break; +case RDI_RegisterCode_X86_ds:{result = REGS_RegCodeX86_ds;}break; +case RDI_RegisterCode_X86_es:{result = REGS_RegCodeX86_es;}break; +case RDI_RegisterCode_X86_fs:{result = REGS_RegCodeX86_fs;}break; +case RDI_RegisterCode_X86_gs:{result = REGS_RegCodeX86_gs;}break; +case RDI_RegisterCode_X86_ymm0:{result = REGS_RegCodeX86_ymm0;}break; +case RDI_RegisterCode_X86_ymm1:{result = REGS_RegCodeX86_ymm1;}break; +case RDI_RegisterCode_X86_ymm2:{result = REGS_RegCodeX86_ymm2;}break; +case RDI_RegisterCode_X86_ymm3:{result = REGS_RegCodeX86_ymm3;}break; +case RDI_RegisterCode_X86_ymm4:{result = REGS_RegCodeX86_ymm4;}break; +case RDI_RegisterCode_X86_ymm5:{result = REGS_RegCodeX86_ymm5;}break; +case RDI_RegisterCode_X86_ymm6:{result = REGS_RegCodeX86_ymm6;}break; +case RDI_RegisterCode_X86_ymm7:{result = REGS_RegCodeX86_ymm7;}break; +} +}break; +} +return result; +} +C_LINKAGE_BEGIN +C_LINKAGE_END + diff --git a/src/regs/raddbg/generated/regs_raddbg.meta.h b/src/regs/raddbgi/generated/regs_raddbgi.meta.h similarity index 53% rename from src/regs/raddbg/generated/regs_raddbg.meta.h rename to src/regs/raddbgi/generated/regs_raddbgi.meta.h index 6e1c7f59..4082c723 100644 --- a/src/regs/raddbg/generated/regs_raddbg.meta.h +++ b/src/regs/raddbgi/generated/regs_raddbgi.meta.h @@ -3,8 +3,10 @@ //- GENERATED CODE -#ifndef REGS_RADDBG_META_H -#define REGS_RADDBG_META_H +#ifndef REGS_RADDBGI_META_H +#define REGS_RADDBGI_META_H +C_LINKAGE_BEGIN +C_LINKAGE_END -#endif // REGS_RADDBG_META_H +#endif // REGS_RADDBGI_META_H diff --git a/src/regs/raddbgi/regs_raddbgi.c b/src/regs/raddbgi/regs_raddbgi.c new file mode 100644 index 00000000..b72739f4 --- /dev/null +++ b/src/regs/raddbgi/regs_raddbgi.c @@ -0,0 +1,4 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#include "regs/raddbgi/generated/regs_raddbgi.meta.c" diff --git a/src/regs/raddbgi/regs_raddbgi.h b/src/regs/raddbgi/regs_raddbgi.h new file mode 100644 index 00000000..4049a5b1 --- /dev/null +++ b/src/regs/raddbgi/regs_raddbgi.h @@ -0,0 +1,10 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef REGS_RADDBGI_H +#define REGS_RADDBGI_H + +internal RDI_RegisterCode regs_rdi_code_from_arch_reg_code(Architecture arch, REGS_RegCode code); +internal REGS_RegCode regs_reg_code_from_arch_rdi_code(Architecture arch, RDI_RegisterCode reg); + +#endif //REGS_RADDBGI_H diff --git a/src/regs/raddbg/regs_raddbg.mc b/src/regs/raddbgi/regs_raddbgi.mdesk similarity index 63% rename from src/regs/raddbg/regs_raddbg.mc rename to src/regs/raddbgi/regs_raddbgi.mdesk index ce76ed45..aad0e4ad 100644 --- a/src/regs/raddbg/regs_raddbg.mc +++ b/src/regs/raddbgi/regs_raddbgi.mdesk @@ -4,11 +4,11 @@ //////////////////////////////// //~ rjf: RADDBG Converter Helper Implementation Generators -@table_gen @c_file +@gen @c_file { - `internal RADDBG_RegisterCode regs_raddbg_code_from_arch_reg_code(Architecture arch, REGS_RegCode code)`; + `internal RDI_RegisterCode regs_rdi_code_from_arch_reg_code(Architecture arch, REGS_RegCode code)`; `{`; - `RADDBG_RegisterCode result = 0;`; + `RDI_RegisterCode result = 0;`; `switch(arch)`; `{`; `default:{}break;`; @@ -17,7 +17,7 @@ `switch(code)` `{`; `default:{}break;`; - @expand(REGS_RegTableX64 a) `case REGS_RegCodeX64_$(a.name):{result = RADDBG_RegisterCode_X64_$(a.name);}break;`; + @expand(REGS_RegTableX64 a) `case REGS_RegCodeX64_$(a.name):{result = RDI_RegisterCode_X64_$(a.name);}break;`; `}`; `}break;`; `case Architecture_x86:`; @@ -25,7 +25,7 @@ `switch(code)` `{`; `default:{}break;`; - @expand(REGS_RegTableX86 a) `case REGS_RegCodeX86_$(a.name):{result = RADDBG_RegisterCode_X86_$(a.name);}break;`; + @expand(REGS_RegTableX86 a) `case REGS_RegCodeX86_$(a.name):{result = RDI_RegisterCode_X86_$(a.name);}break;`; `}`; `}break;`; `}`; @@ -33,9 +33,9 @@ `}`; } -@table_gen @c_file +@gen @c_file { - `internal REGS_RegCode regs_reg_code_from_arch_raddbg_code(Architecture arch, RADDBG_RegisterCode code)`; + `internal REGS_RegCode regs_reg_code_from_arch_rdi_code(Architecture arch, RDI_RegisterCode code)`; `{`; `REGS_RegCode result = 0;`; `switch(arch)`; @@ -46,7 +46,7 @@ `switch(code)` `{`; `default:{}break;`; - @expand(REGS_RegTableX64 a) `case RADDBG_RegisterCode_X64_$(a.name):{result = REGS_RegCodeX64_$(a.name);}break;`; + @expand(REGS_RegTableX64 a) `case RDI_RegisterCode_X64_$(a.name):{result = REGS_RegCodeX64_$(a.name);}break;`; `}`; `}break;`; `case Architecture_x86:`; @@ -54,7 +54,7 @@ `switch(code)` `{`; `default:{}break;`; - @expand(REGS_RegTableX86 a) `case RADDBG_RegisterCode_X86_$(a.name):{result = REGS_RegCodeX86_$(a.name);}break;`; + @expand(REGS_RegTableX86 a) `case RDI_RegisterCode_X86_$(a.name):{result = REGS_RegCodeX86_$(a.name);}break;`; `}`; `}break;`; `}`; diff --git a/src/regs/regs.mdesk b/src/regs/regs.mdesk index 5c5e7f59..cfebf067 100644 --- a/src/regs/regs.mdesk +++ b/src/regs/regs.mdesk @@ -299,141 +299,129 @@ REGS_ArchTable: //////////////////////////////// //~ rjf: X64 Generators -@table_gen_enum REGS_RegCodeX64: +@enum REGS_RegCodeX64: { - `REGS_RegCodeX64_NULL,`; - @expand(REGS_RegTableX64 a) `REGS_RegCodeX64_$(a.name),`; - `REGS_RegCodeX64_COUNT`; + NULL, + @expand(REGS_RegTableX64 a) `$(a.name)`, + COUNT, } -@table_gen_enum REGS_AliasCodeX64: +@enum REGS_AliasCodeX64: { - `REGS_AliasCodeX64_NULL,`; - @expand(REGS_AliasTableX64 a) `REGS_AliasCodeX64_$(a.name),`; - `REGS_AliasCodeX64_COUNT`; + NULL, + @expand(REGS_AliasTableX64 a) `$(a.name)`, + COUNT, } -@table_gen_struct -REGS_RegBlockX64: +@struct REGS_RegBlockX64: { - @expand(REGS_RegTableX64 a) `REGS_Reg$(a.size) $(a.name);`; + @expand(REGS_RegTableX64 a) `REGS_Reg$(a.size) $(a.name)`, } -@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) -regs_g_reg_code_x64_usage_kind_table: +@data(REGS_UsageKind) regs_g_reg_code_x64_usage_kind_table: { - `REGS_UsageKind_Normal,`; - @expand(REGS_RegTableX64 a) `REGS_UsageKind_$(a.usage),`; + `REGS_UsageKind_Normal`; + @expand(REGS_RegTableX64 a) `REGS_UsageKind_$(a.usage)`; } -@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) +@data(REGS_UsageKind) regs_g_alias_code_x64_usage_kind_table: { - `REGS_UsageKind_Normal,`; - @expand(REGS_AliasTableX64 a) `REGS_UsageKind_$(a.usage),`; + `REGS_UsageKind_Normal`; + @expand(REGS_AliasTableX64 a) `REGS_UsageKind_$(a.usage)`; } -@table_gen_data(type:String8, fallback:`{0}`) -regs_g_reg_code_x64_string_table: +@data(String8) regs_g_reg_code_x64_string_table: { - `str8_lit_comp(""),`; - @expand(REGS_RegTableX64 a) `str8_lit_comp("$(a.name)"),`; + `str8_lit_comp("")`; + @expand(REGS_RegTableX64 a) `str8_lit_comp("$(a.name)")`; } -@table_gen_data(type:String8, fallback:`{0}`) -regs_g_alias_code_x64_string_table: +@data(String8) regs_g_alias_code_x64_string_table: { - `str8_lit_comp(""),`; - @expand(REGS_AliasTableX64 a) `str8_lit_comp("$(a.name)"),`; + `str8_lit_comp("")`; + @expand(REGS_AliasTableX64 a) `str8_lit_comp("$(a.name)")`; } -@table_gen_data(type: REGS_Rng, fallback: `{0}`) -regs_g_reg_code_x64_rng_table: +@data(REGS_Rng) regs_g_reg_code_x64_rng_table: { - `{0},`; - @expand(REGS_RegTableX64 a) `{(U16)OffsetOf(REGS_RegBlockX64, $(a.name)), $(a.size/8)},`, + `{0}`; + @expand(REGS_RegTableX64 a) `{(U16)OffsetOf(REGS_RegBlockX64, $(a.name)), $(a.size/8)}`, } -@table_gen_data(type: REGS_Slice, fallback: `{0}`) -regs_g_alias_code_x64_slice_table: +@data(REGS_Slice) regs_g_alias_code_x64_slice_table: { - `{0},`; - @expand(REGS_AliasTableX64 a) `{REGS_RegCodeX64_$(a.base), $(a.off/8), $(a.size/8)},`, + `{0}`; + @expand(REGS_AliasTableX64 a) `{REGS_RegCodeX64_$(a.base), $(a.off/8), $(a.size/8)}`, } //////////////////////////////// //~ rjf: X86 Generators -@table_gen_enum REGS_RegCodeX86: +@enum REGS_RegCodeX86: { - `REGS_RegCodeX86_NULL,`; - @expand(REGS_RegTableX86 a) `REGS_RegCodeX86_$(a.name),`; - `REGS_RegCodeX86_COUNT`; + NULL, + @expand(REGS_RegTableX86 a) `$(a.name)`, + COUNT, } -@table_gen_enum REGS_AliasCodeX86: +@enum REGS_AliasCodeX86: { - `REGS_AliasCodeX86_NULL,`; - @expand(REGS_AliasTableX86 a) `REGS_AliasCodeX86_$(a.name),`; - `REGS_AliasCodeX86_COUNT`; + NULL, + @expand(REGS_AliasTableX86 a) `$(a.name)`, + COUNT, } -@table_gen_struct -REGS_RegBlockX86: +@struct REGS_RegBlockX86: { - @expand(REGS_RegTableX86 a) `REGS_Reg$(a.size) $(a.name);`; + @expand(REGS_RegTableX86 a) `REGS_Reg$(a.size) $(a.name)`, } -@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) +@data(REGS_UsageKind) regs_g_reg_code_x86_usage_kind_table: { - `REGS_UsageKind_Normal,`; - @expand(REGS_RegTableX86 a) `REGS_UsageKind_$(a.usage),`; + `REGS_UsageKind_Normal`; + @expand(REGS_RegTableX86 a) `REGS_UsageKind_$(a.usage)`; } -@table_gen_data(type:REGS_UsageKind, fallback:`REGS_UsageKind_Normal`) -regs_g_alias_code_x86_usage_kind_table: +@data(REGS_UsageKind) regs_g_alias_code_x86_usage_kind_table: { - `REGS_UsageKind_Normal,`; - @expand(REGS_AliasTableX86 a) `REGS_UsageKind_$(a.usage),`; + `REGS_UsageKind_Normal`; + @expand(REGS_AliasTableX86 a) `REGS_UsageKind_$(a.usage)`; } -@table_gen_data(type:String8, fallback:`{0}`) -regs_g_reg_code_x86_string_table: +@data(String8) regs_g_reg_code_x86_string_table: { - `str8_lit_comp(""),`; - @expand(REGS_RegTableX86 a) `str8_lit_comp("$(a.name)"),`; + `str8_lit_comp("")`; + @expand(REGS_RegTableX86 a) `str8_lit_comp("$(a.name)")`; } -@table_gen_data(type:String8, fallback:`{0}`) -regs_g_alias_code_x86_string_table: +@data(String8) regs_g_alias_code_x86_string_table: { - `str8_lit_comp(""),`; - @expand(REGS_AliasTableX86 a) `str8_lit_comp("$(a.name)"),`; + `str8_lit_comp("")`; + @expand(REGS_AliasTableX86 a) `str8_lit_comp("$(a.name)")`; } -@table_gen_data(type: REGS_Rng, fallback: `{0}`) -regs_g_reg_code_x86_rng_table: +@data(REGS_Rng) regs_g_reg_code_x86_rng_table: { - `{0},`; - @expand(REGS_RegTableX86 a) `{(U16)OffsetOf(REGS_RegBlockX86, $(a.name)), $(a.size/8)},`, + `{0}`; + @expand(REGS_RegTableX86 a) `{(U16)OffsetOf(REGS_RegBlockX86, $(a.name)), $(a.size/8)}`, } -@table_gen_data(type: REGS_Slice, fallback: `{0}`) -regs_g_alias_code_x86_slice_table: +@data(REGS_Slice) regs_g_alias_code_x86_slice_table: { - `{0},`; - @expand(REGS_AliasTableX86 a) `{REGS_RegCodeX86_$(a.base), $(a.off/8), $(a.size/8)},`, + `{0}`; + @expand(REGS_AliasTableX86 a) `{REGS_RegCodeX86_$(a.base), $(a.off/8), $(a.size/8)}`, } //////////////////////////////// //~ rjf: Architecture-Dynamic Helper Implementation Generators -@c_file @table_gen +@c_file @gen { `internal U64 regs_block_size_from_architecture(Architecture arch)`; `{`; - `U64 result = 0;`; + `U64 result = 8;`; `switch(arch)`; `{`; `default:{}break;`; @@ -443,7 +431,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal U64 regs_reg_code_count_from_architecture(Architecture arch)`; `{`; @@ -457,7 +445,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal U64 regs_alias_code_count_from_architecture(Architecture arch)`; `{`; @@ -471,7 +459,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal String8 *regs_reg_code_string_table_from_architecture(Architecture arch)`; `{`; @@ -485,7 +473,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal String8 *regs_alias_code_string_table_from_architecture(Architecture arch)`; `{`; @@ -499,7 +487,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal REGS_Rng *regs_reg_code_rng_table_from_architecture(Architecture arch)`; `{`; @@ -513,7 +501,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal REGS_Slice *regs_alias_code_slice_table_from_architecture(Architecture arch)`; `{`; @@ -527,7 +515,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal REGS_UsageKind *regs_reg_code_usage_kind_table_from_architecture(Architecture arch)`; `{`; @@ -541,7 +529,7 @@ regs_g_alias_code_x86_slice_table: `}`; } -@c_file @table_gen +@c_file @gen { `internal REGS_UsageKind *regs_alias_code_usage_kind_table_from_architecture(Architecture arch)`; `{`; diff --git a/src/render/d3d11/generated/render_d3d11.meta.c b/src/render/d3d11/generated/render_d3d11.meta.c index 8969f2d6..08a2c9e0 100644 --- a/src/render/d3d11/generated/render_d3d11.meta.c +++ b/src/render/d3d11/generated/render_d3d11.meta.c @@ -3,7 +3,8 @@ //- GENERATED CODE -String8 r_d3d11_g_vshad_kind_source_table[] = +C_LINKAGE_BEGIN +String8 r_d3d11_g_vshad_kind_source_table[5] = { r_d3d11_g_rect_shader_src, r_d3d11_g_blur_shader_src, @@ -12,7 +13,7 @@ r_d3d11_g_geo3dcomposite_shader_src, r_d3d11_g_finalize_shader_src, }; -String8 r_d3d11_g_vshad_kind_source_name_table[] = +String8 r_d3d11_g_vshad_kind_source_name_table[5] = { str8_lit_comp("r_d3d11_g_rect_shader_src"), str8_lit_comp("r_d3d11_g_blur_shader_src"), @@ -21,7 +22,7 @@ str8_lit_comp("r_d3d11_g_geo3dcomposite_shader_src"), str8_lit_comp("r_d3d11_g_finalize_shader_src"), }; -D3D11_INPUT_ELEMENT_DESC * r_d3d11_g_vshad_kind_elements_ptr_table[] = +D3D11_INPUT_ELEMENT_DESC * r_d3d11_g_vshad_kind_elements_ptr_table[5] = { r_d3d11_g_rect_ilay_elements, 0, @@ -30,7 +31,7 @@ r_d3d11_g_mesh_ilay_elements, 0, }; -U64 r_d3d11_g_vshad_kind_elements_count_table[] = +U64 r_d3d11_g_vshad_kind_elements_count_table[5] = { ArrayCount(r_d3d11_g_rect_ilay_elements) , 0, @@ -39,7 +40,7 @@ ArrayCount(r_d3d11_g_mesh_ilay_elements) , 0, }; -String8 r_d3d11_g_pshad_kind_source_table[] = +String8 r_d3d11_g_pshad_kind_source_table[5] = { r_d3d11_g_rect_shader_src, r_d3d11_g_blur_shader_src, @@ -48,7 +49,7 @@ r_d3d11_g_geo3dcomposite_shader_src, r_d3d11_g_finalize_shader_src, }; -String8 r_d3d11_g_pshad_kind_source_name_table[] = +String8 r_d3d11_g_pshad_kind_source_name_table[5] = { str8_lit_comp("r_d3d11_g_rect_shader_src"), str8_lit_comp("r_d3d11_g_blur_shader_src"), @@ -57,10 +58,12 @@ str8_lit_comp("r_d3d11_g_geo3dcomposite_shader_src"), str8_lit_comp("r_d3d11_g_finalize_shader_src"), }; -U64 r_d3d11_g_uniform_type_kind_size_table[] = +U64 r_d3d11_g_uniform_type_kind_size_table[3] = { sizeof(R_D3D11_Uniforms_Rect), sizeof(R_D3D11_Uniforms_Blur), sizeof(R_D3D11_Uniforms_Mesh), }; +C_LINKAGE_END + diff --git a/src/render/d3d11/generated/render_d3d11.meta.h b/src/render/d3d11/generated/render_d3d11.meta.h index 8262fed9..b56b7e29 100644 --- a/src/render/d3d11/generated/render_d3d11.meta.h +++ b/src/render/d3d11/generated/render_d3d11.meta.h @@ -13,7 +13,7 @@ R_D3D11_VShadKind_Blur, R_D3D11_VShadKind_Mesh, R_D3D11_VShadKind_Geo3DComposite, R_D3D11_VShadKind_Finalize, -R_D3D11_VShadKind_COUNT +R_D3D11_VShadKind_COUNT, } R_D3D11_VShadKind; typedef enum R_D3D11_PShadKind @@ -23,7 +23,7 @@ R_D3D11_PShadKind_Blur, R_D3D11_PShadKind_Mesh, R_D3D11_PShadKind_Geo3DComposite, R_D3D11_PShadKind_Finalize, -R_D3D11_PShadKind_COUNT +R_D3D11_PShadKind_COUNT, } R_D3D11_PShadKind; typedef enum R_D3D11_UniformTypeKind @@ -31,9 +31,10 @@ typedef enum R_D3D11_UniformTypeKind R_D3D11_UniformTypeKind_Rect, R_D3D11_UniformTypeKind_Blur, R_D3D11_UniformTypeKind_Mesh, -R_D3D11_UniformTypeKind_COUNT +R_D3D11_UniformTypeKind_COUNT, } R_D3D11_UniformTypeKind; +C_LINKAGE_BEGIN read_only global String8 r_d3d11_g_rect_shader_src = str8_lit_comp( "" @@ -461,5 +462,6 @@ str8_lit_comp( "" ); +C_LINKAGE_END #endif // RENDER_D3D11_META_H diff --git a/src/render/d3d11/render_d3d11.cpp b/src/render/d3d11/render_d3d11.cpp index c03573e5..30205966 100644 --- a/src/render/d3d11/render_d3d11.cpp +++ b/src/render/d3d11/render_d3d11.cpp @@ -142,7 +142,7 @@ r_init(CmdLine *cmdln) //- rjf: create base device UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; -#if !defined(NDEBUG) +#if BUILD_DEBUG if(cmd_line_has_flag(cmdln, str8_lit("d3d11_debug"))) { creation_flags |= D3D11_CREATE_DEVICE_DEBUG; @@ -182,7 +182,7 @@ r_init(CmdLine *cmdln) } //- rjf: enable break-on-error -#if !defined(NDEBUG) +#if BUILD_DEBUG if(cmd_line_has_flag(cmdln, str8_lit("d3d11_debug"))) { ID3D11InfoQueue *info = 0; @@ -496,6 +496,8 @@ r_window_equip(OS_Handle handle) os_graphical_message(1, str8_lit("Fatal Error"), str8_cstring(buffer)); os_exit_process(1); } + + r_d3d11_state->dxgi_factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); //- rjf: create framebuffer & view window->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&window->framebuffer)); diff --git a/src/render/d3d11/render_d3d11.mdesk b/src/render/d3d11/render_d3d11.mdesk index d5eb5317..ac7d953c 100644 --- a/src/render/d3d11/render_d3d11.mdesk +++ b/src/render/d3d11/render_d3d11.mdesk @@ -462,65 +462,62 @@ ps_main(Vertex2Pixel v2p) : SV_TARGET //////////////////////////////// //~ rjf: Table Generators -@table_gen_enum -R_D3D11_VShadKind: +@enum R_D3D11_VShadKind: { - @expand(R_D3D11_VShadTable a) `R_D3D11_VShadKind_$(a.name),`; - `R_D3D11_VShadKind_COUNT`; + @expand(R_D3D11_VShadTable a) `$(a.name)`, + COUNT, } -@table_gen_enum -R_D3D11_PShadKind: +@enum R_D3D11_PShadKind: { - @expand(R_D3D11_PShadTable a) `R_D3D11_PShadKind_$(a.name),`; - `R_D3D11_PShadKind_COUNT`; + @expand(R_D3D11_PShadTable a) `$(a.name)`, + COUNT, } -@table_gen_enum -R_D3D11_UniformTypeKind: +@enum R_D3D11_UniformTypeKind: { - @expand(R_D3D11_UniformTypeTable a) `R_D3D11_UniformTypeKind_$(a.name),`; - `R_D3D11_UniformTypeKind_COUNT`; + @expand(R_D3D11_UniformTypeTable a) `$(a.name)`, + COUNT, } -@c_file @table_gen_data(type:String8, fallback:`{0}`) +@c_file @data(String8) r_d3d11_g_vshad_kind_source_table: { - @expand(R_D3D11_VShadTable a) `$(a.source),`; + @expand(R_D3D11_VShadTable a) `$(a.source)`; } -@c_file @table_gen_data(type:String8, fallback:`{0}`) +@c_file @data(String8) r_d3d11_g_vshad_kind_source_name_table: { - @expand(R_D3D11_VShadTable a) `str8_lit_comp("$(a.source)"),`; + @expand(R_D3D11_VShadTable a) `str8_lit_comp("$(a.source)")`; } -@c_file @table_gen_data(type:`D3D11_INPUT_ELEMENT_DESC *`, fallback:`0`) +@c_file @data(`D3D11_INPUT_ELEMENT_DESC *`) r_d3d11_g_vshad_kind_elements_ptr_table: { - @expand(R_D3D11_VShadTable a) `$(a.ilay_table),`; + @expand(R_D3D11_VShadTable a) `$(a.ilay_table)`; } -@c_file @table_gen_data(type:U64, fallback:`0`) +@c_file @data(U64) r_d3d11_g_vshad_kind_elements_count_table: { - @expand(R_D3D11_VShadTable a) `$(a.ilay_table != 0 -> "ArrayCount("..a.ilay_table..")") $(a.ilay_table == 0 -> "0"),`; + @expand(R_D3D11_VShadTable a) `$(a.ilay_table != 0 -> "ArrayCount("..a.ilay_table..")") $(a.ilay_table == 0 -> "0")`; } -@c_file @table_gen_data(type:String8, fallback:`{0}`) +@c_file @data(String8) r_d3d11_g_pshad_kind_source_table: { - @expand(R_D3D11_PShadTable a) `$(a.source),`; + @expand(R_D3D11_PShadTable a) `$(a.source)`; } -@c_file @table_gen_data(type:String8, fallback:`{0}`) +@c_file @data(String8) r_d3d11_g_pshad_kind_source_name_table: { - @expand(R_D3D11_PShadTable a) `str8_lit_comp("$(a.source)"),`; + @expand(R_D3D11_PShadTable a) `str8_lit_comp("$(a.source)")`; } -@c_file @table_gen_data(type:U64, fallback:`0`) +@c_file @data(U64) r_d3d11_g_uniform_type_kind_size_table: { - @expand(R_D3D11_UniformTypeTable a) `sizeof(R_D3D11_Uniforms_$(a.name)),`; + @expand(R_D3D11_UniformTypeTable a) `sizeof(R_D3D11_Uniforms_$(a.name))`; } diff --git a/src/render/d3d11/render_d3d11_main.cpp b/src/render/d3d11/render_d3d11_main.cpp index 94367153..1a9e6b0d 100644 --- a/src/render/d3d11/render_d3d11_main.cpp +++ b/src/render/d3d11/render_d3d11_main.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#define SUPPLEMENT_UNIT 1 +#define BUILD_SUPPLEMENTARY_UNIT 1 #define OS_FEATURE_GRAPHICAL 1 #include "base/base_inc.h" diff --git a/src/render/generated/render.meta.c b/src/render/generated/render.meta.c index 3c6ec07e..ca405579 100644 --- a/src/render/generated/render.meta.c +++ b/src/render/generated/render.meta.c @@ -3,10 +3,65 @@ //- GENERATED CODE -U64 r_pass_kind_params_size_table[] = +C_LINKAGE_BEGIN +String8 r_tex2d_format_display_string_table[9] = +{ +str8_lit_comp("R8"), +str8_lit_comp("RG8"), +str8_lit_comp("RGBA8"), +str8_lit_comp("BGRA8"), +str8_lit_comp("R16"), +str8_lit_comp("RGBA16"), +str8_lit_comp("R32"), +str8_lit_comp("RG32"), +str8_lit_comp("RGBA32"), +}; + +U8 r_tex2d_format_bytes_per_pixel_table[9] = +{ +1, +2, +4, +4, +2, +8, +4, +8, +16, +}; + +String8 r_tex2d_kind_display_string_table[2] = +{ +str8_lit_comp("Static"), +str8_lit_comp("Dynamic"), +}; + +String8 r_tex2d_sample_kind_display_string_table[2] = +{ +str8_lit_comp("Nearest"), +str8_lit_comp("Linear"), +}; + +String8 r_pass_kind_display_string_table[3] = +{ +str8_lit_comp("UI"), +str8_lit_comp("Blur"), +str8_lit_comp("Geo3D"), +}; + +U8 r_pass_kind_batch_table[3] = +{ +1, +0, +1, +}; + +U64 r_pass_kind_params_size_table[3] = { sizeof(R_PassParams_UI), sizeof(R_PassParams_Blur), sizeof(R_PassParams_Geo3D), }; +C_LINKAGE_END + diff --git a/src/render/generated/render.meta.h b/src/render/generated/render.meta.h index e2702d56..5ab27d47 100644 --- a/src/render/generated/render.meta.h +++ b/src/render/generated/render.meta.h @@ -17,21 +17,21 @@ R_Tex2DFormat_RGBA16, R_Tex2DFormat_R32, R_Tex2DFormat_RG32, R_Tex2DFormat_RGBA32, -R_Tex2DFormat_COUNT +R_Tex2DFormat_COUNT, } R_Tex2DFormat; typedef enum R_Tex2DKind { R_Tex2DKind_Static, R_Tex2DKind_Dynamic, -R_Tex2DKind_COUNT +R_Tex2DKind_COUNT, } R_Tex2DKind; typedef enum R_Tex2DSampleKind { R_Tex2DSampleKind_Nearest, R_Tex2DSampleKind_Linear, -R_Tex2DSampleKind_COUNT +R_Tex2DSampleKind_COUNT, } R_Tex2DSampleKind; typedef enum R_GeoTopologyKind @@ -40,14 +40,14 @@ R_GeoTopologyKind_Lines, R_GeoTopologyKind_LineStrip, R_GeoTopologyKind_Triangles, R_GeoTopologyKind_TriangleStrip, -R_GeoTopologyKind_COUNT +R_GeoTopologyKind_COUNT, } R_GeoTopologyKind; typedef enum R_BufferKind { R_BufferKind_Static, R_BufferKind_Dynamic, -R_BufferKind_COUNT +R_BufferKind_COUNT, } R_BufferKind; typedef enum R_PassKind @@ -55,60 +55,16 @@ typedef enum R_PassKind R_PassKind_UI, R_PassKind_Blur, R_PassKind_Geo3D, -R_PassKind_COUNT +R_PassKind_COUNT, } R_PassKind; -String8 r_tex2d_format_display_string_table[] = -{ -str8_lit_comp("R8"), -str8_lit_comp("RG8"), -str8_lit_comp("RGBA8"), -str8_lit_comp("BGRA8"), -str8_lit_comp("R16"), -str8_lit_comp("RGBA16"), -str8_lit_comp("R32"), -str8_lit_comp("RG32"), -str8_lit_comp("RGBA32"), -}; - -U8 r_tex2d_format_bytes_per_pixel_table[] = -{ -1, -2, -4, -4, -2, -8, -4, -8, -16, -}; - -String8 r_tex2d_kind_display_string_table[] = -{ -str8_lit_comp("Static"), -str8_lit_comp("Dynamic"), -}; - -String8 r_tex2d_sample_kind_display_string_table[] = -{ -str8_lit_comp("Nearest"), -str8_lit_comp("Linear"), -}; - -String8 r_pass_kind_display_string_table[] = -{ -str8_lit_comp("UI"), -str8_lit_comp("Blur"), -str8_lit_comp("Geo3D"), -}; - -U8 r_pass_kind_batch_table[] = -{ -1, -0, -1, -}; - +C_LINKAGE_BEGIN +extern String8 r_tex2d_format_display_string_table[9]; +extern U8 r_tex2d_format_bytes_per_pixel_table[9]; +extern String8 r_tex2d_kind_display_string_table[2]; +extern String8 r_tex2d_sample_kind_display_string_table[2]; +extern String8 r_pass_kind_display_string_table[3]; +extern U8 r_pass_kind_batch_table[3]; +C_LINKAGE_END #endif // RENDER_META_H diff --git a/src/render/render_core.mdesk b/src/render/render_core.mdesk index 4ca54800..ba3eff73 100644 --- a/src/render/render_core.mdesk +++ b/src/render/render_core.mdesk @@ -59,73 +59,73 @@ R_PassKindTable: //////////////////////////////// //~ rjf: Generators -@table_gen_enum R_Tex2DFormat: +@enum R_Tex2DFormat: { - @expand(R_Tex2DFormatTable a) `R_Tex2DFormat_$(a.name),`; - `R_Tex2DFormat_COUNT`; + @expand(R_Tex2DFormatTable a) `$(a.name)`, + COUNT, } -@table_gen_enum R_Tex2DKind: +@enum R_Tex2DKind: { - @expand(R_Tex2DKindTable a) `R_Tex2DKind_$(a.name),`; - `R_Tex2DKind_COUNT`; + @expand(R_Tex2DKindTable a) `$(a.name)`, + COUNT, } -@table_gen_enum R_Tex2DSampleKind: +@enum R_Tex2DSampleKind: { - @expand(R_Tex2DSampleKindTable a) `R_Tex2DSampleKind_$(a.name),`; - `R_Tex2DSampleKind_COUNT`; + @expand(R_Tex2DSampleKindTable a) `$(a.name)`, + COUNT, } -@table_gen_enum R_GeoTopologyKind: +@enum R_GeoTopologyKind: { - @expand(R_GeoTopologyKindTable a) `R_GeoTopologyKind_$(a.name),`; - `R_GeoTopologyKind_COUNT`; + @expand(R_GeoTopologyKindTable a) `$(a.name)`, + COUNT, } -@table_gen_enum R_BufferKind: +@enum R_BufferKind: { - @expand(R_BufferKindTable a) `R_BufferKind_$(a.name),`; - `R_BufferKind_COUNT`; + @expand(R_BufferKindTable a) `$(a.name)`, + COUNT, } -@table_gen_enum R_PassKind: +@enum R_PassKind: { - @expand(R_PassKindTable a) `R_PassKind_$(a.name),`; - `R_PassKind_COUNT`; + @expand(R_PassKindTable a) `$(a.name)`, + COUNT, } -@table_gen_data(type:String8) r_tex2d_format_display_string_table: +@data(String8) r_tex2d_format_display_string_table: { - @expand(R_Tex2DFormatTable a) `str8_lit_comp("$(a.display_string)"),`; + @expand(R_Tex2DFormatTable a) `str8_lit_comp("$(a.display_string)")`; } -@table_gen_data(type:U8) r_tex2d_format_bytes_per_pixel_table: +@data(U8) r_tex2d_format_bytes_per_pixel_table: { - @expand(R_Tex2DFormatTable a) `$(a.bytes_per_pixel),`; + @expand(R_Tex2DFormatTable a) `$(a.bytes_per_pixel)`; } -@table_gen_data(type:String8) r_tex2d_kind_display_string_table: +@data(String8) r_tex2d_kind_display_string_table: { - @expand(R_Tex2DKindTable a) `str8_lit_comp("$(a.display_string)"),`; + @expand(R_Tex2DKindTable a) `str8_lit_comp("$(a.display_string)")`; } -@table_gen_data(type:String8) r_tex2d_sample_kind_display_string_table: +@data(String8) r_tex2d_sample_kind_display_string_table: { - @expand(R_Tex2DSampleKindTable a) `str8_lit_comp("$(a.display_string)"),`; + @expand(R_Tex2DSampleKindTable a) `str8_lit_comp("$(a.display_string)")`; } -@table_gen_data(type:String8) r_pass_kind_display_string_table: +@data(String8) r_pass_kind_display_string_table: { - @expand(R_PassKindTable a) `str8_lit_comp("$(a.display_string)"),`; + @expand(R_PassKindTable a) `str8_lit_comp("$(a.display_string)")`; } -@table_gen_data(type:U8) r_pass_kind_batch_table: +@data(U8) r_pass_kind_batch_table: { - @expand(R_PassKindTable a) `$(a.batch),`; + @expand(R_PassKindTable a) `$(a.batch)`; } -@table_gen_data(type:U64) @c_file r_pass_kind_params_size_table: +@data(U64) @c_file r_pass_kind_params_size_table: { - @expand(R_PassKindTable a) `sizeof(R_PassParams_$(a.name)),`; + @expand(R_PassKindTable a) `sizeof(R_PassParams_$(a.name))`; } diff --git a/src/scratch/look_at_raddbg.c b/src/scratch/look_at_raddbg.c index 9e3c7313..d141a7dd 100644 --- a/src/scratch/look_at_raddbg.c +++ b/src/scratch/look_at_raddbg.c @@ -6,10 +6,10 @@ #include #include -#include "raddbg_format/raddbg_format.h" -#include "raddbg_format/raddbg_format_parse.h" -#include "raddbg_format/raddbg_format.c" -#include "raddbg_format/raddbg_format_parse.c" +#include "rdi_format/rdi_format.h" +#include "rdi_format/rdi_format_parse.h" +#include "rdi_format/rdi_format.c" +#include "rdi_format/rdi_format_parse.c" int main(int argument_count, char **arguments) { @@ -22,38 +22,38 @@ int main(int argument_count, char **arguments) uint8_t *data = (uint8_t *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, data_size); // parse raw data as raddbg - RADDBG_Parsed rdbg = {0}; - RADDBG_ParseStatus parse_status = raddbg_parse(data, data_size, &rdbg); + RDI_Parsed rdi = {0}; + RDI_ParseStatus parse_status = rdi_parse(data, data_size, &rdi); // usage example: print out all procedure symbol names #if 1 - for(uint64_t procedure_idx = 0; procedure_idx < rdbg.procedure_count; procedure_idx += 1) + for(uint64_t procedure_idx = 0; procedure_idx < rdi.procedure_count; procedure_idx += 1) { - RADDBG_Procedure *procedure = &rdbg.procedures[procedure_idx]; + RDI_Procedure *procedure = &rdi.procedures[procedure_idx]; uint64_t name_size = 0; - uint8_t *name = raddbg_string_from_idx(&rdbg, procedure->name_string_idx, &name_size); + uint8_t *name = rdi_string_from_idx(&rdi, procedure->name_string_idx, &name_size); printf("[%I64u] %.*s\n", procedure_idx, (int)name_size, name); } #endif // usage example: print out all user-defined-type names #if 0 - for(uint64_t udt_idx = 0; udt_idx < rdbg.udt_count; udt_idx += 1) + for(uint64_t udt_idx = 0; udt_idx < rdi.udt_count; udt_idx += 1) { - RADDBG_UDT *udt = &rdbg.udts[udt_idx]; - RADDBG_TypeNode *type = &rdbg.type_nodes[udt->self_type_idx]; + RDI_UDT *udt = &rdi.udts[udt_idx]; + RDI_TypeNode *type = &rdi.type_nodes[udt->self_type_idx]; uint64_t name_size = 0; - uint8_t *name = raddbg_string_from_idx(&rdbg, type->user_defined.name_string_idx, &name_size); + uint8_t *name = rdi_string_from_idx(&rdi, type->user_defined.name_string_idx, &name_size); printf("[%I64u] %.*s\n", udt_idx, (int)name_size, name); } #endif - // for getting more info, look at the `RADDBG_Parsed` structure. all data is + // for getting more info, look at the `RDI_Parsed` structure. all data is // represented as a bunch of flat plain-old-data tables. data which must // reference other data uses indices into that other data's table. for - // example, given a `type_idx`, I will index into `rdbg.type_nodes`. given a - // `udt_idx`, I will index into `rdbg.udts`. given a `scope_idx`, I will - // index into `rdbg.scopes`. and so on. + // example, given a `type_idx`, I will index into `rdi.type_nodes`. given a + // `udt_idx`, I will index into `rdi.udts`. given a `scope_idx`, I will + // index into `rdi.scopes`. and so on. return 0; } diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 0ebb7184..01d1f5c3 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -1,25 +1,86 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include +//////////////////////////////// +//~ rjf: Build Options -int main(int argument_count, char **arguments) +#define BUILD_VERSION_MAJOR 0 +#define BUILD_VERSION_MINOR 9 +#define BUILD_VERSION_PATCH 9 +#define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" +#define BUILD_TITLE "ryan_scratch" +#define BUILD_CONSOLE_INTERFACE 1 + +//////////////////////////////// +//~ rjf: Includes + +//- rjf: [lib] +#include "lib_raddbgi_format/raddbgi_format.h" +#include "lib_raddbgi_format/raddbgi_format_parse.h" +#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_raddbgi_format/raddbgi_format_parse.c" + +//- rjf: [h] +#include "base/base_inc.h" +#include "os/os_inc.h" +#include "task_system/task_system.h" +#include "raddbgi_make_local/raddbgi_make_local.h" +#include "mdesk/mdesk.h" +#include "hash_store/hash_store.h" +#include "file_stream/file_stream.h" +#include "text_cache/text_cache.h" +#include "path/path.h" +#include "txti/txti.h" +#include "coff/coff.h" +#include "pe/pe.h" +#include "codeview/codeview.h" +#include "codeview/codeview_stringize.h" +#include "msf/msf.h" +#include "pdb/pdb.h" +#include "pdb/pdb_stringize.h" +#include "raddbgi_from_pdb/raddbgi_from_pdb.h" +#include "regs/regs.h" +#include "regs/raddbgi/regs_raddbgi.h" +#include "type_graph/type_graph.h" +#include "dbgi/dbgi.h" +#include "demon/demon_inc.h" +#include "eval/eval_inc.h" +#include "unwind/unwind.h" +#include "ctrl/ctrl_inc.h" + +//- rjf: [c] +#include "base/base_inc.c" +#include "os/os_inc.c" +#include "task_system/task_system.c" +#include "raddbgi_make_local/raddbgi_make_local.c" +#include "mdesk/mdesk.c" +#include "hash_store/hash_store.c" +#include "file_stream/file_stream.c" +#include "text_cache/text_cache.c" +#include "path/path.c" +#include "txti/txti.c" +#include "coff/coff.c" +#include "pe/pe.c" +#include "codeview/codeview.c" +#include "codeview/codeview_stringize.c" +#include "msf/msf.c" +#include "pdb/pdb.c" +#include "pdb/pdb_stringize.c" +#include "raddbgi_from_pdb/raddbgi_from_pdb.c" +#include "regs/regs.c" +#include "regs/raddbgi/regs_raddbgi.c" +#include "type_graph/type_graph.c" +#include "dbgi/dbgi.c" +#include "demon/demon_inc.c" +#include "eval/eval_inc.c" +#include "unwind/unwind.c" +#include "ctrl/ctrl_inc.c" + +//////////////////////////////// +//~ rjf: Entry Point + +internal void +entry_point(CmdLine *cmdline) { - for(int i = 0; i < 1000; i += 1) - { - OutputDebugStringA("Hello, this is a long string which is being output in loop #1.\n"); - } - for(int i = 0; i < 1000; i += 1) - { - OutputDebugStringA("Hello, this is a long string which is being output in loop #2.\n"); - } - for(int i = 0; i < 1000; i += 1) - { - OutputDebugStringA("Hello, this is a long string which is being output in loop #3.\n"); - } - for(int i = 0; i < 1000; i += 1) - { - OutputDebugStringA("Hello, this is a long string which is being output in loop #4.\n"); - } - return 0; + } diff --git a/src/task_system/task_system.c b/src/task_system/task_system.c new file mode 100644 index 00000000..98571094 --- /dev/null +++ b/src/task_system/task_system.c @@ -0,0 +1,218 @@ +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal TS_Ticket +ts_ticket_zero(void) +{ + TS_Ticket ticket = {0}; + return ticket; +} + +internal void +ts_ticket_list_push(Arena *arena, TS_TicketList *list, TS_Ticket ticket) +{ + TS_TicketNode *n = push_array(arena, TS_TicketNode, 1); + n->v = ticket; + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +//////////////////////////////// +//~ rjf: Top-Level Layer Initialization + +internal void +ts_init(void) +{ + Arena *arena = arena_alloc(); + ts_shared = push_array(arena, TS_Shared, 1); + ts_shared->arena = arena; + ts_shared->artifact_slots_count = 1024; + ts_shared->artifact_stripes_count = Min(ts_shared->artifact_slots_count, os_logical_core_count()); + ts_shared->artifact_slots = push_array(arena, TS_TaskArtifactSlot, ts_shared->artifact_slots_count); + ts_shared->artifact_stripes = push_array(arena, TS_TaskArtifactStripe, ts_shared->artifact_stripes_count); + for(U64 idx = 0; idx < ts_shared->artifact_stripes_count; idx += 1) + { + ts_shared->artifact_stripes[idx].arena = arena_alloc(); + ts_shared->artifact_stripes[idx].cv = os_condition_variable_alloc(); + ts_shared->artifact_stripes[idx].rw_mutex = os_rw_mutex_alloc(); + } + ts_shared->u2t_ring_size = MB(1); + ts_shared->u2t_ring_base = push_array_no_zero(arena, U8, ts_shared->u2t_ring_size); + ts_shared->u2t_ring_mutex = os_mutex_alloc(); + ts_shared->u2t_ring_cv = os_condition_variable_alloc(); + ts_shared->task_threads_count = os_logical_core_count()-1; + ts_shared->task_threads = push_array(arena, TS_TaskThread, ts_shared->task_threads_count); + for(U64 idx = 0; idx < ts_shared->task_threads_count; idx += 1) + { + ts_shared->task_threads[idx].arena = arena_alloc(); + ts_shared->task_threads[idx].thread = os_launch_thread(ts_task_thread__entry_point, (void *)idx, 0); + } +} + +//////////////////////////////// +//~ rjf: Top-Level Accessors + +internal U64 +ts_thread_count(void) +{ + return ts_shared->task_threads_count; +} + +//////////////////////////////// +//~ rjf: High-Level Task Kickoff / Joining + +internal TS_Ticket +ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p) +{ + // rjf: obtain number & slot/stripefor next artifact + U64 artifact_num = ins_atomic_u64_inc_eval(&ts_shared->artifact_num_gen); + U64 slot_idx = artifact_num%ts_shared->artifact_slots_count; + U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count; + TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx]; + TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx]; + + // rjf: allocate artifact + TS_TaskArtifact *artifact = 0; + OS_MutexScopeW(stripe->rw_mutex) + { + artifact = stripe->free_artifact; + if(artifact != 0) + { + SLLStackPop(stripe->free_artifact); + } + else + { + artifact = push_array_no_zero(stripe->arena, TS_TaskArtifact, 1); + } + artifact->num = artifact_num; + artifact->task_is_done = 0; + artifact->result = 0; + } + + // rjf: form ticket out of artifact info + TS_Ticket ticket = {artifact_num, (U64)artifact}; + + // rjf: push task info to task ring buffer + OS_MutexScope(ts_shared->u2t_ring_mutex) for(;;) + { + U64 unconsumed_size = ts_shared->u2t_ring_write_pos - ts_shared->u2t_ring_read_pos; + U64 available_size = ts_shared->u2t_ring_size-unconsumed_size; + if(available_size >= sizeof(entry_point) + sizeof(p) + sizeof(ticket)) + { + Arena *task_arena = 0; + if(optional_arena_ptr != 0) + { + task_arena = *optional_arena_ptr; + } + ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &entry_point); + ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &task_arena); + ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &p); + ts_shared->u2t_ring_write_pos += ring_write_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_write_pos, &ticket); + if(optional_arena_ptr != 0) + { + *optional_arena_ptr = 0; + } + break; + } + os_condition_variable_wait(ts_shared->u2t_ring_cv, ts_shared->u2t_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ts_shared->u2t_ring_cv); + + return ticket; +} + +internal void * +ts_join(TS_Ticket ticket, U64 endt_us) +{ + void *result = 0; + U64 artifact_num = ticket.u64[0]; + U64 slot_idx = artifact_num%ts_shared->artifact_slots_count; + U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count; + TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx]; + TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx]; + TS_TaskArtifact *artifact = (TS_TaskArtifact *)ticket.u64[1]; + if(artifact != 0) + { + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + B64 task_is_done = artifact->task_is_done; + if(task_is_done) + { + OS_MutexScopeRWPromote(stripe->rw_mutex) + { + result = artifact->result; + SLLStackPush(stripe->free_artifact, artifact); + } + break; + } + if(os_now_microseconds() >= endt_us) + { + break; + } + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Task Threads + +internal void +ts_u2t_dequeue_task(TS_TaskFunctionType **entry_point_out, Arena **arena_out, void **p_out, TS_Ticket *ticket_out) +{ + OS_MutexScope(ts_shared->u2t_ring_mutex) for(;;) + { + U64 unconsumed_size = ts_shared->u2t_ring_write_pos - ts_shared->u2t_ring_read_pos; + if(unconsumed_size >= sizeof(*entry_point_out) + sizeof(*p_out) + sizeof(*ticket_out)) + { + ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, entry_point_out); + ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, arena_out); + ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, p_out); + ts_shared->u2t_ring_read_pos += ring_read_struct(ts_shared->u2t_ring_base, ts_shared->u2t_ring_size, ts_shared->u2t_ring_read_pos, ticket_out); + break; + } + os_condition_variable_wait(ts_shared->u2t_ring_cv, ts_shared->u2t_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ts_shared->u2t_ring_cv); +} + +internal void +ts_task_thread__entry_point(void *p) +{ + U64 thread_idx = (U64)p; + ThreadNameF("[ts] task thread #%I64u", thread_idx); + TS_TaskThread *thread = &ts_shared->task_threads[thread_idx]; + for(;;) + { + //- rjf: grab next task + TS_TaskFunctionType *task_function = 0; + Arena *task_arena = 0; + void *task_params = 0; + TS_Ticket task_ticket = {0}; + ts_u2t_dequeue_task(&task_function, &task_arena, &task_params, &task_ticket); + + //- rjf: use task thread's arena if none specified + if(task_arena == 0) + { + task_arena = thread->arena; + } + + //- rjf: run task + void *task_result = task_function(task_arena, thread_idx, task_params); + + //- rjf: store into artifact + U64 artifact_num = task_ticket.u64[0]; + U64 slot_idx = artifact_num%ts_shared->artifact_slots_count; + U64 stripe_idx = slot_idx%ts_shared->artifact_stripes_count; + TS_TaskArtifactSlot *slot = &ts_shared->artifact_slots[slot_idx]; + TS_TaskArtifactStripe *stripe = &ts_shared->artifact_stripes[stripe_idx]; + TS_TaskArtifact *artifact = (TS_TaskArtifact *)task_ticket.u64[1]; + OS_MutexScopeW(stripe->rw_mutex) + { + artifact->task_is_done = 1; + artifact->result = task_result; + } + os_condition_variable_broadcast(stripe->cv); + } +} diff --git a/src/task_system/task_system.h b/src/task_system/task_system.h new file mode 100644 index 00000000..d8a705eb --- /dev/null +++ b/src/task_system/task_system.h @@ -0,0 +1,140 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef TASK_SYSTEM_H +#define TASK_SYSTEM_H + +//////////////////////////////// +//~ rjf: Task "Ticket" Type +// +// "Tickets" are opaque handles, used to refer to submitted tasks. +// + +typedef struct TS_Ticket TS_Ticket; +struct TS_Ticket +{ + U64 u64[2]; +}; + +typedef struct TS_TicketNode TS_TicketNode; +struct TS_TicketNode +{ + TS_TicketNode *next; + TS_Ticket v; +}; + +typedef struct TS_TicketList TS_TicketList; +struct TS_TicketList +{ + TS_TicketNode *first; + TS_TicketNode *last; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Task Request Types + +#define TS_TASK_FUNCTION_DEF(name) void *name(Arena *arena, U64 thread_idx, void *p) +typedef TS_TASK_FUNCTION_DEF(TS_TaskFunctionType); + +//////////////////////////////// +//~ rjf: Task Artifact Cache Types + +typedef struct TS_TaskArtifact TS_TaskArtifact; +struct TS_TaskArtifact +{ + TS_TaskArtifact *next; + U64 num; + B64 task_is_done; + void *result; +}; + +typedef struct TS_TaskArtifactSlot TS_TaskArtifactSlot; +struct TS_TaskArtifactSlot +{ + TS_TaskArtifact *first; + TS_TaskArtifact *last; +}; + +typedef struct TS_TaskArtifactStripe TS_TaskArtifactStripe; +struct TS_TaskArtifactStripe +{ + Arena *arena; + OS_Handle cv; + OS_Handle rw_mutex; + TS_TaskArtifact *free_artifact; +}; + +//////////////////////////////// +//~ rjf: Per-Thread State + +typedef struct TS_TaskThread TS_TaskThread; +struct TS_TaskThread +{ + Arena *arena; + OS_Handle thread; +}; + +//////////////////////////////// +//~ rjf: Main Shared State + +typedef struct TS_Shared TS_Shared; +struct TS_Shared +{ + Arena *arena; + + // rjf: task artifact cache + U64 artifact_num_gen; + U64 artifact_slots_count; + U64 artifact_stripes_count; + TS_TaskArtifactSlot *artifact_slots; + TS_TaskArtifactStripe *artifact_stripes; + + // rjf: task ring buffer + U64 u2t_ring_size; + U8 *u2t_ring_base; + U64 u2t_ring_write_pos; + U64 u2t_ring_read_pos; + OS_Handle u2t_ring_mutex; + OS_Handle u2t_ring_cv; + + // rjf: task threads + TS_TaskThread *task_threads; + U64 task_threads_count; +}; + +//////////////////////////////// +//~ rjf: Globals + +global TS_Shared *ts_shared = 0; + +//////////////////////////////// +//~ rjf: Basic Type Functions + +internal TS_Ticket ts_ticket_zero(void); +internal void ts_ticket_list_push(Arena *arena, TS_TicketList *list, TS_Ticket ticket); + +//////////////////////////////// +//~ rjf: Top-Level Layer Initialization + +internal void ts_init(void); + +//////////////////////////////// +//~ rjf: Top-Level Accessors + +internal U64 ts_thread_count(void); + +//////////////////////////////// +//~ rjf: High-Level Task Kickoff / Joining + +internal TS_Ticket ts_kickoff(TS_TaskFunctionType *entry_point, Arena **optional_arena_ptr, void *p); +internal void *ts_join(TS_Ticket ticket, U64 endt_us); +#define ts_join_struct(ticket, endt_us, type) (type *)ts_join((ticket), (endt_us)) + +//////////////////////////////// +//~ rjf: Task Threads + +internal void ts_u2t_dequeue_task(TS_TaskFunctionType **entry_point_out, Arena **arena_out, void **p_out, TS_Ticket *ticket_out); +internal void ts_task_thread__entry_point(void *p); + +#endif // TASK_SYSTEM_H diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 9aca682a..a9a3ea43 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -26,9 +26,40 @@ txt_lang_kind_from_extension(String8 extension) { kind = TXT_LangKind_CPlusPlus; } + else if(str8_match(extension, str8_lit("odin"), StringMatchFlag_CaseInsensitive)) + { + kind = TXT_LangKind_Odin; + } return kind; } +internal TXT_LangKind +txt_lang_kind_from_architecture(Architecture arch) +{ + TXT_LangKind kind = TXT_LangKind_Null; + switch(arch) + { + default:{}break; + case Architecture_x64:{kind = TXT_LangKind_DisasmX64Intel;}break; + } + return kind; +} + +internal TXT_LangLexFunctionType * +txt_lex_function_from_lang_kind(TXT_LangKind kind) +{ + TXT_LangLexFunctionType *fn = 0; + switch(kind) + { + default:{}break; + case TXT_LangKind_C: {fn = txt_token_array_from_string__c_cpp;}break; + case TXT_LangKind_CPlusPlus: {fn = txt_token_array_from_string__c_cpp;}break; + case TXT_LangKind_Odin: {fn = txt_token_array_from_string__odin;}break; + case TXT_LangKind_DisasmX64Intel:{fn = txt_token_array_from_string__disasm_x64_intel;}break; + } + return fn; +} + //////////////////////////////// //~ rjf: Token Type Functions @@ -195,7 +226,7 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S }break; case TXT_TokenKind_Numeric: { - 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 != '\''); }break; case TXT_TokenKind_String: { @@ -378,6 +409,410 @@ txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, S return result; } +internal TXT_TokenArray +txt_token_array_from_string__odin(Arena *arena, U64 *bytes_processed_counter, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: generate token list + TXT_TokenChunkList tokens = {0}; + { + B32 comment_is_single_line = 0; + B32 string_is_char = 0; + TXT_TokenKind active_token_kind = TXT_TokenKind_Null; + U64 active_token_start_idx = 0; + B32 escaped = 0; + B32 next_escaped = 0; + U64 byte_process_start_idx = 0; + for(U64 idx = 0; idx <= string.size;) + { + U8 byte = (idx+0 < string.size) ? (string.str[idx+0]) : 0; + U8 next_byte = (idx+1 < string.size) ? (string.str[idx+1]) : 0; + + // rjf: update counter + if(bytes_processed_counter != 0 && ((idx-byte_process_start_idx) >= 1000 || idx == string.size)) + { + ins_atomic_u64_add_eval(bytes_processed_counter, (idx-byte_process_start_idx)); + byte_process_start_idx = idx; + } + + // rjf: escaping + if(escaped && (byte != '\r' && byte != '\n')) + { + next_escaped = 0; + } + else if(!escaped && byte == '\\') + { + next_escaped = 1; + } + + // rjf: take starter, determine active token kind + if(active_token_kind == TXT_TokenKind_Null) + { + // rjf: use next bytes to start a new token + if(0){} + else if(char_is_space(byte)) { active_token_kind = TXT_TokenKind_Whitespace; } + else if(byte == '_' || + byte == '$' || + char_is_alpha(byte)) { active_token_kind = TXT_TokenKind_Identifier; } + else if(char_is_digit(byte, 10) || + (byte == '.' && + char_is_digit(next_byte, 10))) { active_token_kind = TXT_TokenKind_Numeric; } + else if(byte == '"') { active_token_kind = TXT_TokenKind_String; string_is_char = 0; } + else if(byte == '\'') { active_token_kind = TXT_TokenKind_String; string_is_char = 1; } + else if(byte == '/' && next_byte == '/') { active_token_kind = TXT_TokenKind_Comment; comment_is_single_line = 1; } + else if(byte == '/' && next_byte == '*') { active_token_kind = TXT_TokenKind_Comment; comment_is_single_line = 0; } + else if(byte == '~' || byte == '!' || + byte == '%' || byte == '^' || + byte == '&' || byte == '*' || + byte == '(' || byte == ')' || + byte == '-' || byte == '=' || + byte == '+' || byte == '[' || + byte == ']' || byte == '{' || + byte == '}' || byte == ':' || + byte == ';' || byte == ',' || + byte == '.' || byte == '<' || + byte == '>' || byte == '/' || + byte == '?' || byte == '|') { active_token_kind = TXT_TokenKind_Symbol; } + else if(byte == '#') { active_token_kind = TXT_TokenKind_Meta; } + + // rjf: start new token + if(active_token_kind != TXT_TokenKind_Null) + { + active_token_start_idx = idx; + } + + // rjf: invalid token kind -> emit error + else + { + TXT_Token token = {TXT_TokenKind_Error, r1u64(idx, idx+1)}; + txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + } + } + + // rjf: look for ender + U64 ender_pad = 0; + B32 ender_found = 0; + if(active_token_kind != TXT_TokenKind_Null && idx>active_token_start_idx) + { + if(idx == string.size) + { + ender_pad = 0; + ender_found = 1; + } + else switch(active_token_kind) + { + default:break; + case TXT_TokenKind_Whitespace: + { + ender_found = !char_is_space(byte); + }break; + case TXT_TokenKind_Identifier: + { + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + }break; + case TXT_TokenKind_Numeric: + { + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '.' && byte != '\''); + }break; + case TXT_TokenKind_String: + { + ender_found = (!escaped && ((!string_is_char && byte == '"') || (string_is_char && byte == '\''))); + ender_pad += 1; + }break; + case TXT_TokenKind_Symbol: + { + ender_found = (byte != '~' && byte != '!' && + byte != '%' && byte != '^' && + byte != '&' && byte != '*' && + byte != '(' && byte != ')' && + byte != '-' && byte != '=' && + byte != '+' && byte != '[' && + byte != ']' && byte != '{' && + byte != '}' && byte != ':' && + byte != ';' && byte != ',' && + byte != '.' && byte != '<' && + byte != '>' && byte != '/' && + byte != '?' && byte != '|'); + }break; + case TXT_TokenKind_Comment: + { + if(comment_is_single_line) + { + ender_found = (!escaped && (byte == '\r' || byte == '\n')); + } + else + { + ender_found = (active_token_start_idx+1 < idx && byte == '*' && next_byte == '/'); + ender_pad += 2; + } + }break; + case TXT_TokenKind_Meta: + { + ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); + }break; + } + } + + // rjf: next byte is ender => emit token + if(ender_found) + { + TXT_Token token = {active_token_kind, r1u64(active_token_start_idx, idx+ender_pad)}; + active_token_kind = TXT_TokenKind_Null; + + // rjf: identifier -> keyword in special cases + if(token.kind == TXT_TokenKind_Identifier) + { + read_only local_persist String8 odin_keywords[] = + { + str8_lit_comp("asm"), + str8_lit_comp("auto_cast"), + str8_lit_comp("bit_set"), + str8_lit_comp("break"), + str8_lit_comp("case"), + str8_lit_comp("cast"), + str8_lit_comp("context"), + str8_lit_comp("continue"), + str8_lit_comp("defer"), + str8_lit_comp("distinct"), + str8_lit_comp("do"), + str8_lit_comp("dynamic"), + str8_lit_comp("else"), + str8_lit_comp("enum"), + str8_lit_comp("fallthrough"), + str8_lit_comp("for"), + str8_lit_comp("foreign"), + str8_lit_comp("if"), + str8_lit_comp("in"), + str8_lit_comp("map"), + str8_lit_comp("matrix"), + str8_lit_comp("not_in"), + str8_lit_comp("or_break"), + str8_lit_comp("or_continue"), + str8_lit_comp("or_else"), + str8_lit_comp("or_return"), + str8_lit_comp("package"), + str8_lit_comp("proc"), + str8_lit_comp("return"), + str8_lit_comp("struct"), + str8_lit_comp("switch"), + str8_lit_comp("transmute"), + str8_lit_comp("typeid"), + str8_lit_comp("union"), + str8_lit_comp("using"), + str8_lit_comp("when"), + str8_lit_comp("where"), + str8_lit_comp("import"), + }; + String8 token_string = str8_substr(string, r1u64(active_token_start_idx, idx+ender_pad)); + for(U64 keyword_idx = 0; keyword_idx < ArrayCount(odin_keywords); keyword_idx += 1) + { + if(str8_match(odin_keywords[keyword_idx], token_string, 0)) + { + token.kind = TXT_TokenKind_Keyword; + break; + } + } + } + + // rjf: push + txt_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); + + // rjf: increment by ender padding + idx += ender_pad; + } + + // rjf: advance by 1 byte if we haven't found an ender + if(!ender_found) + { + idx += 1; + } + escaped = next_escaped; + } + } + + //- rjf: token list -> token array + TXT_TokenArray result = txt_token_array_from_chunk_list(arena, &tokens); + scratch_end(scratch); + return result; +} + +internal TXT_TokenArray +txt_token_array_from_string__disasm_x64_intel(Arena *arena, U64 *bytes_processed_counter, String8 string) +{ + Temp scratch = scratch_begin(&arena, 1); + + //- rjf: parse tokens + TXT_TokenChunkList tokens = {0}; + { + TXT_TokenKind active_token_kind = TXT_TokenKind_Null; + U64 active_token_start_off = 0; + U64 off = 0; + B32 escaped = 0; + B32 string_is_char = 0; + S32 brace_nest = 0; + for(U64 advance = 0; off <= string.size; off += advance) + { + U8 byte = (off+0 < string.size) ? string.str[off+0] : 0; + U8 next_byte = (off+1 < string.size) ? string.str[off+1] : 0; + B32 ender_found = 0; + advance = (active_token_kind != TXT_TokenKind_Null ? 1 : 0); + if(off == string.size && active_token_kind != TXT_TokenKind_Null) + { + ender_found = 1; + advance = 1; + } + switch(active_token_kind) + { + default: + case TXT_TokenKind_Null: + { + if(byte == ' ' || byte == '\t' || byte == '\v' || byte == '\f' || byte == '\r' || byte == '\n') + { + active_token_start_off = off; + active_token_kind = TXT_TokenKind_Whitespace; + advance = 1; + } + else if(('a' <= byte && byte <= 'z') || ('A' <= byte && byte <= 'Z') || byte == '_') + { + active_token_start_off = off; + active_token_kind = TXT_TokenKind_Keyword; + advance = 1; + } + else if(byte == '\'') + { + active_token_start_off = off; + active_token_kind = TXT_TokenKind_String; + advance = 1; + string_is_char = 1; + } + else if(byte == '"') + { + active_token_start_off = off; + active_token_kind = TXT_TokenKind_String; + advance = 1; + string_is_char = 0; + } + else if(('0' <= byte && byte <= '9') || (byte == '.' && '0' <= next_byte && next_byte <= '9')) + { + active_token_start_off = off; + active_token_kind = TXT_TokenKind_Numeric; + advance = 1; + } + else if(byte == '~' || byte == '!' || byte == '%' || byte == '^' || + byte == '&' || byte == '*' || byte == '(' || byte == ')' || + byte == '-' || byte == '=' || byte == '+' || byte == '[' || + byte == ']' || byte == '{' || byte == '}' || byte == ';' || + byte == ':' || byte == '?' || byte == '/' || byte == '<' || + byte == '>' || byte == ',' || byte == '.') + { + active_token_start_off = off; + active_token_kind = TXT_TokenKind_Symbol; + advance = 1; + if(byte == '{') + { + brace_nest += 1; + } + else if(byte == '}') + { + brace_nest -= 1; + } + } + else + { + active_token_start_off = off; + active_token_kind = TXT_TokenKind_Error; + advance = 1; + } + }break; + case TXT_TokenKind_Whitespace: + if(byte != ' ' && byte != '\t' && byte != '\v' && byte != '\f') + { + ender_found = 1; + advance = 0; + }break; + case TXT_TokenKind_Keyword: + if((byte < 'a' || 'z' < byte) && (byte < 'A' || 'Z' < byte) && (byte < '0' || '9' < byte) && byte != '_') + { + ender_found = 1; + advance = 0; + }break; + case TXT_TokenKind_String: + { + U8 ender_byte = string_is_char ? '\'' : '"'; + if(!escaped && byte == ender_byte) + { + ender_found = 1; + advance = 1; + } + else if(escaped) + { + escaped = 0; + advance = 1; + } + else if(byte == '\\') + { + escaped = 1; + advance = 1; + } + else + { + U8 byte_class = utf8_class[byte>>3]; + if(byte_class > 1) + { + advance = (U64)byte_class; + } + } + }break; + case TXT_TokenKind_Numeric: + if((byte < 'a' || 'z' < byte) && (byte < 'A' || 'Z' < byte) && (byte < '0' || '9' < byte) && byte != '.') + { + ender_found = 1; + advance = 0; + }break; + case TXT_TokenKind_Symbol: + if(1) + { + // NOTE(rjf): avoiding maximum munch rule for now + ender_found = 1; + advance = 0; + } + else if(byte != '~' && byte != '!' && byte != '#' && byte != '%' && + byte != '^' && byte != '&' && byte != '*' && byte != '(' && + byte != ')' && byte != '-' && byte != '=' && byte != '+' && + byte != '[' && byte != ']' && byte != '{' && byte != '}' && + byte != ';' && byte != ':' && byte != '?' && byte != '/' && + byte != '<' && byte != '>' && byte != ',' && byte != '.') + { + ender_found = 1; + advance = 0; + }break; + case TXT_TokenKind_Error: + { + ender_found = 1; + advance = 0; + }break; + } + if(ender_found != 0) + { + if(brace_nest != 0 && active_token_kind == TXT_TokenKind_Keyword) + { + active_token_kind = TXT_TokenKind_Numeric; + } + TXT_Token token = {active_token_kind, r1u64(active_token_start_off, off+advance)}; + txt_token_chunk_list_push(arena, &tokens, 1024, &token); + active_token_kind = TXT_TokenKind_Null; + active_token_start_off = token.range.max; + } + } + } + + //- rjf: token list -> token array + TXT_TokenArray result = txt_token_array_from_chunk_list(arena, &tokens); + scratch_end(scratch); + return result; +} + //////////////////////////////// //~ rjf: Main Layer Initialization @@ -389,7 +824,7 @@ txt_init(void) txt_shared->arena = arena; txt_shared->slots_count = 1024; txt_shared->slots = push_array(arena, TXT_Slot, txt_shared->slots_count); - txt_shared->stripes_count = 64; + txt_shared->stripes_count = Min(txt_shared->slots_count, os_logical_core_count()); txt_shared->stripes = push_array(arena, TXT_Stripe, txt_shared->stripes_count); txt_shared->stripes_free_nodes = push_array(arena, TXT_Node *, txt_shared->stripes_count); for(U64 idx = 0; idx < txt_shared->stripes_count; idx += 1) @@ -398,16 +833,6 @@ txt_init(void) txt_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); txt_shared->stripes[idx].cv = os_condition_variable_alloc(); } - txt_shared->fallback_slots_count = 256; - txt_shared->fallback_stripes_count = 16; - txt_shared->fallback_slots = push_array(arena, TXT_KeyFallbackSlot, txt_shared->fallback_slots_count); - txt_shared->fallback_stripes = push_array(arena, TXT_Stripe, txt_shared->fallback_stripes_count); - for(U64 idx = 0; idx < txt_shared->fallback_stripes_count; idx += 1) - { - txt_shared->fallback_stripes[idx].arena = arena_alloc(); - txt_shared->fallback_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - txt_shared->fallback_stripes[idx].cv = os_condition_variable_alloc(); - } txt_shared->u2p_ring_size = KB(64); txt_shared->u2p_ring_base = push_array_no_zero(arena, U8, txt_shared->u2p_ring_size); txt_shared->u2p_ring_cv = os_condition_variable_alloc(); @@ -485,7 +910,7 @@ txt_scope_close(TXT_Scope *scope) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { - if(u128_match(hash, n->hash)) + if(u128_match(hash, n->hash) && touch->lang == n->lang) { ins_atomic_u64_dec_eval(&n->scope_ref_count); break; @@ -514,6 +939,7 @@ txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node *node) } MemoryZeroStruct(touch); touch->hash = node->hash; + touch->lang = node->lang; SLLStackPush(scope->top_touch, touch); } @@ -521,7 +947,7 @@ txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node *node) //~ rjf: Cache Lookups internal TXT_TextInfo -txt_text_info_from_key_hash_lang(TXT_Scope *scope, U128 key, U128 hash, TXT_LangKind lang) +txt_text_info_from_hash_lang(TXT_Scope *scope, U128 hash, TXT_LangKind lang) { TXT_TextInfo info = {0}; if(!u128_match(hash, u128_zero())) @@ -538,6 +964,8 @@ txt_text_info_from_key_hash_lang(TXT_Scope *scope, U128 key, U128 hash, TXT_Lang if(u128_match(hash, n->hash) && n->lang == lang) { MemoryCopyStruct(&info, &n->info); + info.bytes_processed = ins_atomic_u64_eval(&n->info.bytes_processed); + info.bytes_to_process = ins_atomic_u64_eval(&n->info.bytes_to_process); found = 1; txt_scope_touch_node__stripe_r_guarded(scope, n); break; @@ -579,63 +1007,343 @@ txt_text_info_from_key_hash_lang(TXT_Scope *scope, U128 key, U128 hash, TXT_Lang } if(node_is_new) { - txt_u2p_enqueue_req(key, hash, lang, max_U64); + txt_u2p_enqueue_req(hash, lang, max_U64); } - if(!found) + } + return info; +} + +internal TXT_TextInfo +txt_text_info_from_key_lang(TXT_Scope *scope, U128 key, TXT_LangKind lang, U128 *hash_out) +{ + TXT_TextInfo result = {0}; + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) + { + U128 hash = hs_hash_from_key(key, rewind_idx); + result = txt_text_info_from_hash_lang(scope, hash, lang); + if(result.lines_count != 0) { - U128 fallback_hash = {0}; - TXT_LangKind fallback_lang = TXT_LangKind_Null; - U64 fallback_slot_idx = key.u64[1]%txt_shared->fallback_slots_count; - U64 fallback_stripe_idx = fallback_slot_idx%txt_shared->fallback_stripes_count; - TXT_KeyFallbackSlot *fallback_slot = &txt_shared->fallback_slots[fallback_slot_idx]; - TXT_Stripe *fallback_stripe = &txt_shared->fallback_stripes[fallback_stripe_idx]; - OS_MutexScopeR(fallback_stripe->rw_mutex) for(TXT_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) + if(hash_out) { - if(u128_match(key, n->key)) - { - fallback_hash = n->hash; - break; - } + *hash_out = hash; } - if(!u128_match(fallback_hash, u128_zero())) + break; + } + } + return result; +} + +//////////////////////////////// +//~ rjf: Text Info Extractor Helpers + +internal U64 +txt_off_from_info_pt(TXT_TextInfo *info, TxtPt pt) +{ + U64 off = 0; + if(1 <= pt.line && pt.line <= info->lines_count) + { + Rng1U64 line_range = info->lines_ranges[pt.line-1]; + off = line_range.min + (pt.column-1); + } + return off; +} + +internal TxtPt +txt_pt_from_info_off__linear_scan(TXT_TextInfo *info, U64 off) +{ + TxtPt pt = {0}; + { + for(U64 line_idx = 0; line_idx < info->lines_count; line_idx += 1) + { + if(contains_1u64(info->lines_ranges[line_idx], off)) { - U64 retry_slot_idx = fallback_hash.u64[1]%txt_shared->slots_count; - U64 retry_stripe_idx = retry_slot_idx%txt_shared->stripes_count; - TXT_Slot *retry_slot = &txt_shared->slots[retry_slot_idx]; - TXT_Stripe *retry_stripe = &txt_shared->stripes[retry_stripe_idx]; - OS_MutexScopeR(retry_stripe->rw_mutex) + pt.line = (S64)line_idx + 1; + pt.column = (S64)(off - info->lines_ranges[line_idx].min) + 1; + } + } + } + return pt; +} + +internal TXT_TokenArray +txt_token_array_from_info_line_num__linear_scan(TXT_TextInfo *info, S64 line_num) +{ + TXT_TokenArray line_tokens = {0}; + if(1 <= line_num && line_num <= info->lines_count) + { + Rng1U64 line_range = info->lines_ranges[line_num-1]; + for(U64 token_idx = 0; token_idx < info->tokens.count; token_idx += 1) + { + Rng1U64 token_range = info->tokens.v[token_idx].range; + Rng1U64 token_x_line = intersect_1u64(token_range, line_range); + if(token_x_line.max > token_x_line.min) + { + if(line_tokens.v == 0) { - for(TXT_Node *n = retry_slot->first; n != 0; n = n->next) + line_tokens.v = info->tokens.v+token_idx; + } + line_tokens.count += 1; + } + else if(line_tokens.v != 0) + { + break; + } + } + } + return line_tokens; +} + +internal Rng1U64 +txt_expr_off_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens) +{ + Rng1U64 result = {0}; + Temp scratch = scratch_begin(0, 0); + { + // rjf: unpack line info + TXT_Token *line_tokens_first = line_tokens->v; + TXT_Token *line_tokens_opl = line_tokens->v+line_tokens->count; + + // rjf: find token containing `off` + TXT_Token *pt_token = 0; + for(TXT_Token *token = line_tokens_first; + token < line_tokens_opl; + token += 1) + { + if(contains_1u64(token->range, off)) + { + Rng1U64 token_range_clamped = intersect_1u64(line_range, token->range); + String8 token_string = str8_substr(line_text, r1u64(token_range_clamped.max - line_range.min, token_range_clamped.max - line_range.min)); + B32 token_ender = 0; + switch(token->kind) + { + default:{}break; + case TXT_TokenKind_Symbol: { - if(u128_match(fallback_hash, n->hash) && fallback_lang == n->lang) + token_ender = (str8_match(token_string, str8_lit("]"), 0)); + }break; + case TXT_TokenKind_Identifier: + case TXT_TokenKind_Keyword: + case TXT_TokenKind_String: + case TXT_TokenKind_Meta: + { + token_ender = 1; + }break; + } + if(token_ender) + { + pt_token = token; + } + break; + } + } + + // rjf: found token containing `off`? -> mark that as our initial range + if(pt_token != 0) + { + result = pt_token->range; + } + + // rjf: walk back from pt_token - try to find plausible start of expression + if(pt_token != 0) + { + B32 walkback_done = 0; + S32 nest = 0; + for(TXT_Token *wb_token = pt_token; + wb_token >= line_tokens_first && walkback_done == 0; + wb_token -= 1) + { + Rng1U64 wb_token_range_clamped = intersect_1u64(line_range, wb_token->range); + String8 wb_token_string = str8_substr(line_text, r1u64(wb_token_range_clamped.min - line_range.min, wb_token_range_clamped.max - line_range.min)); + B32 include_wb_token = 0; + switch(wb_token->kind) + { + default:{}break; + case TXT_TokenKind_Symbol: + { + B32 is_scope_resolution = str8_match(wb_token_string, str8_lit("::"), 0); + B32 is_dot = str8_match(wb_token_string, str8_lit("."), 0); + B32 is_arrow = str8_match(wb_token_string, str8_lit("->"), 0); + B32 is_open_bracket = str8_match(wb_token_string, str8_lit("["), 0); + B32 is_close_bracket = str8_match(wb_token_string, str8_lit("]"), 0); + nest -= !!(is_open_bracket); + nest += !!(is_close_bracket); + if(is_scope_resolution || + is_dot || + is_arrow || + is_open_bracket|| + is_close_bracket) { - MemoryCopyStruct(&info, &n->info); - txt_scope_touch_node__stripe_r_guarded(scope, n); - break; + include_wb_token = 1; } - } + }break; + case TXT_TokenKind_Identifier: + { + include_wb_token = 1; + }break; + } + if(include_wb_token) + { + result = union_1u64(result, wb_token->range); + } + else if(nest == 0) + { + walkback_done = 1; } } } } - return info; + scratch_end(scratch); + return result; +} + +internal Rng1U64 +txt_expr_off_range_from_info_data_pt(TXT_TextInfo *info, String8 data, TxtPt pt) +{ + Rng1U64 result = {0}; + Temp scratch = scratch_begin(0, 0); + if(1 <= pt.line && pt.line <= info->lines_count) + { + // rjf: unpack line info + Rng1U64 line_range = info->lines_ranges[pt.line-1]; + String8 line_text = str8_substr(data, line_range); + TXT_LineTokensSlice line_tokens_slice = txt_line_tokens_slice_from_info_data_line_range(scratch.arena, info, data, r1s64(pt.line, pt.line)); + TXT_TokenArray line_tokens = line_tokens_slice.line_tokens[0]; + TXT_Token *line_tokens_first = line_tokens.v; + TXT_Token *line_tokens_opl = line_tokens.v+line_tokens.count; + U64 pt_off = line_range.min + (pt.column-1); + + // rjf: grab offset range of expression + result = txt_expr_off_range_from_line_off_range_string_tokens(pt_off, line_range, line_text, &line_tokens); + } + scratch_end(scratch); + return result; +} + +internal String8 +txt_string_from_info_data_txt_rng(TXT_TextInfo *info, String8 data, TxtRng rng) +{ + Rng1U64 rng_off = r1u64(txt_off_from_info_pt(info, rng.min), txt_off_from_info_pt(info, rng.max)); + String8 result = str8_substr(data, rng_off); + return result; +} + +internal String8 +txt_string_from_info_data_line_num(TXT_TextInfo *info, String8 data, S64 line_num) +{ + String8 result = {0}; + if(1 <= line_num && line_num <= info->lines_count) + { + result = str8_substr(data, info->lines_ranges[line_num-1]); + } + return result; +} + +internal TXT_LineTokensSlice +txt_line_tokens_slice_from_info_data_line_range(Arena *arena, TXT_TextInfo *info, String8 data, Rng1S64 line_range) +{ + TXT_LineTokensSlice result = {0}; + Temp scratch = scratch_begin(&arena, 1); + if(info->lines_count != 0) + { + Rng1S64 line_range_clamped = r1s64(Clamp(1, line_range.min, (S64)info->lines_count), Clamp(1, line_range.max, (S64)info->lines_count)); + U64 line_count = (U64)dim_1s64(line_range_clamped)+1; + + // rjf: allocate output arrays + result.line_tokens = push_array(arena, TXT_TokenArray, line_count); + + // rjf: binary search to find first token + TXT_Token *tokens_first = 0; + ProfScope("binary search to find first token") + { + Rng1U64 slice_range = r1u64(info->lines_ranges[line_range_clamped.min-1].min, info->lines_ranges[line_range_clamped.max-1].max); + U64 min_idx = 0; + U64 opl_idx = info->tokens.count; + for(;;) + { + U64 mid_idx = (opl_idx+min_idx)/2; + if(mid_idx >= opl_idx) + { + break; + } + TXT_Token *mid_token = &info->tokens.v[mid_idx]; + if(mid_token->range.min > slice_range.max) + { + opl_idx = mid_idx; + } + else if(mid_token->range.max < slice_range.min) + { + min_idx = mid_idx; + } + else if(tokens_first == 0 || mid_token->range.min < tokens_first->range.min) + { + tokens_first = mid_token; + opl_idx = mid_idx; + } + if(mid_idx == min_idx && mid_idx+1 == opl_idx) + { + break; + } + } + } + + // rjf: grab per-line tokens + TXT_TokenList *line_tokens_lists = push_array(scratch.arena, TXT_TokenList, line_count); + if(tokens_first != 0) ProfScope("grab per-line tokens") + { + TXT_Token *tokens_opl = info->tokens.v+info->tokens.count; + U64 line_slice_idx = 0; + for(TXT_Token *token = tokens_first; token < tokens_opl && line_slice_idx < line_count;) + { + if(token->range.min < info->lines_ranges[line_slice_idx+line_range.min-1].max) + { + if(token->range.max > info->lines_ranges[line_slice_idx+line_range.min-1].min) + { + txt_token_list_push(scratch.arena, &line_tokens_lists[line_slice_idx], token); + } + B32 need_token_advance = 0; + B32 need_line_advance = 0; + if(token->range.max >= info->lines_ranges[line_slice_idx+line_range.min-1].max) + { + need_line_advance = 1; + } + if(token->range.max <= info->lines_ranges[line_slice_idx+line_range.min-1].max) + { + need_token_advance += 1; + } + if(need_line_advance) { line_slice_idx += 1; } + if(need_token_advance) { token += 1; } + } + else + { + line_slice_idx += 1; + } + } + } + + // rjf: bake per-line tokens to arrays + for(U64 line_slice_idx = 0; line_slice_idx < line_count; line_slice_idx += 1) + { + result.line_tokens[line_slice_idx] = txt_token_array_from_list(arena, &line_tokens_lists[line_slice_idx]); + } + } + scratch_end(scratch); + return result; } //////////////////////////////// //~ rjf: Transfer Threads internal B32 -txt_u2p_enqueue_req(U128 key, U128 hash, TXT_LangKind lang, U64 endt_us) +txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us) { B32 good = 0; OS_MutexScope(txt_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; U64 available_size = txt_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(key)+sizeof(hash)) + if(available_size >= sizeof(hash)+sizeof(lang)) { good = 1; - txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &key); txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &hash); txt_shared->u2p_ring_write_pos += ring_write_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_write_pos, &lang); break; @@ -654,14 +1362,13 @@ txt_u2p_enqueue_req(U128 key, U128 hash, TXT_LangKind lang, U64 endt_us) } internal void -txt_u2p_dequeue_req(U128 *key_out, U128 *hash_out, TXT_LangKind *lang_out) +txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out) { OS_MutexScope(txt_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = txt_shared->u2p_ring_write_pos - txt_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(*key_out) + sizeof(*hash_out)) + if(unconsumed_size >= sizeof(*hash_out) + sizeof(*lang_out)) { - txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, key_out); txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, hash_out); txt_shared->u2p_ring_read_pos += ring_read_struct(txt_shared->u2p_ring_base, txt_shared->u2p_ring_size, txt_shared->u2p_ring_read_pos, lang_out); break; @@ -674,17 +1381,13 @@ txt_u2p_dequeue_req(U128 *key_out, U128 *hash_out, TXT_LangKind *lang_out) internal void txt_parse_thread__entry_point(void *p) { - TCTX tctx_ = {0}; - tctx_init_and_equip(&tctx_); for(;;) { - HS_Scope *scope = hs_scope_open(); - //- rjf: get next key - U128 key = {0}; U128 hash = {0}; TXT_LangKind lang = TXT_LangKind_Null; - txt_u2p_dequeue_req(&key, &hash, &lang); + txt_u2p_dequeue_req(&hash, &lang); + HS_Scope *scope = hs_scope_open(); //- rjf: unpack hash U64 slot_idx = hash.u64[1]%txt_shared->slots_count; @@ -698,7 +1401,7 @@ txt_parse_thread__entry_point(void *p) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { - if(u128_match(n->hash, hash)) + if(u128_match(n->hash, hash) && n->lang == lang) { got_task = !ins_atomic_u32_eval_cond_assign(&n->is_working, 1, 0); break; @@ -720,6 +1423,28 @@ txt_parse_thread__entry_point(void *p) { info_arena = arena_alloc(); + //- rjf: grab pointers to working counters + U64 *bytes_processed_ptr = 0; + U64 *bytes_to_process_ptr = 0; + OS_MutexScopeR(stripe->rw_mutex) + { + for(TXT_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->hash, hash) && n->lang == lang) + { + bytes_processed_ptr = &n->info.bytes_processed; + bytes_to_process_ptr = &n->info.bytes_to_process; + } + } + } + + //- rjf: set # of bytes to process + if(bytes_to_process_ptr) + { + // (line ending calc) (line counting) (line measuring) (lexing) + ins_atomic_u64_eval_assign(bytes_to_process_ptr, Min(data.size, 1024) + data.size + data.size + data.size*(lang != TXT_LangKind_Null)); + } + //- rjf: detect line end kind TXT_LineEndKind line_end_kind = TXT_LineEndKind_Null; { @@ -747,6 +1472,12 @@ txt_parse_thread__entry_point(void *p) info.line_end_kind = line_end_kind; } + //- rjf: bump progress + if(bytes_processed_ptr) + { + ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024)); + } + //- rjf: count # of lines U64 line_count = 1; U64 byte_process_start_idx = 0; @@ -760,6 +1491,16 @@ txt_parse_thread__entry_point(void *p) idx += 1; } } + if(idx && idx%1000 == 0) + { + ins_atomic_u64_add_eval(bytes_processed_ptr, 1000); + } + } + + //- rjf: bump progress + if(bytes_processed_ptr) + { + ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size); } //- rjf: allocate & store line ranges @@ -783,27 +1524,34 @@ txt_parse_thread__entry_point(void *p) idx += 1; } } + if(idx && idx%1000 == 0) + { + ins_atomic_u64_add_eval(bytes_processed_ptr, 1000); + } + } + + //- rjf: bump progress + if(bytes_processed_ptr) + { + ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size + data.size); } //- rjf: lang -> lex function - TXT_LangLexFunctionType *lex_function = 0; - switch(lang) - { - default:{}break; - case TXT_LangKind_C: - case TXT_LangKind_CPlusPlus: - { - lex_function = txt_token_array_from_string__c_cpp; - }break; - } + TXT_LangLexFunctionType *lex_function = txt_lex_function_from_lang_kind(lang); //- rjf: lex function * data -> tokens TXT_TokenArray tokens = {0}; if(lex_function != 0) { - tokens = lex_function(info_arena, 0, data); + tokens = lex_function(info_arena, bytes_processed_ptr, data); } info.tokens = tokens; + + //- rjf: bump progress + if(bytes_processed_ptr) + { + ins_atomic_u64_eval_assign(bytes_processed_ptr, Min(data.size, 1024) + data.size + data.size + data.size*(lex_function != 0)); + } } //- rjf: commit results to cache @@ -811,9 +1559,11 @@ txt_parse_thread__entry_point(void *p) { for(TXT_Node *n = slot->first; n != 0; n = n->next) { - if(u128_match(n->hash, hash)) + if(u128_match(n->hash, hash) && n->lang == lang) { n->arena = info_arena; + info.bytes_processed = n->info.bytes_processed; + info.bytes_to_process = n->info.bytes_to_process; MemoryCopyStruct(&n->info, &info); ins_atomic_u32_eval_assign(&n->is_working, 0); ins_atomic_u64_inc_eval(&n->load_count); @@ -822,34 +1572,6 @@ txt_parse_thread__entry_point(void *p) } } - //- rjf: commit this key/hash pair to fallback cache - if(got_task && !u128_match(key, u128_zero()) && !u128_match(hash, u128_zero())) - { - U64 fallback_slot_idx = key.u64[1]%txt_shared->fallback_slots_count; - U64 fallback_stripe_idx = fallback_slot_idx%txt_shared->fallback_stripes_count; - TXT_KeyFallbackSlot *fallback_slot = &txt_shared->fallback_slots[fallback_slot_idx]; - TXT_Stripe *fallback_stripe = &txt_shared->fallback_stripes[fallback_stripe_idx]; - OS_MutexScopeW(fallback_stripe->rw_mutex) - { - TXT_KeyFallbackNode *node = 0; - for(TXT_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(fallback_stripe->arena, TXT_KeyFallbackNode, 1); - SLLQueuePush(fallback_slot->first, fallback_slot->last, node); - } - node->key = key; - node->hash = hash; - } - } - hs_scope_close(scope); } } diff --git a/src/text_cache/text_cache.h b/src/text_cache/text_cache.h index 3bced5bb..17b32ea9 100644 --- a/src/text_cache/text_cache.h +++ b/src/text_cache/text_cache.h @@ -32,15 +32,6 @@ typedef enum TXT_TokenKind } TXT_TokenKind; -typedef enum TXT_LangKind -{ - TXT_LangKind_Null, - TXT_LangKind_C, - TXT_LangKind_CPlusPlus, - TXT_LangKind_COUNT -} -TXT_LangKind; - typedef struct TXT_Token TXT_Token; struct TXT_Token { @@ -103,37 +94,51 @@ struct TXT_TextInfo U64 lines_max_size; TXT_LineEndKind line_end_kind; TXT_TokenArray tokens; + U64 bytes_processed; + U64 bytes_to_process; }; +typedef struct TXT_LineTokensSlice TXT_LineTokensSlice; +struct TXT_LineTokensSlice +{ + TXT_TokenArray *line_tokens; +}; + +//////////////////////////////// +//~ rjf: Language Kind Types + +typedef enum TXT_LangKind +{ + TXT_LangKind_Null, + TXT_LangKind_C, + TXT_LangKind_CPlusPlus, + TXT_LangKind_Odin, + TXT_LangKind_DisasmX64Intel, + TXT_LangKind_COUNT +} +TXT_LangKind; + typedef TXT_TokenArray TXT_LangLexFunctionType(Arena *arena, U64 *bytes_processed_counter, String8 string); //////////////////////////////// //~ rjf: Cache Types -typedef struct TXT_KeyFallbackNode TXT_KeyFallbackNode; -struct TXT_KeyFallbackNode -{ - TXT_KeyFallbackNode *next; - U128 key; - U128 hash; -}; - -typedef struct TXT_KeyFallbackSlot TXT_KeyFallbackSlot; -struct TXT_KeyFallbackSlot -{ - TXT_KeyFallbackNode *first; - TXT_KeyFallbackNode *last; -}; - typedef struct TXT_Node TXT_Node; struct TXT_Node { + // rjf: links TXT_Node *next; TXT_Node *prev; + + // rjf: key U128 hash; TXT_LangKind lang; + + // rjf: artifacts Arena *arena; TXT_TextInfo info; + + // rjf: metadata B32 is_working; U64 scope_ref_count; U64 last_time_touched_us; @@ -164,6 +169,7 @@ struct TXT_Touch { TXT_Touch *next; U128 hash; + TXT_LangKind lang; }; typedef struct TXT_Scope TXT_Scope; @@ -202,12 +208,6 @@ struct TXT_Shared TXT_Stripe *stripes; TXT_Node **stripes_free_nodes; - // rjf: fallback cache - U64 fallback_slots_count; - U64 fallback_stripes_count; - TXT_KeyFallbackSlot *fallback_slots; - TXT_Stripe *fallback_stripes; - // rjf: user -> parse thread U64 u2p_ring_size; U8 *u2p_ring_base; @@ -234,6 +234,8 @@ global TXT_Shared *txt_shared = 0; //~ rjf: Basic Helpers internal TXT_LangKind txt_lang_kind_from_extension(String8 extension); +internal TXT_LangKind txt_lang_kind_from_architecture(Architecture arch); +internal TXT_LangLexFunctionType *txt_lex_function_from_lang_kind(TXT_LangKind kind); //////////////////////////////// //~ rjf: Token Type Functions @@ -247,6 +249,8 @@ internal TXT_TokenArray txt_token_array_from_list(Arena *arena, TXT_TokenList *l //~ rjf: Lexing Functions internal TXT_TokenArray txt_token_array_from_string__c_cpp(Arena *arena, U64 *bytes_processed_counter, String8 string); +internal TXT_TokenArray txt_token_array_from_string__odin(Arena *arena, U64 *bytes_processed_counter, String8 string); +internal TXT_TokenArray txt_token_array_from_string__disasm_x64_intel(Arena *arena, U64 *bytes_processed_counter, String8 string); //////////////////////////////// //~ rjf: Main Layer Initialization @@ -274,13 +278,26 @@ internal void txt_scope_touch_node__stripe_r_guarded(TXT_Scope *scope, TXT_Node //////////////////////////////// //~ rjf: Cache Lookups -internal TXT_TextInfo txt_text_info_from_key_hash_lang(TXT_Scope *scope, U128 key, U128 hash, TXT_LangKind lang); +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); //////////////////////////////// -//~ rjf: Transfer Threads +//~ rjf: Text Info Extractor Helpers -internal B32 txt_u2p_enqueue_req(U128 key, U128 hash, TXT_LangKind lang, U64 endt_us); -internal void txt_u2p_dequeue_req(U128 *key_out, U128 *hash_out, TXT_LangKind *lang_out); +internal U64 txt_off_from_info_pt(TXT_TextInfo *info, TxtPt pt); +internal TxtPt txt_pt_from_info_off__linear_scan(TXT_TextInfo *info, U64 off); +internal TXT_TokenArray txt_token_array_from_info_line_num__linear_scan(TXT_TextInfo *info, S64 line_num); +internal Rng1U64 txt_expr_off_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens); +internal Rng1U64 txt_expr_off_range_from_info_data_pt(TXT_TextInfo *info, String8 data, TxtPt pt); +internal String8 txt_string_from_info_data_txt_rng(TXT_TextInfo *info, String8 data, TxtRng rng); +internal String8 txt_string_from_info_data_line_num(TXT_TextInfo *info, String8 data, S64 line_num); +internal TXT_LineTokensSlice txt_line_tokens_slice_from_info_data_line_range(Arena *arena, TXT_TextInfo *info, String8 data, Rng1S64 line_range); + +//////////////////////////////// +//~ rjf: Parse Threads + +internal B32 txt_u2p_enqueue_req(U128 hash, TXT_LangKind lang, U64 endt_us); +internal void txt_u2p_dequeue_req(U128 *hash_out, TXT_LangKind *lang_out); internal void txt_parse_thread__entry_point(void *p); //////////////////////////////// @@ -288,4 +305,4 @@ internal void txt_parse_thread__entry_point(void *p); internal void txt_evictor_thread__entry_point(void *p); -#endif //TEXT_CACHE_H +#endif // TEXT_CACHE_H diff --git a/src/texture_cache/texture_cache.c b/src/texture_cache/texture_cache.c index 18a606fa..300eda12 100644 --- a/src/texture_cache/texture_cache.c +++ b/src/texture_cache/texture_cache.c @@ -24,7 +24,7 @@ tex_init(void) tex_shared = push_array(arena, TEX_Shared, 1); tex_shared->arena = arena; tex_shared->slots_count = 1024; - tex_shared->stripes_count = 64; + tex_shared->stripes_count = Min(tex_shared->slots_count, os_logical_core_count()); tex_shared->slots = push_array(arena, TEX_Slot, tex_shared->slots_count); tex_shared->stripes = push_array(arena, TEX_Stripe, tex_shared->stripes_count); tex_shared->stripes_free_nodes = push_array(arena, TEX_Node *, tex_shared->stripes_count); @@ -34,16 +34,6 @@ tex_init(void) tex_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); tex_shared->stripes[idx].cv = os_condition_variable_alloc(); } - tex_shared->fallback_slots_count = 1024; - tex_shared->fallback_stripes_count = 64; - tex_shared->fallback_slots = push_array(arena, TEX_KeyFallbackSlot, tex_shared->fallback_slots_count); - tex_shared->fallback_stripes = push_array(arena, TEX_Stripe, tex_shared->fallback_stripes_count); - for(U64 idx = 0; idx < tex_shared->fallback_stripes_count; idx += 1) - { - tex_shared->fallback_stripes[idx].arena = arena_alloc(); - tex_shared->fallback_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - tex_shared->fallback_stripes[idx].cv = os_condition_variable_alloc(); - } tex_shared->u2x_ring_size = KB(64); tex_shared->u2x_ring_base = push_array_no_zero(arena, U8, tex_shared->u2x_ring_size); tex_shared->u2x_ring_cv = os_condition_variable_alloc(); @@ -158,10 +148,9 @@ tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node *node) //~ rjf: Cache Lookups internal R_Handle -tex_texture_from_key_hash_topology(TEX_Scope *scope, U128 key, U128 hash, TEX_Topology topology) +tex_texture_from_hash_topology(TEX_Scope *scope, U128 hash, TEX_Topology topology) { R_Handle handle = {0}; - if(!u128_match(u128_zero(), hash)) { U64 slot_idx = hash.u64[1]%tex_shared->slots_count; U64 stripe_idx = slot_idx%tex_shared->stripes_count; @@ -217,42 +206,23 @@ tex_texture_from_key_hash_topology(TEX_Scope *scope, U128 key, U128 hash, TEX_To } if(node_is_new) { - tex_u2x_enqueue_req(key, hash, topology, max_U64); + tex_u2x_enqueue_req(hash, topology, max_U64); } - if(r_handle_match(handle, r_handle_zero())) + } + return handle; +} + +internal R_Handle +tex_texture_from_key_topology(TEX_Scope *scope, U128 key, TEX_Topology topology) +{ + R_Handle handle = {0}; + for(U64 rewind_idx = 0; rewind_idx < 2; rewind_idx += 1) + { + U128 hash = hs_hash_from_key(key, rewind_idx); + handle = tex_texture_from_hash_topology(scope, hash, topology); + if(!r_handle_match(handle, r_handle_zero())) { - U128 fallback_hash = {0}; - U64 fallback_slot_idx = key.u64[1]%tex_shared->fallback_slots_count; - U64 fallback_stripe_idx = fallback_slot_idx%tex_shared->fallback_stripes_count; - TEX_KeyFallbackSlot *fallback_slot = &tex_shared->fallback_slots[fallback_slot_idx]; - TEX_Stripe *fallback_stripe = &tex_shared->fallback_stripes[fallback_stripe_idx]; - OS_MutexScopeR(fallback_stripe->rw_mutex) for(TEX_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) - { - if(u128_match(key, n->key)) - { - fallback_hash = n->hash; - break; - } - } - if(!u128_match(fallback_hash, u128_zero())) - { - U64 retry_slot_idx = fallback_hash.u64[1]%tex_shared->slots_count; - U64 retry_stripe_idx = retry_slot_idx%tex_shared->stripes_count; - TEX_Slot *retry_slot = &tex_shared->slots[retry_slot_idx]; - TEX_Stripe *retry_stripe = &tex_shared->stripes[retry_stripe_idx]; - OS_MutexScopeR(retry_stripe->rw_mutex) - { - for(TEX_Node *n = retry_slot->first; n != 0; n = n->next) - { - if(u128_match(fallback_hash, n->hash) && MemoryMatchStruct(&topology, &n->topology)) - { - handle = n->texture; - tex_scope_touch_node__stripe_r_guarded(scope, n); - break; - } - } - } - } + break; } } return handle; @@ -262,17 +232,16 @@ tex_texture_from_key_hash_topology(TEX_Scope *scope, U128 key, U128 hash, TEX_To //~ rjf: Transfer Threads internal B32 -tex_u2x_enqueue_req(U128 key, U128 hash, TEX_Topology top, U64 endt_us) +tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us) { B32 good = 0; OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; U64 available_size = tex_shared->u2x_ring_size-unconsumed_size; - if(available_size >= sizeof(key)+sizeof(hash)+sizeof(top)) + if(available_size >= sizeof(hash)+sizeof(top)) { good = 1; - tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &key); tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &hash); tex_shared->u2x_ring_write_pos += ring_write_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_write_pos, &top); break; @@ -291,14 +260,13 @@ tex_u2x_enqueue_req(U128 key, U128 hash, TEX_Topology top, U64 endt_us) } internal void -tex_u2x_dequeue_req(U128 *key_out, U128 *hash_out, TEX_Topology *top_out) +tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out) { OS_MutexScope(tex_shared->u2x_ring_mutex) for(;;) { U64 unconsumed_size = tex_shared->u2x_ring_write_pos-tex_shared->u2x_ring_read_pos; - if(unconsumed_size >= sizeof(*key_out)+sizeof(*hash_out)+sizeof(*top_out)) + if(unconsumed_size >= sizeof(*hash_out)+sizeof(*top_out)) { - tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, key_out); tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, hash_out); tex_shared->u2x_ring_read_pos += ring_read_struct(tex_shared->u2x_ring_base, tex_shared->u2x_ring_size, tex_shared->u2x_ring_read_pos, top_out); break; @@ -311,17 +279,14 @@ tex_u2x_dequeue_req(U128 *key_out, U128 *hash_out, TEX_Topology *top_out) internal void tex_xfer_thread__entry_point(void *p) { - TCTX tctx_ = {0}; - tctx_init_and_equip(&tctx_); for(;;) { HS_Scope *scope = hs_scope_open(); //- rjf: decode - U128 key = {0}; U128 hash = {0}; TEX_Topology top = {0}; - tex_u2x_dequeue_req(&key, &hash, &top); + tex_u2x_dequeue_req(&hash, &top); //- rjf: unpack hash U64 slot_idx = hash.u64[1]%tex_shared->slots_count; @@ -372,34 +337,6 @@ tex_xfer_thread__entry_point(void *p) } } - //- rjf: commit this key/hash pair to fallback cache - if(got_task && !u128_match(key, u128_zero()) && !u128_match(hash, u128_zero())) - { - U64 fallback_slot_idx = key.u64[1]%tex_shared->fallback_slots_count; - U64 fallback_stripe_idx = fallback_slot_idx%tex_shared->fallback_stripes_count; - TEX_KeyFallbackSlot *fallback_slot = &tex_shared->fallback_slots[fallback_slot_idx]; - TEX_Stripe *fallback_stripe = &tex_shared->fallback_stripes[fallback_stripe_idx]; - OS_MutexScopeW(fallback_stripe->rw_mutex) - { - TEX_KeyFallbackNode *node = 0; - for(TEX_KeyFallbackNode *n = fallback_slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(fallback_stripe->arena, TEX_KeyFallbackNode, 1); - SLLQueuePush(fallback_slot->first, fallback_slot->last, node); - } - node->key = key; - node->hash = hash; - } - } - hs_scope_close(scope); } } diff --git a/src/texture_cache/texture_cache.h b/src/texture_cache/texture_cache.h index 8245ccdd..ff8ac5a5 100644 --- a/src/texture_cache/texture_cache.h +++ b/src/texture_cache/texture_cache.h @@ -17,21 +17,6 @@ struct TEX_Topology //////////////////////////////// //~ rjf: Cache Types -typedef struct TEX_KeyFallbackNode TEX_KeyFallbackNode; -struct TEX_KeyFallbackNode -{ - TEX_KeyFallbackNode *next; - U128 key; - U128 hash; -}; - -typedef struct TEX_KeyFallbackSlot TEX_KeyFallbackSlot; -struct TEX_KeyFallbackSlot -{ - TEX_KeyFallbackNode *first; - TEX_KeyFallbackNode *last; -}; - typedef struct TEX_Node TEX_Node; struct TEX_Node { @@ -109,12 +94,6 @@ struct TEX_Shared TEX_Stripe *stripes; TEX_Node **stripes_free_nodes; - // rjf: fallback cache - U64 fallback_slots_count; - U64 fallback_stripes_count; - TEX_KeyFallbackSlot *fallback_slots; - TEX_Stripe *fallback_stripes; - // rjf: user -> xfer thread U64 u2x_ring_size; U8 *u2x_ring_base; @@ -168,13 +147,14 @@ internal void tex_scope_touch_node__stripe_r_guarded(TEX_Scope *scope, TEX_Node //////////////////////////////// //~ rjf: Cache Lookups -internal R_Handle tex_texture_from_key_hash_topology(TEX_Scope *scope, U128 key, U128 hash, TEX_Topology topology); +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); //////////////////////////////// //~ rjf: Transfer Threads -internal B32 tex_u2x_enqueue_req(U128 key, U128 hash, TEX_Topology top, U64 endt_us); -internal void tex_u2x_dequeue_req(U128 *key_out, U128 *hash_out, TEX_Topology *top_out); +internal B32 tex_u2x_enqueue_req(U128 hash, TEX_Topology top, U64 endt_us); +internal void tex_u2x_dequeue_req(U128 *hash_out, TEX_Topology *top_out); internal void tex_xfer_thread__entry_point(void *p); //////////////////////////////// diff --git a/src/txti/txti.c b/src/txti/txti.c index e8df7bed..9fc4cf06 100644 --- a/src/txti/txti.c +++ b/src/txti/txti.c @@ -47,622 +47,6 @@ txti_hash_from_string(String8 string) return result; } -internal TXTI_LangKind -txti_lang_kind_from_extension(String8 extension) -{ - TXTI_LangKind kind = TXTI_LangKind_Null; - if(str8_match(extension, str8_lit("c"), 0) || - str8_match(extension, str8_lit("h"), 0)) - { - kind = TXTI_LangKind_C; - } - else if(str8_match(extension, str8_lit("cpp"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("cxx"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("cc"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("c++"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("C"), 0) || - str8_match(extension, str8_lit("hpp"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("hxx"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("hh"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("h++"), StringMatchFlag_CaseInsensitive) || - str8_match(extension, str8_lit("H"), 0)) - { - kind = TXTI_LangKind_CPlusPlus; - } - else if(str8_match(extension, str8_lit("odin"), 0)) - { - kind = TXTI_LangKind_Odin; - } - return kind; -} - -//////////////////////////////// -//~ rjf: Token Type Functions - -internal void -txti_token_chunk_list_push(Arena *arena, TXTI_TokenChunkList *list, U64 cap, TXTI_Token *token) -{ - TXTI_TokenChunkNode *node = list->last; - if(node == 0 || node->count >= node->cap) - { - node = push_array(arena, TXTI_TokenChunkNode, 1); - SLLQueuePush(list->first, list->last, node); - node->cap = cap; - node->v = push_array_no_zero(arena, TXTI_Token, node->cap); - list->chunk_count += 1; - } - MemoryCopyStruct(&node->v[node->count], token); - node->count += 1; - list->token_count += 1; -} - -internal void -txti_token_list_push(Arena *arena, TXTI_TokenList *list, TXTI_Token *token) -{ - TXTI_TokenNode *node = push_array(arena, TXTI_TokenNode, 1); - MemoryCopyStruct(&node->v, token); - SLLQueuePush(list->first, list->last, node); - list->count += 1; -} - -internal TXTI_TokenArray -txti_token_array_from_chunk_list(Arena *arena, TXTI_TokenChunkList *list) -{ - TXTI_TokenArray array = {0}; - array.count = list->token_count; - array.v = push_array_no_zero(arena, TXTI_Token, array.count); - U64 idx = 0; - for(TXTI_TokenChunkNode *n = list->first; n != 0; n = n->next) - { - MemoryCopy(array.v+idx, n->v, n->count*sizeof(TXTI_Token)); - idx += n->count; - } - return array; -} - -internal TXTI_TokenArray -txti_token_array_from_list(Arena *arena, TXTI_TokenList *list) -{ - TXTI_TokenArray array = {0}; - array.count = list->count; - array.v = push_array_no_zero(arena, TXTI_Token, array.count); - U64 idx = 0; - for(TXTI_TokenNode *n = list->first; n != 0; n = n->next) - { - MemoryCopyStruct(array.v+idx, &n->v); - idx += 1; - } - return array; -} - -//////////////////////////////// -//~ rjf: Lexing Functions - -internal TXTI_TokenArray -txti_token_array_from_string__cpp(Arena *arena, U64 *bytes_processed_counter, String8 string) -{ - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: generate token list - TXTI_TokenChunkList tokens = {0}; - { - B32 comment_is_single_line = 0; - B32 string_is_char = 0; - TXTI_TokenKind active_token_kind = TXTI_TokenKind_Null; - U64 active_token_start_idx = 0; - B32 escaped = 0; - B32 next_escaped = 0; - U64 byte_process_start_idx = 0; - for(U64 idx = 0; idx <= string.size;) - { - U8 byte = (idx+0 < string.size) ? (string.str[idx+0]) : 0; - U8 next_byte = (idx+1 < string.size) ? (string.str[idx+1]) : 0; - - // rjf: update counter - if(bytes_processed_counter != 0 && ((idx-byte_process_start_idx) >= 1000 || idx == string.size)) - { - ins_atomic_u64_add_eval(bytes_processed_counter, (idx-byte_process_start_idx)); - byte_process_start_idx = idx; - } - - // rjf: escaping - if(escaped && (byte != '\r' && byte != '\n')) - { - next_escaped = 0; - } - else if(!escaped && byte == '\\') - { - next_escaped = 1; - } - - // rjf: take starter, determine active token kind - if(active_token_kind == TXTI_TokenKind_Null) - { - // rjf: use next bytes to start a new token - if(0){} - else if(char_is_space(byte)) { active_token_kind = TXTI_TokenKind_Whitespace; } - else if(byte == '_' || - byte == '$' || - char_is_alpha(byte)) { active_token_kind = TXTI_TokenKind_Identifier; } - else if(char_is_digit(byte, 10) || - (byte == '.' && - char_is_digit(next_byte, 10))) { active_token_kind = TXTI_TokenKind_Numeric; } - else if(byte == '"') { active_token_kind = TXTI_TokenKind_String; string_is_char = 0; } - else if(byte == '\'') { active_token_kind = TXTI_TokenKind_String; string_is_char = 1; } - else if(byte == '/' && next_byte == '/') { active_token_kind = TXTI_TokenKind_Comment; comment_is_single_line = 1; } - else if(byte == '/' && next_byte == '*') { active_token_kind = TXTI_TokenKind_Comment; comment_is_single_line = 0; } - else if(byte == '~' || byte == '!' || - byte == '%' || byte == '^' || - byte == '&' || byte == '*' || - byte == '(' || byte == ')' || - byte == '-' || byte == '=' || - byte == '+' || byte == '[' || - byte == ']' || byte == '{' || - byte == '}' || byte == ':' || - byte == ';' || byte == ',' || - byte == '.' || byte == '<' || - byte == '>' || byte == '/' || - byte == '?' || byte == '|') { active_token_kind = TXTI_TokenKind_Symbol; } - else if(byte == '#') { active_token_kind = TXTI_TokenKind_Meta; } - - // rjf: start new token - if(active_token_kind != TXTI_TokenKind_Null) - { - active_token_start_idx = idx; - } - - // rjf: invalid token kind -> emit error - else - { - TXTI_Token token = {TXTI_TokenKind_Error, r1u64(idx, idx+1)}; - txti_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); - } - } - - // rjf: look for ender - U64 ender_pad = 0; - B32 ender_found = 0; - if(active_token_kind != TXTI_TokenKind_Null && idx>active_token_start_idx) - { - if(idx == string.size) - { - ender_pad = 0; - ender_found = 1; - } - else switch(active_token_kind) - { - default:break; - case TXTI_TokenKind_Whitespace: - { - ender_found = !char_is_space(byte); - }break; - case TXTI_TokenKind_Identifier: - { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); - }break; - case TXTI_TokenKind_Numeric: - { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '.'); - }break; - case TXTI_TokenKind_String: - { - ender_found = (!escaped && ((!string_is_char && byte == '"') || (string_is_char && byte == '\''))); - ender_pad += 1; - }break; - case TXTI_TokenKind_Symbol: - { - ender_found = (byte != '~' && byte != '!' && - byte != '%' && byte != '^' && - byte != '&' && byte != '*' && - byte != '(' && byte != ')' && - byte != '-' && byte != '=' && - byte != '+' && byte != '[' && - byte != ']' && byte != '{' && - byte != '}' && byte != ':' && - byte != ';' && byte != ',' && - byte != '.' && byte != '<' && - byte != '>' && byte != '/' && - byte != '?' && byte != '|'); - }break; - case TXTI_TokenKind_Comment: - { - if(comment_is_single_line) - { - ender_found = (!escaped && (byte == '\r' || byte == '\n')); - } - else - { - ender_found = (active_token_start_idx+1 < idx && byte == '*' && next_byte == '/'); - ender_pad += 2; - } - }break; - case TXTI_TokenKind_Meta: - { - ender_found = (!escaped && (byte == '\r' || byte == '\n')); - }break; - } - } - - // rjf: next byte is ender => emit token - if(ender_found) - { - TXTI_Token token = {active_token_kind, r1u64(active_token_start_idx, idx+ender_pad)}; - active_token_kind = TXTI_TokenKind_Null; - - // rjf: identifier -> keyword in special cases - if(token.kind == TXTI_TokenKind_Identifier) - { - read_only local_persist String8 cpp_keywords[] = - { - str8_lit_comp("alignas"), - str8_lit_comp("alignof"), - str8_lit_comp("and"), - str8_lit_comp("and_eq"), - str8_lit_comp("asm"), - str8_lit_comp("atomic_cancel"), - str8_lit_comp("atomic_commit"), - str8_lit_comp("atomic_noexcept"), - str8_lit_comp("auto"), - str8_lit_comp("bitand"), - str8_lit_comp("bitor"), - str8_lit_comp("bool"), - str8_lit_comp("break"), - str8_lit_comp("case"), - str8_lit_comp("catch"), - str8_lit_comp("char"), - str8_lit_comp("char8_t"), - str8_lit_comp("char16_t"), - str8_lit_comp("char32_t"), - str8_lit_comp("class"), - str8_lit_comp("compl"), - str8_lit_comp("concept"), - str8_lit_comp("const"), - str8_lit_comp("consteval"), - str8_lit_comp("constexpr"), - str8_lit_comp("constinit"), - str8_lit_comp("const_cast"), - str8_lit_comp("continue"), - str8_lit_comp("co_await"), - str8_lit_comp("co_return"), - str8_lit_comp("co_yield"), - str8_lit_comp("decltype"), - str8_lit_comp("default"), - str8_lit_comp("delete"), - str8_lit_comp("do"), - str8_lit_comp("double"), - str8_lit_comp("dynamic_cast"), - str8_lit_comp("else"), - str8_lit_comp("enum"), - str8_lit_comp("explicit"), - str8_lit_comp("export"), - str8_lit_comp("extern"), - str8_lit_comp("false"), - str8_lit_comp("float"), - str8_lit_comp("for"), - str8_lit_comp("friend"), - str8_lit_comp("goto"), - str8_lit_comp("if"), - str8_lit_comp("inline"), - str8_lit_comp("int"), - str8_lit_comp("long"), - str8_lit_comp("mutable"), - str8_lit_comp("namespace"), - str8_lit_comp("new"), - str8_lit_comp("noexcept"), - str8_lit_comp("not"), - str8_lit_comp("not_eq"), - str8_lit_comp("nullptr"), - str8_lit_comp("operator"), - str8_lit_comp("or"), - str8_lit_comp("or_eq"), - str8_lit_comp("private"), - str8_lit_comp("protected"), - str8_lit_comp("public"), - str8_lit_comp("reflexpr"), - str8_lit_comp("register"), - str8_lit_comp("reinterpret_cast"), - str8_lit_comp("requires"), - str8_lit_comp("return"), - str8_lit_comp("short"), - str8_lit_comp("signed"), - str8_lit_comp("sizeof"), - str8_lit_comp("static"), - str8_lit_comp("static_assert"), - str8_lit_comp("static_cast"), - str8_lit_comp("struct"), - str8_lit_comp("switch"), - str8_lit_comp("synchronized"), - str8_lit_comp("template"), - str8_lit_comp("this"), - str8_lit_comp("thread_local"), - str8_lit_comp("throw"), - str8_lit_comp("true"), - str8_lit_comp("try"), - str8_lit_comp("typedef"), - str8_lit_comp("typeid"), - str8_lit_comp("typename"), - str8_lit_comp("union"), - str8_lit_comp("unsigned"), - str8_lit_comp("using"), - str8_lit_comp("virtual"), - str8_lit_comp("void"), - str8_lit_comp("volatile"), - str8_lit_comp("wchar_t"), - str8_lit_comp("while"), - str8_lit_comp("xor"), - str8_lit_comp("xor_eq"), - }; - String8 token_string = str8_substr(string, r1u64(active_token_start_idx, idx+ender_pad)); - for(U64 keyword_idx = 0; keyword_idx < ArrayCount(cpp_keywords); keyword_idx += 1) - { - if(str8_match(cpp_keywords[keyword_idx], token_string, 0)) - { - token.kind = TXTI_TokenKind_Keyword; - break; - } - } - } - - // rjf: push - txti_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); - - // rjf: increment by ender padding - idx += ender_pad; - } - - // rjf: advance by 1 byte if we haven't found an ender - if(!ender_found) - { - idx += 1; - } - escaped = next_escaped; - } - } - - //- rjf: token list -> token array - TXTI_TokenArray result = txti_token_array_from_chunk_list(arena, &tokens); - scratch_end(scratch); - return result; -} - -internal TXTI_TokenArray -txti_token_array_from_string__odin(Arena *arena, U64 *bytes_processed_counter, String8 string) -{ - //- jle: based on txti_token_array_from_string__cpp (alot of it is exactly the same) - // - // tokenization is a lot like C - // unique set of keywords - // has #tags and #directives - // - // tokenizer source code can be found here - // https://github.com/odin-lang/Odin/tree/master/core/odin/tokenizer - - Temp scratch = scratch_begin(&arena, 1); - - //- rjf: generate token list - TXTI_TokenChunkList tokens = {0}; - { - B32 comment_is_single_line = 0; - B32 string_is_char = 0; - TXTI_TokenKind active_token_kind = TXTI_TokenKind_Null; - U64 active_token_start_idx = 0; - B32 escaped = 0; - B32 next_escaped = 0; - U64 byte_process_start_idx = 0; - for(U64 idx = 0; idx <= string.size;) - { - U8 byte = (idx+0 < string.size) ? (string.str[idx+0]) : 0; - U8 next_byte = (idx+1 < string.size) ? (string.str[idx+1]) : 0; - - // rjf: update counter - if(bytes_processed_counter != 0 && ((idx-byte_process_start_idx) >= 1000 || idx == string.size)) - { - ins_atomic_u64_add_eval(bytes_processed_counter, (idx-byte_process_start_idx)); - byte_process_start_idx = idx; - } - - // rjf: escaping - if(escaped && (byte != '\r' && byte != '\n')) - { - next_escaped = 0; - } - else if(!escaped && byte == '\\') - { - next_escaped = 1; - } - - // rjf: take starter, determine active token kind - if(active_token_kind == TXTI_TokenKind_Null) - { - // rjf: use next bytes to start a new token - if(0){} - else if(char_is_space(byte)) { active_token_kind = TXTI_TokenKind_Whitespace; } - else if(byte == '_' || - byte == '$' || - char_is_alpha(byte)) { active_token_kind = char_is_lower(byte) ? TXTI_TokenKind_Identifier: TXTI_TokenKind_Type; } - else if(char_is_digit(byte, 10) || - (byte == '.' && - char_is_digit(next_byte, 10))) { active_token_kind = TXTI_TokenKind_Numeric; } - else if(byte == '"') { active_token_kind = TXTI_TokenKind_String; string_is_char = 0; } - else if(byte == '\'') { active_token_kind = TXTI_TokenKind_String; string_is_char = 1; } - else if(byte == '/' && next_byte == '/') { active_token_kind = TXTI_TokenKind_Comment; comment_is_single_line = 1; } - else if(byte == '/' && next_byte == '*') { active_token_kind = TXTI_TokenKind_Comment; comment_is_single_line = 0; } - else if(byte == '~' || byte == '!' || - byte == '%' || byte == '^' || - byte == '&' || byte == '*' || - byte == '(' || byte == ')' || - byte == '-' || byte == '=' || - byte == '+' || byte == '[' || - byte == ']' || byte == '{' || - byte == '}' || byte == ':' || - byte == ';' || byte == ',' || - byte == '.' || byte == '<' || - byte == '>' || byte == '/' || - byte == '?' || byte == '|') { active_token_kind = TXTI_TokenKind_Symbol; } - else if(byte == '#') { active_token_kind = TXTI_TokenKind_Meta; } - - // rjf: start new token - if(active_token_kind != TXTI_TokenKind_Null) - { - active_token_start_idx = idx; - } - - // rjf: invalid token kind -> emit error - else - { - TXTI_Token token = {TXTI_TokenKind_Error, r1u64(idx, idx+1)}; - txti_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); - } - } - - // rjf: look for ender - U64 ender_pad = 0; - B32 ender_found = 0; - if(active_token_kind != TXTI_TokenKind_Null && idx>active_token_start_idx) - { - if(idx == string.size) - { - ender_pad = 0; - ender_found = 1; - } - else switch(active_token_kind) - { - default:break; - case TXTI_TokenKind_Whitespace: - { - ender_found = !char_is_space(byte); - }break; - case TXTI_TokenKind_Identifier: - case TXTI_TokenKind_Type: - { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); - }break; - case TXTI_TokenKind_Numeric: - { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '.'); - }break; - case TXTI_TokenKind_String: - { - ender_found = (!escaped && ((!string_is_char && byte == '"') || (string_is_char && byte == '\''))); - ender_pad += 1; - }break; - case TXTI_TokenKind_Symbol: - { - ender_found = (byte != '~' && byte != '!' && - byte != '%' && byte != '^' && - byte != '&' && byte != '*' && - byte != '(' && byte != ')' && - byte != '-' && byte != '=' && - byte != '+' && byte != '[' && - byte != ']' && byte != '{' && - byte != '}' && byte != ':' && - byte != ';' && byte != ',' && - byte != '.' && byte != '<' && - byte != '>' && byte != '/' && - byte != '?' && byte != '|'); - }break; - case TXTI_TokenKind_Comment: - { - if(comment_is_single_line) - { - ender_found = (!escaped && (byte == '\r' || byte == '\n')); - } - else - { - ender_found = (active_token_start_idx+1 < idx && byte == '*' && next_byte == '/'); - ender_pad += 2; - } - }break; - case TXTI_TokenKind_Meta: - { - ender_found = (!char_is_alpha(byte) && !char_is_digit(byte, 10) && byte != '_' && byte != '$'); - }break; - } - } - - // rjf: next byte is ender => emit token - if(ender_found) - { - TXTI_Token token = {active_token_kind, r1u64(active_token_start_idx, idx+ender_pad)}; - active_token_kind = TXTI_TokenKind_Null; - - // rjf: identifier -> keyword in special cases - if(token.kind == TXTI_TokenKind_Identifier) - { - read_only local_persist String8 cpp_keywords[] = - { - str8_lit_comp("asm"), - str8_lit_comp("auto_cast"), - str8_lit_comp("bit_set"), - str8_lit_comp("break"), - str8_lit_comp("case"), - str8_lit_comp("cast"), - str8_lit_comp("context"), - str8_lit_comp("continue"), - str8_lit_comp("defer"), - str8_lit_comp("distinct"), - str8_lit_comp("do"), - str8_lit_comp("dynamic"), - str8_lit_comp("else"), - str8_lit_comp("enum"), - str8_lit_comp("fallthrough"), - str8_lit_comp("for"), - str8_lit_comp("foreign"), - str8_lit_comp("if"), - str8_lit_comp("in"), - str8_lit_comp("map"), - str8_lit_comp("matrix"), - str8_lit_comp("not_in"), - str8_lit_comp("or_break"), - str8_lit_comp("or_continue"), - str8_lit_comp("or_else"), - str8_lit_comp("or_return"), - str8_lit_comp("package"), - str8_lit_comp("proc"), - str8_lit_comp("return"), - str8_lit_comp("struct"), - str8_lit_comp("switch"), - str8_lit_comp("transmute"), - str8_lit_comp("typeid"), - str8_lit_comp("union"), - str8_lit_comp("using"), - str8_lit_comp("when"), - str8_lit_comp("where"), - str8_lit_comp("import"), - }; - String8 token_string = str8_substr(string, r1u64(active_token_start_idx, idx+ender_pad)); - for(U64 keyword_idx = 0; keyword_idx < ArrayCount(cpp_keywords); keyword_idx += 1) - { - if(str8_match(cpp_keywords[keyword_idx], token_string, 0)) - { - token.kind = TXTI_TokenKind_Keyword; - break; - } - } - } - - // rjf: push - txti_token_chunk_list_push(scratch.arena, &tokens, 4096, &token); - - // rjf: increment by ender padding - idx += ender_pad; - } - - // rjf: advance by 1 byte if we haven't found an ender - if(!ender_found) - { - idx += 1; - } - escaped = next_escaped; - } - } - - //- rjf: token list -> token array - TXTI_TokenArray result = txti_token_array_from_chunk_list(arena, &tokens); - scratch_end(scratch); - return result; -} - //////////////////////////////// //~ rjf: Message Type Functions @@ -849,7 +233,7 @@ txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line result.line_count = (U64)dim_1s64(line_range_clamped)+1; result.line_text = push_array(arena, String8, result.line_count); result.line_ranges = push_array(arena, Rng1U64, result.line_count); - result.line_tokens = push_array(arena, TXTI_TokenArray, result.line_count); + result.line_tokens = push_array(arena, TXT_TokenArray, result.line_count); // rjf: fill line ranges & text U64 line_slice_idx = 0; @@ -868,7 +252,7 @@ txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line } // rjf: binary search to find first token - TXTI_Token *tokens_first = 0; + TXT_Token *tokens_first = 0; ProfScope("binary search to find first token") { Rng1U64 slice_range = r1u64(result.line_ranges[0].min, result.line_ranges[result.line_count-1].max); @@ -881,7 +265,7 @@ txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line { break; } - TXTI_Token *mid_token = &buffer->tokens.v[mid_idx]; + TXT_Token *mid_token = &buffer->tokens.v[mid_idx]; if(mid_token->range.min > slice_range.max) { opl_idx = mid_idx; @@ -903,18 +287,18 @@ txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line } // rjf: grab per-line tokens - TXTI_TokenList *line_tokens_lists = push_array(scratch.arena, TXTI_TokenList, result.line_count); + TXT_TokenList *line_tokens_lists = push_array(scratch.arena, TXT_TokenList, result.line_count); if(tokens_first != 0) ProfScope("grab per-line tokens") { - TXTI_Token *tokens_opl = buffer->tokens.v+buffer->tokens.count; + TXT_Token *tokens_opl = buffer->tokens.v+buffer->tokens.count; U64 line_slice_idx = 0; - for(TXTI_Token *token = tokens_first; token < tokens_opl && line_slice_idx < result.line_count;) + for(TXT_Token *token = tokens_first; token < tokens_opl && line_slice_idx < result.line_count;) { if(token->range.min < result.line_ranges[line_slice_idx].max) { if(token->range.max > result.line_ranges[line_slice_idx].min) { - txti_token_list_push(scratch.arena, &line_tokens_lists[line_slice_idx], token); + txt_token_list_push(scratch.arena, &line_tokens_lists[line_slice_idx], token); } B32 need_token_advance = 0; B32 need_line_advance = 0; @@ -939,7 +323,7 @@ txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line // rjf: bake per-line tokens to arrays for(U64 line_slice_idx = 0; line_slice_idx < result.line_count; line_slice_idx += 1) { - result.line_tokens[line_slice_idx] = txti_token_array_from_list(arena, &line_tokens_lists[line_slice_idx]); + result.line_tokens[line_slice_idx] = txt_token_array_from_list(arena, &line_tokens_lists[line_slice_idx]); } } } @@ -975,8 +359,8 @@ txti_string_from_handle_txt_rng(Arena *arena, TXTI_Handle handle, TxtRng range) switch(info.line_end_kind) { default: - case TXTI_LineEndKind_LF:{join.sep = str8_lit("\n");}break; - case TXTI_LineEndKind_CRLF:{join.sep = str8_lit("\r\n");}break; + case TXT_LineEndKind_LF:{join.sep = str8_lit("\n");}break; + case TXT_LineEndKind_CRLF:{join.sep = str8_lit("\r\n");}break; } result = str8_list_join(arena, &line_strings, &join); } @@ -997,18 +381,18 @@ txti_string_from_handle_line_num(Arena *arena, TXTI_Handle handle, S64 line_num) } internal Rng1U64 -txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXTI_TokenArray *line_tokens) +txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens) { Rng1U64 result = {0}; Temp scratch = scratch_begin(0, 0); { // rjf: unpack line info - TXTI_Token *line_tokens_first = line_tokens->v; - TXTI_Token *line_tokens_opl = line_tokens->v+line_tokens->count; + TXT_Token *line_tokens_first = line_tokens->v; + TXT_Token *line_tokens_opl = line_tokens->v+line_tokens->count; // rjf: find token containing `off` - TXTI_Token *pt_token = 0; - for(TXTI_Token *token = line_tokens_first; + TXT_Token *pt_token = 0; + for(TXT_Token *token = line_tokens_first; token < line_tokens_opl; token += 1) { @@ -1020,14 +404,14 @@ txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, S switch(token->kind) { default:{}break; - case TXTI_TokenKind_Symbol: + case TXT_TokenKind_Symbol: { token_ender = (str8_match(token_string, str8_lit("]"), 0)); }break; - case TXTI_TokenKind_Identifier: - case TXTI_TokenKind_Keyword: - case TXTI_TokenKind_String: - case TXTI_TokenKind_Meta: + case TXT_TokenKind_Identifier: + case TXT_TokenKind_Keyword: + case TXT_TokenKind_String: + case TXT_TokenKind_Meta: { token_ender = 1; }break; @@ -1051,7 +435,7 @@ txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, S { B32 walkback_done = 0; S32 nest = 0; - for(TXTI_Token *wb_token = pt_token; + for(TXT_Token *wb_token = pt_token; wb_token >= line_tokens_first && walkback_done == 0; wb_token -= 1) { @@ -1061,7 +445,7 @@ txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, S switch(wb_token->kind) { default:{}break; - case TXTI_TokenKind_Symbol: + case TXT_TokenKind_Symbol: { B32 is_scope_resolution = str8_match(wb_token_string, str8_lit("::"), 0); B32 is_dot = str8_match(wb_token_string, str8_lit("."), 0); @@ -1079,7 +463,7 @@ txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, S include_wb_token = 1; } }break; - case TXTI_TokenKind_Identifier: + case TXT_TokenKind_Identifier: { include_wb_token = 1; }break; @@ -1110,9 +494,9 @@ txti_expr_range_from_handle_pt(TXTI_Handle handle, TxtPt pt) // rjf: unpack line info String8 line_text = slice.line_text[0]; Rng1U64 line_range = slice.line_ranges[0]; - TXTI_TokenArray line_tokens = slice.line_tokens[0]; - TXTI_Token *line_tokens_first = line_tokens.v; - TXTI_Token *line_tokens_opl = line_tokens.v+line_tokens.count; + TXT_TokenArray line_tokens = slice.line_tokens[0]; + TXT_Token *line_tokens_first = line_tokens.v; + TXT_Token *line_tokens_opl = line_tokens.v+line_tokens.count; U64 pt_off = line_range.min + (pt.column-1); // rjf: grab offset range of expression @@ -1182,11 +566,8 @@ txti_set_external_change_detection_enabled(B32 enabled) internal void txti_mut_thread_entry_point(void *p) { - TCTX tctx_; - tctx_init_and_equip(&tctx_); - U64 mut_thread_idx = (U64)p; - ProfThreadName("[txti] mut #%I64u", mut_thread_idx); + ThreadNameF("[txti] mut #%I64u", mut_thread_idx); TXTI_MutThread *mut_thread = &txti_state->mut_threads[mut_thread_idx]; for(;;) { @@ -1222,14 +603,14 @@ txti_mut_thread_entry_point(void *p) //- rjf: load file if we need it B32 load_valid = 0; String8 file_contents = {0}; - TXTI_LangKind lang_kind = TXTI_LangKind_Null; + TXT_LangKind lang_kind = TXT_LangKind_Null; U64 timestamp = 0; if(msg->kind == TXTI_MsgKind_Reload) ProfScope("reload file") { FileProperties pre_load_props = os_properties_from_file_path(msg->string); OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, msg->string); file_contents = os_string_from_file_range(scratch.arena, file, r1u64(0, pre_load_props.size)); - lang_kind = txti_lang_kind_from_extension(str8_skip_last_dot(msg->string)); + lang_kind = txt_lang_kind_from_extension(str8_skip_last_dot(msg->string)); os_file_close(file); FileProperties post_load_props = os_properties_from_file_path(msg->string); load_valid = (post_load_props.modified == pre_load_props.modified); @@ -1240,23 +621,10 @@ txti_mut_thread_entry_point(void *p) } //- rjf: nonzero lang kind -> unpack lang info - TXTI_LangLexFunctionType *lex_function = 0; - switch(lang_kind) - { - default:{}break; - case TXTI_LangKind_C: - case TXTI_LangKind_CPlusPlus: - { - lex_function = txti_token_array_from_string__cpp; - }break; - case TXTI_LangKind_Odin: - { - lex_function = txti_token_array_from_string__odin; - }break; - } + TXT_LangLexFunctionType *lex_function = txt_lex_function_from_lang_kind(lang_kind); //- rjf: detect line end kind - TXTI_LineEndKind line_end_kind = TXTI_LineEndKind_Null; + TXT_LineEndKind line_end_kind = TXT_LineEndKind_Null; if(load_valid) { U64 lf_count = 0; @@ -1274,11 +642,11 @@ txti_mut_thread_entry_point(void *p) } if(cr_count >= lf_count/2 && lf_count >= 1) { - line_end_kind = TXTI_LineEndKind_CRLF; + line_end_kind = TXT_LineEndKind_CRLF; } else if(lf_count >= 1) { - line_end_kind = TXTI_LineEndKind_LF; + line_end_kind = TXT_LineEndKind_LF; } } @@ -1333,11 +701,11 @@ txti_mut_thread_entry_point(void *p) if(entity != 0) { entity->buffer_apply_gen += 1; - if(line_end_kind != TXTI_LineEndKind_Null) + if(line_end_kind != TXT_LineEndKind_Null) { entity->line_end_kind = line_end_kind; } - if(lang_kind != TXTI_LangKind_Null) + if(lang_kind != TXT_LangKind_Null) { entity->lang_kind = lang_kind; } @@ -1495,9 +863,7 @@ txti_mut_thread_entry_point(void *p) internal void txti_detector_thread_entry_point(void *p) { - TCTX tctx_; - tctx_init_and_equip(&tctx_); - ProfThreadName("[txti] detector"); + ThreadNameF("[txti] detector"); for(;;) { if(ins_atomic_u64_eval(&txti_state->detector_thread_enabled)) diff --git a/src/txti/txti.h b/src/txti/txti.h index fd3e87d4..48b1844b 100644 --- a/src/txti/txti.h +++ b/src/txti/txti.h @@ -56,104 +56,6 @@ struct TXTI_Handle U64 u64[2]; }; -//////////////////////////////// -//~ rjf: Parsed Text Info Types - -typedef enum TXTI_LineEndKind -{ - TXTI_LineEndKind_Null, - TXTI_LineEndKind_LF, - TXTI_LineEndKind_CRLF, - TXTI_LineEndKind_COUNT -} -TXTI_LineEndKind; - -typedef enum TXTI_TokenKind -{ - TXTI_TokenKind_Null, - TXTI_TokenKind_Error, - TXTI_TokenKind_Whitespace, - TXTI_TokenKind_Keyword, - TXTI_TokenKind_Identifier, - TXTI_TokenKind_Numeric, - TXTI_TokenKind_String, - TXTI_TokenKind_Symbol, - TXTI_TokenKind_Comment, - TXTI_TokenKind_Meta, // preprocessor, etc. - TXTI_TokenKind_Type, - TXTI_TokenKind_COUNT -} -TXTI_TokenKind; - -typedef struct TXTI_Token TXTI_Token; -struct TXTI_Token -{ - TXTI_TokenKind kind; - Rng1U64 range; -}; - -typedef struct TXTI_TokenChunkNode TXTI_TokenChunkNode; -struct TXTI_TokenChunkNode -{ - TXTI_TokenChunkNode *next; - U64 count; - U64 cap; - TXTI_Token *v; -}; - -typedef struct TXTI_TokenChunkList TXTI_TokenChunkList; -struct TXTI_TokenChunkList -{ - TXTI_TokenChunkNode *first; - TXTI_TokenChunkNode *last; - U64 chunk_count; - U64 token_count; -}; - -typedef struct TXTI_TokenNode TXTI_TokenNode; -struct TXTI_TokenNode -{ - TXTI_TokenNode *next; - TXTI_Token v; -}; - -typedef struct TXTI_TokenList TXTI_TokenList; -struct TXTI_TokenList -{ - TXTI_TokenNode *first; - TXTI_TokenNode *last; - U64 count; -}; - -typedef struct TXTI_TokenArray TXTI_TokenArray; -struct TXTI_TokenArray -{ - U64 count; - TXTI_Token *v; -}; - -typedef struct TXTI_TokenArrayArray TXTI_TokenArrayArray; -struct TXTI_TokenArrayArray -{ - U64 count; - TXTI_TokenArray *v; -}; - -//////////////////////////////// -//~ rjf: Language Kinds - -typedef enum TXTI_LangKind -{ - TXTI_LangKind_Null, - TXTI_LangKind_C, - TXTI_LangKind_CPlusPlus, - TXTI_LangKind_Odin, - TXTI_LangKind_COUNT -} -TXTI_LangKind; - -typedef TXTI_TokenArray TXTI_LangLexFunctionType(Arena *arena, U64 *bytes_processed_counter, String8 string); - //////////////////////////////// //~ rjf: Buffer Entity Types @@ -175,7 +77,7 @@ struct TXTI_Buffer U64 lines_max_size; // rjf: tokens - TXTI_TokenArray tokens; + TXT_TokenArray tokens; }; typedef struct TXTI_Entity TXTI_Entity; @@ -189,8 +91,8 @@ struct TXTI_Entity U64 mut_gen; // rjf: metadata - TXTI_LineEndKind line_end_kind; - TXTI_LangKind lang_kind; + TXT_LineEndKind line_end_kind; + TXT_LangKind lang_kind; U64 bytes_processed; U64 bytes_to_process; U64 working_count; @@ -240,8 +142,8 @@ struct TXTI_BufferInfo { String8 path; U64 timestamp; - TXTI_LineEndKind line_end_kind; - TXTI_LangKind lang_kind; + TXT_LineEndKind line_end_kind; + TXT_LangKind lang_kind; U64 total_line_count; U64 last_line_size; U64 max_line_size; @@ -257,7 +159,7 @@ struct TXTI_Slice U64 line_count; String8 *line_text; Rng1U64 *line_ranges; - TXTI_TokenArray *line_tokens; + TXT_TokenArray *line_tokens; }; //////////////////////////////// @@ -342,20 +244,6 @@ internal void txti_init(void); //~ rjf: Basic Helpers internal U64 txti_hash_from_string(String8 string); -internal TXTI_LangKind txti_lang_kind_from_extension(String8 extension); - -//////////////////////////////// -//~ rjf: Token Type Functions - -internal void txti_token_chunk_list_push(Arena *arena, TXTI_TokenChunkList *list, U64 cap, TXTI_Token *token); -internal void txti_token_list_push(Arena *arena, TXTI_TokenList *list, TXTI_Token *token); -internal TXTI_TokenArray txti_token_array_from_chunk_list(Arena *arena, TXTI_TokenChunkList *list); -internal TXTI_TokenArray txti_token_array_from_list(Arena *arena, TXTI_TokenList *list); - -//////////////////////////////// -//~ rjf: Lexing Functions - -internal TXTI_TokenArray txti_token_array_from_string__cpp(Arena *arena, U64 *bytes_processed_counter, String8 string); //////////////////////////////// //~ rjf: Message Type Functions @@ -375,7 +263,7 @@ internal TXTI_BufferInfo txti_buffer_info_from_handle(Arena *arena, TXTI_Handle internal TXTI_Slice txti_slice_from_handle_line_range(Arena *arena, TXTI_Handle handle, Rng1S64 line_range); internal String8 txti_string_from_handle_txt_rng(Arena *arena, TXTI_Handle handle, TxtRng range); internal String8 txti_string_from_handle_line_num(Arena *arena, TXTI_Handle handle, S64 line_num); -internal Rng1U64 txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXTI_TokenArray *line_tokens); +internal Rng1U64 txti_expr_range_from_line_off_range_string_tokens(U64 off, Rng1U64 line_range, String8 line_text, TXT_TokenArray *line_tokens); internal TxtRng txti_expr_range_from_handle_pt(TXTI_Handle handle, TxtPt pt); //- rjf: buffer mutations diff --git a/src/type_graph/generated/type_graph.meta.c b/src/type_graph/generated/type_graph.meta.c index b9d27fe6..23e43829 100644 --- a/src/type_graph/generated/type_graph.meta.c +++ b/src/type_graph/generated/type_graph.meta.c @@ -3,3 +3,122 @@ //- GENERATED CODE +C_LINKAGE_BEGIN +U8 tg_kind_basic_byte_size_table[54] = +{ +0, +0, +0xFF, +1, +2, +4, +1, +2, +4, +1, +2, +4, +8, +16, +32, +64, +1, +2, +4, +8, +16, +32, +64, +1, +2, +4, +4, +6, +8, +10, +16, +8, +16, +20, +32, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +0, +}; + +String8 tg_kind_basic_string_table[54] = +{ +str8_lit_comp(""), +str8_lit_comp("void"), +str8_lit_comp("HANDLE"), +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(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +str8_lit_comp(""), +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(""), +str8_lit_comp(""), +}; + +C_LINKAGE_END + diff --git a/src/type_graph/generated/type_graph.meta.h b/src/type_graph/generated/type_graph.meta.h index 34bdea1f..8a4021b2 100644 --- a/src/type_graph/generated/type_graph.meta.h +++ b/src/type_graph/generated/type_graph.meta.h @@ -63,133 +63,21 @@ TG_Kind_IncompleteEnum, TG_Kind_Bitfield, TG_Kind_Variadic, TG_Kind_COUNT, -TG_Kind_FirstBasic = TG_Kind_Void, -TG_Kind_LastBasic = TG_Kind_ComplexF128, -TG_Kind_FirstInteger = TG_Kind_Char8, -TG_Kind_LastInteger = TG_Kind_S512, -TG_Kind_FirstSigned1 = TG_Kind_Char8, -TG_Kind_LastSigned1 = TG_Kind_Char32, -TG_Kind_FirstSigned2 = TG_Kind_S8, -TG_Kind_LastSigned2 = TG_Kind_S512, +TG_Kind_FirstBasic = TG_Kind_Void, +TG_Kind_LastBasic = TG_Kind_ComplexF128, +TG_Kind_FirstInteger = TG_Kind_Char8, +TG_Kind_LastInteger = TG_Kind_S512, +TG_Kind_FirstSigned1 = TG_Kind_Char8, +TG_Kind_LastSigned1 = TG_Kind_Char32, +TG_Kind_FirstSigned2 = TG_Kind_S8, +TG_Kind_LastSigned2 = TG_Kind_S512, TG_Kind_FirstIncomplete = TG_Kind_IncompleteStruct, TG_Kind_LastIncomplete = TG_Kind_IncompleteEnum, } TG_Kind; -U8 tg_kind_basic_byte_size_table[] = -{ -0, -0, -0xFF, -1, -2, -4, -1, -2, -4, -1, -2, -4, -8, -16, -32, -64, -1, -2, -4, -8, -16, -32, -64, -1, -2, -4, -4, -6, -8, -10, -16, -8, -16, -20, -32, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -0, -}; - -String8 tg_kind_basic_string_table[] = -{ -str8_lit_comp(""), -str8_lit_comp("void"), -str8_lit_comp("HANDLE"), -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(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -str8_lit_comp(""), -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(""), -str8_lit_comp(""), -}; - +C_LINKAGE_BEGIN +extern U8 tg_kind_basic_byte_size_table[54]; +extern String8 tg_kind_basic_string_table[54]; +C_LINKAGE_END #endif // TYPE_GRAPH_META_H diff --git a/src/type_graph/type_graph.c b/src/type_graph/type_graph.c index 48bfa512..4a9af695 100644 --- a/src/type_graph/type_graph.c +++ b/src/type_graph/type_graph.c @@ -1,6 +1,11 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) +//////////////////////////////// +//~ rjf: Generated Code + +#include "generated/type_graph.meta.c" + //////////////////////////////// //~ rjf: Basic Helpers @@ -54,85 +59,85 @@ tg_key_list_copy(Arena *arena, TG_KeyList *src) //~ rjf: RADDBG <-> TG Enum Conversions internal TG_Kind -tg_kind_from_raddbg_type_kind(RADDBG_TypeKind kind) +tg_kind_from_rdi_type_kind(RDI_TypeKind kind) { TG_Kind result = TG_Kind_Null; switch(kind) { default:{}break; - case RADDBG_TypeKind_Void: {result = TG_Kind_Void;}break; - case RADDBG_TypeKind_Handle: {result = TG_Kind_Handle;}break; - case RADDBG_TypeKind_Char8: {result = TG_Kind_Char8;}break; - case RADDBG_TypeKind_Char16: {result = TG_Kind_Char16;}break; - case RADDBG_TypeKind_Char32: {result = TG_Kind_Char32;}break; - case RADDBG_TypeKind_UChar8: {result = TG_Kind_UChar8;}break; - case RADDBG_TypeKind_UChar16: {result = TG_Kind_UChar16;}break; - case RADDBG_TypeKind_UChar32: {result = TG_Kind_UChar32;}break; - case RADDBG_TypeKind_U8: {result = TG_Kind_U8;}break; - case RADDBG_TypeKind_U16: {result = TG_Kind_U16;}break; - case RADDBG_TypeKind_U32: {result = TG_Kind_U32;}break; - case RADDBG_TypeKind_U64: {result = TG_Kind_U64;}break; - case RADDBG_TypeKind_U128: {result = TG_Kind_U128;}break; - case RADDBG_TypeKind_U256: {result = TG_Kind_U256;}break; - case RADDBG_TypeKind_U512: {result = TG_Kind_U512;}break; - case RADDBG_TypeKind_S8: {result = TG_Kind_S8;}break; - case RADDBG_TypeKind_S16: {result = TG_Kind_S16;}break; - case RADDBG_TypeKind_S32: {result = TG_Kind_S32;}break; - case RADDBG_TypeKind_S64: {result = TG_Kind_S64;}break; - case RADDBG_TypeKind_S128: {result = TG_Kind_S128;}break; - case RADDBG_TypeKind_S256: {result = TG_Kind_S256;}break; - case RADDBG_TypeKind_S512: {result = TG_Kind_S512;}break; - case RADDBG_TypeKind_Bool: {result = TG_Kind_Bool;}break; - case RADDBG_TypeKind_F16: {result = TG_Kind_F16;}break; - case RADDBG_TypeKind_F32: {result = TG_Kind_F32;}break; - case RADDBG_TypeKind_F32PP: {result = TG_Kind_F32PP;}break; - case RADDBG_TypeKind_F48: {result = TG_Kind_F48;}break; - case RADDBG_TypeKind_F64: {result = TG_Kind_F64;}break; - case RADDBG_TypeKind_F80: {result = TG_Kind_F80;}break; - case RADDBG_TypeKind_F128: {result = TG_Kind_F128;}break; - case RADDBG_TypeKind_ComplexF32: {result = TG_Kind_ComplexF32;}break; - case RADDBG_TypeKind_ComplexF64: {result = TG_Kind_ComplexF64;}break; - case RADDBG_TypeKind_ComplexF80: {result = TG_Kind_ComplexF80;}break; - case RADDBG_TypeKind_ComplexF128: {result = TG_Kind_ComplexF128;}break; - case RADDBG_TypeKind_Modifier: {result = TG_Kind_Modifier;}break; - case RADDBG_TypeKind_Ptr: {result = TG_Kind_Ptr;}break; - case RADDBG_TypeKind_LRef: {result = TG_Kind_LRef;}break; - case RADDBG_TypeKind_RRef: {result = TG_Kind_RRef;}break; - case RADDBG_TypeKind_Array: {result = TG_Kind_Array;}break; - case RADDBG_TypeKind_Function: {result = TG_Kind_Function;}break; - case RADDBG_TypeKind_Method: {result = TG_Kind_Method;}break; - case RADDBG_TypeKind_MemberPtr: {result = TG_Kind_MemberPtr;}break; - case RADDBG_TypeKind_Struct: {result = TG_Kind_Struct;}break; - case RADDBG_TypeKind_Class: {result = TG_Kind_Class;}break; - case RADDBG_TypeKind_Union: {result = TG_Kind_Union;}break; - case RADDBG_TypeKind_Enum: {result = TG_Kind_Enum;}break; - case RADDBG_TypeKind_Alias: {result = TG_Kind_Alias;}break; - case RADDBG_TypeKind_IncompleteStruct: {result = TG_Kind_IncompleteStruct;}break; - case RADDBG_TypeKind_IncompleteUnion: {result = TG_Kind_IncompleteUnion;}break; - case RADDBG_TypeKind_IncompleteClass: {result = TG_Kind_IncompleteClass;}break; - case RADDBG_TypeKind_IncompleteEnum: {result = TG_Kind_IncompleteEnum;}break; - case RADDBG_TypeKind_Bitfield: {result = TG_Kind_Bitfield;}break; - case RADDBG_TypeKind_Variadic: {result = TG_Kind_Variadic;}break; + case RDI_TypeKind_Void: {result = TG_Kind_Void;}break; + case RDI_TypeKind_Handle: {result = TG_Kind_Handle;}break; + case RDI_TypeKind_Char8: {result = TG_Kind_Char8;}break; + case RDI_TypeKind_Char16: {result = TG_Kind_Char16;}break; + case RDI_TypeKind_Char32: {result = TG_Kind_Char32;}break; + case RDI_TypeKind_UChar8: {result = TG_Kind_UChar8;}break; + case RDI_TypeKind_UChar16: {result = TG_Kind_UChar16;}break; + case RDI_TypeKind_UChar32: {result = TG_Kind_UChar32;}break; + case RDI_TypeKind_U8: {result = TG_Kind_U8;}break; + case RDI_TypeKind_U16: {result = TG_Kind_U16;}break; + case RDI_TypeKind_U32: {result = TG_Kind_U32;}break; + case RDI_TypeKind_U64: {result = TG_Kind_U64;}break; + case RDI_TypeKind_U128: {result = TG_Kind_U128;}break; + case RDI_TypeKind_U256: {result = TG_Kind_U256;}break; + case RDI_TypeKind_U512: {result = TG_Kind_U512;}break; + case RDI_TypeKind_S8: {result = TG_Kind_S8;}break; + case RDI_TypeKind_S16: {result = TG_Kind_S16;}break; + case RDI_TypeKind_S32: {result = TG_Kind_S32;}break; + case RDI_TypeKind_S64: {result = TG_Kind_S64;}break; + case RDI_TypeKind_S128: {result = TG_Kind_S128;}break; + case RDI_TypeKind_S256: {result = TG_Kind_S256;}break; + case RDI_TypeKind_S512: {result = TG_Kind_S512;}break; + case RDI_TypeKind_Bool: {result = TG_Kind_Bool;}break; + case RDI_TypeKind_F16: {result = TG_Kind_F16;}break; + case RDI_TypeKind_F32: {result = TG_Kind_F32;}break; + case RDI_TypeKind_F32PP: {result = TG_Kind_F32PP;}break; + case RDI_TypeKind_F48: {result = TG_Kind_F48;}break; + case RDI_TypeKind_F64: {result = TG_Kind_F64;}break; + case RDI_TypeKind_F80: {result = TG_Kind_F80;}break; + case RDI_TypeKind_F128: {result = TG_Kind_F128;}break; + case RDI_TypeKind_ComplexF32: {result = TG_Kind_ComplexF32;}break; + case RDI_TypeKind_ComplexF64: {result = TG_Kind_ComplexF64;}break; + case RDI_TypeKind_ComplexF80: {result = TG_Kind_ComplexF80;}break; + case RDI_TypeKind_ComplexF128: {result = TG_Kind_ComplexF128;}break; + case RDI_TypeKind_Modifier: {result = TG_Kind_Modifier;}break; + case RDI_TypeKind_Ptr: {result = TG_Kind_Ptr;}break; + case RDI_TypeKind_LRef: {result = TG_Kind_LRef;}break; + case RDI_TypeKind_RRef: {result = TG_Kind_RRef;}break; + case RDI_TypeKind_Array: {result = TG_Kind_Array;}break; + case RDI_TypeKind_Function: {result = TG_Kind_Function;}break; + case RDI_TypeKind_Method: {result = TG_Kind_Method;}break; + case RDI_TypeKind_MemberPtr: {result = TG_Kind_MemberPtr;}break; + case RDI_TypeKind_Struct: {result = TG_Kind_Struct;}break; + case RDI_TypeKind_Class: {result = TG_Kind_Class;}break; + case RDI_TypeKind_Union: {result = TG_Kind_Union;}break; + case RDI_TypeKind_Enum: {result = TG_Kind_Enum;}break; + case RDI_TypeKind_Alias: {result = TG_Kind_Alias;}break; + case RDI_TypeKind_IncompleteStruct: {result = TG_Kind_IncompleteStruct;}break; + case RDI_TypeKind_IncompleteUnion: {result = TG_Kind_IncompleteUnion;}break; + case RDI_TypeKind_IncompleteClass: {result = TG_Kind_IncompleteClass;}break; + case RDI_TypeKind_IncompleteEnum: {result = TG_Kind_IncompleteEnum;}break; + case RDI_TypeKind_Bitfield: {result = TG_Kind_Bitfield;}break; + case RDI_TypeKind_Variadic: {result = TG_Kind_Variadic;}break; } return result; } internal TG_MemberKind -tg_member_kind_from_raddbg_member_kind(RADDBG_MemberKind kind) +tg_member_kind_from_rdi_member_kind(RDI_MemberKind kind) { TG_MemberKind result = TG_MemberKind_Null; switch(kind) { default:{}break; - case RADDBG_MemberKind_DataField: {result = TG_MemberKind_DataField;}break; - case RADDBG_MemberKind_StaticData: {result = TG_MemberKind_StaticData;}break; - case RADDBG_MemberKind_Method: {result = TG_MemberKind_Method;}break; - case RADDBG_MemberKind_StaticMethod: {result = TG_MemberKind_StaticMethod;}break; - case RADDBG_MemberKind_VirtualMethod: {result = TG_MemberKind_VirtualMethod;}break; - case RADDBG_MemberKind_VTablePtr: {result = TG_MemberKind_VTablePtr;}break; - case RADDBG_MemberKind_Base: {result = TG_MemberKind_Base;}break; - case RADDBG_MemberKind_VirtualBase: {result = TG_MemberKind_VirtualBase;}break; - case RADDBG_MemberKind_NestedType: {result = TG_MemberKind_NestedType;}break; + case RDI_MemberKind_DataField: {result = TG_MemberKind_DataField;}break; + case RDI_MemberKind_StaticData: {result = TG_MemberKind_StaticData;}break; + case RDI_MemberKind_Method: {result = TG_MemberKind_Method;}break; + case RDI_MemberKind_StaticMethod: {result = TG_MemberKind_StaticMethod;}break; + case RDI_MemberKind_VirtualMethod: {result = TG_MemberKind_VirtualMethod;}break; + case RDI_MemberKind_VTablePtr: {result = TG_MemberKind_VTablePtr;}break; + case RDI_MemberKind_Base: {result = TG_MemberKind_Base;}break; + case RDI_MemberKind_VirtualBase: {result = TG_MemberKind_VirtualBase;}break; + case RDI_MemberKind_NestedType: {result = TG_MemberKind_NestedType;}break; } return result; } @@ -274,7 +279,7 @@ tg_cons_type_make(TG_Graph *graph, TG_Kind kind, TG_Key direct_type_key, U64 u64 //~ rjf: Graph Introspection API internal TG_Type * -tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_type_from_graph_rdi_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { TG_Type *type = &tg_type_nil; U64 reg_byte_count = 0; @@ -319,7 +324,7 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg }break; case TG_Kind_Array: { - U64 ptee_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, cons_type->direct_type_key); + U64 ptee_size = tg_byte_size_from_graph_rdi_key(graph, rdi, cons_type->direct_type_key); type->byte_size = ptee_size * type->count; }break; } @@ -331,20 +336,20 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg case TG_KeyKind_Ext: { U64 type_node_idx = key.u64[0]; - if(0 <= type_node_idx && type_node_idx < rdbg->type_nodes_count) + if(0 <= type_node_idx && type_node_idx < rdi->type_nodes_count) { - RADDBG_TypeNode *rdbg_type = &rdbg->type_nodes[type_node_idx]; - TG_Kind kind = tg_kind_from_raddbg_type_kind(rdbg_type->kind); + RDI_TypeNode *rdi_type = &rdi->type_nodes[type_node_idx]; + TG_Kind kind = tg_kind_from_rdi_type_kind(rdi_type->kind); //- rjf: record types => unpack name * members & produce - if(RADDBG_TypeKind_FirstRecord <= rdbg_type->kind && rdbg_type->kind <= RADDBG_TypeKind_LastRecord) + if(RDI_TypeKind_FirstRecord <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastRecord) { // rjf: unpack name String8 name = {0}; - name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: unpack UDT info - RADDBG_UDT *udt = raddbg_element_from_idx(rdbg, udts, rdbg_type->user_defined.udt_idx); + RDI_UDT *udt = rdi_element_from_idx(rdi, udts, rdi_type->user_defined.udt_idx); // rjf: unpack members TG_Member *members = 0; @@ -352,23 +357,23 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg { members_count = udt->member_count; members = push_array(arena, TG_Member, members_count); - if(members_count != 0 && 0 <= udt->member_first && udt->member_first+udt->member_count <= rdbg->members_count) + if(members_count != 0 && 0 <= udt->member_first && udt->member_first+udt->member_count <= rdi->members_count) { for(U32 member_idx = udt->member_first; member_idx < udt->member_first+udt->member_count; member_idx += 1) { - RADDBG_Member *src = &rdbg->members[member_idx]; + RDI_Member *src = &rdi->members[member_idx]; TG_Kind member_type_kind = TG_Kind_Null; - if(src->type_idx < rdbg->type_nodes_count) + if(src->type_idx < rdi->type_nodes_count) { - RADDBG_TypeNode *member_type = &rdbg->type_nodes[src->type_idx]; - member_type_kind = tg_kind_from_raddbg_type_kind(member_type->kind); + RDI_TypeNode *member_type = &rdi->type_nodes[src->type_idx]; + member_type_kind = tg_kind_from_rdi_type_kind(member_type->kind); } TG_Member *dst = &members[member_idx-udt->member_first]; - dst->kind = tg_member_kind_from_raddbg_member_kind(src->kind); + dst->kind = tg_member_kind_from_rdi_member_kind(src->kind); dst->type_key = tg_key_ext(member_type_kind, (U64)src->type_idx); - dst->name.str = raddbg_string_from_idx(rdbg, src->name_string_idx, &dst->name.size); + dst->name.str = rdi_string_from_idx(rdi, src->name_string_idx, &dst->name.size); dst->off = (U64)src->off; } } @@ -378,46 +383,46 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg type = push_array(arena, TG_Type, 1); type->kind = kind; type->name = push_str8_copy(arena, name); - type->byte_size = (U64)rdbg_type->byte_size; + type->byte_size = (U64)rdi_type->byte_size; type->count = members_count; type->members = members; } //- rjf: enum types => unpack name * values & produce - else if(rdbg_type->kind == RADDBG_TypeKind_Enum) + else if(rdi_type->kind == RDI_TypeKind_Enum) { // rjf: unpack name String8 name = {0}; - name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: unpack direct type TG_Key direct_type_key = zero_struct; - if(rdbg_type->user_defined.direct_type_idx < type_node_idx) + if(rdi_type->user_defined.direct_type_idx < type_node_idx) { - RADDBG_TypeNode *direct_type_node = &rdbg->type_nodes[rdbg_type->user_defined.direct_type_idx]; - TG_Kind direct_type_kind = tg_kind_from_raddbg_type_kind(direct_type_node->kind); - direct_type_key = tg_key_ext(direct_type_kind, (U64)rdbg_type->user_defined.direct_type_idx); + RDI_TypeNode *direct_type_node = &rdi->type_nodes[rdi_type->user_defined.direct_type_idx]; + TG_Kind direct_type_kind = tg_kind_from_rdi_type_kind(direct_type_node->kind); + direct_type_key = tg_key_ext(direct_type_kind, (U64)rdi_type->user_defined.direct_type_idx); } // rjf: unpack members TG_EnumVal *enum_vals = 0; U32 enum_vals_count = 0; { - U32 udt_idx = rdbg_type->user_defined.udt_idx; - if(0 <= udt_idx && udt_idx < rdbg->udts_count) + U32 udt_idx = rdi_type->user_defined.udt_idx; + if(0 <= udt_idx && udt_idx < rdi->udts_count) { - RADDBG_UDT *udt = &rdbg->udts[udt_idx]; + RDI_UDT *udt = &rdi->udts[udt_idx]; enum_vals_count = udt->member_count; enum_vals = push_array(arena, TG_EnumVal, enum_vals_count); - if(0 <= udt->member_first && udt->member_first+udt->member_count < rdbg->enum_members_count) + if(0 <= udt->member_first && udt->member_first+udt->member_count < rdi->enum_members_count) { for(U32 member_idx = udt->member_first; member_idx < udt->member_first+udt->member_count; member_idx += 1) { - RADDBG_EnumMember *src = &rdbg->enum_members[member_idx]; + RDI_EnumMember *src = &rdi->enum_members[member_idx]; TG_EnumVal *dst = &enum_vals[member_idx-udt->member_first]; - dst->name.str = raddbg_string_from_idx(rdbg, src->name_string_idx, &dst->name.size); + dst->name.str = rdi_string_from_idx(rdi, src->name_string_idx, &dst->name.size); dst->val = src->val; } } @@ -428,39 +433,39 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg type = push_array(arena, TG_Type, 1); type->kind = kind; type->name = push_str8_copy(arena, name); - type->byte_size = (U64)rdbg_type->byte_size; + type->byte_size = (U64)rdi_type->byte_size; type->count = enum_vals_count; type->enum_vals = enum_vals; type->direct_type_key = direct_type_key; } //- rjf: constructed types - if(RADDBG_TypeKind_FirstConstructed <= rdbg_type->kind && rdbg_type->kind <= RADDBG_TypeKind_LastConstructed) + else if(RDI_TypeKind_FirstConstructed <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastConstructed) { // rjf: unpack direct type B32 direct_type_is_good = 0; TG_Key direct_type_key = zero_struct; U64 direct_type_byte_size = 0; - if(rdbg_type->constructed.direct_type_idx < type_node_idx) + if(rdi_type->constructed.direct_type_idx < type_node_idx) { - RADDBG_TypeNode *direct_type_node = &rdbg->type_nodes[rdbg_type->constructed.direct_type_idx]; - TG_Kind direct_type_kind = tg_kind_from_raddbg_type_kind(direct_type_node->kind); - direct_type_key = tg_key_ext(direct_type_kind, (U64)rdbg_type->constructed.direct_type_idx); + RDI_TypeNode *direct_type_node = &rdi->type_nodes[rdi_type->constructed.direct_type_idx]; + TG_Kind direct_type_kind = tg_kind_from_rdi_type_kind(direct_type_node->kind); + direct_type_key = tg_key_ext(direct_type_kind, (U64)rdi_type->constructed.direct_type_idx); direct_type_is_good = 1; direct_type_byte_size = (U64)direct_type_node->byte_size; } // rjf: construct based on kind - switch(rdbg_type->kind) + switch(rdi_type->kind) { - case RADDBG_TypeKind_Modifier: + case RDI_TypeKind_Modifier: { TG_Flags flags = 0; - if(rdbg_type->flags & RADDBG_TypeModifierFlag_Const) + if(rdi_type->flags & RDI_TypeModifierFlag_Const) { flags |= TG_Flag_Const; } - if(rdbg_type->flags & RADDBG_TypeModifierFlag_Volatile) + if(rdi_type->flags & RDI_TypeModifierFlag_Volatile) { flags |= TG_Flag_Volatile; } @@ -470,9 +475,9 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg type->byte_size = direct_type_byte_size; type->flags = flags; }break; - case RADDBG_TypeKind_Ptr: - case RADDBG_TypeKind_LRef: - case RADDBG_TypeKind_RRef: + case RDI_TypeKind_Ptr: + case RDI_TypeKind_LRef: + case RDI_TypeKind_RRef: { type = push_array(arena, TG_Type, 1); type->kind = kind; @@ -480,20 +485,20 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg type->byte_size = graph->address_size; }break; - case RADDBG_TypeKind_Array: + case RDI_TypeKind_Array: { type = push_array(arena, TG_Type, 1); type->kind = kind; type->direct_type_key = direct_type_key; - type->count = rdbg_type->constructed.count; + type->count = rdi_type->constructed.count; type->byte_size = direct_type_byte_size * type->count; }break; - case RADDBG_TypeKind_Function: + case RDI_TypeKind_Function: { - U32 count = rdbg_type->constructed.count; - U32 idx_run_first = rdbg_type->constructed.param_idx_run_first; + U32 count = rdi_type->constructed.count; + U32 idx_run_first = rdi_type->constructed.param_idx_run_first; U32 check_count = 0; - U32 *idx_run = raddbg_idx_run_from_first_count(rdbg, idx_run_first, count, &check_count); + U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); if(check_count == count) { type = push_array(arena, TG_Type, 1); @@ -507,8 +512,8 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg U32 param_type_idx = idx_run[idx]; if(param_type_idx < type_node_idx) { - RADDBG_TypeNode *param_type_node = &rdbg->type_nodes[param_type_idx]; - TG_Kind param_kind = tg_kind_from_raddbg_type_kind(param_type_node->kind); + RDI_TypeNode *param_type_node = &rdi->type_nodes[param_type_idx]; + TG_Kind param_kind = tg_kind_from_rdi_type_kind(param_type_node->kind); type->param_type_keys[idx] = tg_key_ext(param_kind, (U64)param_type_idx); } else @@ -518,15 +523,15 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg } } }break; - case RADDBG_TypeKind_Method: + case RDI_TypeKind_Method: { // NOTE(rjf): for methods, the `direct` type points at the owner type. // the return type, instead of being encoded via the `direct` type, is // encoded via the first parameter. - U32 count = rdbg_type->constructed.count; - U32 idx_run_first = rdbg_type->constructed.param_idx_run_first; + U32 count = rdi_type->constructed.count; + U32 idx_run_first = rdi_type->constructed.param_idx_run_first; U32 check_count = 0; - U32 *idx_run = raddbg_idx_run_from_first_count(rdbg, idx_run_first, count, &check_count); + U32 *idx_run = rdi_idx_run_from_first_count(rdi, idx_run_first, count, &check_count); if(check_count == count) { type = push_array(arena, TG_Type, 1); @@ -540,8 +545,8 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg U32 param_type_idx = idx_run[idx]; if(param_type_idx < type_node_idx) { - RADDBG_TypeNode *param_type_node = &rdbg->type_nodes[param_type_idx]; - TG_Kind param_kind = tg_kind_from_raddbg_type_kind(param_type_node->kind); + RDI_TypeNode *param_type_node = &rdi->type_nodes[param_type_idx]; + TG_Kind param_kind = tg_kind_from_rdi_type_kind(param_type_node->kind); type->param_type_keys[idx] = tg_key_ext(param_kind, (U64)param_type_idx); } else @@ -557,15 +562,15 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg } } }break; - case RADDBG_TypeKind_MemberPtr: + case RDI_TypeKind_MemberPtr: { // rjf: unpack owner type TG_Key owner_type_key = zero_struct; - if(rdbg_type->constructed.owner_type_idx < type_node_idx) + if(rdi_type->constructed.owner_type_idx < type_node_idx) { - RADDBG_TypeNode *owner_type_node = &rdbg->type_nodes[rdbg_type->constructed.owner_type_idx]; - TG_Kind owner_type_kind = tg_kind_from_raddbg_type_kind(owner_type_node->kind); - owner_type_key = tg_key_ext(owner_type_kind, (U64)rdbg_type->constructed.owner_type_idx); + RDI_TypeNode *owner_type_node = &rdi->type_nodes[rdi_type->constructed.owner_type_idx]; + TG_Kind owner_type_kind = tg_kind_from_rdi_type_kind(owner_type_node->kind); + owner_type_key = tg_key_ext(owner_type_kind, (U64)rdi_type->constructed.owner_type_idx); } type = push_array(arena, TG_Type, 1); type->kind = kind; @@ -577,20 +582,20 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg } //- rjf: alias types - else if(rdbg_type->kind == RADDBG_TypeKind_Alias) + else if(rdi_type->kind == RDI_TypeKind_Alias) { // rjf: unpack name String8 name = {0}; - name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: unpack direct type TG_Key direct_type_key = zero_struct; U64 direct_type_byte_size = 0; - if(rdbg_type->user_defined.direct_type_idx < type_node_idx) + if(rdi_type->user_defined.direct_type_idx < type_node_idx) { - RADDBG_TypeNode *direct_type_node = &rdbg->type_nodes[rdbg_type->user_defined.direct_type_idx]; - TG_Kind direct_type_kind = tg_kind_from_raddbg_type_kind(direct_type_node->kind); - direct_type_key = tg_key_ext(direct_type_kind, (U64)rdbg_type->user_defined.direct_type_idx); + RDI_TypeNode *direct_type_node = &rdi->type_nodes[rdi_type->user_defined.direct_type_idx]; + TG_Kind direct_type_kind = tg_kind_from_rdi_type_kind(direct_type_node->kind); + direct_type_key = tg_key_ext(direct_type_kind, (U64)rdi_type->user_defined.direct_type_idx); direct_type_byte_size = direct_type_node->byte_size; } @@ -602,12 +607,35 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg type->direct_type_key = direct_type_key; } + //- rjf: bitfields + else if(RDI_TypeKind_Bitfield == rdi_type->kind) + { + // rjf: unpack direct type + TG_Key direct_type_key = zero_struct; + U64 direct_type_byte_size = 0; + if(rdi_type->bitfield.direct_type_idx < type_node_idx) + { + RDI_TypeNode *direct_type_node = &rdi->type_nodes[rdi_type->bitfield.direct_type_idx]; + TG_Kind direct_type_kind = tg_kind_from_rdi_type_kind(direct_type_node->kind); + direct_type_key = tg_key_ext(direct_type_kind, (U64)rdi_type->bitfield.direct_type_idx); + direct_type_byte_size = direct_type_node->byte_size; + } + + // rjf: produce + type = push_array(arena, TG_Type, 1); + type->kind = kind; + type->byte_size = direct_type_byte_size; + type->direct_type_key = direct_type_key; + type->off = (U32)rdi_type->bitfield.off; + type->count = (U64)rdi_type->bitfield.size; + } + //- rjf: incomplete types - else if(RADDBG_TypeKind_FirstIncomplete <= rdbg_type->kind && rdbg_type->kind <= RADDBG_TypeKind_LastIncomplete) + else if(RDI_TypeKind_FirstIncomplete <= rdi_type->kind && rdi_type->kind <= RDI_TypeKind_LastIncomplete) { // rjf: unpack name String8 name = {0}; - name.str = raddbg_string_from_idx(rdbg, rdbg_type->user_defined.name_string_idx, &name.size); + name.str = rdi_string_from_idx(rdi, rdi_type->user_defined.name_string_idx, &name.size); // rjf: produce type = push_array(arena, TG_Type, 1); @@ -790,7 +818,7 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg } internal TG_Key -tg_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_direct_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { TG_Key result = zero_struct; switch(key.kind) @@ -800,7 +828,7 @@ tg_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key case TG_KeyKind_Cons: { Temp scratch = scratch_begin(0, 0); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); result = type->direct_type_key; scratch_end(scratch); }break; @@ -809,16 +837,16 @@ tg_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key } internal TG_Key -tg_unwrapped_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_unwrapped_direct_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { - key = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, key); - key = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - key = tg_unwrapped_from_graph_raddbg_key(graph, rdbg, key); + key = tg_unwrapped_from_graph_rdi_key(graph, rdi, key); + key = tg_direct_from_graph_rdi_key(graph, rdi, key); + key = tg_unwrapped_from_graph_rdi_key(graph, rdi, key); return key; } internal TG_Key -tg_owner_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_owner_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { TG_Key result = zero_struct; switch(key.kind) @@ -828,7 +856,7 @@ tg_owner_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) case TG_KeyKind_Cons: { Temp scratch = scratch_begin(0, 0); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); result = type->owner_type_key; scratch_end(scratch); }break; @@ -837,14 +865,14 @@ tg_owner_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) } internal TG_Key -tg_ptee_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_ptee_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { TG_Key result = key; B32 passed_ptr = 0; for(;;) { TG_Kind kind = tg_kind_from_key(result); - result = tg_direct_from_graph_raddbg_key(graph, rdbg, result); + result = tg_direct_from_graph_rdi_key(graph, rdi, result); if(kind == TG_Kind_Ptr || kind == TG_Kind_LRef || kind == TG_Kind_RRef) { passed_ptr = 1; @@ -869,7 +897,7 @@ tg_ptee_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) } internal TG_Key -tg_unwrapped_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_unwrapped_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { TG_Key result = key; for(B32 good = 1; good;) @@ -879,7 +907,7 @@ tg_unwrapped_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key kind == TG_Kind_Modifier || kind == TG_Kind_Alias) { - result = tg_direct_from_graph_raddbg_key(graph, rdbg, result); + result = tg_direct_from_graph_rdi_key(graph, rdi, result); } else { @@ -890,7 +918,7 @@ tg_unwrapped_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key } internal U64 -tg_byte_size_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_byte_size_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { U64 result = 0; switch(key.kind) @@ -905,7 +933,7 @@ tg_byte_size_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key case TG_KeyKind_Cons: { Temp scratch = scratch_begin(0, 0); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); result = type->byte_size; scratch_end(scratch); }break; @@ -940,12 +968,12 @@ tg_member_copy(Arena *arena, TG_Member *src) } internal TG_MemberArray -tg_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_members_from_graph_rdi_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { TG_MemberArray result = {0}; Temp scratch = scratch_begin(&arena, 1); { - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); if(type->members != 0) { result.count = type->count; @@ -962,7 +990,7 @@ tg_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *r } internal TG_MemberArray -tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_data_members_from_graph_rdi_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { Temp scratch = scratch_begin(&arena, 1); TG_Kind root_type_kind = tg_kind_from_key(key); @@ -971,7 +999,7 @@ tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Pars TG_MemberList members_list = {0}; B32 members_need_offset_sort = 0; { - TG_Type *root_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *root_type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); typedef struct Task Task; struct Task { @@ -1010,7 +1038,7 @@ tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Pars t->inheritance_chain = tg_key_list_copy(scratch.arena, &task->inheritance_chain); tg_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 = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, type->members[member_idx].type_key); + t->type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, type->members[member_idx].type_key); SLLQueuePush(first_task, last_task, t); members_need_offset_sort = 1; } @@ -1059,7 +1087,7 @@ tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Pars TG_Member *member = &members.v[idx]; if(idx+1 < members.count) { - U64 member_byte_size = tg_byte_size_from_graph_raddbg_key(graph, rdbg, member->type_key); + U64 member_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, member->type_key); Rng1U64 member_byte_range = r1u64(member->off, member->off + member_byte_size); if(member[1].off > member_byte_range.max) { @@ -1086,11 +1114,11 @@ tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Pars { if(members.count+padding_idx > n->prev_member_idx+1) { - MemoryCopy(new_members.v + n->prev_member_idx + 2, - new_members.v + n->prev_member_idx + 1, - sizeof(TG_Member) * (members.count + padding_idx - (n->prev_member_idx+1))); + MemoryCopy(new_members.v + n->prev_member_idx + padding_idx + 2, + new_members.v + n->prev_member_idx + padding_idx + 1, + sizeof(TG_Member) * (members.count + padding_idx - (n->prev_member_idx + padding_idx + 1))); } - TG_Member *padding_member = &new_members.v[n->prev_member_idx+1]; + TG_Member *padding_member = &new_members.v[n->prev_member_idx+padding_idx+1]; MemoryZeroStruct(padding_member); padding_member->kind = TG_MemberKind_Padding; padding_member->type_key = tg_cons_type_make(graph, TG_Kind_Array, tg_key_basic(TG_Kind_U8), n->size); @@ -1106,7 +1134,7 @@ tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Pars } internal void -tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec, B32 skip_return) +tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key, String8List *out, U32 prec, B32 skip_return) { String8 keyword = {0}; TG_Kind kind = tg_kind_from_key(key); @@ -1115,7 +1143,7 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke default: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); str8_list_push(arena, out, push_str8_copy(arena, type->name)); str8_list_push(arena, out, str8_lit(" ")); scratch_end(scratch); @@ -1123,16 +1151,19 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke case TG_Kind_Bitfield: { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, prec, skip_return); + Temp scratch = scratch_begin(&arena, 1); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); + tg_lhs_string_from_key(arena, graph, rdi, type->direct_type_key, out, prec, skip_return); + str8_list_pushf(arena, out, ": %I64u", type->count); + scratch_end(scratch); }break; case TG_Kind_Modifier: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); TG_Key direct = type->direct_type_key; - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + tg_lhs_string_from_key(arena, graph, rdi, direct, out, 1, skip_return); if(type->flags & TG_Flag_Const) { str8_list_push(arena, out, str8_lit("const ")); @@ -1156,7 +1187,7 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke case TG_Kind_Alias: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); str8_list_push(arena, out, push_str8_copy(arena, type->name)); str8_list_push(arena, out, str8_lit(" ")); scratch_end(scratch); @@ -1169,7 +1200,7 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke fwd_udt:; { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, 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)); @@ -1179,8 +1210,8 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke case TG_Kind_Array: { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 2, skip_return); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_lhs_string_from_key(arena, graph, rdi, direct, out, 2, skip_return); if(prec == 1) { str8_list_push(arena, out, str8_lit("(")); @@ -1191,8 +1222,8 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke { if(!skip_return) { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 2, 0); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_lhs_string_from_key(arena, graph, rdi, direct, out, 2, 0); } if(prec == 1) { @@ -1202,32 +1233,32 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke case TG_Kind_Ptr: { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_lhs_string_from_key(arena, graph, rdi, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("*")); }break; case TG_Kind_LRef: { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_lhs_string_from_key(arena, graph, rdi, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("&")); }break; case TG_Kind_RRef: { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_lhs_string_from_key(arena, graph, rdi, direct, out, 1, skip_return); str8_list_push(arena, out, str8_lit("&&")); }break; case TG_Kind_MemberPtr: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); TG_Key direct = type->direct_type_key; - tg_lhs_string_from_key(arena, graph, rdbg, direct, out, 1, skip_return); - TG_Type *container = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, type->owner_type_key); + tg_lhs_string_from_key(arena, graph, rdi, direct, out, 1, skip_return); + TG_Type *container = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, type->owner_type_key); if(container->kind != TG_Kind_Null) { str8_list_push(arena, out, push_str8_copy(arena, container->name)); @@ -1243,7 +1274,7 @@ tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke } internal void -tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec) +tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key, String8List *out, U32 prec) { TG_Kind kind = tg_kind_from_key(key); switch(kind) @@ -1252,8 +1283,8 @@ tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke case TG_Kind_Bitfield: { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_rhs_string_from_key(arena, graph, rdbg, direct, out, prec); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_rhs_string_from_key(arena, graph, rdi, direct, out, prec); }break; case TG_Kind_Modifier: @@ -1262,14 +1293,14 @@ tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke case TG_Kind_RRef: case TG_Kind_MemberPtr: { - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_rhs_string_from_key(arena, graph, rdbg, direct, out, 1); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_rhs_string_from_key(arena, graph, rdi, direct, out, 1); }break; case TG_Kind_Array: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); if(prec == 1) { str8_list_push(arena, out, str8_lit(")")); @@ -1278,15 +1309,15 @@ tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke str8_list_push(arena, out, str8_lit("[")); str8_list_push(arena, out, count_str); str8_list_push(arena, out, str8_lit("]")); - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_rhs_string_from_key(arena, graph, rdbg, direct, out, 2); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_rhs_string_from_key(arena, graph, rdi, direct, out, 2); scratch_end(scratch); }break; case TG_Kind_Function: { Temp scratch = scratch_begin(&arena, 1); - TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); + TG_Type *type = tg_type_from_graph_rdi_key(scratch.arena, graph, rdi, key); if(prec == 1) { str8_list_push(arena, out, str8_lit(")")); @@ -1305,7 +1336,7 @@ tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke for(U64 param_idx = 0; param_idx < param_count; param_idx += 1) { TG_Key param_type_key = param_type_keys[param_idx]; - String8 param_str = tg_string_from_key(arena, graph, rdbg, param_type_key); + String8 param_str = tg_string_from_key(arena, graph, rdi, param_type_key); String8 param_str_trimmed = str8_skip_chop_whitespace(param_str); str8_list_push(arena, out, param_str_trimmed); if(param_idx+1 < param_count) @@ -1315,20 +1346,20 @@ tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Ke } str8_list_push(arena, out, str8_lit(")")); } - TG_Key direct = tg_direct_from_graph_raddbg_key(graph, rdbg, key); - tg_rhs_string_from_key(arena, graph, rdbg, direct, out, 2); + TG_Key direct = tg_direct_from_graph_rdi_key(graph, rdi, key); + tg_rhs_string_from_key(arena, graph, rdi, direct, out, 2); scratch_end(scratch); }break; } } internal String8 -tg_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) +tg_string_from_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key) { Temp scratch = scratch_begin(&arena, 1); String8List list = {0}; - tg_lhs_string_from_key(scratch.arena, graph, rdbg, key, &list, 0, 0); - tg_rhs_string_from_key(scratch.arena, graph, rdbg, key, &list, 0); + tg_lhs_string_from_key(scratch.arena, graph, rdi, key, &list, 0, 0); + tg_rhs_string_from_key(scratch.arena, graph, rdi, key, &list, 0); String8 result = str8_list_join(arena, &list, 0); scratch_end(scratch); return result; diff --git a/src/type_graph/type_graph.h b/src/type_graph/type_graph.h index 68bf9b60..a413dc24 100644 --- a/src/type_graph/type_graph.h +++ b/src/type_graph/type_graph.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef TYPE_GRAPH_NEW_H -#define TYPE_GRAPH_NEW_H +#ifndef TYPE_GRAPH_H +#define TYPE_GRAPH_H //////////////////////////////// //~ rjf: Generated Code @@ -203,8 +203,8 @@ internal TG_KeyList tg_key_list_copy(Arena *arena, TG_KeyList *src); //////////////////////////////// //~ rjf: RADDBG <-> TG Enum Conversions -internal TG_Kind tg_kind_from_raddbg_type_kind(RADDBG_TypeKind kind); -internal TG_MemberKind tg_member_kind_from_raddbg_member_kind(RADDBG_MemberKind kind); +internal TG_Kind tg_kind_from_rdi_type_kind(RDI_TypeKind kind); +internal TG_MemberKind tg_member_kind_from_rdi_member_kind(RDI_MemberKind kind); //////////////////////////////// //~ rjf: Key Type Functions @@ -225,19 +225,19 @@ internal TG_Key tg_cons_type_make(TG_Graph *graph, TG_Kind kind, TG_Key direct_t //////////////////////////////// //~ rjf: Graph Introspection API -internal TG_Type *tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_Key tg_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_Key tg_unwrapped_direct_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_Key tg_owner_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_Key tg_ptee_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_Key tg_unwrapped_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal U64 tg_byte_size_from_graph_raddbg_key(TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_Type *tg_type_from_graph_rdi_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_Key tg_direct_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_Key tg_unwrapped_direct_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_Key tg_owner_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_Key tg_ptee_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_Key tg_unwrapped_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal U64 tg_byte_size_from_graph_rdi_key(TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); internal TG_Kind tg_kind_from_key(TG_Key key); internal TG_Member *tg_member_copy(Arena *arena, TG_Member *src); -internal TG_MemberArray tg_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal TG_MemberArray tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); -internal void tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec, B32 skip_return); -internal void tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key, String8List *out, U32 prec); -internal String8 tg_string_from_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key); +internal TG_MemberArray tg_members_from_graph_rdi_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal TG_MemberArray tg_data_members_from_graph_rdi_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); +internal void tg_lhs_string_from_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key, String8List *out, U32 prec, B32 skip_return); +internal void tg_rhs_string_from_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key, String8List *out, U32 prec); +internal String8 tg_string_from_key(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, TG_Key key); -#endif // TYPE_GRAPH_NEW_H +#endif // TYPE_GRAPH_H diff --git a/src/type_graph/type_graph.mdesk b/src/type_graph/type_graph.mdesk index eac88139..ec342cdf 100644 --- a/src/type_graph/type_graph.mdesk +++ b/src/type_graph/type_graph.mdesk @@ -67,31 +67,28 @@ TG_KindTable: //////////////////////////////// //~ rjf: Generators -@table_gen_enum -TG_Kind: +@enum TG_Kind: { - @expand(TG_KindTable a) `TG_Kind_$(a.name),`; - `TG_Kind_COUNT,`; - `TG_Kind_FirstBasic = TG_Kind_Void,`; - `TG_Kind_LastBasic = TG_Kind_ComplexF128,`; - `TG_Kind_FirstInteger = TG_Kind_Char8,`; - `TG_Kind_LastInteger = TG_Kind_S512,`; - `TG_Kind_FirstSigned1 = TG_Kind_Char8,`; - `TG_Kind_LastSigned1 = TG_Kind_Char32,`; - `TG_Kind_FirstSigned2 = TG_Kind_S8,`; - `TG_Kind_LastSigned2 = TG_Kind_S512,`; - `TG_Kind_FirstIncomplete = TG_Kind_IncompleteStruct,`; - `TG_Kind_LastIncomplete = TG_Kind_IncompleteEnum,`; + @expand(TG_KindTable a) `$(a.name)`, + COUNT, + `FirstBasic = TG_Kind_Void`, + `LastBasic = TG_Kind_ComplexF128`, + `FirstInteger = TG_Kind_Char8`, + `LastInteger = TG_Kind_S512`, + `FirstSigned1 = TG_Kind_Char8`, + `LastSigned1 = TG_Kind_Char32`, + `FirstSigned2 = TG_Kind_S8`, + `LastSigned2 = TG_Kind_S512`, + `FirstIncomplete = TG_Kind_IncompleteStruct`, + `LastIncomplete = TG_Kind_IncompleteEnum`, } -@table_gen_data(type:U8, fallback:0) -tg_kind_basic_byte_size_table: +@data(U8) tg_kind_basic_byte_size_table: { - @expand(TG_KindTable a) `$(a.basic_byte_size),`; + @expand(TG_KindTable a) `$(a.basic_byte_size)`; } -@table_gen_data(type:String8, fallback:`{0}`) -tg_kind_basic_string_table: +@data(String8) tg_kind_basic_string_table: { - @expand(TG_KindTable a) `str8_lit_comp("$(a.basic_string)"),`; + @expand(TG_KindTable a) `str8_lit_comp("$(a.basic_string)")`; } diff --git a/src/ui/generated/ui.meta.c b/src/ui/generated/ui.meta.c index 8a81693b..cb7ca0aa 100644 --- a/src/ui/generated/ui.meta.c +++ b/src/ui/generated/ui.meta.c @@ -185,3 +185,6 @@ internal F32 ui_set_next_corner_radius_11(F32 v) { UI_StackSetNextImpl(ui_state, internal F32 ui_set_next_blur_size(F32 v) { UI_StackSetNextImpl(ui_state, BlurSize, blur_size, F32, v) } internal F32 ui_set_next_text_padding(F32 v) { UI_StackSetNextImpl(ui_state, TextPadding, text_padding, F32, v) } internal UI_TextAlign ui_set_next_text_alignment(UI_TextAlign v) { UI_StackSetNextImpl(ui_state, TextAlignment, text_alignment, UI_TextAlign, v) } +C_LINKAGE_BEGIN +C_LINKAGE_END + diff --git a/src/ui/generated/ui.meta.h b/src/ui/generated/ui.meta.h index e901b86e..bd3a2bc4 100644 --- a/src/ui/generated/ui.meta.h +++ b/src/ui/generated/ui.meta.h @@ -350,5 +350,7 @@ internal F32 ui_set_next_corner_radius_11(F32 v); internal F32 ui_set_next_blur_size(F32 v); internal F32 ui_set_next_text_padding(F32 v); internal UI_TextAlign ui_set_next_text_alignment(UI_TextAlign v); +C_LINKAGE_BEGIN +C_LINKAGE_END #endif // UI_META_H diff --git a/src/ui/ui.mdesk b/src/ui/ui.mdesk index 61c179fb..f94bfdaf 100644 --- a/src/ui/ui.mdesk +++ b/src/ui/ui.mdesk @@ -63,14 +63,14 @@ UI_StackTable: //- rjf: declaring stack node types -@table_gen +@gen { @expand(UI_StackTable a) `typedef struct UI_$(a.name)Node UI_$(a.name)Node; struct UI_$(a.name)Node{UI_$(a.name)Node *next; $(a.type) v;};` } //- rjf: declaring all default stack tops -@table_gen +@gen { `#define UI_DeclStackNils \\`; `struct\\`; @@ -81,7 +81,7 @@ UI_StackTable: //- rjf: initializing all default stack tops -@table_gen +@gen { `#define UI_InitStackNils(state) \\`; @expand(UI_StackTable a) `state->$(a.name_lower)_nil_stack_top.v = $(a.default);\\`; @@ -90,7 +90,7 @@ UI_StackTable: //- rjf: declaring all stack nodes & free lists -@table_gen +@gen { `#define UI_DeclStacks \\`; `struct\\`; @@ -101,7 +101,7 @@ UI_StackTable: //- rjf: initing all stack nodes -@table_gen +@gen { `#define UI_InitStacks(state) \\`; @expand(UI_StackTable a) `state->$(a.name_lower)_stack.top = &state->$(a.name_lower)_nil_stack_top; state->$(a.name_lower)_stack.bottom_val = $(a.default); state->$(a.name_lower)_stack.free = 0; state->$(a.name_lower)_stack.auto_pop = 0;\\`; @@ -110,7 +110,7 @@ UI_StackTable: //- rjf: auto-popping all stacks -@table_gen +@gen { `#define UI_AutoPopStacks(state) \\` @expand(UI_StackTable a) @@ -120,7 +120,7 @@ UI_StackTable: //- rjf: decls for the stack function operation headers -@table_gen +@gen { @expand(UI_StackTable a) `internal $(a.type) $(=>35) ui_top_$(a.name_lower)(void);` @@ -136,7 +136,7 @@ UI_StackTable: //- rjf: defer-loop helpers -@table_gen @c_file +@gen @c_file { `#if 0`; @expand(UI_StackTable a) @@ -146,7 +146,7 @@ UI_StackTable: //- rjf: decls for the stack operation implementations -@table_gen @c_file +@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)) }`; diff --git a/src/ui/ui_basic_widgets.c b/src/ui/ui_basic_widgets.c index 417abf17..7edbfd2b 100644 --- a/src/ui/ui_basic_widgets.c +++ b/src/ui/ui_basic_widgets.c @@ -96,7 +96,7 @@ ui_hover_label(String8 string) { UI_Box *box = ui_build_box_from_string(UI_BoxFlag_Clickable|UI_BoxFlag_DrawText, string); UI_Signal interact = ui_signal_from_box(box); - if(interact.hovering) + if(ui_hovering(interact)) { box->flags |= UI_BoxFlag_DrawBorder; } @@ -271,7 +271,7 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, //- rjf: interact UI_Signal sig = ui_signal_from_box(box); - if(!is_focus_active && (sig.double_clicked || sig.keyboard_clicked)) + if(!is_focus_active && sig.f&(UI_SignalFlag_DoubleClicked|UI_SignalFlag_KeyboardPressed)) { String8 edit_string = pre_edit_value; edit_string.size = Min(edit_buffer_size, pre_edit_value.size); @@ -282,14 +282,14 @@ ui_line_edit(TxtPt *cursor, TxtPt *mark, U8 *edit_buffer, U64 edit_buffer_size, *cursor = txt_pt(1, edit_string.size+1); *mark = txt_pt(1, 1); } - if(is_focus_active && sig.keyboard_clicked) + if(is_focus_active && sig.f&UI_SignalFlag_KeyboardPressed) { ui_set_auto_focus_active_key(ui_key_zero()); - sig.commit = 1; + sig.f |= UI_SignalFlag_Commit; } - if(is_focus_active && sig.dragging) + if(is_focus_active && ui_dragging(sig)) { - if(sig.pressed) + if(ui_pressed(sig)) { *mark = mouse_pt; } @@ -565,7 +565,7 @@ ui_sat_val_picker(F32 hue, F32 *out_sat, F32 *out_val, String8 string) UI_Signal sig = ui_signal_from_box(box); // rjf: click+draw behavior - if(sig.dragging) + if(ui_dragging(sig)) { Vec2F32 dim = dim_2f32(box->rect); *out_sat = (ui_mouse().x - box->rect.x0) / dim.x; @@ -662,7 +662,7 @@ ui_hue_picker(F32 *out_hue, F32 sat, F32 val, String8 string) UI_Signal sig = ui_signal_from_box(box); // rjf: click+draw behavior - if(sig.dragging) + if(ui_dragging(sig)) { Vec2F32 dim = dim_2f32(box->rect); *out_hue = (ui_mouse().y - box->rect.y0) / dim.y; @@ -740,7 +740,7 @@ ui_alpha_picker(F32 *out_alpha, String8 string) UI_Signal sig = ui_signal_from_box(box); // rjf: click+draw behavior - if(sig.dragging) + if(ui_dragging(sig)) { Vec2F32 dim = dim_2f32(box->rect); F32 drag_pct = (ui_mouse().y - box->rect.y0) / dim.y; @@ -889,9 +889,9 @@ ui_table_begin(U64 column_pct_count, F32 **column_pcts, String8 string) // rjf: boundary dragging UI_Signal interact = ui_signal_from_box(box); - if(interact.dragging) + if(ui_dragging(interact)) { - if(interact.pressed) + if(ui_pressed(interact)) { Vec2F32 v = v2f32(*left_pct_ptr, *right_pct_ptr); ui_store_drag_struct(&v); @@ -1228,9 +1228,9 @@ ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_ran UI_ScrollPt start_pt; F32 scroll_space_px; }; - if(scroller_sig.dragging) + if(ui_dragging(scroller_sig)) { - if(scroller_sig.pressed) + if(ui_pressed(scroller_sig)) { UI_ScrollBarDragData drag_data = {pt, (floor_f32(dim_2f32(scroll_area_box->rect).v[axis])-floor_f32(dim_2f32(scroller_box->rect).v[axis]))}; ui_store_drag_struct(&drag_data); @@ -1244,13 +1244,13 @@ ui_scroll_bar(Axis2 axis, UI_Size off_axis_size, UI_ScrollPt pt, Rng1S64 idx_ran ui_scroll_pt_target_idx(&new_pt, new_idx); new_pt.off = 0; } - if(min_scroll_sig.dragging || space_before_sig.dragging) + if(ui_dragging(min_scroll_sig) || ui_dragging(space_before_sig)) { S64 new_idx = new_pt.idx-1; new_idx = Clamp(idx_range.min, new_idx, idx_range.max); ui_scroll_pt_target_idx(&new_pt, new_idx); } - if(max_scroll_sig.dragging || space_after_sig.dragging) + if(ui_dragging(max_scroll_sig) || ui_dragging(space_after_sig)) { S64 new_idx = new_pt.idx+1; new_idx = Clamp(idx_range.min, new_idx, idx_range.max); diff --git a/src/ui/ui_core.c b/src/ui/ui_core.c index 0ee5cf2b..be62687e 100644 --- a/src/ui/ui_core.c +++ b/src/ui/ui_core.c @@ -591,9 +591,9 @@ ui_hot_key(void) } internal UI_Key -ui_active_key(Side side) +ui_active_key(UI_MouseButtonKind button_kind) { - return ui_state->active_box_key[side]; + return ui_state->active_box_key[button_kind]; } //- rjf: controls over interaction @@ -601,7 +601,10 @@ ui_active_key(Side side) internal void ui_kill_action(void) { - ui_state->active_box_key[Side_Min] = ui_state->active_box_key[Side_Max] = ui_key_zero(); + for(EachEnumVal(UI_MouseButtonKind, k)) + { + ui_state->active_box_key[k] = ui_key_zero(); + } } //- rjf: box cache lookup @@ -958,32 +961,41 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act } //- rjf: reset hot if we don't have an active widget - if(ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) && - ui_key_match(ui_state->active_box_key[Side_Max], ui_key_zero())) { - ui_state->hot_box_key = ui_key_zero(); + B32 has_active = 0; + for(EachEnumVal(UI_MouseButtonKind, k)) + { + if(!ui_key_match(ui_state->active_box_key[k], ui_key_zero())) + { + has_active = 1; + } + } + if(!has_active) + { + ui_state->hot_box_key = ui_key_zero(); + } } //- rjf: reset active if our active box is disabled - for(Side side = (Side)0; side < Side_COUNT; side = (Side)(side+1)) + for(EachEnumVal(UI_MouseButtonKind, k)) { - if(!ui_key_match(ui_state->active_box_key[side], ui_key_zero())) + if(!ui_key_match(ui_state->active_box_key[k], ui_key_zero())) { - UI_Box *box = ui_box_from_key(ui_state->active_box_key[side]); + UI_Box *box = ui_box_from_key(ui_state->active_box_key[k]); if(!ui_box_is_nil(box) && box->flags & UI_BoxFlag_Disabled) { - ui_state->active_box_key[side] = ui_key_zero(); + ui_state->active_box_key[k] = ui_key_zero(); } } } //- rjf: reset active keys if they have been pruned - for(Side side = Side_Min; side < Side_COUNT; side = (Side)(side + 1)) + for(EachEnumVal(UI_MouseButtonKind, k)) { - UI_Box *box = ui_box_from_key(ui_state->active_box_key[side]); + UI_Box *box = ui_box_from_key(ui_state->active_box_key[k]); if(ui_box_is_nil(box)) { - ui_state->active_box_key[side] = ui_key_zero(); + ui_state->active_box_key[k] = ui_key_zero(); } } @@ -993,19 +1005,13 @@ ui_begin_build(OS_EventList *events, OS_Handle window, UI_NavActionList *nav_act if((event->kind == OS_EventKind_Press || event->kind == OS_EventKind_Release) && !os_handle_match(event->window, window)) { - for(Side side = Side_Min; side < Side_COUNT; side = (Side)(side + 1)) + for(EachEnumVal(UI_MouseButtonKind, k)) { - ui_state->active_box_key[side] = ui_key_zero(); + ui_state->active_box_key[k] = ui_key_zero(); } break; } } - - //- rjf: tick click timers - for(Side side = (Side)0; side < Side_COUNT; side = (Side)(side + 1)) - { - ui_state->time_since_last_click[side] += real_dt; - } } internal void @@ -1154,7 +1160,7 @@ ui_end_build(void) { // rjf: grab states informing animation B32 is_hot = ui_key_match(box->key, ui_state->hot_box_key); - B32 is_active = ui_key_match(box->key, ui_state->active_box_key[Side_Min]); + 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+10 < ui_state->build_index || box->first_touched_build_index == box->first_disabled_build_index); B32 is_focus_hot = !!(box->flags & UI_BoxFlag_FocusHot) && !(box->flags & UI_BoxFlag_FocusHotDisabled); @@ -1273,7 +1279,7 @@ ui_end_build(void) //- rjf: hover cursor { UI_Box *hot = ui_box_from_key(ui_state->hot_box_key); - UI_Box *active = ui_box_from_key(ui_state->active_box_key[Side_Min]); + UI_Box *active = ui_box_from_key(ui_state->active_box_key[UI_MouseButtonKind_Left]); UI_Box *box = ui_box_is_nil(active) ? hot : active; OS_Cursor cursor = box->hover_cursor; if(box->flags & UI_BoxFlag_Disabled && box->flags & UI_BoxFlag_Clickable) @@ -1313,58 +1319,68 @@ ui_end_build(void) } //- rjf: hovering possibly-truncated drawn text -> store text - if(ui_key_match(ui_key_zero(), ui_state->active_box_key[Side_Min]) && - ui_key_match(ui_key_zero(), ui_state->active_box_key[Side_Max])) { - B32 found = 0; - for(UI_Box *box = ui_state->root, *next = 0; !ui_box_is_nil(box); box = next) + B32 inactive = 1; + for(EachEnumVal(UI_MouseButtonKind, k)) { - UI_BoxRec rec = ui_box_rec_df_pre(box, ui_state->root); - next = rec.next; - 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(!ui_key_match(ui_key_zero(), ui_state->active_box_key[k])) { - if(b->flags & UI_BoxFlag_DrawText && !(b->flags & UI_BoxFlag_DisableTextTrunc)) + inactive = 0; + break; + } + } + if(inactive) + { + B32 found = 0; + for(UI_Box *box = ui_state->root, *next = 0; !ui_box_is_nil(box); box = next) + { + UI_BoxRec rec = ui_box_rec_df_pre(box, ui_state->root); + next = rec.next; + 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) { - 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; - B32 text_is_truncated = (drawn_text_dim.x + text_pos.x > b->rect.x1); - B32 mouse_is_hovering = contains_2f32(r2f32p(text_pos.x, - b->rect.y0, - Min(text_pos.x+drawn_text_dim.x, b->rect.x1), - b->rect.y1), - ui_state->mouse); - if(text_is_truncated && mouse_is_hovering) + if(b->flags & UI_BoxFlag_DrawText && !(b->flags & UI_BoxFlag_DisableTextTrunc)) { - if(!str8_match(box_display_string, ui_state->string_hover_string, 0)) + 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; + B32 text_is_truncated = (drawn_text_dim.x + text_pos.x > b->rect.x1); + B32 mouse_is_hovering = contains_2f32(r2f32p(text_pos.x, + b->rect.y0, + Min(text_pos.x+drawn_text_dim.x, b->rect.x1), + b->rect.y1), + ui_state->mouse); + if(text_is_truncated && mouse_is_hovering) { - 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 = d_fancy_run_list_copy(ui_state->string_hover_arena, &b->display_string_runs); - ui_state->string_hover_begin_us = os_now_microseconds(); + if(!str8_match(box_display_string, ui_state->string_hover_string, 0)) + { + 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 = d_fancy_run_list_copy(ui_state->string_hover_arena, &b->display_string_runs); + ui_state->string_hover_begin_us = os_now_microseconds(); + } + ui_state->string_hover_build_index = ui_state->build_index; + found = 1; + goto break_all_hover_string; } - ui_state->string_hover_build_index = ui_state->build_index; - found = 1; + } + if(b != box && contains_2f32(b->rect, ui_state->mouse) && b->flags & UI_BoxFlag_DrawText) + { goto break_all_hover_string; } } - if(b != box && contains_2f32(b->rect, ui_state->mouse) && b->flags & UI_BoxFlag_DrawText) - { - goto break_all_hover_string; - } } - } - break_all_hover_string:; - if(!found) - { - arena_clear(ui_state->string_hover_arena); - ui_state->string_hover_build_index = 0; - MemoryZeroStruct(&ui_state->string_hover_string); - } - if(found && !ui_string_hover_active()) - { - ui_state->is_animating = 1; + break_all_hover_string:; + if(!found) + { + arena_clear(ui_state->string_hover_arena); + ui_state->string_hover_build_index = 0; + MemoryZeroStruct(&ui_state->string_hover_string); + } + if(found && !ui_string_hover_active()) + { + ui_state->is_animating = 1; + } } } @@ -1568,7 +1584,6 @@ ui_layout_enforce_constraints__in_place_rec(UI_Box *root, Axis2 axis) 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; - child->fixed_size.v[axis] = child->fixed_size.v[axis]; } } } @@ -2356,73 +2371,25 @@ internal UI_Signal ui_signal_from_box(UI_Box *box) { ProfBeginFunction(); - UI_Signal result = {0}; - result.box = box; - result.event_flags = os_get_event_flags(); - B32 disabled = !!(box->flags & UI_BoxFlag_Disabled); - B32 is_focused = !!(box->flags & UI_BoxFlag_FocusHot) && !(box->flags & UI_BoxFlag_FocusHotDisabled); + B32 is_focus_hot = box->flags & UI_BoxFlag_FocusHot && !(box->flags & UI_BoxFlag_FocusHotDisabled); + UI_Signal sig = {box}; + sig.event_flags |= os_get_event_flags(); - //- rjf: gather events - OS_Event *left_press = 0; - OS_Event *left_release = 0; - OS_Event *right_press = 0; - OS_Event *right_release = 0; - for(OS_Event *evt = ui_state->events->first; evt != 0; evt = evt->next) + ////////////////////////////// + //- rjf: calculate possibly-clipped box rectangle + // + Rng2F32 rect = box->rect; + for(UI_Box *b = box->parent; !ui_box_is_nil(b); b = b->parent) { - if(os_handle_match(ui_state->window, evt->window)) + if(b->flags & UI_BoxFlag_Clip) { - if(left_press == 0 && evt->kind == OS_EventKind_Press && evt->key == OS_Key_LeftMouseButton) - { - left_press = evt; - } - if(left_release == 0 && evt->kind == OS_EventKind_Release && evt->key == OS_Key_LeftMouseButton) - { - left_release = evt; - } - if(right_press == 0 && evt->kind == OS_EventKind_Press && evt->key == OS_Key_RightMouseButton) - { - right_press = evt; - } - if(right_release == 0 && evt->kind == OS_EventKind_Release && evt->key == OS_Key_RightMouseButton) - { - right_release = evt; - } - } - } - - //- rjf: unpack mouse position info - Vec2F32 mouse = ui_state->mouse; - if(left_press != 0) { mouse = left_press->pos; } - if(left_release != 0) { mouse = left_release->pos; } - if(right_press != 0) { mouse = right_press->pos; } - if(right_release != 0) { mouse = right_release->pos; } - B32 mouse_is_over = contains_2f32(box->rect, mouse); - - //- rjf: check for parent that is clipping - if(box->flags & (UI_BoxFlag_Clickable|UI_BoxFlag_ViewScroll) && mouse_is_over) - { - for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent) - { - if(parent->flags & UI_BoxFlag_Clip) - { - mouse_is_over = mouse_is_over && contains_2f32(parent->rect, mouse); - break; - } - } - } - - //- rjf: get default nav ancestor - UI_Box *default_nav_parent = &ui_g_nil_box; - for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) - { - if(p->flags & UI_BoxFlag_DefaultFocusNav) - { - default_nav_parent = p; - break; + rect = intersect_2f32(rect, b->rect); } } + ////////////////////////////// //- rjf: determine if we're under the context menu or not + // B32 ctx_menu_is_ancestor = 0; ProfScope("check context menu ancestor") { @@ -2436,276 +2403,340 @@ ui_signal_from_box(UI_Box *box) } } - //- rjf: clip against floaters - if(mouse_is_over) ProfScope("clip against floaters") + ////////////////////////////// + //- rjf: calculate blacklist rectangles + // + Rng2F32 blacklist_rect = {0}; + if(!ctx_menu_is_ancestor && ui_state->ctx_menu_open) { - if(!ctx_menu_is_ancestor && ui_state->ctx_menu_open != 0 && contains_2f32(ui_state->ctx_menu_root->rect, mouse)) - { - mouse_is_over = 0; - } + blacklist_rect = ui_state->ctx_menu_root->rect; } - //- rjf: mouse clickability - if(box->flags & UI_BoxFlag_MouseClickable && !ui_key_match(ui_key_zero(), box->key)) ProfScope("clickability") + ////////////////////////////// + //- rjf: process events related to this box + // + B32 view_scrolled = 0; + for(OS_Event *evt = ui_state->events->first, *next = 0; + evt != 0; + evt = next) { - // rjf: hot management - if((ui_key_match(ui_key_zero(), ui_state->active_box_key[Side_Min]) && - ui_key_match(ui_key_zero(), ui_state->active_box_key[Side_Max])) && - ui_key_match(ui_key_zero(), ui_state->hot_box_key) && - mouse_is_over) + B32 taken = 0; + next = evt->next; + + //- rjf: skip disqualified events + if(!os_handle_match(evt->window, ui_state->window)) {continue;} + + //- rjf: unpack event + Vec2F32 evt_mouse = evt->pos; + B32 evt_mouse_in_bounds = !contains_2f32(blacklist_rect, evt_mouse) && contains_2f32(rect, evt_mouse); + UI_MouseButtonKind evt_mouse_button_kind = (evt->key == OS_Key_LeftMouseButton ? UI_MouseButtonKind_Left : + evt->key == OS_Key_MiddleMouseButton ? UI_MouseButtonKind_Middle : + evt->key == OS_Key_RightMouseButton ? UI_MouseButtonKind_Right : + UI_MouseButtonKind_Left); + B32 evt_key_is_mouse = (evt->key == OS_Key_LeftMouseButton || + evt->key == OS_Key_MiddleMouseButton || + evt->key == OS_Key_RightMouseButton); + sig.event_flags |= evt->flags; + + //- rjf: mouse presses in box -> set hot/active; mark signal accordingly + if(box->flags & UI_BoxFlag_MouseClickable && + evt->kind == OS_EventKind_Press && + evt_mouse_in_bounds && + evt_key_is_mouse) { ui_state->hot_box_key = box->key; + ui_state->active_box_key[evt_mouse_button_kind] = box->key; + sig.f |= (UI_SignalFlag_LeftPressed<drag_start_mouse = evt->pos; + if(ui_key_match(box->key, ui_state->press_key_history[evt_mouse_button_kind][0]) && + evt->timestamp_us-ui_state->press_timestamp_history_us[evt_mouse_button_kind][0] <= 1000000*os_double_click_time()) + { + sig.f |= (UI_SignalFlag_LeftDoubleClicked<key, ui_state->press_key_history[evt_mouse_button_kind][0]) && + ui_key_match(box->key, ui_state->press_key_history[evt_mouse_button_kind][1]) && + evt->timestamp_us-ui_state->press_timestamp_history_us[evt_mouse_button_kind][0] <= 1000000*os_double_click_time() && + ui_state->press_timestamp_history_us[evt_mouse_button_kind][0] - ui_state->press_timestamp_history_us[evt_mouse_button_kind][1] <= 1000000*os_double_click_time()) + { + sig.f |= (UI_SignalFlag_LeftTripleClicked<press_timestamp_history_us[evt_mouse_button_kind][1], &ui_state->press_timestamp_history_us[evt_mouse_button_kind][0], + sizeof(ui_state->press_timestamp_history_us[evt_mouse_button_kind][0]) * ArrayCount(ui_state->press_timestamp_history_us[evt_mouse_button_kind])-1); + MemoryCopy(&ui_state->press_key_history[evt_mouse_button_kind][1], &ui_state->press_key_history[evt_mouse_button_kind][0], + sizeof(ui_state->press_key_history[evt_mouse_button_kind][0]) * ArrayCount(ui_state->press_key_history[evt_mouse_button_kind])-1); + MemoryCopy(&ui_state->press_pos_history[evt_mouse_button_kind][1], &ui_state->press_pos_history[evt_mouse_button_kind][0], + sizeof(ui_state->press_pos_history[evt_mouse_button_kind][0]) * ArrayCount(ui_state->press_pos_history[evt_mouse_button_kind])-1); + ui_state->press_timestamp_history_us[evt_mouse_button_kind][0] = evt->timestamp_us; + ui_state->press_key_history[evt_mouse_button_kind][0] = box->key; + ui_state->press_pos_history[evt_mouse_button_kind][0] = evt_mouse; + taken = 1; } - else if(ui_key_match(ui_state->hot_box_key, box->key) && - !mouse_is_over && - !ui_key_match(ui_state->active_box_key[Side_Min], box->key) && - !ui_key_match(ui_state->active_box_key[Side_Max], box->key)) + + //- rjf: mouse releases in active box -> unset active; mark signal accordingly + if(box->flags & UI_BoxFlag_MouseClickable && + evt->kind == OS_EventKind_Release && + ui_key_match(ui_state->active_box_key[evt_mouse_button_kind], box->key) && + evt_mouse_in_bounds && + evt_key_is_mouse) + { + ui_state->active_box_key[evt_mouse_button_kind] = ui_key_zero(); + sig.f |= (UI_SignalFlag_LeftReleased< unset hot/active + if(box->flags & UI_BoxFlag_MouseClickable && + evt->kind == OS_EventKind_Release && + ui_key_match(ui_state->active_box_key[evt_mouse_button_kind], box->key) && + !evt_mouse_in_bounds && + evt_key_is_mouse) { ui_state->hot_box_key = ui_key_zero(); + ui_state->active_box_key[evt_mouse_button_kind] = ui_key_zero(); + sig.f |= (UI_SignalFlag_LeftReleased<hot_box_key, box->key) && - ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) && - left_press != 0) + //- rjf: focus is hot & keyboard click -> mark signal + if(box->flags & UI_BoxFlag_KeyboardClickable && + is_focus_hot && + evt->kind == OS_EventKind_Press && + evt->key == OS_Key_Return) { - os_eat_event(ui_state->events, left_press); - result.pressed = 1; - ui_state->active_box_key[Side_Min] = box->key; - } - else if(!disabled && - ui_key_match(ui_state->active_box_key[Side_Min], box->key) && - left_release != 0) - { - os_eat_event(ui_state->events, left_release); - result.released = 1; - result.clicked = mouse_is_over; - ui_state->hot_box_key = mouse_is_over ? box->key : ui_key_zero(); - ui_state->active_box_key[Side_Min] = ui_key_zero(); + sig.f |= UI_SignalFlag_KeyboardPressed; + taken = 1; } - // rjf: active management (right click) - if(!disabled && - ui_key_match(ui_state->hot_box_key, box->key) && - ui_key_match(ui_state->active_box_key[Side_Max], ui_key_zero()) && - right_press != 0) + //- rjf: scrolling + if(box->flags & UI_BoxFlag_Scroll && + evt->kind == OS_EventKind_Scroll && + evt->flags != OS_EventFlag_Ctrl && + evt_mouse_in_bounds) { - os_eat_event(ui_state->events, right_press); - // NOTE(rjf): Add this in if it ever needs to exist: - // result.right_pressed = 1; - ui_state->active_box_key[Side_Max] = box->key; - } - else if(!disabled && - ui_key_match(ui_state->active_box_key[Side_Max], box->key) && - right_release != 0) - { - os_eat_event(ui_state->events, right_release); - // NOTE(rjf): Add this in if it ever needs to exist: - // result.right_released = 1; - result.right_clicked = mouse_is_over; - ui_state->active_box_key[Side_Max] = ui_key_zero(); - } - - // rjf: dragging - if(ui_key_match(ui_state->active_box_key[Side_Min], box->key)) - { - result.dragging = 1; - if(result.pressed) + Vec2F32 delta = evt->delta; + if(evt->flags & OS_EventFlag_Shift) { - ui_state->drag_start_mouse = mouse; + Swap(F32, delta.x, delta.y); } + sig.scroll.x += (S16)(delta.x/30.f); + sig.scroll.y += (S16)(delta.y/30.f); + taken = 1; } - } - - //- rjf: plain scrolling - if(box->flags & UI_BoxFlag_Scroll) - { - OS_EventList *events = ui_events(); - for(OS_Event *event = events->first, *next = 0; event != 0; event = next) + + //- rjf: view scrolling + if(box->flags & UI_BoxFlag_ViewScroll && box->first_touched_build_index != box->last_touched_build_index && + evt->kind == OS_EventKind_Scroll && + evt->flags != OS_EventFlag_Ctrl && + evt_mouse_in_bounds) { - next = event->next; - if(os_handle_match(event->window, ui_state->window) && event->flags != OS_EventFlag_Ctrl) + Vec2F32 delta = evt->delta; + if(evt->flags & OS_EventFlag_Shift) { - switch(event->kind) + Swap(F32, delta.x, delta.y); + } + if(!(box->flags & UI_BoxFlag_ViewScrollX)) + { + if(delta.y == 0) { - default:break; - case OS_EventKind_Scroll: - if(mouse_is_over) - { - Vec2F32 delta = event->delta; - if(event->flags & OS_EventFlag_Shift) - { - Swap(F32, delta.x, delta.y); - } - os_eat_event(events, event); - result.scroll.x += (S16)(delta.x/30.f); - result.scroll.y += (S16)(delta.y/30.f); - }break; + delta.y = delta.x; } + delta.x = 0; } - } - } - - //- rjf: view scrolling - if(box->first_touched_build_index != box->last_touched_build_index && box->flags & UI_BoxFlag_ViewScroll) - { - OS_EventList *events = ui_events(); - for(OS_Event *event = events->first, *next = 0; event != 0; event = next) - { - next = event->next; - if(os_handle_match(event->window, ui_state->window) && event->flags != OS_EventFlag_Ctrl) + if(!(box->flags & UI_BoxFlag_ViewScrollY)) { - switch(event->kind) + if(delta.x == 0) { - default:break; - case OS_EventKind_Scroll: - if(mouse_is_over) - { - Vec2F32 delta = event->delta; - if(event->flags & OS_EventFlag_Shift) - { - Swap(F32, delta.x, delta.y); - } - if(!(box->flags & UI_BoxFlag_ViewScrollX)) - { - delta.x = 0; - } - if(!(box->flags & UI_BoxFlag_ViewScrollY)) - { - delta.y = 0; - } - os_eat_event(events, event); - box->view_off_target.x += delta.x; - box->view_off_target.y += delta.y; - }break; + delta.x = delta.y; } + delta.y = 0; } + os_eat_event(ui_state->events, evt); + box->view_off_target.x += delta.x; + box->view_off_target.y += delta.y; + view_scrolled = 1; + taken = 1; } - if(box->flags & UI_BoxFlag_ViewClamp) + + //- rjf: taken -> eat event + if(taken) { - Vec2F32 max_view_off_target = - { - ClampBot(0, box->view_bounds.x - box->fixed_size.x), - ClampBot(0, box->view_bounds.y - box->fixed_size.y), - }; - if(box->flags & UI_BoxFlag_ViewClampX) { box->view_off_target.x = Clamp(0, box->view_off_target.x, max_view_off_target.x); } - if(box->flags & UI_BoxFlag_ViewClampY) { box->view_off_target.y = Clamp(0, box->view_off_target.y, max_view_off_target.y); } + os_eat_event(ui_state->events, evt); } } - //- rjf: focus + clicks - B32 keyboard_click = 0; - if(!disabled && is_focused && box->flags & UI_BoxFlag_KeyboardClickable) + ////////////////////////////// + //- rjf: process nav actions related to this box + // { - if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return) != 0) - // TODO(rjf): need to handle case where this would conflict with typing. - // if(os_key_press(ui_events(), ui_window(), 0, OS_Key_Return) != 0 || - // os_key_press(ui_events(), ui_window(), 0, OS_Key_Space) != 0) - { - keyboard_click = 1; - result.clicked = 1; - result.pressed = 1; - result.keyboard_clicked = 1; - } - } - - //- rjf: focus + ctrl+clicks - if(!disabled && is_focused && box->flags & UI_BoxFlag_KeyboardClickable) - { - if(os_key_press(ui_events(), ui_window(), OS_EventFlag_Shift, OS_Key_Return)) - { - result.right_clicked = 1; - } - } - - //- rjf: focus & ctrl+c - if(is_focused && box->flags & UI_BoxFlag_KeyboardClickable) - { - for(UI_NavActionNode *n = ui_nav_actions()->first, *next = 0; n != 0; n = next) + for(UI_NavActionNode *n = ui_state->nav_actions->first, *next = 0; + n != 0; + n = next) { next = n->next; - if(n->v.flags & UI_NavActionFlag_Copy) + UI_NavAction *action = &n->v; + B32 taken = 0; + if(is_focus_hot && box->flags & UI_BoxFlag_KeyboardClickable && action->flags & UI_NavActionFlag_Copy) { ui_state->clipboard_copy_key = box->key; + taken = 1; + } + if(box->flags & UI_BoxFlag_Clickable && box->fastpath_codepoint != 0) + { + B32 ancestor_is_focused = 0; + for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent) + { + if(parent->flags & UI_BoxFlag_FocusActive) + { + ancestor_is_focused = 1; + if(parent->flags & UI_BoxFlag_FocusActiveDisabled || + !ui_key_match(parent->default_nav_focus_active_key, ui_key_zero())) + { + ancestor_is_focused = 0; + break; + } + } + } + if(ancestor_is_focused && action->insertion.size != 0) + { + Temp scratch = scratch_begin(0, 0); + String32 insertion32 = str32_from_8(scratch.arena, action->insertion); + if(insertion32.size == 1 && insertion32.str[0] == box->fastpath_codepoint) + { + taken = 1; + sig.f |= UI_SignalFlag_Clicked|UI_SignalFlag_Pressed; + } + scratch_end(scratch); + } + } + if(taken) + { ui_nav_eat_action_node(ui_nav_actions(), n); } } } - //- rjf: focused ancestors and fastpath codepoint -> click - if(box->flags & UI_BoxFlag_Clickable && box->fastpath_codepoint != 0) + ////////////////////////////// + //- rjf: clamp view scrolling + // + if(view_scrolled && box->flags & UI_BoxFlag_ViewClamp) { - B32 is_focused = 0; - for(UI_Box *parent = box->parent; !ui_box_is_nil(parent); parent = parent->parent) + Vec2F32 max_view_off_target = { - if(parent->flags & UI_BoxFlag_FocusActive) - { - is_focused = 1; - if(parent->flags & UI_BoxFlag_FocusActiveDisabled || - !ui_key_match(parent->default_nav_focus_active_key, ui_key_zero())) - { - is_focused = 0; - break; - } - } - } - if(is_focused) + ClampBot(0, box->view_bounds.x - box->fixed_size.x), + ClampBot(0, box->view_bounds.y - box->fixed_size.y), + }; + if(box->flags & UI_BoxFlag_ViewClampX) { box->view_off_target.x = Clamp(0, box->view_off_target.x, max_view_off_target.x); } + if(box->flags & UI_BoxFlag_ViewClampY) { box->view_off_target.y = Clamp(0, box->view_off_target.y, max_view_off_target.y); } + } + + ////////////////////////////// + //- rjf: active -> dragging + // + if(box->flags & UI_BoxFlag_MouseClickable) + { + for(EachEnumVal(UI_MouseButtonKind, k)) { - Temp scratch = scratch_begin(0, 0); - B32 clicked = 0; - for(UI_NavActionNode *n = ui_nav_actions()->first; n != 0; n = n->next) + if(ui_key_match(ui_state->active_box_key[k], box->key) || + sig.f & (UI_SignalFlag_LeftPressed<v; - if(action->insertion.size != 0) - { - String32 insertion32 = str32_from_8(scratch.arena, action->insertion); - if(insertion32.size == 1 && insertion32.str[0] == box->fastpath_codepoint) - { - clicked = 1; - ui_nav_eat_action_node(ui_nav_actions(), n); - break; - } - } + sig.f |= (UI_SignalFlag_LeftDragging< double-dragging + // + if(box->flags & UI_BoxFlag_MouseClickable) { - if(ui_key_match(ui_state->last_click_key[Side_Min], box->key) && - ui_state->time_since_last_click[Side_Min] < os_double_click_time()) + for(EachEnumVal(UI_MouseButtonKind, k)) { - result.double_clicked = 1; + if(sig.f & (UI_SignalFlag_LeftDragging<press_key_history[k][0], box->key) && + ui_key_match(ui_state->press_key_history[k][1], box->key) && + ui_state->press_timestamp_history_us[k][0] - ui_state->press_timestamp_history_us[k][1] <= 1000000*os_double_click_time() && + length_2f32(sub_2f32(ui_state->press_pos_history[k][0], ui_state->press_pos_history[k][1])) < 10.f) + { + sig.f |= (UI_SignalFlag_LeftDoubleDragging<time_since_last_click[Side_Min] = 0; - ui_state->last_click_key[Side_Min] = box->key; } + ////////////////////////////// + //- rjf: dragging started via triple-click -> triple-dragging + // + if(box->flags & UI_BoxFlag_MouseClickable) + { + for(EachEnumVal(UI_MouseButtonKind, k)) + { + if(sig.f & (UI_SignalFlag_LeftDragging<press_key_history[k][0], box->key) && + ui_key_match(ui_state->press_key_history[k][1], box->key) && + ui_key_match(ui_state->press_key_history[k][2], box->key) && + ui_state->press_timestamp_history_us[k][0] - ui_state->press_timestamp_history_us[k][1] <= 1000000*os_double_click_time() && + ui_state->press_timestamp_history_us[k][1] - ui_state->press_timestamp_history_us[k][2] <= 1000000*os_double_click_time() && + length_2f32(sub_2f32(ui_state->press_pos_history[k][0], ui_state->press_pos_history[k][1])) < 10.f && + length_2f32(sub_2f32(ui_state->press_pos_history[k][1], ui_state->press_pos_history[k][2])) < 10.f) + { + sig.f |= (UI_SignalFlag_LeftTripleDragging< always mark mouse-over + // + { + if(contains_2f32(rect, ui_state->mouse) && + !contains_2f32(blacklist_rect, ui_state->mouse)) + { + sig.f |= UI_SignalFlag_MouseOver; + } + } + + ////////////////////////////// + //- rjf: mouse is over this box's rect, no other hot key? -> set hot key, mark hovering + // + { + if(box->flags & UI_BoxFlag_MouseClickable && + contains_2f32(rect, ui_state->mouse) && + !contains_2f32(blacklist_rect, ui_state->mouse) && + (ui_key_match(ui_state->hot_box_key, ui_key_zero()) || ui_key_match(ui_state->hot_box_key, box->key)) && + (ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], ui_key_zero()) || ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Left], box->key)) && + (ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Middle], ui_key_zero()) || ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Middle], box->key)) && + (ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Right], ui_key_zero()) || ui_key_match(ui_state->active_box_key[UI_MouseButtonKind_Right], box->key))) + { + ui_state->hot_box_key = box->key; + sig.f |= UI_SignalFlag_Hovering; + } + } + + ////////////////////////////// //- rjf: clicking on something outside the context menu kills the context menu - if(!ctx_menu_is_ancestor && result.pressed) + // + if(!ctx_menu_is_ancestor && sig.f & (UI_SignalFlag_LeftPressed|UI_SignalFlag_RightPressed|UI_SignalFlag_MiddlePressed)) { ui_ctx_menu_close(); } - //- rjf: set hovering status - result.hovering = mouse_is_over && ((ui_key_match(ui_state->hot_box_key, ui_key_zero()) || - ui_key_match(ui_state->hot_box_key, box->key)) && - (ui_key_match(ui_state->active_box_key[Side_Min], ui_key_zero()) || - ui_key_match(ui_state->active_box_key[Side_Min], box->key))); - result.mouse_over = mouse_is_over; + ////////////////////////////// + //- rjf: get default nav ancestor + // + UI_Box *default_nav_parent = &ui_g_nil_box; + for(UI_Box *p = ui_top_parent(); !ui_box_is_nil(p); p = p->parent) + { + if(p->flags & UI_BoxFlag_DefaultFocusNav) + { + default_nav_parent = p; + break; + } + } + ////////////////////////////// //- rjf: clicking in default nav -> set navigation state to this box - if(box->flags & UI_BoxFlag_ClickToFocus && result.pressed && !ui_box_is_nil(default_nav_parent)) + // + if(box->flags & UI_BoxFlag_ClickToFocus && sig.f&UI_SignalFlag_Pressed && !ui_box_is_nil(default_nav_parent)) { default_nav_parent->default_nav_focus_next_hot_key = box->key; if(!ui_key_match(default_nav_parent->default_nav_focus_active_key, box->key)) @@ -2714,15 +2745,9 @@ ui_signal_from_box(UI_Box *box) } } - //- rjf: focus & external commit events -> commit - if(is_focused && ui_state->external_focus_commit) - { - ui_state->external_focus_commit = 0; - result.commit = 1; - } ProfEnd(); - return result; + return sig; } //////////////////////////////// diff --git a/src/ui/ui_core.h b/src/ui/ui_core.h index 1d4663a1..3b511a92 100644 --- a/src/ui/ui_core.h +++ b/src/ui/ui_core.h @@ -31,6 +31,18 @@ struct UI_IconInfo String8 icon_kind_text_map[UI_IconKind_COUNT]; }; +//////////////////////////////// +//~ rjf: Mouse Button Kinds + +typedef enum UI_MouseButtonKind +{ + UI_MouseButtonKind_Left, + UI_MouseButtonKind_Middle, + UI_MouseButtonKind_Right, + UI_MouseButtonKind_COUNT +} +UI_MouseButtonKind; + //////////////////////////////// //~ rjf: Focus Types @@ -339,24 +351,89 @@ struct UI_BoxList U64 count; }; +typedef U32 UI_SignalFlags; +enum +{ + // rjf: mouse press -> box was pressed while hovering + UI_SignalFlag_LeftPressed = (1<<0), + UI_SignalFlag_MiddlePressed = (1<<1), + UI_SignalFlag_RightPressed = (1<<2), + + // rjf: dragging -> box was previously pressed, user is still holding button + UI_SignalFlag_LeftDragging = (1<<3), + UI_SignalFlag_MiddleDragging = (1<<4), + UI_SignalFlag_RightDragging = (1<<5), + + // rjf: double-dragging -> box was previously double-clicked, user is still holding button + UI_SignalFlag_LeftDoubleDragging = (1<<6), + UI_SignalFlag_MiddleDoubleDragging= (1<<7), + UI_SignalFlag_RightDoubleDragging = (1<<8), + + // rjf: triple-dragging -> box was previously triple-clicked, user is still holding button + UI_SignalFlag_LeftTripleDragging = (1<<9), + UI_SignalFlag_MiddleTripleDragging= (1<<10), + UI_SignalFlag_RightTripleDragging = (1<<11), + + // rjf: released -> box was previously pressed & user released, in or out of bounds + UI_SignalFlag_LeftReleased = (1<<12), + UI_SignalFlag_MiddleReleased = (1<<13), + UI_SignalFlag_RightReleased = (1<<14), + + // rjf: clicked -> box was previously pressed & user released, in bounds + UI_SignalFlag_LeftClicked = (1<<15), + UI_SignalFlag_MiddleClicked = (1<<16), + UI_SignalFlag_RightClicked = (1<<17), + + // rjf: double clicked -> box was previously clicked, pressed again + UI_SignalFlag_LeftDoubleClicked = (1<<18), + UI_SignalFlag_MiddleDoubleClicked = (1<<19), + UI_SignalFlag_RightDoubleClicked = (1<<20), + + // rjf: triple clicked -> box was previously clicked twice, pressed again + UI_SignalFlag_LeftTripleClicked = (1<<21), + UI_SignalFlag_MiddleTripleClicked = (1<<22), + UI_SignalFlag_RightTripleClicked = (1<<23), + + // rjf: keyboard pressed -> box had focus, user activated via their keyboard + UI_SignalFlag_KeyboardPressed = (1<<24), + + // rjf: passive mouse info + UI_SignalFlag_Hovering = (1<<25), // hovering specifically this box + UI_SignalFlag_MouseOver = (1<<26), // mouse is over, but may be occluded + + // rjf: committing state changes via user interaction + UI_SignalFlag_Commit = (1<<27), + + // rjf: high-level combos + UI_SignalFlag_Pressed = UI_SignalFlag_LeftPressed|UI_SignalFlag_KeyboardPressed, + UI_SignalFlag_Released = UI_SignalFlag_LeftReleased, + UI_SignalFlag_Clicked = UI_SignalFlag_LeftClicked|UI_SignalFlag_KeyboardPressed, + UI_SignalFlag_DoubleClicked = UI_SignalFlag_LeftDoubleClicked, + UI_SignalFlag_TripleClicked = UI_SignalFlag_LeftTripleClicked, + UI_SignalFlag_Dragging = UI_SignalFlag_LeftDragging, +}; + typedef struct UI_Signal UI_Signal; struct UI_Signal { UI_Box *box; OS_EventFlags event_flags; Vec2S16 scroll; - B8 clicked :1; - B8 keyboard_clicked :1; - B8 double_clicked :1; - B8 right_clicked :1; - B8 pressed :1; - B8 released :1; - B8 dragging :1; - B8 hovering :1; - B8 mouse_over :1; - B8 commit :1; + UI_SignalFlags f; }; +#define ui_pressed(s) !!((s).f&UI_SignalFlag_Pressed) +#define ui_clicked(s) !!((s).f&UI_SignalFlag_Clicked) +#define ui_released(s) !!((s).f&UI_SignalFlag_Released) +#define ui_double_clicked(s) !!((s).f&UI_SignalFlag_DoubleClicked) +#define ui_triple_clicked(s) !!((s).f&UI_SignalFlag_TripleClicked) +#define ui_middle_clicked(s) !!((s).f&UI_SignalFlag_MiddleClicked) +#define ui_right_clicked(s) !!((s).f&UI_SignalFlag_RightClicked) +#define ui_dragging(s) !!((s).f&UI_SignalFlag_Dragging) +#define ui_hovering(s) !!((s).f&UI_SignalFlag_Hovering) +#define ui_mouse_over(s) !!((s).f&UI_SignalFlag_MouseOver) +#define ui_committed(s) !!((s).f&UI_SignalFlag_Commit) + typedef struct UI_Nav UI_Nav; struct UI_Nav { @@ -415,10 +492,11 @@ struct UI_State //- rjf: user interaction state UI_Key hot_box_key; - UI_Key active_box_key[Side_COUNT]; + UI_Key active_box_key[UI_MouseButtonKind_COUNT]; UI_Key clipboard_copy_key; - F32 time_since_last_click[Side_COUNT]; - UI_Key last_click_key[Side_COUNT]; + U64 press_timestamp_history_us[UI_MouseButtonKind_COUNT][3]; + UI_Key press_key_history[UI_MouseButtonKind_COUNT][3]; + Vec2F32 press_pos_history[UI_MouseButtonKind_COUNT][3]; Vec2F32 drag_start_mouse; Arena *drag_state_arena; String8 drag_state_data; @@ -551,7 +629,7 @@ internal D_FancyRunList ui_string_hover_runs(Arena *arena); //- rjf: interaction keys internal UI_Key ui_hot_key(void); -internal UI_Key ui_active_key(Side side); +internal UI_Key ui_active_key(UI_MouseButtonKind button_kind); //- rjf: controls over interaction internal void ui_kill_action(void); diff --git a/src/unwind/unwind.c b/src/unwind/unwind.c index 85704be8..51c65f53 100644 --- a/src/unwind/unwind.c +++ b/src/unwind/unwind.c @@ -2,401 +2,39 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ allen: Unwind Functions - -//- mem view construction +//~ rjf: Memory View Helpers internal UNW_MemView -unw_memview_from_data(String8 data, U64 base_vaddr){ +unw_memview_from_data(String8 data, U64 base_vaddr) +{ UNW_MemView result = {0}; result.data = data.str; result.addr_first = base_vaddr; result.addr_opl = base_vaddr + data.size; - return(result); + return result; } -//- mem view user face for unwind users - internal B32 -unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out){ +unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out) +{ B32 result = 0; - if (memview->addr_first <= addr && addr + size <= memview->addr_opl){ + if(memview->addr_first <= addr && addr + size <= memview->addr_opl) + { MemoryCopy(out, (U8*)memview->data + addr - memview->addr_first, size); result = 1; } - return(result); + return result; } - //////////////////////////////// -//~ allen: PE X64 Unwind Functions +//~ rjf: PE/X64 Unwind Implementation -//- main interface +//- rjf: helpers -internal UNW_Result -unw_pe_x64(String8 bindata, PE_BinInfo *bin, - U64 base_vaddr, UNW_MemView *memview, UNW_X64_Regs *regs){ - UNW_Result result = {0}; - U64 missed_read_addr = 0; - - //- grab ip_voff (several places can use this) - U64 ip_voff = regs->rip.u64 - base_vaddr; - - //- get pdata entry from current ip - PE_IntelPdata *initial_pdata = 0; - { - U64 initial_pdata_off = pe_intel_pdata_off_from_voff__binary_search(bindata, bin, ip_voff); - if (initial_pdata_off != 0){ - initial_pdata = (PE_IntelPdata*)(bindata.str + initial_pdata_off); - } - } - - //- no pdata; unwind by reading stack pointer - if (initial_pdata == 0){ - // read ip from stack pointer - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if (!unw_memview_read_struct(memview, sp, &new_ip)){ - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - //- got pdata; perform unwinding with exception handling - else{ - // try epilog unwind - B32 did_epilog_unwind = 0; - if (unw_pe_x64__voff_is_in_epilog(bindata, bin, ip_voff, initial_pdata)){ - result = unw_pe_x64__epilog(bindata, bin, base_vaddr, memview, regs); - did_epilog_unwind = 1; - } - - // try xdata unwind - if (!did_epilog_unwind){ - B32 did_machframe = 0; - - // get frame reg - REGS_Reg64 *frame_reg = 0; - U64 frame_off = 0; - - { - U64 unwind_info_off = initial_pdata->voff_unwind_info; - UNW_PE_Info *unwind_info = (UNW_PE_Info*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - - U32 frame_reg_id = UNW_PE_INFO_REG_FROM_FRAME(unwind_info->frame); - U64 frame_off_val = UNW_PE_INFO_OFF_FROM_FRAME(unwind_info->frame); - - if (frame_reg_id != 0){ - frame_reg = unw_pe_x64__gpr_reg(regs, frame_reg_id); - // TODO(allen): at this point if frame_reg is zero, the exe is corrupted. - } - frame_off = frame_off_val; - } - - PE_IntelPdata *last_pdata = 0; - PE_IntelPdata *pdata = initial_pdata; - for (;pdata != last_pdata;){ - //- get unwind info & codes - U64 unwind_info_off = pdata->voff_unwind_info; - UNW_PE_Info *unwind_info = (UNW_PE_Info*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - UNW_PE_Code *unwind_codes = (UNW_PE_Code*)(unwind_info + 1); - - //- get frame base - U64 frame_base = regs->rsp.u64; - if (frame_reg != 0){ - U64 raw_frame_base = frame_reg->u64; - U64 adjusted_frame_base = raw_frame_base - frame_off*16; - if (adjusted_frame_base < raw_frame_base){ - frame_base = adjusted_frame_base; - } - else{ - frame_base = 0; - } - } - - //- rjf: bad unwind info -> abort - if(unwind_info == 0) - { - result.dead = 1; - goto error_out; - } - - //- op code interpreter - UNW_PE_Code *code_ptr = unwind_codes; - UNW_PE_Code *code_opl = unwind_codes + unwind_info->codes_num; - for (UNW_PE_Code *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr){ - // extract op code parts - U32 op_code = UNW_PE_CODE_FROM_FLAGS(code_ptr->flags); - U32 op_info = UNW_PE_INFO_FROM_FLAGS(code_ptr->flags); - - // determine number of op code slots - U32 slot_count = unw_pe_x64__slot_count_from_op_code(op_code); - if (op_code == UNW_PE_OpCode_ALLOC_LARGE && op_info == 1){ - slot_count += 1; - } - - // check op code slot count - if (slot_count == 0 || code_ptr + slot_count > code_opl){ - result.dead = 1; - goto end_xdata_unwind; - } - - // set next op code pointer - next_code_ptr = code_ptr + slot_count; - - // interpret this op code - U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; - if (code_voff <= ip_voff){ - switch (op_code){ - case UNW_PE_OpCode_PUSH_NONVOL: - { - // read value from stack pointer - U64 sp = regs->rsp.u64; - U64 value = 0; - if (!unw_memview_read_struct(memview, sp, &value)){ - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - regs->rsp.u64 = new_sp; - }break; - - case UNW_PE_OpCode_ALLOC_LARGE: - { - // read alloc size - U64 size = 0; - if (op_info == 0){ - size = code_ptr[1].u16*8; - } - else if (op_info == 1){ - size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - } - else{ - result.dead = 1; - goto end_xdata_unwind; - } - - // advance stack pointer - U64 sp = regs->rsp.u64; - U64 new_sp = sp + size; - - // advance stack pointer - regs->rsp.u64 = new_sp; - }break; - - case UNW_PE_OpCode_ALLOC_SMALL: - { - // advance stack pointer - regs->rsp.u64 += op_info*8 + 8; - }break; - - case UNW_PE_OpCode_SET_FPREG: - { - // put stack pointer back to the frame base - regs->rsp.u64 = frame_base; - }break; - - case UNW_PE_OpCode_SAVE_NONVOL: - { - // read value from frame base - U64 off = code_ptr[1].u16*8; - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case UNW_PE_OpCode_SAVE_NONVOL_FAR: - { - // read value from frame base - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case UNW_PE_OpCode_EPILOG: - { - result.dead = 1; - }break; - - case UNW_PE_OpCode_SPARE_CODE: - { - result.dead = 1; - // Assert(!"Hit me!"); - // TODO(allen): ??? - }break; - - case UNW_PE_OpCode_SAVE_XMM128: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16*16; - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case UNW_PE_OpCode_SAVE_XMM128_FAR: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case UNW_PE_OpCode_PUSH_MACHFRAME: - { - // NOTE(rjf): this was found by stepping through kernel code after an exception was - // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main - - if (op_info > 1){ - result.dead = 1; - goto end_xdata_unwind; - } - - // read values - U64 sp_og = regs->rsp.u64; - U64 sp_adj = sp_og; - if (op_info == 1){ - sp_adj += 8; - } - - U64 ip_value = 0; - if (!unw_memview_read_struct(memview, sp_adj, &ip_value)){ - missed_read_addr = sp_adj; - goto error_out; - } - - U64 sp_after_ip = sp_adj + 8; - U16 ss_value = 0; - if (!unw_memview_read_struct(memview, sp_after_ip, &ss_value)){ - missed_read_addr = sp_after_ip; - goto error_out; - } - - U64 sp_after_ss = sp_after_ip + 8; - U64 rflags_value = 0; - if (!unw_memview_read_struct(memview, sp_after_ss, &rflags_value)){ - missed_read_addr = sp_after_ss; - goto error_out; - } - - U64 sp_after_rflags = sp_after_ss + 8; - U64 sp_value = 0; - if (!unw_memview_read_struct(memview, sp_after_rflags, &sp_value)){ - missed_read_addr = sp_after_rflags; - goto error_out; - } - - // commit registers - regs->rip.u64 = ip_value; - regs->ss.u16 = ss_value; - regs->rflags.u64 = rflags_value; - regs->rsp.u64 = sp_value; - - // mark machine frame - did_machframe = 1; - }break; - } - } - } - - //- iterate pdata chain - U32 flags = UNW_PE_INFO_FLAGS_FROM_HDR(unwind_info->header); - if (!(flags & UNW_PE_InfoFlag_CHAINED)){ - break; - } - - U64 code_count_rounded = AlignPow2(unwind_info->codes_num, 2); - U64 code_size = code_count_rounded*sizeof(UNW_PE_OpCode); - U64 chained_pdata_off = unwind_info_off + sizeof(UNW_PE_Info) + code_size; - - last_pdata = pdata; - pdata = (PE_IntelPdata*)pe_ptr_from_voff(bindata, bin, chained_pdata_off); - } - - if (!did_machframe){ - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if (!unw_memview_read_struct(memview, sp, &new_ip)){ - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - end_xdata_unwind:; - } - } - - error_out:; - - if (missed_read_addr != 0){ - result.dead = 1; - result.missed_read = 1; - result.missed_read_addr = missed_read_addr; - } - - if (!result.dead){ - result.stack_pointer = regs->rsp.u64; - } - - return(result); -} - -//- pe x64 helpers - -internal UNW_Result -unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, - U64 base_vaddr, UNW_MemView*memview, UNW_X64_Regs *regs){ - UNW_Result result = {0}; +internal UNW_Step +unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView*memview, REGS_RegBlockX64 *regs) +{ + UNW_Step result = {0}; U64 missed_read_addr = 0; //- setup parsing context @@ -412,27 +50,32 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, //- parsing loop - for (;keep_parsing;){ + for(;keep_parsing;) + { keep_parsing = 0; U8 inst_byte = 0; - if (off + sizeof(inst_byte) <= inst_size){ + if(off + sizeof(inst_byte) <= inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); } off += 1; U8 rex = 0; - if ((inst_byte & 0xF0) == 0x40){ + if((inst_byte & 0xF0) == 0x40) + { rex = inst_byte & 0xF; // rex prefix - if (off + sizeof(inst_base) <= inst_size){ + if(off + sizeof(inst_base) <= inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); } off += 1; } - switch (inst_byte){ + switch(inst_byte) + { // pop case 0x58: case 0x59: @@ -445,13 +88,14 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, { U64 sp = regs->rsp.u64; U64 value = 0; - if (!unw_memview_read_struct(memview, sp, &value)){ + if(!unw_memview_read_struct(memview, sp, &value)) + { missed_read_addr = sp; goto error_out; } // modify register - UNW_PE_X64_GprReg gpr_reg = (inst_byte - 0x58) + (rex & 1)*8; + PE_UnwindGprRegX64 gpr_reg = (inst_byte - 0x58) + (rex & 1)*8; REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); // not a final instruction @@ -470,7 +114,8 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, // read the 4-byte immediate S32 imm = 0; - if (off + sizeof(imm) < inst_size){ + if(off + sizeof(imm) < inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&imm, ptr, sizeof(imm)); } @@ -491,7 +136,8 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, // read the 1-byte immediate S8 imm = 0; - if (off + sizeof(imm) < inst_size){ + if(off + sizeof(imm) < inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&imm, ptr, sizeof(imm)); } @@ -507,11 +153,12 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, { // read source register U8 modrm = 0; - if (off + sizeof(modrm) < inst_size){ + if(off + sizeof(modrm) < inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&modrm, ptr, sizeof(modrm)); } - UNW_PE_X64_GprReg gpr_reg = (modrm & 7) + (rex & 1)*8; + PE_UnwindGprRegX64 gpr_reg = (modrm & 7) + (rex & 1)*8; REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); U64 reg_value = reg->u64; @@ -520,9 +167,11 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, S32 imm = 0; // read 1-byte immediate - if ((modrm >> 6) == 1){ + if((modrm >> 6) == 1) + { S8 imm8 = 0; - if (off + sizeof(imm8) < inst_size){ + if(off + sizeof(imm8) < inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&imm8, ptr, sizeof(imm8)); } @@ -531,8 +180,10 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, } // read 4-byte immediate - else{ - if (off + sizeof(imm) < inst_size){ + else + { + if(off + sizeof(imm) < inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&imm, ptr, sizeof(imm)); } @@ -549,14 +200,16 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, // read new ip U64 sp = regs->rsp.u64; U64 new_ip = 0; - if (!unw_memview_read_struct(memview, sp, &new_ip)){ + if(!unw_memview_read_struct(memview, sp, &new_ip)) + { missed_read_addr = sp; goto error_out; } // read 2-byte immediate & advance stack pointer U16 imm = 0; - if (off + sizeof(imm) < inst_size){ + if(off + sizeof(imm) < inst_size) + { void *ptr = (U8*)inst_base + off; MemoryCopy(&imm, ptr, sizeof(imm)); } @@ -577,7 +230,8 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, // read new ip U64 sp = regs->rsp.u64; U64 new_ip = 0; - if (!unw_memview_read_struct(memview, sp, &new_ip)){ + if(!unw_memview_read_struct(memview, sp, &new_ip)) + { missed_read_addr = sp; goto error_out; } @@ -611,7 +265,8 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, error_out:; - if (missed_read_addr != 0){ + if(missed_read_addr != 0) + { result.dead = 1; result.missed_read = 1; result.missed_read_addr = missed_read_addr; @@ -620,28 +275,9 @@ unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, return(result); } -internal U32 -unw_pe_x64__slot_count_from_op_code(UNW_PE_OpCode opcode){ - U32 result = 0; - switch (opcode){ - case UNW_PE_OpCode_PUSH_NONVOL: result = 1; break; - case UNW_PE_OpCode_ALLOC_LARGE: result = 2; break; - case UNW_PE_OpCode_ALLOC_SMALL: result = 1; break; - case UNW_PE_OpCode_SET_FPREG: result = 1; break; - case UNW_PE_OpCode_SAVE_NONVOL: result = 2; break; - case UNW_PE_OpCode_SAVE_NONVOL_FAR: result = 3; break; - case UNW_PE_OpCode_EPILOG: result = 2; break; - case UNW_PE_OpCode_SPARE_CODE: result = 3; break; - case UNW_PE_OpCode_SAVE_XMM128: result = 2; break; - case UNW_PE_OpCode_SAVE_XMM128_FAR: result = 3; break; - case UNW_PE_OpCode_PUSH_MACHFRAME: result = 1; break; - } - return(result); -} - internal B32 -unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, - U64 voff, PE_IntelPdata *final_pdata){ +unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, U64 voff, PE_IntelPdata *final_pdata) +{ // NOTE(allen): There are restrictions placed on how an epilog is allowed // to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160) // Here we interpret machine code directly according to the rules @@ -815,27 +451,409 @@ unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, } internal REGS_Reg64* -unw_pe_x64__gpr_reg(UNW_X64_Regs *regs, UNW_PE_X64_GprReg unw_reg){ +unw_pe_x64__gpr_reg(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 unw_reg){ static REGS_Reg64 dummy = {0}; REGS_Reg64 *result = &dummy; switch (unw_reg){ - case UNW_PE_X64_GprReg_RAX: result = ®s->rax; break; - case UNW_PE_X64_GprReg_RCX: result = ®s->rcx; break; - case UNW_PE_X64_GprReg_RDX: result = ®s->rdx; break; - case UNW_PE_X64_GprReg_RBX: result = ®s->rbx; break; - case UNW_PE_X64_GprReg_RSP: result = ®s->rsp; break; - case UNW_PE_X64_GprReg_RBP: result = ®s->rbp; break; - case UNW_PE_X64_GprReg_RSI: result = ®s->rsi; break; - case UNW_PE_X64_GprReg_RDI: result = ®s->rdi; break; - case UNW_PE_X64_GprReg_R8 : result = ®s->r8 ; break; - case UNW_PE_X64_GprReg_R9 : result = ®s->r9 ; break; - case UNW_PE_X64_GprReg_R10: result = ®s->r10; break; - case UNW_PE_X64_GprReg_R11: result = ®s->r11; break; - case UNW_PE_X64_GprReg_R12: result = ®s->r12; break; - case UNW_PE_X64_GprReg_R13: result = ®s->r13; break; - case UNW_PE_X64_GprReg_R14: result = ®s->r14; break; - case UNW_PE_X64_GprReg_R15: result = ®s->r15; break; + case PE_UnwindGprRegX64_RAX: result = ®s->rax; break; + case PE_UnwindGprRegX64_RCX: result = ®s->rcx; break; + case PE_UnwindGprRegX64_RDX: result = ®s->rdx; break; + case PE_UnwindGprRegX64_RBX: result = ®s->rbx; break; + case PE_UnwindGprRegX64_RSP: result = ®s->rsp; break; + case PE_UnwindGprRegX64_RBP: result = ®s->rbp; break; + case PE_UnwindGprRegX64_RSI: result = ®s->rsi; break; + case PE_UnwindGprRegX64_RDI: result = ®s->rdi; break; + case PE_UnwindGprRegX64_R8 : result = ®s->r8 ; break; + case PE_UnwindGprRegX64_R9 : result = ®s->r9 ; break; + case PE_UnwindGprRegX64_R10: result = ®s->r10; break; + case PE_UnwindGprRegX64_R11: result = ®s->r11; break; + case PE_UnwindGprRegX64_R12: result = ®s->r12; break; + case PE_UnwindGprRegX64_R13: result = ®s->r13; break; + case PE_UnwindGprRegX64_R14: result = ®s->r14; break; + case PE_UnwindGprRegX64_R15: result = ®s->r15; break; } return(result); } +//- rjf: unwind step + +internal UNW_Step +unw_unwind_pe_x64(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs) +{ + UNW_Step result = {0}; + U64 missed_read_addr = 0; + + //- grab ip_voff (several places can use this) + U64 ip_voff = regs->rip.u64 - base_vaddr; + + //- get pdata entry from current ip + PE_IntelPdata *initial_pdata = 0; + { + U64 initial_pdata_off = pe_intel_pdata_off_from_voff__binary_search(bindata, bin, ip_voff); + if(initial_pdata_off != 0) + { + initial_pdata = (PE_IntelPdata*)(bindata.str + initial_pdata_off); + } + } + + //- no pdata; unwind by reading stack pointer + if(initial_pdata == 0) + { + // read ip from stack pointer + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!unw_memview_read_struct(memview, sp, &new_ip)) + { + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + } + + //- got pdata; perform unwinding with exception handling + else + { + // try epilog unwind + B32 did_epilog_unwind = 0; + if(unw_pe_x64__voff_is_in_epilog(bindata, bin, ip_voff, initial_pdata)) + { + result = unw_pe_x64__epilog(bindata, bin, base_vaddr, memview, regs); + did_epilog_unwind = 1; + } + + // try xdata unwind + if(!did_epilog_unwind) + { + B32 did_machframe = 0; + + // get frame reg + REGS_Reg64 *frame_reg = 0; + U64 frame_off = 0; + + { + U64 unwind_info_off = initial_pdata->voff_unwind_info; + PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); + + U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info->frame); + U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info->frame); + + if (frame_reg_id != 0){ + frame_reg = unw_pe_x64__gpr_reg(regs, frame_reg_id); + // TODO(allen): at this point if frame_reg is zero, the exe is corrupted. + } + frame_off = frame_off_val; + } + + PE_IntelPdata *last_pdata = 0; + PE_IntelPdata *pdata = initial_pdata; + for (;pdata != last_pdata;) + { + //- rjf: unpack unwind info & codes + U64 unwind_info_off = pdata->voff_unwind_info; + PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); + PE_UnwindCode *unwind_codes = (PE_UnwindCode*)(unwind_info + 1); + + //- rjf: unpack frame base + U64 frame_base = regs->rsp.u64; + if(frame_reg != 0) + { + U64 raw_frame_base = frame_reg->u64; + U64 adjusted_frame_base = raw_frame_base - frame_off*16; + if(adjusted_frame_base < raw_frame_base) + { + frame_base = adjusted_frame_base; + } + else + { + frame_base = 0; + } + } + + //- rjf: bad unwind info -> abort + if(unwind_info == 0) + { + result.dead = 1; + goto error_out; + } + + //- op code interpreter + PE_UnwindCode *code_ptr = unwind_codes; + PE_UnwindCode *code_opl = unwind_codes + unwind_info->codes_num; + for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) + { + // extract op code parts + U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); + U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); + + // determine number of op code slots + U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); + if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) + { + slot_count += 1; + } + + // check op code slot count + if (slot_count == 0 || code_ptr + slot_count > code_opl){ + result.dead = 1; + goto end_xdata_unwind; + } + + // set next op code pointer + next_code_ptr = code_ptr + slot_count; + + // interpret this op code + U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; + if (code_voff <= ip_voff){ + switch (op_code){ + case PE_UnwindOpCode_PUSH_NONVOL: + { + // read value from stack pointer + U64 sp = regs->rsp.u64; + U64 value = 0; + if(!unw_memview_read_struct(memview, sp, &value)) + { + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + regs->rsp.u64 = new_sp; + }break; + + case PE_UnwindOpCode_ALLOC_LARGE: + { + // read alloc size + U64 size = 0; + if (op_info == 0){ + size = code_ptr[1].u16*8; + } + else if (op_info == 1){ + size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + } + else{ + result.dead = 1; + goto end_xdata_unwind; + } + + // advance stack pointer + U64 sp = regs->rsp.u64; + U64 new_sp = sp + size; + + // advance stack pointer + regs->rsp.u64 = new_sp; + }break; + + case PE_UnwindOpCode_ALLOC_SMALL: + { + // advance stack pointer + regs->rsp.u64 += op_info*8 + 8; + }break; + + case PE_UnwindOpCode_SET_FPREG: + { + // put stack pointer back to the frame base + regs->rsp.u64 = frame_base; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL: + { + // read value from frame base + U64 off = code_ptr[1].u16*8; + U64 addr = frame_base + off; + U64 value = 0; + if (!unw_memview_read_struct(memview, addr, &value)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL_FAR: + { + // read value from frame base + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + U64 value = 0; + if (!unw_memview_read_struct(memview, addr, &value)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_EPILOG: + { + result.dead = 1; + }break; + + case PE_UnwindOpCode_SPARE_CODE: + { + result.dead = 1; + // Assert(!"Hit me!"); + // TODO(allen): ??? + }break; + + case PE_UnwindOpCode_SAVE_XMM128: + { + // read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16*16; + U64 addr = frame_base + off; + if (!unw_memview_read(memview, addr, 16, buf)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_SAVE_XMM128_FAR: + { + // read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + if (!unw_memview_read(memview, addr, 16, buf)){ + missed_read_addr = addr; + goto error_out; + } + + // commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_PUSH_MACHFRAME: + { + // NOTE(rjf): this was found by stepping through kernel code after an exception was + // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main + + if(op_info > 1) + { + result.dead = 1; + goto end_xdata_unwind; + } + + // read values + U64 sp_og = regs->rsp.u64; + U64 sp_adj = sp_og; + if(op_info == 1) + { + sp_adj += 8; + } + + U64 ip_value = 0; + if(!unw_memview_read_struct(memview, sp_adj, &ip_value)) + { + missed_read_addr = sp_adj; + goto error_out; + } + + U64 sp_after_ip = sp_adj + 8; + U16 ss_value = 0; + if(!unw_memview_read_struct(memview, sp_after_ip, &ss_value)) + { + missed_read_addr = sp_after_ip; + goto error_out; + } + + U64 sp_after_ss = sp_after_ip + 8; + U64 rflags_value = 0; + if(!unw_memview_read_struct(memview, sp_after_ss, &rflags_value)) + { + missed_read_addr = sp_after_ss; + goto error_out; + } + + U64 sp_after_rflags = sp_after_ss + 8; + U64 sp_value = 0; + if(!unw_memview_read_struct(memview, sp_after_rflags, &sp_value)) + { + missed_read_addr = sp_after_rflags; + goto error_out; + } + + // commit registers + regs->rip.u64 = ip_value; + regs->ss.u16 = ss_value; + regs->rflags.u64 = rflags_value; + regs->rsp.u64 = sp_value; + + // mark machine frame + did_machframe = 1; + }break; + } + } + } + + //- iterate pdata chain + U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info->header); + if (!(flags & PE_UnwindInfoFlag_CHAINED)){ + break; + } + + U64 code_count_rounded = AlignPow2(unwind_info->codes_num, 2); + U64 code_size = code_count_rounded*sizeof(PE_UnwindOpCode); + U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; + + last_pdata = pdata; + pdata = (PE_IntelPdata*)pe_ptr_from_voff(bindata, bin, chained_pdata_off); + } + + if(!did_machframe) + { + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!unw_memview_read_struct(memview, sp, &new_ip)) + { + missed_read_addr = sp; + goto error_out; + } + + // advance stack pointer + U64 new_sp = sp + 8; + + // commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + } + + end_xdata_unwind:; + } + } + + error_out:; + + if(missed_read_addr != 0) + { + result.dead = 1; + result.missed_read = 1; + result.missed_read_addr = missed_read_addr; + } + + if(!result.dead) + { + result.stack_pointer = regs->rsp.u64; + } + + return(result); +} diff --git a/src/unwind/unwind.h b/src/unwind/unwind.h index 3d34d9bf..310e940c 100644 --- a/src/unwind/unwind.h +++ b/src/unwind/unwind.h @@ -5,11 +5,20 @@ #define UNWIND_H //////////////////////////////// -//~ allen: Unwind Types +//~ rjf: Memory View Types +// +// Memory views are used to provide a slice (or, in the future, slices) of data +// required to do a proper unwind. This is generally a very small region in an +// address space, generally some things on the stack. But, some formats don't +// restrict this in an organized way, and so theoretically you might have some +// unwind information require arbitrary reads at an unknown address. So this +// "memory view" concept serves as kind of a "stand-in" for "provided memory +// info from the user". This keeps the control flow of this layer simpler, so +// we aren't calling a user-supplied hook to read memory or anything like that. -// * applies to (any X,Y: unwind(X, Y)) - -typedef struct UNW_MemView{ +typedef struct UNW_MemView UNW_MemView; +struct UNW_MemView +{ // Upgrade Path: // 1. A list of ranges like this one // 2. Binary-searchable list of ranges @@ -18,297 +27,36 @@ typedef struct UNW_MemView{ void *data; U64 addr_first; U64 addr_opl; -} UNW_MemView; +}; -typedef struct UNW_Result{ +//////////////////////////////// +//~ rjf: Unwind Step Results + +typedef struct UNW_Step UNW_Step; +struct UNW_Step +{ B32 dead; B32 missed_read; U64 missed_read_addr; U64 stack_pointer; -} UNW_Result; - +}; //////////////////////////////// -//~ allen: X64 Unwind Types +//~ rjf: Memory View Helpers -// * applies to (any X: unwind(X, X64)) - -typedef REGS_RegBlockX64 UNW_X64_Regs; - - - - -//////////////////////////////// -//~ allen: PE X64 Unwind Types - -//- pe format unwind types - -#define UNW_PE_OpCodeXList(X) \ -X(PUSH_NONVOL , 0) \ -X(ALLOC_LARGE , 1) \ -X(ALLOC_SMALL , 2) \ -X(SET_FPREG , 3) \ -X(SAVE_NONVOL , 4) \ -X(SAVE_NONVOL_FAR, 5) \ -X(EPILOG , 6) \ -X(SPARE_CODE , 7) \ -X(SAVE_XMM128 , 8) \ -X(SAVE_XMM128_FAR, 9) \ -X(PUSH_MACHFRAME , 10) - -#define UNW_PE_CODE_FROM_FLAGS(f) ((f)&0xF) -#define UNW_PE_INFO_FROM_FLAGS(f) (((f) >> 4)&0xF) - -typedef U32 UNW_PE_OpCode; -enum UNW_PE_OpCodeEnum{ -#define X(N,C) UNW_PE_OpCode_##N = C, - UNW_PE_OpCodeXList(X) -#undef X -}; - -typedef union UNW_PE_Code{ - struct{ - U8 off_in_prolog; - U8 flags; - }; - U16 u16; -} UNW_PE_Code; - -typedef U8 UNW_PE_InfoFlags; -enum UNW_PE_InfoFlagsEnum{ - UNW_PE_InfoFlag_EHANDLER = (1 << 0), - UNW_PE_InfoFlag_UHANDLER = (1 << 1), - UNW_PE_InfoFlag_FHANDLER = 3, - UNW_PE_InfoFlag_CHAINED = (1 << 2), -} UNW_PE_InfoFlagsEnum; - -#define UNW_PE_INFO_VERSION_FROM_HDR(x) ((x)&0x7) -#define UNW_PE_INFO_FLAGS_FROM_HDR(x) (((x) >> 3)&0x1F) -#define UNW_PE_INFO_REG_FROM_FRAME(x) ((x)&0xF) -#define UNW_PE_INFO_OFF_FROM_FRAME(x) (((x) >> 4)&0xF) - -typedef struct UNW_PE_Info{ - U8 header; - U8 prolog_size; - U8 codes_num; - U8 frame; -} UNW_PE_Info; - - -//////////////////////////////// -//~ allen: PE X64 Unwind Types - -// * applies to (unwind(PE, X64)) - -typedef U8 UNW_PE_X64_GprReg; -enum{ - UNW_PE_X64_GprReg_RAX = 0, - UNW_PE_X64_GprReg_RCX = 1, - UNW_PE_X64_GprReg_RDX = 2, - UNW_PE_X64_GprReg_RBX = 3, - UNW_PE_X64_GprReg_RSP = 4, - UNW_PE_X64_GprReg_RBP = 5, - UNW_PE_X64_GprReg_RSI = 6, - UNW_PE_X64_GprReg_RDI = 7, - UNW_PE_X64_GprReg_R8 = 8, - UNW_PE_X64_GprReg_R9 = 9, - UNW_PE_X64_GprReg_R10 = 10, - UNW_PE_X64_GprReg_R11 = 11, - UNW_PE_X64_GprReg_R12 = 12, - UNW_PE_X64_GprReg_R13 = 13, - UNW_PE_X64_GprReg_R14 = 14, - UNW_PE_X64_GprReg_R15 = 15, -}; - - - - -//////////////////////////////// -//~ allen: ELF/DW Unwind Types - -// * 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, -}; - - - -//////////////////////////////// -//~ allen: Unwind Functions - -//- mem view construction internal UNW_MemView unw_memview_from_data(String8 data, U64 base_vaddr); - -//- mem view user face for unwind users internal B32 unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out); - #define unw_memview_read_struct(v,addr,p) unw_memview_read((v), (addr), sizeof(*(p)), (p)) - //////////////////////////////// -//~ allen: PE X64 Unwind Functions +//~ rjf: PE/X64 Unwind Implementation -//- main interface -internal UNW_Result unw_pe_x64(String8 bindata, PE_BinInfo *bin, - U64 base_vaddr, UNW_MemView *memview, - UNW_X64_Regs *regs_inout); +//- rjf: helpers +internal UNW_Step unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs_inout); +internal B32 unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, U64 voff, PE_IntelPdata *final_pdata); +internal REGS_Reg64 *unw_pe_x64__gpr_reg(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 unw_reg); +//- rjf: unwind step +internal UNW_Step unw_unwind_pe_x64(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs_inout); -//- pe x64 helpers -internal UNW_Result unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, - U64 base_vaddr, UNW_MemView*memview, - UNW_X64_Regs *regs_inout); - -internal U32 unw_pe_x64__slot_count_from_op_code(UNW_PE_OpCode opcode); -internal B32 unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, - U64 voff, PE_IntelPdata *final_pdata); - -internal REGS_Reg64 *unw_pe_x64__gpr_reg(UNW_X64_Regs *regs, UNW_PE_X64_GprReg unw_reg); - -#endif //UNWIND_H +#endif // UNWIND_H