mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-06-12 23:31:38 -07:00
Merge tag 'v0.9.23-alpha'
This commit is contained in:
+96
-7
@@ -1,16 +1,105 @@
|
||||
# Change Log v9.22.0-alpha
|
||||
# v0.9.23-alpha
|
||||
|
||||
## Linker
|
||||
## Debugger Changes
|
||||
|
||||
- Further improved PDB -> RDI conversion performance & memory usage.
|
||||
- Adjusted limits for the amount of PDB -> RDI conversion work that the
|
||||
debugger will kick off, to prevent PDB -> RDI conversion interfering with
|
||||
debuggee performance.
|
||||
- Reintroduced the `list` lens, which gathers all nodes in a linked list, and
|
||||
visualizes them as a flat list of pointers (the same as how an array of
|
||||
pointers is visualized).
|
||||
- Fixed a crash when closing empty Geometry 3D views. (#652, #657)
|
||||
- Fixed the debugger not visualizing `enum` types when evaluated through a
|
||||
bitfield type. (#655)
|
||||
- Fixed the PDB -> RDI conversion not correctly generating location information
|
||||
for function parameters, when the EXE/PDB were built to include support for
|
||||
Edit and Continue (`-ZI` switch). (#656)
|
||||
|
||||
## Binary Utility Changes
|
||||
|
||||
- Fixed a crash when using the `--compress` option, when generating RDI files.
|
||||
|
||||
# v0.9.22-alpha
|
||||
|
||||
## Debugger Changes
|
||||
|
||||
- Further improved PDB -> RDI conversion performance.
|
||||
- Capped the number of additional threads / processes spawned for PDB -> RDI
|
||||
conversion.
|
||||
- Prioritize PDB -> RDI conversion based on what is actually found to be
|
||||
necessary by the debugger, rather than converting all PDBs in the order in
|
||||
which they're discovered.
|
||||
- Added preliminary support for DWARF -> RDI conversion on Windows.
|
||||
- The debugger now relies on source file checksums to determine whether or not
|
||||
a source file is out-of-date with respect to what was compiled when debug info
|
||||
was produced, rather than just the modification timestamp.
|
||||
- The debugger now will rely on debug info to detect the language of source code
|
||||
files, if it cannot infer from the source file's extension, or view settings.
|
||||
This will enable features like syntax highlighting and hover evaluation in
|
||||
cases like `.inl` files being included in C++ projects.
|
||||
- The debugger now will restore the last focused window when continuing
|
||||
automatically. (#245, #596)
|
||||
- Watch tables have been simplified in that they no longer have a separate
|
||||
column for evaluation types, since this was usually taking a lot more space
|
||||
than it deserved. The type of evaluations is still displayed in watch table
|
||||
cells, and it can always be evaluated directly via `typeof`.
|
||||
- Type evaluations have been simplified in watch tables as well; they no longer
|
||||
have untitled columns for sizes and offsets, this is instead displayed as
|
||||
an extra note by default. Similar behavior to the original behavior can still
|
||||
be obtained using the `columns` view, if needed.
|
||||
- The debugger no longer uses complex `union` types for most registers, and
|
||||
instead just displays the register value plainly.
|
||||
- The hover evaluation UI has been made larger when needed.
|
||||
- The debugger now prefers matching global, function, and type identifiers to
|
||||
the most relevant debug info and module in context; this fixes evaluation in
|
||||
some multi-process debugging contexts. (#581)
|
||||
- Fixed the debugger unnecessarily stripping `enum` type information when
|
||||
accessed through array operators. (#634)
|
||||
- The debugger now understands a standalone `unsigned` keyword as an
|
||||
`unsigned int` type, to match C rules.
|
||||
- The debugger now uses the current working directory to form the working
|
||||
directory for targets specified on the command line, to match behavior when
|
||||
running a command from the command line without the debugger.
|
||||
- Improved call stack computation performance.
|
||||
- Improved debugger memory usage over long periods of time.
|
||||
- Fixed string-pointer comparison not working with not-equal (`!=`) operations.
|
||||
- Fixed a bug which was causing bad debuggee performance on some threads after
|
||||
some interactions with the debugger controller.
|
||||
- Fixed incorrect results when adding two register values. (#642)
|
||||
- Fixed the interpretation of register expressions in visualizers. (#649)
|
||||
- Fixed "forever loading" states in disassembly views in some cases. (#643)
|
||||
- Fixed jittering on window resizing. (#636)
|
||||
- Fixed the bitmap visualizer crashing in some circumstances relating to
|
||||
unsupported bitmap sizes. (#444, #563)
|
||||
- Fixed a crash when an empty `cast()` expression would be evaluated. (#625)
|
||||
- Fixed a crash when an invalid expression would be visualized using the `text`
|
||||
view. (#647)
|
||||
|
||||
## Linker Changes
|
||||
|
||||
- Changed symbol resolution in libaries to match MSVC behavior.
|
||||
- Optimized image building step to reduce memory usage.
|
||||
- Linker memory maps all input files by default to lower memory usage. (`/RAD_MEMORY_MAP_FILES`)
|
||||
- If debug info is available, linker uses it to show file and line number for unresolved relocations.
|
||||
- Improved base relocation build performance for large images, cutting build time by 70%.
|
||||
- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability with existing response files
|
||||
- Linker memory maps all input files by default to lower memory usage.
|
||||
(`/RAD_MEMORY_MAP_FILES`)
|
||||
- If debug info is available, linker uses it to show file and line number for
|
||||
unresolved relocations.
|
||||
- Improved base relocation build performance for large images, cutting build
|
||||
time by 70%.
|
||||
- Added stubs for `/Brepro`, `/D2`, and /ErrorReport to improve compatability
|
||||
with existing response files
|
||||
- Implemented section garbage collection (`/OPT:REF`)
|
||||
- Fixed bug where thread local variables pointed to incorrect types.
|
||||
- Changed rules for weak and undefined symbols, now weak symbol is not allowed to replace an undefined symbol.
|
||||
- Changed rules for weak and undefined symbols, now weak symbol is not allowed
|
||||
to replace an undefined symbol.
|
||||
- Linker no longer creates thunks for imports that don't require them.
|
||||
|
||||
## Binary Utility Changes
|
||||
|
||||
- The binary utility, like the debugger, now can convert DWARF debug info to
|
||||
RDI files. When both DWARF and PDB info is present, it can now convert both,
|
||||
and produce a single final RDI file with all information.
|
||||
- Textual dumping of RDI files is now done in parallel, massively improving
|
||||
dumping performance.
|
||||
- PDB -> Breakpad conversion performance has now been parallelized to a greater
|
||||
degree, improving performance.
|
||||
|
||||
@@ -285,38 +285,45 @@ not depend on any other layers in the codebase. The folders which contain these
|
||||
layers are prefixed with `lib_`, like `lib_rdi`.
|
||||
|
||||
A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `async` (`ASYNC_`): Implements a system for asynchronous work to be queued
|
||||
and executed on a thread pool.
|
||||
- `artifact_cache` (`AC_`): Implements an asynchronously-filled cache of
|
||||
computation artifacts, which are automatically evicted when not accessed. Used
|
||||
for asynchronously streaming and caching process memory and file system
|
||||
contents, as well as asynchronously preparing visualizer data.
|
||||
- `base` (no namespace): Universal, codebase-wide constructs. Strings, math,
|
||||
memory allocators, helper macros, command-line parsing, and so on. Requires
|
||||
no other codebase layers.
|
||||
- `codeview` (`CV_`): Code for parsing and writing the CodeView format.
|
||||
- `coff` (`COFF_`): Code for parsing and writing the COFF (Common Object File
|
||||
Format) file format.
|
||||
- `content` (`C_`): Implements a cache for general data blobs, keyed by a
|
||||
128-bit hash of the data. Also implements a keying system on top, where keys
|
||||
refer to a unique identity which corresponds to a history of 128-bit hashes.
|
||||
Used as a general data store by other layers.
|
||||
- `ctrl` (`CTRL_`): The debugger's "control system" layer. Implements
|
||||
asynchronous process control, stepping, and breakpoints for all attached
|
||||
processes. Runs in lockstep with attached processes. When it runs, attached
|
||||
processes are halted. When attached processes are running, it is halted.
|
||||
Driven by a debugger frontend on another thread.
|
||||
- `dasm_cache` (`DASM_`): Asynchronous disassembly computation, and a cache to
|
||||
store asynchronously produced disassembly artifacts.
|
||||
- `dbgi` (`DI_`): Asynchronous debug info loading, and a cache for loaded
|
||||
debug info. Loads RAD Debug Info (RDI) files. Launches separate processes for
|
||||
on-demand conversion to the RDI format if necessary. Also provides various
|
||||
asynchronous operations for using debug information, like fuzzy searching
|
||||
across all records in loaded debug information.
|
||||
- `dbg_engine` (`D_`): Implements the core debugger system, without any
|
||||
graphical components. This contains top-level logic for things like stepping,
|
||||
launching, freezing threads, mid-run breakpoint addition, some caches, and so
|
||||
on.
|
||||
- `dbg_info` (`DI_`): Implements asynchronous debug info conversion and loading.
|
||||
Maintains a cache for loaded debug info. Loads RAD Debug Info (RDI) files.
|
||||
Launches separate processes for on-demand conversion to the RDI format if
|
||||
necessary. Also provides various asynchronous operations for using debug info,
|
||||
like fuzzy searching across all records in loaded debug info.
|
||||
- `demon` (`DMN_`): 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`.
|
||||
- `disasm` (`DASM_`): Implements disassembly generation, including exposing the
|
||||
ability to compute and cache disassembly asynchronously.
|
||||
- `draw` (`DR_`): Implements a high-level graphics drawing API for the
|
||||
debugger's purposes, using the underlying `render` abstraction layer. Provides
|
||||
high-level APIs for various draw commands, but takes care of batching them,
|
||||
and so on.
|
||||
- `dwarf` (`DW_`): Code for parsing the DWARF format.
|
||||
- `eh` (`EH_`): Code for parsing the EH frame format.
|
||||
- `elf` (`ELF_`): Code for parsing the ELF format.
|
||||
- `eval` (`E_`): A compiler for an expression language, built for evaluation of
|
||||
variables, registers, types, and more, from debugger-attached processes,
|
||||
@@ -327,23 +334,17 @@ A list of the layers in the codebase and their associated namespaces is below:
|
||||
visualization engine, which can be used to visualize evaluations (provided by
|
||||
the `eval` layer) in a number of ways. Implements core data structures and
|
||||
transforms for watch tables.
|
||||
- `file_stream` (`FS_`): Provides asynchronous file loading, storing the
|
||||
artifacts inside of the cache implemented by the `hash_store` layer, and
|
||||
hot-reloading the contents of files when they change. Allows callers to map
|
||||
file paths to data hashes, which can then be used to obtain the file's data.
|
||||
- `file_stream` (`FS_`): Implements asynchronous file streaming, storing the
|
||||
artifacts inside of the cache implemented by the `content` and
|
||||
`artifact_cache` layers, hot-reloading the contents of files when they change.
|
||||
Allows callers to map file paths to data hashes, which can then be used to
|
||||
obtain the file's data.
|
||||
- `font_cache` (`FNT_`): Implements a cache of rasterized font data, both in
|
||||
CPU-side data for text shaping, and in GPU texture atlases for rasterized
|
||||
glyphs. All cache information is sourced from the `font_provider` abstraction
|
||||
layer.
|
||||
- `font_provider` (`FP_`): An abstraction layer for various font file decoding
|
||||
and font rasterization backends.
|
||||
- `geo_cache` (`GEO_`): Implements an asynchronously-filled cache for GPU
|
||||
geometry data, filled by data sourced in the `hash_store` layer's cache. Used
|
||||
for asynchronously preparing data for visualization.
|
||||
- `hash_store` (`HS_`): Implements a cache for general data blobs, keyed by a
|
||||
128-bit hash of the data. Also implements a keying system on top, where keys
|
||||
refer to a unique identity which corresponds to a history of 128-bit hashes.
|
||||
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 debugger. Does not depend on
|
||||
`base`, and can be independently relocated to other codebases.
|
||||
@@ -386,9 +387,6 @@ A list of the layers in the codebase and their associated namespaces is below:
|
||||
- `pdb` (`PDB_`): Code for parsing and writing the PDB file format.
|
||||
- `pe` (`PE_`): Code for parsing and writing the PE (Portable Executable) file
|
||||
format.
|
||||
- `ptr_graph_cache` (`PG_`): An in-progress layer which will supply
|
||||
asynchronously-computed pointer graphs, used for graph visualization in the
|
||||
debugger, including structures like trees and linked lists.
|
||||
- `radbin` (`RB_`): The layer implementing the `radbin` binary utility
|
||||
executable.
|
||||
- `raddbg` (`RD_`): The layer which ties everything together for the main
|
||||
@@ -419,13 +417,9 @@ A list of the layers in the codebase and their associated namespaces is below:
|
||||
layer.
|
||||
- `scratch` (no namespace): Scratch space for small and transient test programs.
|
||||
- `tester` (no namespace): A program used for automated testing.
|
||||
- `texture_cache` (`TEX_`): An asynchronously-filled cache for GPU texture data,
|
||||
filled by data sourced in the `hash_store` layer's cache. Used for
|
||||
asynchronously preparing data for visualization.
|
||||
- `text_cache` (`TXT_`): An asynchronously-filled cache for textual analysis
|
||||
data (tokens, line ranges, and so on), filled by data sourced in the
|
||||
`hash_store` layer's cache. Used for asynchronously preparing data for
|
||||
visualization (like for the source code viewer).
|
||||
- `text` (`TXT_`): Implements text processing functions, like parsing line
|
||||
breaks, and lexing and parsing source code. Also offers an API to do this
|
||||
asynchronously.
|
||||
- `third_party` (no namespace): External code from other projects, which some
|
||||
layers in the codebase depend on. All external code is included and built
|
||||
directly within the codebase.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
cd /D "%~dp0"
|
||||
:restart
|
||||
|
||||
:: --- Usage Notes (2024/1/10) ------------------------------------------------
|
||||
::
|
||||
@@ -39,12 +40,13 @@ if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] &&
|
||||
|
||||
:: --- Unpack Command Line Build Arguments ------------------------------------
|
||||
set auto_compile_flags=
|
||||
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
||||
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
|
||||
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
|
||||
if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled]
|
||||
if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled]
|
||||
if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled]
|
||||
if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend]
|
||||
if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info]
|
||||
if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview
|
||||
if "%pgo%"=="1" (
|
||||
if "%no_meta%"=="" echo ERROR: PGO build must have no_meta argument || exit /b 1
|
||||
where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1
|
||||
if "%clang%"=="1" (
|
||||
if "%pgo_run%" == "1" (
|
||||
@@ -70,7 +72,7 @@ set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags%
|
||||
set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf
|
||||
set cl_out= /out:
|
||||
set cl_linker=
|
||||
set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16
|
||||
set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 -msha
|
||||
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 clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf
|
||||
@@ -117,8 +119,8 @@ for /f %%i in ('call git describe --always --dirty') do set compile=%compile%
|
||||
for /f %%i in ('call git rev-parse HEAD') do set compile=%compile% -DBUILD_GIT_HASH_FULL=\"%%i\"
|
||||
|
||||
:: --- Build & Run Metaprogram ------------------------------------------------
|
||||
if "%no_meta%"=="1" echo [skipping metagen]
|
||||
if not "%no_meta%"=="1" (
|
||||
if "%meta%"=="1" (
|
||||
echo [doing metagen]
|
||||
pushd build
|
||||
%compile_debug% ..\src\metagen\metagen_main.c %compile_link% %out%metagen.exe || exit /b 1
|
||||
metagen.exe || exit /b 1
|
||||
@@ -166,5 +168,5 @@ if "%pgo_run%"=="1" (
|
||||
call %~dp0build\radlink @lyra.rsp /rad_alt_pch_dir:%~dp0local\lyra_pgo || exit /b 1
|
||||
popd
|
||||
)
|
||||
call %0 %*
|
||||
goto restart
|
||||
)
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ load_paths =
|
||||
commands =
|
||||
{
|
||||
//- rjf: [raddbg]
|
||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
.f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg meta telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
//- rjf: [raddbg wsl]
|
||||
|
||||
@@ -72,7 +72,7 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
||||
Stripe *stripe = stripe_from_slot_idx(&cache->stripes, slot_idx);
|
||||
|
||||
//- rjf: cache * key -> existing artifact
|
||||
B32 artifact_is_stale = 0;
|
||||
B32 artifact_is_stale = 1;
|
||||
B32 got_artifact = 0;
|
||||
B32 need_request = 0;
|
||||
AC_Artifact artifact = {0};
|
||||
@@ -161,11 +161,15 @@ ac_artifact_from_key_(Access *access, String8 key, AC_ArtifactParams *params, U6
|
||||
}
|
||||
n->v.key = str8_copy(req_batch->arena, key);
|
||||
n->v.gen = params->gen;
|
||||
n->v.last_requested_gen = &node->last_requested_gen;
|
||||
n->v.create = params->create;
|
||||
n->v.cancel_signal = params->cancel_signal;
|
||||
}
|
||||
cond_var_broadcast(async_tick_start_cond_var);
|
||||
ins_atomic_u32_eval_assign(&async_loop_again, 1);
|
||||
if(params->flags & AC_Flag_HighPriority)
|
||||
{
|
||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: get value from node, if possible
|
||||
@@ -340,23 +344,25 @@ ac_async_tick(void)
|
||||
AC_Request *r = &task->wide[idx];
|
||||
|
||||
// rjf: any new higher priority tasks? -> cancel
|
||||
if(task_idx == 1 && idx != 0) MutexScope(ac_shared->req_batches[0].mutex)
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0)
|
||||
if(task_idx == 1 && idx != 0 && ins_atomic_u32_eval(&async_loop_again_high_priority))
|
||||
{
|
||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
// rjf: cancelled? -> exit
|
||||
if(ins_atomic_u64_eval(cancelled_ptr))
|
||||
if(ins_atomic_u32_eval(cancelled_ptr))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// rjf: compute val
|
||||
B32 retry = 0;
|
||||
AC_Artifact val = r->create(r->key, r->gen, r->last_requested_gen, &retry);
|
||||
U64 gen = r->gen;
|
||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
||||
|
||||
// rjf: retry? -> resubmit request
|
||||
if(retry && lane_idx() == 0)
|
||||
@@ -406,7 +412,7 @@ ac_async_tick(void)
|
||||
{
|
||||
if(str8_match(n->key, r->key, 0))
|
||||
{
|
||||
n->last_completed_gen = r->gen;
|
||||
n->last_completed_gen = gen;
|
||||
n->val = val;
|
||||
ins_atomic_u64_dec_eval(&n->working_count);
|
||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
||||
@@ -437,12 +443,10 @@ ac_async_tick(void)
|
||||
for(;;)
|
||||
{
|
||||
// rjf: any new higher priority tasks? -> cancel
|
||||
if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2) MutexScope(ac_shared->req_batches[0].mutex)
|
||||
if(task_idx == 1 && ins_atomic_u64_eval(req_take_counter_ptr) >= task->thin_count/2 &&
|
||||
ins_atomic_u32_eval(&async_loop_again_high_priority))
|
||||
{
|
||||
if(ac_shared->req_batches[0].wide_count != 0 || ac_shared->req_batches[0].thin_count != 0)
|
||||
{
|
||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
||||
}
|
||||
ins_atomic_u64_eval_assign(cancelled_ptr, 1);
|
||||
}
|
||||
|
||||
// rjf: cancelled? -> exit
|
||||
@@ -456,9 +460,18 @@ ac_async_tick(void)
|
||||
if(req_idx >= task->thin_count) { break; }
|
||||
AC_Request *r = &task->thin[req_idx];
|
||||
|
||||
// rjf: push thin lane ctx
|
||||
U64 thin_lane_ctx_broadcast_memory = 0;
|
||||
LaneCtx thin_lane_ctx = {0, 1, {0}, &thin_lane_ctx_broadcast_memory};
|
||||
LaneCtx lane_ctx_restore = lane_ctx(thin_lane_ctx);
|
||||
|
||||
// rjf: compute val
|
||||
B32 retry = 0;
|
||||
AC_Artifact val = r->create(r->key, r->gen, r->last_requested_gen, &retry);
|
||||
U64 gen = r->gen;
|
||||
AC_Artifact val = r->create(r->key, r->cancel_signal, &retry, &gen);
|
||||
|
||||
// rjf: restore wide lane ctx
|
||||
lane_ctx(lane_ctx_restore);
|
||||
|
||||
// rjf: retry? -> resubmit request
|
||||
if(retry)
|
||||
@@ -508,7 +521,7 @@ ac_async_tick(void)
|
||||
{
|
||||
if(str8_match(n->key, r->key, 0))
|
||||
{
|
||||
n->last_completed_gen = r->gen;
|
||||
n->last_completed_gen = gen;
|
||||
n->val = val;
|
||||
ins_atomic_u64_dec_eval(&n->working_count);
|
||||
ins_atomic_u64_inc_eval(&n->completion_count);
|
||||
|
||||
@@ -16,7 +16,7 @@ struct AC_Artifact
|
||||
////////////////////////////////
|
||||
//~ rjf: Artifact Computation Function Types
|
||||
|
||||
typedef AC_Artifact AC_CreateFunctionType(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out);
|
||||
typedef AC_Artifact AC_CreateFunctionType(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
typedef void AC_DestroyFunctionType(AC_Artifact artifact);
|
||||
|
||||
typedef U32 AC_Flags;
|
||||
@@ -37,6 +37,7 @@ struct AC_ArtifactParams
|
||||
U64 gen;
|
||||
U64 evict_threshold_us;
|
||||
B32 *stale_out;
|
||||
B32 *cancel_signal;
|
||||
AC_Flags flags;
|
||||
};
|
||||
|
||||
@@ -48,7 +49,7 @@ struct AC_Request
|
||||
{
|
||||
String8 key;
|
||||
U64 gen;
|
||||
U64 *last_requested_gen;
|
||||
B32 *cancel_signal;
|
||||
AC_CreateFunctionType *create;
|
||||
};
|
||||
|
||||
@@ -138,6 +139,11 @@ global AC_Shared *ac_shared = 0;
|
||||
|
||||
internal void ac_init(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal B32 ac_cancelled(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Lookups
|
||||
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#undef LAYER_COLOR
|
||||
#define LAYER_COLOR 0x59b6c3ff
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Layer Initialization
|
||||
|
||||
internal void
|
||||
async_init(CmdLine *cmdline)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
async_shared = push_array(arena, ASYNC_Shared, 1);
|
||||
async_shared->arena = arena;
|
||||
for EachEnumVal(ASYNC_Priority, p)
|
||||
{
|
||||
ASYNC_Ring *ring = &async_shared->rings[p];
|
||||
ring->ring_size = MB(8);
|
||||
ring->ring_base = push_array_no_zero(arena, U8, ring->ring_size);
|
||||
ring->ring_mutex = mutex_alloc();
|
||||
ring->ring_cv = cond_var_alloc();
|
||||
}
|
||||
async_shared->ring_mutex = mutex_alloc();
|
||||
async_shared->ring_cv = cond_var_alloc();
|
||||
String8 work_thread_count_string = cmd_line_string(cmdline, str8_lit("work_threads_count"));
|
||||
if(work_thread_count_string.size == 0 || !try_u64_from_str8_c_rules(work_thread_count_string, &async_shared->work_threads_count))
|
||||
{
|
||||
async_shared->work_threads_count = Max(4, os_get_system_info()->logical_processor_count-1);
|
||||
}
|
||||
async_shared->work_threads_count = Max(4, async_shared->work_threads_count);
|
||||
async_shared->work_threads = push_array(arena, Thread, async_shared->work_threads_count);
|
||||
for EachIndex(idx, async_shared->work_threads_count)
|
||||
{
|
||||
async_shared->work_threads[idx] = thread_launch(async_work_thread__entry_point, (void *)idx);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Accessors
|
||||
|
||||
internal U64
|
||||
async_thread_count(void)
|
||||
{
|
||||
return async_shared->work_threads_count;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Kickoffs
|
||||
|
||||
internal B32
|
||||
async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
|
||||
{
|
||||
// rjf: choose ring
|
||||
ASYNC_Ring *ring = &async_shared->rings[params->priority];
|
||||
|
||||
// rjf: build work package
|
||||
ASYNC_Work work = {0};
|
||||
work.work_function = work_function;
|
||||
work.input = params->input;
|
||||
work.output = params->output;
|
||||
work.semaphore = params->semaphore;
|
||||
work.completion_counter = params->completion_counter;
|
||||
work.working_counter = params->working_counter;
|
||||
|
||||
// rjf: loop; try to write into user -> writer ring buffer. if we're on a
|
||||
// worker thread, determine if we need to execute this task locally on this
|
||||
// thread, and skip ring buffer if so.
|
||||
B32 queued_in_ring_buffer = 0;
|
||||
B32 need_to_execute_on_this_thread = 0;
|
||||
MutexScope(ring->ring_mutex) for(;;)
|
||||
{
|
||||
U64 num_available_work_threads = (async_shared->work_threads_count - ins_atomic_u64_eval(&async_shared->work_threads_live_count));
|
||||
if(num_available_work_threads == 0 && async_work_thread_depth > 0)
|
||||
{
|
||||
need_to_execute_on_this_thread = 1;
|
||||
break;
|
||||
}
|
||||
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
|
||||
U64 available_size = ring->ring_size - unconsumed_size;
|
||||
if(available_size >= sizeof(work))
|
||||
{
|
||||
queued_in_ring_buffer = 1;
|
||||
if(!MemoryIsZeroStruct(¶ms->semaphore))
|
||||
{
|
||||
os_semaphore_take(params->semaphore, max_U64);
|
||||
}
|
||||
ring->ring_write_pos += ring_write_struct(ring->ring_base, ring->ring_size, ring->ring_write_pos, &work);
|
||||
break;
|
||||
}
|
||||
if(os_now_microseconds() >= params->endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
cond_var_wait(ring->ring_cv, ring->ring_mutex, params->endt_us);
|
||||
}
|
||||
|
||||
// rjf: broadcast ring buffer cv if we wrote successfully
|
||||
if(queued_in_ring_buffer)
|
||||
{
|
||||
cond_var_broadcast(ring->ring_cv);
|
||||
cond_var_broadcast(async_shared->ring_cv);
|
||||
}
|
||||
|
||||
// rjf: if we did not queue successfully, and we have determined that
|
||||
// we need to execute this work on the current thread, then execute the
|
||||
// work before returning
|
||||
if(need_to_execute_on_this_thread)
|
||||
{
|
||||
async_execute_work(work);
|
||||
}
|
||||
|
||||
// rjf: return success signal
|
||||
B32 result = (queued_in_ring_buffer || need_to_execute_on_this_thread);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Helper
|
||||
|
||||
internal void
|
||||
async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t)
|
||||
{
|
||||
ASYNC_TaskNode *n = push_array(arena, ASYNC_TaskNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
n->v = t;
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal ASYNC_Task *
|
||||
async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params)
|
||||
{
|
||||
ASYNC_Task *task = push_array(arena, ASYNC_Task, 1);
|
||||
task->semaphore = os_semaphore_alloc(1, 1, str8_zero());
|
||||
ASYNC_WorkParams params_refined = {0};
|
||||
MemoryCopyStruct(¶ms_refined, params);
|
||||
params_refined.endt_us = max_U64;
|
||||
params_refined.semaphore = task->semaphore;
|
||||
if(params_refined.output == 0)
|
||||
{
|
||||
params_refined.output = &task->output;
|
||||
}
|
||||
async_push_work_(work_function, ¶ms_refined);
|
||||
return task;
|
||||
}
|
||||
|
||||
internal void *
|
||||
async_task_join(ASYNC_Task *task)
|
||||
{
|
||||
void *result = 0;
|
||||
if(task != 0 && !MemoryIsZeroStruct(&task->semaphore))
|
||||
{
|
||||
os_semaphore_take(task->semaphore, max_U64);
|
||||
os_semaphore_release(task->semaphore);
|
||||
MemoryZeroStruct(&task->semaphore);
|
||||
result = (void *)ins_atomic_u64_eval(&task->output);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Execution
|
||||
|
||||
internal ASYNC_Work
|
||||
async_pop_work(void)
|
||||
{
|
||||
ASYNC_Work work = {0};
|
||||
B32 done = 0;
|
||||
ASYNC_Priority taken_priority = ASYNC_Priority_Low;
|
||||
MutexScope(async_shared->ring_mutex) for(;!done;)
|
||||
{
|
||||
for(ASYNC_Priority priority = ASYNC_Priority_High;; priority = (ASYNC_Priority)(priority - 1))
|
||||
{
|
||||
ASYNC_Ring *ring = &async_shared->rings[priority];
|
||||
MutexScope(ring->ring_mutex)
|
||||
{
|
||||
U64 unconsumed_size = ring->ring_write_pos - ring->ring_read_pos;
|
||||
if(unconsumed_size >= sizeof(work))
|
||||
{
|
||||
ring->ring_read_pos += ring_read_struct(ring->ring_base, ring->ring_size, ring->ring_read_pos, &work);
|
||||
done = 1;
|
||||
taken_priority = priority;
|
||||
}
|
||||
}
|
||||
if(done)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(priority == ASYNC_Priority_Low)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!done)
|
||||
{
|
||||
cond_var_wait(async_shared->ring_cv, async_shared->ring_mutex, max_U64);
|
||||
}
|
||||
}
|
||||
cond_var_broadcast(async_shared->ring_cv);
|
||||
cond_var_broadcast(async_shared->rings[taken_priority].ring_cv);
|
||||
return work;
|
||||
}
|
||||
|
||||
internal void
|
||||
async_execute_work(ASYNC_Work work)
|
||||
{
|
||||
//- rjf: run work
|
||||
async_work_thread_depth += 1;
|
||||
void *work_out = work.work_function(async_work_thread_idx, work.input);
|
||||
async_work_thread_depth -= 1;
|
||||
|
||||
//- rjf: store output
|
||||
if(work.output != 0)
|
||||
{
|
||||
ins_atomic_u64_eval_assign((U64 *)work.output, (U64)work_out);
|
||||
}
|
||||
|
||||
//- rjf: release semaphore
|
||||
if(!MemoryIsZeroStruct(&work.semaphore))
|
||||
{
|
||||
os_semaphore_drop(work.semaphore);
|
||||
}
|
||||
|
||||
//- rjf: increment completion counter
|
||||
if(work.completion_counter != 0)
|
||||
{
|
||||
ins_atomic_u64_inc_eval(work.completion_counter);
|
||||
}
|
||||
|
||||
//- rjf: decrement working counter
|
||||
if(work.working_counter != 0)
|
||||
{
|
||||
ins_atomic_u64_dec_eval(work.working_counter);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Root Allocation/Deallocation
|
||||
|
||||
internal ASYNC_Root *
|
||||
async_root_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
ASYNC_Root *root = push_array(arena, ASYNC_Root, 1);
|
||||
root->arenas = push_array(arena, Arena *, async_thread_count());
|
||||
root->arenas[0] = arena;
|
||||
for(U64 idx = 1; idx < async_thread_count(); idx += 1)
|
||||
{
|
||||
root->arenas[idx] = arena_alloc();
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
internal void
|
||||
async_root_release(ASYNC_Root *root)
|
||||
{
|
||||
for(U64 idx = 1; idx < async_thread_count(); idx += 1)
|
||||
{
|
||||
arena_release(root->arenas[idx]);
|
||||
}
|
||||
arena_release(root->arenas[0]);
|
||||
}
|
||||
|
||||
internal Arena *
|
||||
async_root_thread_arena(ASYNC_Root *root)
|
||||
{
|
||||
return root->arenas[async_work_thread_idx];
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Thread Entry Point
|
||||
|
||||
internal void
|
||||
async_work_thread__entry_point(void *p)
|
||||
{
|
||||
U64 thread_idx = (U64)p;
|
||||
ThreadNameF("async_work_thread_%I64u", thread_idx);
|
||||
async_work_thread_idx = thread_idx;
|
||||
for(;;)
|
||||
{
|
||||
ASYNC_Work work = async_pop_work();
|
||||
ins_atomic_u64_inc_eval(&async_shared->work_threads_live_count);
|
||||
async_execute_work(work);
|
||||
ins_atomic_u64_dec_eval(&async_shared->work_threads_live_count);
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef ASYNC_H
|
||||
#define ASYNC_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Function Type
|
||||
|
||||
#define ASYNC_WORK_SIG(name) void *name(U64 thread_idx, void *input)
|
||||
#define ASYNC_WORK_DEF(name) internal ASYNC_WORK_SIG(name)
|
||||
typedef ASYNC_WORK_SIG(ASYNC_WorkFunctionType);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Types
|
||||
|
||||
typedef enum ASYNC_Priority
|
||||
{
|
||||
ASYNC_Priority_Low,
|
||||
ASYNC_Priority_High,
|
||||
ASYNC_Priority_COUNT
|
||||
}
|
||||
ASYNC_Priority;
|
||||
|
||||
typedef struct ASYNC_WorkParams ASYNC_WorkParams;
|
||||
struct ASYNC_WorkParams
|
||||
{
|
||||
void *input;
|
||||
void **output;
|
||||
Semaphore semaphore;
|
||||
U64 *completion_counter;
|
||||
U64 *working_counter;
|
||||
U64 endt_us;
|
||||
ASYNC_Priority priority;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_Work ASYNC_Work;
|
||||
struct ASYNC_Work
|
||||
{
|
||||
ASYNC_WorkFunctionType *work_function;
|
||||
void *input;
|
||||
void **output;
|
||||
Semaphore semaphore;
|
||||
U64 *completion_counter;
|
||||
U64 *working_counter;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Types
|
||||
|
||||
typedef struct ASYNC_Task ASYNC_Task;
|
||||
struct ASYNC_Task
|
||||
{
|
||||
Semaphore semaphore;
|
||||
void *output;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_TaskNode ASYNC_TaskNode;
|
||||
struct ASYNC_TaskNode
|
||||
{
|
||||
ASYNC_TaskNode *next;
|
||||
ASYNC_Task *v;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_TaskList ASYNC_TaskList;
|
||||
struct ASYNC_TaskList
|
||||
{
|
||||
ASYNC_TaskNode *first;
|
||||
ASYNC_TaskNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Root (Per-Worker-Thread Arena Bundle)
|
||||
|
||||
typedef struct ASYNC_Root ASYNC_Root;
|
||||
struct ASYNC_Root
|
||||
{
|
||||
Arena **arenas;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Bundle
|
||||
|
||||
typedef struct ASYNC_Ring ASYNC_Ring;
|
||||
struct ASYNC_Ring
|
||||
{
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_write_pos;
|
||||
U64 ring_read_pos;
|
||||
Mutex ring_mutex;
|
||||
CondVar ring_cv;
|
||||
};
|
||||
|
||||
typedef struct ASYNC_Shared ASYNC_Shared;
|
||||
struct ASYNC_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
|
||||
// rjf: user -> work thread ring buffers
|
||||
ASYNC_Ring rings[ASYNC_Priority_COUNT];
|
||||
Mutex ring_mutex;
|
||||
CondVar ring_cv;
|
||||
|
||||
// rjf: work threads
|
||||
Thread *work_threads;
|
||||
U64 work_threads_count;
|
||||
U64 work_threads_live_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
thread_static B32 async_work_thread_depth = 0;
|
||||
thread_static U64 async_work_thread_idx = 0;
|
||||
global ASYNC_Shared *async_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Layer Initialization
|
||||
|
||||
internal void async_init(CmdLine *cmdline);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Top-Level Accessors
|
||||
|
||||
internal U64 async_thread_count(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Kickoffs
|
||||
|
||||
internal B32 async_push_work_(ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
|
||||
#define async_push_work(function, ...) async_push_work_((function), &(ASYNC_WorkParams){.endt_us = max_U64, .priority = ASYNC_Priority_High, __VA_ARGS__})
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Task-Based Work Helper
|
||||
|
||||
internal void async_task_list_push(Arena *arena, ASYNC_TaskList *list, ASYNC_Task *t);
|
||||
internal ASYNC_Task *async_task_launch_(Arena *arena, ASYNC_WorkFunctionType *work_function, ASYNC_WorkParams *params);
|
||||
#define async_task_launch(arena, work_function, ...) async_task_launch_((arena), (work_function), &(ASYNC_WorkParams){.endt_us = max_U64, __VA_ARGS__})
|
||||
internal void *async_task_join(ASYNC_Task *task);
|
||||
#define async_task_join_struct(task, T) (T *)async_task_join(task)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Execution
|
||||
|
||||
internal ASYNC_Work async_pop_work(void);
|
||||
internal void async_execute_work(ASYNC_Work work);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Root Allocation/Deallocation
|
||||
|
||||
internal ASYNC_Root *async_root_alloc(void);
|
||||
internal void async_root_release(ASYNC_Root *root);
|
||||
internal Arena *async_root_thread_arena(ASYNC_Root *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Work Thread Entry Point
|
||||
|
||||
internal void async_work_thread__entry_point(void *p);
|
||||
|
||||
#endif // ASYNC_H
|
||||
@@ -159,7 +159,7 @@
|
||||
#endif
|
||||
|
||||
#if !defined(BUILD_VERSION_PATCH)
|
||||
# define BUILD_VERSION_PATCH 22
|
||||
# define BUILD_VERSION_PATCH 23
|
||||
#endif
|
||||
|
||||
#define BUILD_VERSION_STRING_LITERAL Stringify(BUILD_VERSION_MAJOR) "." Stringify(BUILD_VERSION_MINOR) "." Stringify(BUILD_VERSION_PATCH)
|
||||
|
||||
@@ -407,6 +407,12 @@ bit_size_from_arch(Arch arch)
|
||||
return arch_bitsize;
|
||||
}
|
||||
|
||||
internal U64
|
||||
byte_size_from_arch(Arch arch)
|
||||
{
|
||||
return bit_size_from_arch(arch) / 8;
|
||||
}
|
||||
|
||||
internal U64
|
||||
max_instruction_size_from_arch(Arch arch)
|
||||
{
|
||||
|
||||
@@ -84,6 +84,37 @@
|
||||
# define C_LINKAGE
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Optimization Settings
|
||||
|
||||
#if COMPILER_MSVC
|
||||
# define OPTIMIZE_BEGIN _Pragma("optimize(\"\", on)")
|
||||
# define OPTIMIZE_END _Pragma("optimize(\"\", off)")
|
||||
#elif COMPILER_CLANG
|
||||
# define OPTIMIZE_BEGIN _Pragma("clang optimize on")
|
||||
# define OPTIMIZE_END _Pragma("clang optimize off")
|
||||
#elif COMPILER_GCC
|
||||
# define OPTIMIZE_BEGIN _Pragma("GCC push_options") _Pragma("GCC optimize(\"O2\")")
|
||||
# define OPTIMIZE_END _Pragma("GCC pop_options")
|
||||
#else
|
||||
# define OPTIMIZE_BEGIN
|
||||
# define OPTIMIZE_END
|
||||
#endif
|
||||
|
||||
#if COMPILER_MSVC && !BUILD_DEBUG
|
||||
# define NO_OPTIMIZE_BEGIN _Pragma("optimize(\"\", off)")
|
||||
# define NO_OPTIMIZE_END _Pragma("optimize(\"\", on)")
|
||||
#elif COMPILER_CLANG && !BUILD_DEBUG
|
||||
# define NO_OPTIMIZE_BEGIN _Pragma("clang optimize off")
|
||||
# define NO_OPTIMIZE_END _Pragma("clang optimize on")
|
||||
#elif COMPILER_GCC && !BUILD_DEBUG
|
||||
# define NO_OPTIMIZE_BEGIN _Pragma("GCC push_options") _Pragma("GCC optimize(\"O0\")")
|
||||
# define NO_OPTIMIZE_END _Pragma("GCC pop_options")
|
||||
#else
|
||||
# define NO_OPTIMIZE_BEGIN
|
||||
# define NO_OPTIMIZE_END
|
||||
#endif
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Versions
|
||||
|
||||
@@ -959,6 +990,7 @@ internal B32 txt_rng_contains(TxtRng r, TxtPt pt);
|
||||
//~ rjf: Toolchain/Environment Enum Functions
|
||||
|
||||
internal U64 bit_size_from_arch(Arch arch);
|
||||
internal U64 byte_size_from_arch(Arch arch);
|
||||
internal U64 max_instruction_size_from_arch(Arch arch);
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -7,6 +7,7 @@ global CondVar async_tick_start_cond_var = {0};
|
||||
global Mutex async_tick_start_mutex = {0};
|
||||
global Mutex async_tick_stop_mutex = {0};
|
||||
global B32 async_loop_again = 0;
|
||||
global B32 async_loop_again_high_priority = 0;
|
||||
global B32 global_async_exit = 0;
|
||||
thread_static B32 is_async_thread = 0;
|
||||
|
||||
@@ -69,10 +70,7 @@ main_thread_base_entry_point(int arguments_count, char **arguments)
|
||||
mtx_init();
|
||||
#endif
|
||||
#if defined(DBG_INFO_H) && !defined(DI_INIT_MANUAL)
|
||||
di_init();
|
||||
#endif
|
||||
#if defined(DBG_INFO2_H) && !defined(DI_INIT_MANUAL)
|
||||
di2_init(&cmdline);
|
||||
di_init(&cmdline);
|
||||
#endif
|
||||
#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL)
|
||||
dmn_init();
|
||||
@@ -194,6 +192,7 @@ async_thread_entry_point(void *params)
|
||||
MutexScope(async_tick_start_mutex) cond_var_wait(async_tick_start_cond_var, async_tick_start_mutex, os_now_microseconds()+100000);
|
||||
}
|
||||
ins_atomic_u32_eval_assign(&async_loop_again, 0);
|
||||
ins_atomic_u32_eval_assign(&async_loop_again_high_priority, 0);
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
@@ -209,8 +208,8 @@ async_thread_entry_point(void *params)
|
||||
#if defined(FILE_STREAM_H)
|
||||
fs_async_tick();
|
||||
#endif
|
||||
#if defined(DBG_INFO2_H)
|
||||
di2_async_tick();
|
||||
#if defined(DBG_INFO_H)
|
||||
di_async_tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MD5
|
||||
|
||||
#include "third_party/martins_hash/md5.h"
|
||||
|
||||
internal MD5
|
||||
md5_from_data(String8 data)
|
||||
{
|
||||
md5_ctx ctx = {0};
|
||||
md5_init(&ctx);
|
||||
md5_update(&ctx, (void*)data.str, data.size);
|
||||
MD5 result = {0};
|
||||
md5_finish(&ctx, result.u8);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: SHA
|
||||
|
||||
#include "third_party/martins_hash/sha1.h"
|
||||
#include "third_party/martins_hash/sha256.h"
|
||||
|
||||
internal SHA1
|
||||
sha1_from_data(String8 data)
|
||||
{
|
||||
SHA1 result = {0};
|
||||
{
|
||||
sha1_ctx ctx = {0};
|
||||
sha1_init(&ctx);
|
||||
sha1_update(&ctx, data.str, data.size);
|
||||
sha1_finish(&ctx, result.u8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal SHA256
|
||||
sha256_from_data(String8 data)
|
||||
{
|
||||
SHA256 result = {0};
|
||||
{
|
||||
sha256_ctx ctx = {0};
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, data.str, data.size);
|
||||
sha256_finish(&ctx, result.u8);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef BASE_HASH_H
|
||||
#define BASE_HASH_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Hash Result Types
|
||||
|
||||
typedef union MD5 MD5;
|
||||
union MD5
|
||||
{
|
||||
U8 u8[16];
|
||||
U16 u16[8];
|
||||
U32 u32[4];
|
||||
U64 u64[2];
|
||||
U128 u128;
|
||||
};
|
||||
|
||||
typedef union SHA1 SHA1;
|
||||
union SHA1
|
||||
{
|
||||
U8 u8[20];
|
||||
};
|
||||
|
||||
typedef union SHA256 SHA256;
|
||||
union SHA256
|
||||
{
|
||||
U8 u8[32];
|
||||
U16 u16[16];
|
||||
U32 u32[8];
|
||||
U64 u64[4];
|
||||
U128 u128[2];
|
||||
U256 u256;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: MD5
|
||||
|
||||
internal MD5 md5_from_data(String8 data);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: SHA
|
||||
|
||||
internal SHA1 sha1_from_data(String8 data);
|
||||
internal SHA256 sha256_from_data(String8 data);
|
||||
|
||||
#endif // BASE_HASH_H
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "base_arena.c"
|
||||
#include "base_math.c"
|
||||
#include "base_strings.c"
|
||||
#include "base_hash.c"
|
||||
#include "base_threads.c"
|
||||
#include "base_thread_context.c"
|
||||
#include "base_command_line.c"
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "base_arena.h"
|
||||
#include "base_math.h"
|
||||
#include "base_strings.h"
|
||||
#include "base_hash.h"
|
||||
#include "base_threads.h"
|
||||
#include "base_thread_context.h"
|
||||
#include "base_command_line.h"
|
||||
|
||||
@@ -708,12 +708,19 @@ rgba_from_u32(U32 hex)
|
||||
//~ rjf: List Type Functions
|
||||
|
||||
internal void
|
||||
rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal Rng1U64Node *
|
||||
rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng)
|
||||
{
|
||||
Rng1U64Node *n = push_array(arena, Rng1U64Node, 1);
|
||||
MemoryCopyStruct(&n->v, &rng);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
rng1u64_list_push_node(list, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
internal void
|
||||
|
||||
@@ -678,7 +678,8 @@ internal Vec4F32 rgba_from_u32(U32 hex);
|
||||
////////////////////////////////
|
||||
//~ rjf: List Type Functions
|
||||
|
||||
internal void rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
|
||||
internal void rng1u64_list_push_node(Rng1U64List *list, Rng1U64Node *n);
|
||||
internal Rng1U64Node * rng1u64_list_push(Arena *arena, Rng1U64List *list, Rng1U64 rng);
|
||||
internal void rng1u64_list_concat(Rng1U64List *list, Rng1U64List *to_concat);
|
||||
internal Rng1U64Array rng1u64_array_from_list(Arena *arena, Rng1U64List *list);
|
||||
internal U64 rng_1u64_array_bsearch(Rng1U64Array arr, U64 value);
|
||||
|
||||
@@ -219,7 +219,7 @@ access_pt_is_expired_(AccessPt *pt, AccessPtExpireParams *params)
|
||||
U64 last_time_touched_us = ins_atomic_u64_eval(&pt->last_time_touched_us);
|
||||
U64 last_update_idx_touched = ins_atomic_u64_eval(&pt->last_update_idx_touched);
|
||||
B32 result = (access_refcount == 0 &&
|
||||
last_time_touched_us + params->time < os_now_microseconds() &&
|
||||
last_update_idx_touched + params->update_idxs < update_tick_idx());
|
||||
last_time_touched_us + params->time <= os_now_microseconds() &&
|
||||
last_update_idx_touched + params->update_idxs <= update_tick_idx());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1460,14 +1460,18 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
U32 line_count_unclamped = file->num_lines;
|
||||
U32 block_size = file->block_size;
|
||||
|
||||
// file_name from file_off
|
||||
// file_name / checksum from file_off
|
||||
String8 file_name = {0};
|
||||
CV_C13ChecksumKind checksum_kind = CV_C13ChecksumKind_Null;
|
||||
String8 checksum_value = {0};
|
||||
if(file_off + sizeof(CV_C13Checksum) <= file_chksms->size)
|
||||
{
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off), (char*)(strtbl.str + strtbl.size));
|
||||
checksum_kind = checksum->kind;
|
||||
checksum_value = str8_skip(c13_data, file_chksms->off + file_off + sizeof(*checksum));
|
||||
checksum_value.size = Min(checksum->len, checksum_value.size);
|
||||
}
|
||||
|
||||
// array layouts
|
||||
@@ -1503,13 +1507,15 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
// 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->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;
|
||||
lines_parsed->file_name = file_name;
|
||||
lines_parsed->checksum_kind = checksum_kind;
|
||||
lines_parsed->checksum = checksum_value;
|
||||
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
|
||||
@@ -1539,12 +1545,16 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
|
||||
// rjf: file_off -> file_name
|
||||
String8 file_name = {0};
|
||||
CV_C13ChecksumKind checksum_kind = CV_C13ChecksumKind_Null;
|
||||
String8 checksum_value = {0};
|
||||
if(hdr->file_off + sizeof(CV_C13Checksum) <= file_chksms->size)
|
||||
{
|
||||
CV_C13Checksum *checksum = (CV_C13Checksum*)(c13_data.str + file_chksms->off + hdr->file_off);
|
||||
U32 name_off = checksum->name_off;
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off),
|
||||
(char*)(strtbl.str + strtbl.size));
|
||||
file_name = str8_cstring_capped((char*)(strtbl.str + name_off), (char*)(strtbl.str + strtbl.size));
|
||||
checksum_kind = checksum->kind;
|
||||
checksum_value = str8_skip(c13_data, file_chksms->off + hdr->file_off + sizeof(*checksum));
|
||||
checksum_value.size = Min(checksum->len, checksum_value.size);
|
||||
}
|
||||
|
||||
// rjf: parse extra files
|
||||
@@ -1564,8 +1574,10 @@ cv_c13_parsed_from_data(Arena *arena, String8 c13_data, String8 strtbl, COFF_Sec
|
||||
CV_C13InlineeLinesParsedNode *n = push_array(arena, CV_C13InlineeLinesParsedNode, 1);
|
||||
SLLQueuePush(node->inlinee_lines_first, node->inlinee_lines_last, n);
|
||||
n->v.inlinee = hdr->inlinee;
|
||||
n->v.file_name = file_name;
|
||||
n->v.file_off = hdr->file_off;
|
||||
n->v.file_name = file_name;
|
||||
n->v.checksum_kind = checksum_kind;
|
||||
n->v.checksum = checksum_value;
|
||||
n->v.first_source_ln = hdr->first_source_ln;
|
||||
n->v.extra_file_count = extra_file_count;
|
||||
n->v.extra_files = extra_files;
|
||||
|
||||
@@ -150,6 +150,8 @@ struct CV_C13LinesParsed
|
||||
|
||||
// parsed info
|
||||
String8 file_name;
|
||||
CV_C13ChecksumKind checksum_kind;
|
||||
String8 checksum;
|
||||
U64 *voffs; // [line_count + 1]
|
||||
U32 *line_nums; // [line_count]
|
||||
U16 *col_nums; // [2*line_count]
|
||||
@@ -166,12 +168,14 @@ struct CV_C13LinesParsedNode
|
||||
typedef struct CV_C13InlineeLinesParsed CV_C13InlineeLinesParsed;
|
||||
struct CV_C13InlineeLinesParsed
|
||||
{
|
||||
CV_ItemId inlinee;
|
||||
U32 file_off;
|
||||
String8 file_name;
|
||||
U32 first_source_ln;
|
||||
U32 extra_file_count;
|
||||
U32 *extra_files;
|
||||
CV_ItemId inlinee;
|
||||
U32 file_off;
|
||||
String8 file_name;
|
||||
CV_C13ChecksumKind checksum_kind;
|
||||
String8 checksum;
|
||||
U32 first_source_ln;
|
||||
U32 extra_file_count;
|
||||
U32 *extra_files;
|
||||
};
|
||||
|
||||
typedef struct CV_C13InlineeLinesParsedNode CV_C13InlineeLinesParsedNode;
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal CFG_KeyMap *
|
||||
cfg_key_map_from_cfg(Arena *arena)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
CFG_KeyMap *key_map = push_array(arena, CFG_KeyMap, 1);
|
||||
{
|
||||
key_map->name_slots_count = 4096;
|
||||
key_map->name_slots = push_array(arena, CFG_KeyMapSlot, key_map->name_slots_count);
|
||||
key_map->binding_slots_count = 4096;
|
||||
key_map->binding_slots = push_array(arena, CFG_KeyMapSlot, key_map->binding_slots_count);
|
||||
|
||||
//- rjf: gather & parse all explicitly stored keybinding sets
|
||||
CFG_NodePtrList keybindings_cfg_list = cfg_node_top_level_list_from_string(scratch.arena, str8_lit("keybindings"));
|
||||
for(CFG_NodePtrNode *n = keybindings_cfg_list.first; n != 0; n = n->next)
|
||||
{
|
||||
CFG_Node *keybindings_root = n->v;
|
||||
for(CFG_Node *keybinding = keybindings_root->first; keybinding != &cfg_nil_node; keybinding = keybinding->next)
|
||||
{
|
||||
String8 name = {0};
|
||||
CFG_Binding binding = {0};
|
||||
for(CFG_Node *child = keybinding->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(0){}
|
||||
else if(str8_match(child->string, str8_lit("ctrl"), 0)) { binding.modifiers |= OS_Modifier_Ctrl; }
|
||||
else if(str8_match(child->string, str8_lit("alt"), 0)) { binding.modifiers |= OS_Modifier_Alt; }
|
||||
else if(str8_match(child->string, str8_lit("shift"), 0)) { binding.modifiers |= OS_Modifier_Shift; }
|
||||
else
|
||||
{
|
||||
OS_Key key = OS_Key_Null;
|
||||
for EachEnumVal(OS_Key, k)
|
||||
{
|
||||
if(str8_match(child->string, os_g_key_cfg_string_table[k], StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
key = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(key != OS_Key_Null)
|
||||
{
|
||||
binding.key = key;
|
||||
}
|
||||
else
|
||||
{
|
||||
name = child->string;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(name.size != 0)
|
||||
{
|
||||
U64 name_hash = d_hash_from_string(name);
|
||||
U64 binding_hash = d_hash_from_string(str8_struct(&binding));
|
||||
U64 name_slot_idx = name_hash%key_map->name_slots_count;
|
||||
U64 binding_slot_idx = binding_hash%key_map->binding_slots_count;
|
||||
CFG_KeyMapNode *n = push_array(arena, CFG_KeyMapNode, 1);
|
||||
n->cfg_id = keybinding->id;
|
||||
n->name = push_str8_copy(arena, name);
|
||||
n->binding = binding;
|
||||
SLLQueuePush_N(key_map->name_slots[name_slot_idx].first, key_map->name_slots[name_slot_idx].last, n, name_hash_next);
|
||||
SLLQueuePush_N(key_map->binding_slots[binding_slot_idx].first, key_map->binding_slots[binding_slot_idx].last, n, binding_hash_next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return key_map;
|
||||
}
|
||||
|
||||
internal CFG_KeyMapNodePtrList
|
||||
cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string)
|
||||
{
|
||||
CFG_KeyMapNodePtrList list = {0};
|
||||
{
|
||||
U64 hash = d_hash_from_string(string);
|
||||
U64 slot_idx = hash%key_map->name_slots_count;
|
||||
for(CFG_KeyMapNode *n = key_map->name_slots[slot_idx].first; n != 0; n = n->name_hash_next)
|
||||
{
|
||||
if(str8_match(n->name, string, 0))
|
||||
{
|
||||
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
|
||||
ptr->v = n;
|
||||
SLLQueuePush(list.first, list.last, ptr);
|
||||
list.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
internal CFG_KeyMapNodePtrList
|
||||
cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding)
|
||||
{
|
||||
CFG_KeyMapNodePtrList list = {0};
|
||||
{
|
||||
U64 hash = d_hash_from_string(str8_struct(&binding));
|
||||
U64 slot_idx = hash%key_map->binding_slots_count;
|
||||
for(CFG_KeyMapNode *n = key_map->binding_slots[slot_idx].first; n != 0; n = n->binding_hash_next)
|
||||
{
|
||||
if(MemoryMatchStruct(&binding, &n->binding))
|
||||
{
|
||||
CFG_KeyMapNodePtr *ptr = push_array(arena, CFG_KeyMapNodePtr, 1);
|
||||
ptr->v = n;
|
||||
SLLQueuePush(list.first, list.last, ptr);
|
||||
list.count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_BINDINGS_H
|
||||
#define CONFIG_BINDINGS_H
|
||||
|
||||
typedef struct CFG_Binding CFG_Binding;
|
||||
struct CFG_Binding
|
||||
{
|
||||
OS_Key key;
|
||||
OS_Modifiers modifiers;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapNode CFG_KeyMapNode;
|
||||
struct CFG_KeyMapNode
|
||||
{
|
||||
CFG_KeyMapNode *name_hash_next;
|
||||
CFG_KeyMapNode *binding_hash_next;
|
||||
CFG_ID cfg_id;
|
||||
String8 name;
|
||||
CFG_Binding binding;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapNodePtr CFG_KeyMapNodePtr;
|
||||
struct CFG_KeyMapNodePtr
|
||||
{
|
||||
CFG_KeyMapNodePtr *next;
|
||||
CFG_KeyMapNode *v;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapNodePtrList CFG_KeyMapNodePtrList;
|
||||
struct CFG_KeyMapNodePtrList
|
||||
{
|
||||
CFG_KeyMapNodePtr *first;
|
||||
CFG_KeyMapNodePtr *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMapSlot CFG_KeyMapSlot;
|
||||
struct CFG_KeyMapSlot
|
||||
{
|
||||
CFG_KeyMapNode *first;
|
||||
CFG_KeyMapNode *last;
|
||||
};
|
||||
|
||||
typedef struct CFG_KeyMap CFG_KeyMap;
|
||||
struct CFG_KeyMap
|
||||
{
|
||||
U64 name_slots_count;
|
||||
CFG_KeyMapSlot *name_slots;
|
||||
U64 binding_slots_count;
|
||||
CFG_KeyMapSlot *binding_slots;
|
||||
};
|
||||
|
||||
internal CFG_KeyMap *cfg_key_map_from_cfg(Arena *arena);
|
||||
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_name(Arena *arena, CFG_KeyMap *key_map, String8 string);
|
||||
internal CFG_KeyMapNodePtrList cfg_key_map_node_ptr_list_from_binding(Arena *arena, CFG_KeyMap *key_map, CFG_Binding binding);
|
||||
|
||||
#endif // CONFIG_BINDINGS_H
|
||||
@@ -0,0 +1,896 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: ID Functions
|
||||
|
||||
internal void
|
||||
cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id)
|
||||
{
|
||||
CFG_IDNode *n = push_array(arena, CFG_IDNode, 1);
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
n->v = id;
|
||||
}
|
||||
|
||||
internal CFG_IDList
|
||||
cfg_id_list_copy(Arena *arena, CFG_IDList *src)
|
||||
{
|
||||
CFG_IDList dst = {0};
|
||||
for EachNode(n, CFG_IDNode, src->first)
|
||||
{
|
||||
cfg_id_list_push(arena, &dst, n->v);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Pointer Data Structure Functions
|
||||
|
||||
internal void
|
||||
cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
|
||||
{
|
||||
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
|
||||
DLLPushBack(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
n->v = node;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node)
|
||||
{
|
||||
CFG_NodePtrNode *n = push_array(arena, CFG_NodePtrNode, 1);
|
||||
DLLPushFront(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
n->v = node;
|
||||
}
|
||||
|
||||
internal CFG_NodePtrArray
|
||||
cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list)
|
||||
{
|
||||
CFG_NodePtrArray array = {0};
|
||||
array.count = list->count;
|
||||
array.v = push_array_no_zero(arena, CFG_Node *, array.count);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, CFG_NodePtrNode, list->first)
|
||||
{
|
||||
array.v[idx] = n->v;
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Data Structure Functions
|
||||
|
||||
internal void
|
||||
cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema)
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(name);
|
||||
U64 slot_idx = hash%table->slots_count;
|
||||
CFG_SchemaNode *node = 0;
|
||||
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->name, name, 0))
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
node = push_array(arena, CFG_SchemaNode, 1);
|
||||
node->name = str8_copy(arena, name);
|
||||
node->schema = schema;
|
||||
SLLStackPush(table->slots[slot_idx], node);
|
||||
}
|
||||
}
|
||||
|
||||
internal MD_Node *
|
||||
cfg_schema_from_name(CFG_SchemaTable *table, String8 name)
|
||||
{
|
||||
MD_Node *result = &md_nil_node;
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(name);
|
||||
U64 slot_idx = hash%table->slots_count;
|
||||
CFG_SchemaNode *node = 0;
|
||||
for(CFG_SchemaNode *n = table->slots[slot_idx]; n != 0; n = n->next)
|
||||
{
|
||||
if(str8_match(n->name, name, 0))
|
||||
{
|
||||
result = n->schema;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal MD_NodePtrList
|
||||
cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name)
|
||||
{
|
||||
MD_NodePtrList result = {0};
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List tasks = {0};
|
||||
String8Node seed_task = {0, name};
|
||||
str8_list_push_node(&tasks, &seed_task);
|
||||
for EachNode(task, String8Node, tasks.first)
|
||||
{
|
||||
MD_Node *schema = cfg_schema_from_name(table, task->string);
|
||||
if(!md_node_is_nil(schema))
|
||||
{
|
||||
md_node_ptr_list_push_front(arena, &result, schema);
|
||||
for MD_EachNode(tag, schema->first_tag)
|
||||
{
|
||||
if(str8_match(tag->string, str8_lit("inherit"), 0))
|
||||
{
|
||||
str8_list_push(scratch.arena, &tasks, tag->first->string);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Reading Functions
|
||||
|
||||
//- rjf: context selection
|
||||
|
||||
internal void
|
||||
cfg_ctx_select(CFG_Ctx *ctx)
|
||||
{
|
||||
cfg_ctx = ctx;
|
||||
}
|
||||
|
||||
//- rjf: tree navigations
|
||||
|
||||
internal U64
|
||||
cfg_change_gen(void)
|
||||
{
|
||||
U64 result = 0;
|
||||
if(cfg_ctx != 0)
|
||||
{
|
||||
result = cfg_ctx->change_gen;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_root(void)
|
||||
{
|
||||
CFG_Node *result = &cfg_nil_node;
|
||||
if(cfg_ctx != 0)
|
||||
{
|
||||
result = cfg_ctx->root;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_from_id(CFG_ID id)
|
||||
{
|
||||
CFG_Node *result = &cfg_nil_node;
|
||||
if(id != 0 &&
|
||||
id == cfg_ctx->last_accessed_id &&
|
||||
id == cfg_ctx->last_accessed->id)
|
||||
{
|
||||
result = cfg_ctx->last_accessed;
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&id));
|
||||
U64 slot_idx = hash%cfg_ctx->id_slots_count;
|
||||
for(CFG_NodePtrNode *n = cfg_ctx->id_slots[slot_idx].first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->v->id == id)
|
||||
{
|
||||
result = n->v;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cfg_ctx->last_accessed_id = id;
|
||||
cfg_ctx->last_accessed = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_child_from_string(CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *child = &cfg_nil_node;
|
||||
if(string.size != 0)
|
||||
{
|
||||
for(CFG_Node *c = parent->first; c != &cfg_nil_node; c = c->next)
|
||||
{
|
||||
if(str8_match(c->string, string, 0))
|
||||
{
|
||||
child = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return child;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *result = cfg_node_child_from_string(parent, string);
|
||||
if(result == &cfg_nil_node)
|
||||
{
|
||||
result = parent;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_NodePtrList
|
||||
cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_NodePtrList result = {0};
|
||||
for(CFG_Node *child = parent->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(str8_match(child->string, string, 0))
|
||||
{
|
||||
cfg_node_ptr_list_push(arena, &result, child);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_NodePtrList
|
||||
cfg_node_top_level_list_from_string(Arena *arena, String8 string)
|
||||
{
|
||||
CFG_NodePtrList result = {0};
|
||||
for(CFG_Node *bucket = cfg_ctx->root->first; bucket != &cfg_nil_node; bucket = bucket->next)
|
||||
{
|
||||
for(CFG_Node *tln = bucket->first; tln != &cfg_nil_node; tln = tln->next)
|
||||
{
|
||||
if(str8_match(tln->string, string, 0))
|
||||
{
|
||||
cfg_node_ptr_list_push(arena, &result, tln);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_NodeRec
|
||||
cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node)
|
||||
{
|
||||
CFG_NodeRec rec = {&cfg_nil_node};
|
||||
if(node->first != &cfg_nil_node)
|
||||
{
|
||||
rec.next = node->first;
|
||||
rec.push_count = 1;
|
||||
}
|
||||
else for(CFG_Node *p = node; p != root; p = p->parent, rec.pop_count += 1)
|
||||
{
|
||||
if(p->next != &cfg_nil_node)
|
||||
{
|
||||
rec.next = p->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
//- rjf: serialization
|
||||
|
||||
internal String8
|
||||
cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8List strings = {0};
|
||||
{
|
||||
typedef struct NestTask NestTask;
|
||||
struct NestTask
|
||||
{
|
||||
NestTask *next;
|
||||
CFG_Node *cfg;
|
||||
MD_Node *schema;
|
||||
B32 is_simple;
|
||||
};
|
||||
NestTask *top_nest_task = 0;
|
||||
CFG_NodeRec rec = {0};
|
||||
for(CFG_Node *c = root; c != &cfg_nil_node; c = rec.next)
|
||||
{
|
||||
// rjf: look up parent's schemas
|
||||
MD_NodePtrList schemas = {0};
|
||||
if(top_nest_task != 0)
|
||||
{
|
||||
CFG_Node *parent = top_nest_task->cfg;
|
||||
schemas = cfg_schemas_from_name(scratch.arena, schema_table, parent->string);
|
||||
}
|
||||
|
||||
// rjf: look up child schema
|
||||
MD_Node *c_schema = &md_nil_node;
|
||||
for(MD_NodePtrNode *n = schemas.first; n != 0 && c_schema == &md_nil_node; n = n->next)
|
||||
{
|
||||
c_schema = md_child_from_string(n->v, c->string, 0);
|
||||
}
|
||||
|
||||
// rjf: push name of this node
|
||||
if(c->string.size != 0 || c->first == &cfg_nil_node)
|
||||
{
|
||||
// rjf: extract the textualized form for this string (we may need to escape / relativize)
|
||||
String8 c_serialized_string = c->string;
|
||||
{
|
||||
MD_Node *c_schema = &md_nil_node;
|
||||
if(top_nest_task != 0)
|
||||
{
|
||||
c_schema = top_nest_task->schema;
|
||||
}
|
||||
|
||||
// rjf: paths -> relativize
|
||||
if(!md_node_has_tag(c_schema->first, str8_lit("no_relativize"), 0))
|
||||
{
|
||||
if(str8_match(c_schema->first->string, str8_lit("path"), 0))
|
||||
{
|
||||
String8 path_absolute = c->string;
|
||||
String8 path_relative = path_relative_dst_from_absolute_dst_src(arena, path_absolute, root_path);
|
||||
c_serialized_string = path_relative;
|
||||
}
|
||||
else if(str8_match(c_schema->first->string, str8_lit("path_pt"), 0))
|
||||
{
|
||||
String8 value = c->string;
|
||||
String8TxtPtPair parts = str8_txt_pt_pair_from_string(value);
|
||||
String8 path_relative = path_relative_dst_from_absolute_dst_src(scratch.arena, parts.string, root_path);
|
||||
c_serialized_string = push_str8f(arena, "%S:%I64d:%I64d", path_relative, parts.pt.line, parts.pt.column);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: all strings -> escape
|
||||
c_serialized_string = escaped_from_raw_str8(arena, c_serialized_string);
|
||||
}
|
||||
|
||||
// rjf: generate all strings for this node's string
|
||||
String8List c_name_strings = {0};
|
||||
{
|
||||
B32 name_can_be_pushed_standalone = 0;
|
||||
{
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
MD_TokenizeResult c_name_tokenize = md_tokenize_from_text(temp.arena, c_serialized_string);
|
||||
name_can_be_pushed_standalone = (c_name_tokenize.tokens.count == 1 && c_name_tokenize.tokens.v[0].flags & (MD_TokenFlag_Identifier|
|
||||
MD_TokenFlag_Numeric|
|
||||
MD_TokenFlag_StringLiteral|
|
||||
MD_TokenFlag_Symbol));
|
||||
temp_end(temp);
|
||||
}
|
||||
if(name_can_be_pushed_standalone)
|
||||
{
|
||||
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
|
||||
str8_list_push(scratch.arena, &c_name_strings, c_serialized_string);
|
||||
str8_list_push(scratch.arena, &c_name_strings, str8_lit("\""));
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if we're in a simple nesting task, then just break children by space
|
||||
if(top_nest_task != 0 && top_nest_task->is_simple)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(" "));
|
||||
}
|
||||
|
||||
// rjf: join c's strings with main string list
|
||||
str8_list_concat_in_place(&strings, &c_name_strings);
|
||||
}
|
||||
|
||||
// rjf: grab next recursion
|
||||
rec = cfg_node_rec__depth_first(root, c);
|
||||
|
||||
// rjf: push a new nesting task before descending to children
|
||||
if(c->first != &cfg_nil_node)
|
||||
{
|
||||
B32 is_simple_children_list = 1;
|
||||
for(CFG_Node *child = c->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(child->first != &cfg_nil_node && child != c->last)
|
||||
{
|
||||
is_simple_children_list = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
NestTask *task = push_array(scratch.arena, NestTask, 1);
|
||||
task->cfg = c;
|
||||
task->schema = c_schema;
|
||||
task->is_simple = is_simple_children_list;
|
||||
SLLStackPush(top_nest_task, task);
|
||||
}
|
||||
|
||||
// rjf: tree navigations -> encode hierarchy
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
if(top_nest_task->is_simple && c->string.size != 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(":"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(c->string.size != 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(":\n"));
|
||||
}
|
||||
str8_list_push(scratch.arena, &strings, str8_lit("{"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1, SLLStackPop(top_nest_task))
|
||||
{
|
||||
if(top_nest_task->is_simple)
|
||||
{
|
||||
if(top_nest_task->cfg->string.size == 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit(" }"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit("\n}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!top_nest_task || top_nest_task->is_simple == 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &strings, str8_lit("\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
String8 result_unindented = str8_list_join(scratch.arena, &strings, 0);
|
||||
String8 result = indented_from_string(arena, result_unindented);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Writing Functions
|
||||
|
||||
//- rjf: state creation / destroying
|
||||
|
||||
internal CFG_State *
|
||||
cfg_state_alloc(void)
|
||||
{
|
||||
Arena *arena = arena_alloc();
|
||||
CFG_State *state = push_array(arena, CFG_State, 1);
|
||||
state->arena = arena;
|
||||
state->ctx.id_slots_count = 4096;
|
||||
state->ctx.id_slots = push_array(arena, CFG_NodePtrSlot, state->ctx.id_slots_count);
|
||||
state->ctx.root = cfg_node_alloc(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_state_release(CFG_State *state)
|
||||
{
|
||||
arena_release(state->arena);
|
||||
}
|
||||
|
||||
//- rjf: state -> ctx
|
||||
|
||||
internal CFG_Ctx *
|
||||
cfg_state_ctx(CFG_State *state)
|
||||
{
|
||||
CFG_Ctx *ctx = &state->ctx;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
//- rjf: string allocations
|
||||
|
||||
internal U64
|
||||
cfg_string_bucket_num_from_size(U64 size)
|
||||
{
|
||||
U64 bucket_num = 0;
|
||||
if(size > 0)
|
||||
{
|
||||
for EachElement(idx, cfg_string_bucket_chunk_sizes)
|
||||
{
|
||||
if(size <= cfg_string_bucket_chunk_sizes[idx])
|
||||
{
|
||||
bucket_num = idx+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bucket_num;
|
||||
}
|
||||
|
||||
internal String8
|
||||
cfg_string_alloc(CFG_State *state, String8 string)
|
||||
{
|
||||
//- rjf: allocate node
|
||||
CFG_StringChunkNode *node = 0;
|
||||
{
|
||||
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
|
||||
if(bucket_num == ArrayCount(cfg_string_bucket_chunk_sizes))
|
||||
{
|
||||
CFG_StringChunkNode *best_node = 0;
|
||||
CFG_StringChunkNode *best_node_prev = 0;
|
||||
U64 best_node_size = max_U64;
|
||||
{
|
||||
for(CFG_StringChunkNode *n = state->free_string_chunks[bucket_num-1], *prev = 0; n != 0; (prev = n, n = n->next))
|
||||
{
|
||||
if(n->size >= string.size && n->size < best_node_size)
|
||||
{
|
||||
best_node = n;
|
||||
best_node_prev = prev;
|
||||
best_node_size = n->size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(best_node != 0)
|
||||
{
|
||||
node = best_node;
|
||||
if(best_node_prev)
|
||||
{
|
||||
best_node_prev->next = best_node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->free_string_chunks[bucket_num-1] = best_node->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
U64 chunk_size = u64_up_to_pow2(string.size);
|
||||
node = (CFG_StringChunkNode *)push_array(state->arena, U8, chunk_size);
|
||||
}
|
||||
}
|
||||
else if(bucket_num != 0)
|
||||
{
|
||||
node = state->free_string_chunks[bucket_num-1];
|
||||
if(node != 0)
|
||||
{
|
||||
SLLStackPop(state->free_string_chunks[bucket_num-1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = (CFG_StringChunkNode *)push_array(state->arena, U8, cfg_string_bucket_chunk_sizes[bucket_num-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: fill node
|
||||
String8 result = {0};
|
||||
if(node != 0)
|
||||
{
|
||||
result.str = (U8 *)node;
|
||||
result.size = string.size;
|
||||
MemoryCopy(result.str, string.str, result.size);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_string_release(CFG_State *state, String8 string)
|
||||
{
|
||||
U64 bucket_num = cfg_string_bucket_num_from_size(string.size);
|
||||
if(1 <= bucket_num && bucket_num <= ArrayCount(cfg_string_bucket_chunk_sizes))
|
||||
{
|
||||
U64 bucket_idx = bucket_num-1;
|
||||
CFG_StringChunkNode *node = (CFG_StringChunkNode *)string.str;
|
||||
SLLStackPush(state->free_string_chunks[bucket_idx], node);
|
||||
node->size = u64_up_to_pow2(string.size);
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: tree building
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_alloc(CFG_State *state)
|
||||
{
|
||||
state->ctx.change_gen += 1;
|
||||
|
||||
// rjf: allocate
|
||||
CFG_Node *result = state->free;
|
||||
{
|
||||
if(result)
|
||||
{
|
||||
SLLStackPop(state->free);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = push_array_no_zero(state->arena, CFG_Node, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: generate ID & fill
|
||||
state->id_gen += 1;
|
||||
MemoryZeroStruct(result);
|
||||
result->first = result->last = result->next = result->prev = result->parent = &cfg_nil_node;
|
||||
result->id = state->id_gen;
|
||||
|
||||
// rjf: store to ID -> cfg map
|
||||
{
|
||||
CFG_NodePtrNode *cfg_id_node = state->free_id_node;
|
||||
if(cfg_id_node != 0)
|
||||
{
|
||||
SLLStackPop(state->free_id_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
cfg_id_node = push_array(state->arena, CFG_NodePtrNode, 1);
|
||||
}
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&result->id));
|
||||
U64 slot_idx = hash%state->ctx.id_slots_count;
|
||||
DLLPushBack(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, cfg_id_node);
|
||||
cfg_id_node->v = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_release(CFG_State *state, CFG_Node *node)
|
||||
{
|
||||
state->ctx.change_gen += 1;
|
||||
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// rjf: unhook from context
|
||||
cfg_node_unhook(state, node->parent, node);
|
||||
|
||||
// rjf: gather root & all descendants
|
||||
CFG_NodePtrList nodes = {0};
|
||||
for(CFG_Node *c = node; c != &cfg_nil_node; c = cfg_node_rec__depth_first(node, c).next)
|
||||
{
|
||||
cfg_node_ptr_list_push(scratch.arena, &nodes, c);
|
||||
}
|
||||
|
||||
// rjf: release all nodes
|
||||
for(CFG_NodePtrNode *n = nodes.first; n != 0; n = n->next)
|
||||
{
|
||||
CFG_Node *c = n->v;
|
||||
cfg_string_release(state, c->string);
|
||||
SLLStackPush(state->free, c);
|
||||
c->first = c->last = c->prev = c->parent = 0;
|
||||
c->id = 0;
|
||||
c->string = str8_zero();
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&c->id));
|
||||
U64 slot_idx = hash%state->ctx.id_slots_count;
|
||||
for(CFG_NodePtrNode *n = state->ctx.id_slots[slot_idx].first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->v == c)
|
||||
{
|
||||
DLLRemove(state->ctx.id_slots[slot_idx].first, state->ctx.id_slots[slot_idx].last, n);
|
||||
SLLStackPush(state->free_id_node, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_release_all_children(CFG_State *state, CFG_Node *node)
|
||||
{
|
||||
for(CFG_Node *child = node->first, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
|
||||
{
|
||||
next = child->next;
|
||||
cfg_node_release(state, child);
|
||||
}
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *node = cfg_node_alloc(state);
|
||||
cfg_node_insert_child(state, parent, parent->last, node);
|
||||
cfg_node_equip_string(state, node, string);
|
||||
return node;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
CFG_Node *result = cfg_node_new(state, parent, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
string = push_str8_copy(scratch.arena, string);
|
||||
for(CFG_Node *child = parent->first->next, *next = &cfg_nil_node; child != &cfg_nil_node; child = next)
|
||||
{
|
||||
next = child->next;
|
||||
cfg_node_release(state, child);
|
||||
}
|
||||
if(parent->first == &cfg_nil_node)
|
||||
{
|
||||
cfg_node_new(state, parent, str8_zero());
|
||||
}
|
||||
CFG_Node *child = parent->first;
|
||||
cfg_node_equip_string(state, child, string);
|
||||
scratch_end(scratch);
|
||||
return child;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
CFG_Node *result = cfg_node_new_replace(state, parent, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root)
|
||||
{
|
||||
CFG_NodeRec rec = {0};
|
||||
CFG_Node *dst_root = &cfg_nil_node;
|
||||
CFG_Node *dst_parent = &cfg_nil_node;
|
||||
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
|
||||
{
|
||||
CFG_Node *dst = cfg_node_new(state, dst_parent, src->string);
|
||||
if(dst_root == &cfg_nil_node)
|
||||
{
|
||||
dst_root = dst;
|
||||
}
|
||||
rec = cfg_node_rec__depth_first(src_root, src);
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
dst_parent = dst;
|
||||
}
|
||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
||||
{
|
||||
dst_parent = dst_parent->parent;
|
||||
}
|
||||
}
|
||||
return dst_root;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string)
|
||||
{
|
||||
cfg_string_release(state, node->string);
|
||||
node->string = cfg_string_alloc(state, string);
|
||||
state->ctx.change_gen += 1;
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
String8 string = push_str8fv(scratch.arena, fmt, args);
|
||||
cfg_node_equip_string(state, node, string);
|
||||
va_end(args);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child)
|
||||
{
|
||||
if(parent != &cfg_nil_node)
|
||||
{
|
||||
if(new_child->parent != &cfg_nil_node)
|
||||
{
|
||||
cfg_node_unhook(state, new_child->parent, new_child);
|
||||
}
|
||||
DLLInsert_NPZ(&cfg_nil_node, parent->first, parent->last, prev_child, new_child, next, prev);
|
||||
new_child->parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child)
|
||||
{
|
||||
if(child != &cfg_nil_node && parent == child->parent && parent != &cfg_nil_node)
|
||||
{
|
||||
DLLRemove_NPZ(&cfg_nil_node, parent->first, parent->last, child, next, prev);
|
||||
child->parent = &cfg_nil_node;
|
||||
}
|
||||
}
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string)
|
||||
{
|
||||
CFG_Node *node = cfg_node_child_from_string(parent, string);
|
||||
if(node == &cfg_nil_node)
|
||||
{
|
||||
node = cfg_node_new(state, parent, string);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
//- rjf: deserialization
|
||||
|
||||
internal CFG_NodePtrList
|
||||
cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string)
|
||||
{
|
||||
CFG_NodePtrList result = {0};
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
//- rjf: parse the string as metadesk
|
||||
MD_Node *root = md_tree_from_string(scratch.arena, string);
|
||||
|
||||
//- rjf: iterate the top-level metadesk trees, generate new cfg trees for each
|
||||
for MD_EachNode(tln, root->first)
|
||||
{
|
||||
CFG_Node *dst_root_n = &cfg_nil_node;
|
||||
CFG_Node *dst_active_parent_n = &cfg_nil_node;
|
||||
MD_NodeRec rec = {0};
|
||||
for(MD_Node *src_n = tln; !md_node_is_nil(src_n); src_n = rec.next)
|
||||
{
|
||||
// rjf: lookup schema for this string
|
||||
MD_Node *schema = &md_nil_node;
|
||||
{
|
||||
MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, schema_table, dst_active_parent_n->parent->string);
|
||||
for(MD_NodePtrNode *n = schemas.first; n != 0 && schema == &md_nil_node; n = n->next)
|
||||
{
|
||||
schema = md_child_from_string(n->v, dst_active_parent_n->string, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: extract & transform metadesk node's string (it is raw textual data, so we need to
|
||||
// go escaped -> raw, and derelativize paths)
|
||||
String8 dst_n_string = {0};
|
||||
{
|
||||
String8 src_n_string = src_n->string;
|
||||
String8 src_n_string__raw = raw_from_escaped_str8(scratch.arena, src_n_string);
|
||||
if(!md_node_has_tag(schema->first, str8_lit("no_relativize"), 0))
|
||||
{
|
||||
if(str8_match(schema->first->string, str8_lit("path"), 0))
|
||||
{
|
||||
src_n_string__raw = path_absolute_dst_from_relative_dst_src(scratch.arena, src_n_string__raw, root_path);
|
||||
}
|
||||
else if(str8_match(schema->first->string, str8_lit("path_pt"), 0))
|
||||
{
|
||||
String8TxtPtPair parts = str8_txt_pt_pair_from_string(src_n_string__raw);
|
||||
src_n_string__raw = push_str8f(scratch.arena, "%S:%I64d:%I64d", path_absolute_dst_from_relative_dst_src(scratch.arena, parts.string, root_path), parts.pt.line, parts.pt.column);
|
||||
}
|
||||
}
|
||||
dst_n_string = src_n_string__raw;
|
||||
}
|
||||
|
||||
// rjf: allocate, fill, & insert new cfg for this metadesk node
|
||||
CFG_Node *dst_n = cfg_node_alloc(state);
|
||||
cfg_node_equip_string(state, dst_n, dst_n_string);
|
||||
if(dst_active_parent_n != &cfg_nil_node)
|
||||
{
|
||||
cfg_node_insert_child(state, dst_active_parent_n, dst_active_parent_n->last, dst_n);
|
||||
}
|
||||
|
||||
// rjf: recurse
|
||||
rec = md_node_rec_depth_first_pre(src_n, tln);
|
||||
if(dst_active_parent_n == &cfg_nil_node)
|
||||
{
|
||||
dst_root_n = dst_n;
|
||||
}
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
dst_active_parent_n = dst_n;
|
||||
}
|
||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
||||
{
|
||||
dst_active_parent_n = dst_active_parent_n->parent;
|
||||
}
|
||||
}
|
||||
cfg_node_ptr_list_push(arena, &result, dst_root_n);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_CORE_H
|
||||
#define CONFIG_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: IDs
|
||||
|
||||
typedef U64 CFG_ID;
|
||||
|
||||
typedef struct CFG_IDNode CFG_IDNode;
|
||||
struct CFG_IDNode
|
||||
{
|
||||
CFG_IDNode *next;
|
||||
CFG_ID v;
|
||||
};
|
||||
|
||||
typedef struct CFG_IDList CFG_IDList;
|
||||
struct CFG_IDList
|
||||
{
|
||||
CFG_IDNode *first;
|
||||
CFG_IDNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tree Types
|
||||
|
||||
typedef struct CFG_Node CFG_Node;
|
||||
struct CFG_Node
|
||||
{
|
||||
CFG_Node *first;
|
||||
CFG_Node *last;
|
||||
CFG_Node *next;
|
||||
CFG_Node *prev;
|
||||
CFG_Node *parent;
|
||||
CFG_ID id;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrNode CFG_NodePtrNode;
|
||||
struct CFG_NodePtrNode
|
||||
{
|
||||
CFG_NodePtrNode *next;
|
||||
CFG_NodePtrNode *prev;
|
||||
CFG_Node *v;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrSlot CFG_NodePtrSlot;
|
||||
struct CFG_NodePtrSlot
|
||||
{
|
||||
CFG_NodePtrNode *first;
|
||||
CFG_NodePtrNode *last;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrList CFG_NodePtrList;
|
||||
struct CFG_NodePtrList
|
||||
{
|
||||
CFG_NodePtrNode *first;
|
||||
CFG_NodePtrNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodePtrArray CFG_NodePtrArray;
|
||||
struct CFG_NodePtrArray
|
||||
{
|
||||
CFG_Node **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct CFG_NodeRec CFG_NodeRec;
|
||||
struct CFG_NodeRec
|
||||
{
|
||||
CFG_Node *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String Allocator
|
||||
|
||||
read_only global U64 cfg_string_bucket_chunk_sizes[] =
|
||||
{
|
||||
16,
|
||||
64,
|
||||
256,
|
||||
1024,
|
||||
4096,
|
||||
16384,
|
||||
65536,
|
||||
0xffffffffffffffffull,
|
||||
};
|
||||
|
||||
typedef struct CFG_StringChunkNode CFG_StringChunkNode;
|
||||
struct CFG_StringChunkNode
|
||||
{
|
||||
CFG_StringChunkNode *next;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config State Bundles
|
||||
|
||||
typedef struct CFG_Ctx CFG_Ctx;
|
||||
struct CFG_Ctx
|
||||
{
|
||||
CFG_Node *root;
|
||||
U64 id_slots_count;
|
||||
CFG_NodePtrSlot *id_slots;
|
||||
U64 change_gen;
|
||||
CFG_ID last_accessed_id;
|
||||
CFG_Node *last_accessed;
|
||||
};
|
||||
|
||||
typedef struct CFG_State CFG_State;
|
||||
struct CFG_State
|
||||
{
|
||||
Arena *arena;
|
||||
CFG_Node *free;
|
||||
CFG_NodePtrNode *free_id_node;
|
||||
CFG_StringChunkNode *free_string_chunks[ArrayCount(cfg_string_bucket_chunk_sizes)];
|
||||
U64 id_gen;
|
||||
CFG_Ctx ctx;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Table
|
||||
|
||||
typedef struct CFG_SchemaNode CFG_SchemaNode;
|
||||
struct CFG_SchemaNode
|
||||
{
|
||||
CFG_SchemaNode *next;
|
||||
String8 name;
|
||||
MD_Node *schema;
|
||||
};
|
||||
|
||||
typedef struct CFG_SchemaTable CFG_SchemaTable;
|
||||
struct CFG_SchemaTable
|
||||
{
|
||||
CFG_SchemaNode **slots;
|
||||
U64 slots_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global CFG_Node cfg_nil_node =
|
||||
{
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
&cfg_nil_node,
|
||||
};
|
||||
|
||||
thread_static CFG_Ctx *cfg_ctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: ID Functions
|
||||
|
||||
internal void cfg_id_list_push(Arena *arena, CFG_IDList *list, CFG_ID id);
|
||||
internal CFG_IDList cfg_id_list_copy(Arena *arena, CFG_IDList *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Node Pointer Data Structure Functions
|
||||
|
||||
internal void cfg_node_ptr_list_push(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
|
||||
internal void cfg_node_ptr_list_push_front(Arena *arena, CFG_NodePtrList *list, CFG_Node *node);
|
||||
#define cfg_node_ptr_list_first(list) ((list)->count ? (list)->first->v : &cfg_nil_node)
|
||||
#define cfg_node_ptr_list_last(list) ((list)->count ? (list)->last->v : &cfg_nil_node)
|
||||
internal CFG_NodePtrArray cfg_node_ptr_array_from_list(Arena *arena, CFG_NodePtrList *list);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Schema Data Structure Functions
|
||||
|
||||
internal void cfg_schema_table_insert(Arena *arena, CFG_SchemaTable *table, String8 name, MD_Node *schema);
|
||||
internal MD_Node *cfg_schema_from_name(CFG_SchemaTable *table, String8 name);
|
||||
internal MD_NodePtrList cfg_schemas_from_name(Arena *arena, CFG_SchemaTable *table, String8 name);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Reading Functions
|
||||
|
||||
//- rjf: context selection
|
||||
internal void cfg_ctx_select(CFG_Ctx *ctx);
|
||||
|
||||
//- rjf: tree navigations
|
||||
internal U64 cfg_change_gen(void);
|
||||
internal CFG_Node *cfg_node_root(void);
|
||||
internal CFG_Node *cfg_node_from_id(CFG_ID id);
|
||||
internal CFG_Node *cfg_node_child_from_string(CFG_Node *parent, String8 string);
|
||||
internal CFG_Node *cfg_node_child_from_string_or_parent(CFG_Node *parent, String8 string);
|
||||
internal CFG_NodePtrList cfg_node_child_list_from_string(Arena *arena, CFG_Node *parent, String8 string);
|
||||
internal CFG_NodePtrList cfg_node_top_level_list_from_string(Arena *arena, String8 string);
|
||||
internal CFG_NodeRec cfg_node_rec__depth_first(CFG_Node *root, CFG_Node *node);
|
||||
|
||||
//- rjf: serialization
|
||||
internal String8 cfg_string_from_tree(Arena *arena, CFG_SchemaTable *schema_table, String8 root_path, CFG_Node *root);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Writing Functions
|
||||
|
||||
//- rjf: state creation / destroying
|
||||
internal CFG_State *cfg_state_alloc(void);
|
||||
internal void cfg_state_release(CFG_State *state);
|
||||
|
||||
//- rjf: state -> ctx
|
||||
internal CFG_Ctx *cfg_state_ctx(CFG_State *state);
|
||||
|
||||
//- rjf: string allocations
|
||||
internal U64 cfg_string_bucket_num_from_size(U64 size);
|
||||
internal String8 cfg_string_alloc(CFG_State *state, String8 string);
|
||||
internal void cfg_string_release(CFG_State *state, String8 string);
|
||||
|
||||
//- rjf: tree building
|
||||
internal CFG_Node *cfg_node_alloc(CFG_State *state);
|
||||
internal void cfg_node_release(CFG_State *state, CFG_Node *node);
|
||||
internal void cfg_node_release_all_children(CFG_State *state, CFG_Node *node);
|
||||
internal CFG_Node *cfg_node_new(CFG_State *state, CFG_Node *parent, String8 string);
|
||||
internal CFG_Node *cfg_node_newf(CFG_State *state, CFG_Node *parent, char *fmt, ...);
|
||||
internal CFG_Node *cfg_node_new_replace(CFG_State *state, CFG_Node *parent, String8 string);
|
||||
internal CFG_Node *cfg_node_new_replacef(CFG_State *state, CFG_Node *parent, char *fmt, ...);
|
||||
internal CFG_Node *cfg_node_deep_copy(CFG_State *state, CFG_Node *src_root);
|
||||
internal void cfg_node_equip_string(CFG_State *state, CFG_Node *node, String8 string);
|
||||
internal void cfg_node_equip_stringf(CFG_State *state, CFG_Node *node, char *fmt, ...);
|
||||
internal void cfg_node_insert_child(CFG_State *state, CFG_Node *parent, CFG_Node *prev_child, CFG_Node *new_child);
|
||||
internal void cfg_node_unhook(CFG_State *state, CFG_Node *parent, CFG_Node *child);
|
||||
internal CFG_Node *cfg_node_child_from_string_or_alloc(CFG_State *state, CFG_Node *parent, String8 string);
|
||||
|
||||
//- rjf: deserialization
|
||||
internal CFG_NodePtrList cfg_node_ptr_list_from_string(Arena *arena, CFG_State *state, CFG_SchemaTable *schema_table, String8 root_path, String8 string);
|
||||
|
||||
#endif // CONFIG_CORE_H
|
||||
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#include "config_core.c"
|
||||
#include "config_panels.c"
|
||||
#if defined(OS_GFX_H)
|
||||
# include "config_bindings.c"
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_INC_H
|
||||
#define CONFIG_INC_H
|
||||
|
||||
#include "config_core.h"
|
||||
#include "config_panels.h"
|
||||
#if defined(OS_GFX_H)
|
||||
# include "config_bindings.h"
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_INC_H
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal CFG_Node *
|
||||
cfg_window_from_cfg(CFG_Node *cfg)
|
||||
{
|
||||
CFG_Node *result = &cfg_nil_node;
|
||||
for(CFG_Node *c = cfg; c != &cfg_nil_node; c = c->parent)
|
||||
{
|
||||
if(c->parent->parent == cfg_node_root() && str8_match(c->string, str8_lit("window"), 0))
|
||||
{
|
||||
result = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CFG_PanelTree
|
||||
cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
CFG_Node *wcfg = cfg_window_from_cfg(cfg_root);
|
||||
CFG_Node *src_root = cfg_node_child_from_string(wcfg, str8_lit("panels"));
|
||||
CFG_PanelNode *dst_root = &cfg_nil_panel_node;
|
||||
CFG_PanelNode *dst_focused = &cfg_nil_panel_node;
|
||||
{
|
||||
Axis2 active_split_axis = cfg_node_child_from_string(wcfg, str8_lit("split_x")) != &cfg_nil_node ? Axis2_X : Axis2_Y;
|
||||
CFG_NodeRec rec = {0};
|
||||
CFG_PanelNode *dst_active_parent = &cfg_nil_panel_node;
|
||||
for(CFG_Node *src = src_root; src != &cfg_nil_node; src = rec.next)
|
||||
{
|
||||
// rjf: build a panel node
|
||||
CFG_PanelNode *dst = push_array(arena, CFG_PanelNode, 1);
|
||||
MemoryCopyStruct(dst, &cfg_nil_panel_node);
|
||||
dst->parent = dst_active_parent;
|
||||
if(dst_active_parent != &cfg_nil_panel_node)
|
||||
{
|
||||
DLLPushBack_NPZ(&cfg_nil_panel_node, dst_active_parent->first, dst_active_parent->last, dst, next, prev);
|
||||
dst_active_parent->child_count += 1;
|
||||
}
|
||||
if(dst_root == &cfg_nil_panel_node)
|
||||
{
|
||||
dst_root = dst;
|
||||
}
|
||||
|
||||
// rjf: extract cfg info
|
||||
B32 panel_has_children = 0;
|
||||
dst->cfg = src;
|
||||
dst->pct_of_parent = (src == src_root ? 1.f : (F32)f64_from_str8(src->string));
|
||||
dst->tab_side = (cfg_node_child_from_string(src, str8_lit("tabs_on_bottom")) != &cfg_nil_node ? Side_Max : Side_Min);
|
||||
dst->split_axis = active_split_axis;
|
||||
for(CFG_Node *src_child = src->first; src_child != &cfg_nil_node; src_child = src_child->next)
|
||||
{
|
||||
MD_TokenizeResult tokenize = md_tokenize_from_text(scratch.arena, src_child->string);
|
||||
if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Numeric)
|
||||
{
|
||||
panel_has_children = 1;
|
||||
}
|
||||
else if(str8_match(src_child->string, str8_lit("tabs_on_bottom"), 0))
|
||||
{
|
||||
// NOTE(rjf): skip - this is a panel option.
|
||||
}
|
||||
else if(str8_match(src_child->string, str8_lit("selected"), 0))
|
||||
{
|
||||
dst_focused = dst;
|
||||
}
|
||||
else if(tokenize.tokens.count == 1 && tokenize.tokens.v[0].flags & MD_TokenFlag_Identifier)
|
||||
{
|
||||
cfg_node_ptr_list_push(arena, &dst->tabs, src_child);
|
||||
if(cfg_node_child_from_string(src_child, str8_lit("selected")) != &cfg_nil_node)
|
||||
{
|
||||
dst->selected_tab = src_child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: recurse
|
||||
rec = cfg_node_rec__depth_first(src_root, src);
|
||||
if(!panel_has_children)
|
||||
{
|
||||
MemoryZeroStruct(&rec);
|
||||
rec.next = &cfg_nil_node;
|
||||
for(CFG_Node *p = src; p != src_root && p != &cfg_nil_node; p = p->parent, rec.pop_count += 1)
|
||||
{
|
||||
if(p->next != &cfg_nil_node)
|
||||
{
|
||||
rec.next = p->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(rec.push_count > 0)
|
||||
{
|
||||
dst_active_parent = dst;
|
||||
active_split_axis = axis2_flip(active_split_axis);
|
||||
}
|
||||
else for(S32 pop_idx = 0; pop_idx < rec.pop_count; pop_idx += 1)
|
||||
{
|
||||
dst_active_parent = dst_active_parent->parent;
|
||||
active_split_axis = axis2_flip(active_split_axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
scratch_end(scratch);
|
||||
CFG_PanelTree tree = {dst_root, dst_focused};
|
||||
return tree;
|
||||
}
|
||||
|
||||
internal CFG_PanelNodeRec
|
||||
cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off)
|
||||
{
|
||||
CFG_PanelNodeRec rec = {&cfg_nil_panel_node};
|
||||
if(*MemberFromOffset(CFG_PanelNode **, panel, child_off) != &cfg_nil_panel_node)
|
||||
{
|
||||
rec.next = *MemberFromOffset(CFG_PanelNode **, panel, child_off);
|
||||
rec.push_count += 1;
|
||||
}
|
||||
else for(CFG_PanelNode *p = panel; p != &cfg_nil_panel_node && p != root; p = p->parent, rec.pop_count += 1)
|
||||
{
|
||||
if(*MemberFromOffset(CFG_PanelNode **, p, sib_off) != &cfg_nil_panel_node)
|
||||
{
|
||||
rec.next = *MemberFromOffset(CFG_PanelNode **, p, sib_off);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
internal CFG_PanelNode *
|
||||
cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg)
|
||||
{
|
||||
CFG_PanelNode *result = &cfg_nil_panel_node;
|
||||
for(CFG_PanelNode *p = root;
|
||||
p != &cfg_nil_panel_node;
|
||||
p = cfg_panel_node_rec__depth_first_pre(root, p).next)
|
||||
{
|
||||
if(p->cfg == cfg)
|
||||
{
|
||||
result = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal Rng2F32
|
||||
cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel)
|
||||
{
|
||||
Rng2F32 rect = parent_rect;
|
||||
if(parent != &cfg_nil_panel_node)
|
||||
{
|
||||
Vec2F32 parent_rect_size = dim_2f32(parent_rect);
|
||||
Axis2 axis = parent->split_axis;
|
||||
rect.p1.v[axis] = rect.p0.v[axis];
|
||||
for(CFG_PanelNode *child = parent->first; child != &cfg_nil_panel_node; child = child->next)
|
||||
{
|
||||
rect.p1.v[axis] += parent_rect_size.v[axis] * child->pct_of_parent;
|
||||
if(child == panel)
|
||||
{
|
||||
break;
|
||||
}
|
||||
rect.p0.v[axis] = rect.p1.v[axis];
|
||||
}
|
||||
//rect.p0.v[axis] += parent_rect_size.v[axis] * panel->off_pct_of_parent.v[axis];
|
||||
//rect.p0.v[axis2_flip(axis)] += parent_rect_size.v[axis2_flip(axis)] * panel->off_pct_of_parent.v[axis2_flip(axis)];
|
||||
}
|
||||
rect.x0 = round_f32(rect.x0);
|
||||
rect.x1 = round_f32(rect.x1);
|
||||
rect.y0 = round_f32(rect.y0);
|
||||
rect.y1 = round_f32(rect.y1);
|
||||
return rect;
|
||||
}
|
||||
|
||||
internal Rng2F32
|
||||
cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// rjf: count ancestors
|
||||
U64 ancestor_count = 0;
|
||||
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
|
||||
{
|
||||
ancestor_count += 1;
|
||||
}
|
||||
|
||||
// rjf: gather ancestors
|
||||
CFG_PanelNode **ancestors = push_array(scratch.arena, CFG_PanelNode *, ancestor_count);
|
||||
{
|
||||
U64 ancestor_idx = 0;
|
||||
for(CFG_PanelNode *p = panel->parent; p != &cfg_nil_panel_node; p = p->parent)
|
||||
{
|
||||
ancestors[ancestor_idx] = p;
|
||||
ancestor_idx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: go from highest ancestor => panel and calculate rect
|
||||
Rng2F32 parent_rect = root_rect;
|
||||
for(S64 ancestor_idx = (S64)ancestor_count-1;
|
||||
0 <= ancestor_idx && ancestor_idx < ancestor_count;
|
||||
ancestor_idx -= 1)
|
||||
{
|
||||
CFG_PanelNode *ancestor = ancestors[ancestor_idx];
|
||||
CFG_PanelNode *parent = ancestor->parent;
|
||||
if(parent != &cfg_nil_panel_node)
|
||||
{
|
||||
parent_rect = cfg_target_rect_from_panel_node_child(parent_rect, parent, ancestor);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: calculate final rect
|
||||
Rng2F32 rect = cfg_target_rect_from_panel_node_child(parent_rect, panel->parent, panel);
|
||||
|
||||
scratch_end(scratch);
|
||||
return rect;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef CONFIG_PANELS_H
|
||||
#define CONFIG_PANELS_H
|
||||
|
||||
typedef struct CFG_PanelNode CFG_PanelNode;
|
||||
struct CFG_PanelNode
|
||||
{
|
||||
// rjf: links data
|
||||
CFG_PanelNode *first;
|
||||
CFG_PanelNode *last;
|
||||
CFG_PanelNode *next;
|
||||
CFG_PanelNode *prev;
|
||||
CFG_PanelNode *parent;
|
||||
U64 child_count;
|
||||
CFG_Node *cfg;
|
||||
|
||||
// rjf: split data
|
||||
Axis2 split_axis;
|
||||
F32 pct_of_parent;
|
||||
|
||||
// rjf: tab params
|
||||
Side tab_side;
|
||||
|
||||
// rjf: which tabs are attached
|
||||
CFG_NodePtrList tabs;
|
||||
CFG_Node *selected_tab;
|
||||
};
|
||||
|
||||
typedef struct CFG_PanelTree CFG_PanelTree;
|
||||
struct CFG_PanelTree
|
||||
{
|
||||
CFG_PanelNode *root;
|
||||
CFG_PanelNode *focused;
|
||||
};
|
||||
|
||||
typedef struct CFG_PanelNodeRec CFG_PanelNodeRec;
|
||||
struct CFG_PanelNodeRec
|
||||
{
|
||||
CFG_PanelNode *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
read_only global CFG_PanelNode cfg_nil_panel_node =
|
||||
{
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
&cfg_nil_panel_node,
|
||||
0,
|
||||
&cfg_nil_node,
|
||||
.selected_tab = &cfg_nil_node,
|
||||
};
|
||||
|
||||
internal CFG_Node *cfg_window_from_cfg(CFG_Node *cfg);
|
||||
internal CFG_PanelTree cfg_panel_tree_from_cfg(Arena *arena, CFG_Node *cfg_root);
|
||||
internal CFG_PanelNodeRec cfg_panel_node_rec__depth_first(CFG_PanelNode *root, CFG_PanelNode *panel, U64 sib_off, U64 child_off);
|
||||
#define cfg_panel_node_rec__depth_first_pre(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, next), OffsetOf(CFG_PanelNode, first))
|
||||
#define cfg_panel_node_rec__depth_first_pre_rev(root, p) cfg_panel_node_rec__depth_first((root), (p), OffsetOf(CFG_PanelNode, prev), OffsetOf(CFG_PanelNode, last))
|
||||
internal CFG_PanelNode *cfg_panel_node_from_tree_cfg(CFG_PanelNode *root, CFG_Node *cfg);
|
||||
internal Rng2F32 cfg_target_rect_from_panel_node_child(Rng2F32 parent_rect, CFG_PanelNode *parent, CFG_PanelNode *panel);
|
||||
internal Rng2F32 cfg_target_rect_from_panel_node(Rng2F32 root_rect, CFG_PanelNode *root, CFG_PanelNode *panel);
|
||||
|
||||
#endif // CONFIG_PANELS_H
|
||||
+29
-39
@@ -7,21 +7,6 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
#if !defined(XXH_IMPLEMENTATION)
|
||||
# define XXH_IMPLEMENTATION
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
# include "third_party/xxHash/xxhash.h"
|
||||
#endif
|
||||
|
||||
internal U128
|
||||
c_hash_from_data(String8 data)
|
||||
{
|
||||
U128 u128 = {0};
|
||||
XXH128_hash_t hash = XXH3_128bits(data.str, data.size);
|
||||
MemoryCopy(&u128, &hash, sizeof(u128));
|
||||
return u128;
|
||||
}
|
||||
|
||||
internal C_ID
|
||||
c_id_make(U64 u64_0, U64 u64_1)
|
||||
{
|
||||
@@ -181,27 +166,36 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
||||
C_Stripe *key_stripe = &c_shared->key_stripes[key_stripe_idx];
|
||||
|
||||
//- rjf: hash data, unpack hash
|
||||
U128 hash = c_hash_from_data(data);
|
||||
U128 hash = u128_hash_from_str8(data);
|
||||
U64 slot_idx = hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 stripe_idx = slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *slot = &c_shared->blob_slots[slot_idx];
|
||||
C_Stripe *stripe = &c_shared->blob_stripes[stripe_idx];
|
||||
|
||||
//- rjf: commit data to cache - if already there, just bump key refcount
|
||||
ProfScope("commit data to cache - if already there, just bump key refcount") MutexScopeW(stripe->rw_mutex)
|
||||
//- rjf: commit to (hash -> data) cache
|
||||
ProfScope("commit to (hash -> data) cache") RWMutexScope(stripe->rw_mutex, 1)
|
||||
{
|
||||
C_BlobNode *existing_node = 0;
|
||||
// rjf: find existing node
|
||||
C_BlobNode *node = 0;
|
||||
for(C_BlobNode *n = slot->first; n != 0; n = n->next)
|
||||
{
|
||||
if(u128_match(n->hash, hash))
|
||||
{
|
||||
existing_node = n;
|
||||
node = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_node == 0)
|
||||
|
||||
// rjf: release duplicate data if node already exists
|
||||
if(node != 0 && data_arena != 0 && *data_arena != 0)
|
||||
{
|
||||
C_BlobNode *node = c_shared->blob_stripes_free_nodes[stripe_idx];
|
||||
arena_release(*data_arena);
|
||||
}
|
||||
|
||||
// rjf: allocate node if needed
|
||||
if(node == 0)
|
||||
{
|
||||
node = c_shared->blob_stripes_free_nodes[stripe_idx];
|
||||
if(node)
|
||||
{
|
||||
SLLStackPop(c_shared->blob_stripes_free_nodes[stripe_idx]);
|
||||
@@ -217,29 +211,24 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
||||
node->arena = *data_arena;
|
||||
}
|
||||
node->data = data;
|
||||
node->key_ref_count = 1;
|
||||
DLLPushBack(slot->first, slot->last, node);
|
||||
}
|
||||
else
|
||||
{
|
||||
existing_node->key_ref_count += 1;
|
||||
if(data_arena != 0)
|
||||
{
|
||||
arena_release(*data_arena);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: bump key ref count
|
||||
node->key_ref_count += 1;
|
||||
|
||||
// rjf "steal" arena from caller
|
||||
if(data_arena != 0)
|
||||
{
|
||||
*data_arena = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: commit this hash to key cache
|
||||
//- rjf: commit to (key -> list(hash)) cache
|
||||
U128 key_expired_hash = {0};
|
||||
ProfScope("commit this hash to key cache") MutexScopeW(key_stripe->rw_mutex)
|
||||
ProfScope("commit to (key -> list(hash)) cache") RWMutexScope(key_stripe->rw_mutex, 1)
|
||||
{
|
||||
// rjf: find existing key
|
||||
B32 key_is_new = 0;
|
||||
C_KeyNode *key_node = 0;
|
||||
for(C_KeyNode *n = key_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
@@ -251,6 +240,7 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
||||
}
|
||||
|
||||
// rjf: create key node if it doesn't exist
|
||||
B32 key_is_new = 0;
|
||||
if(!key_node)
|
||||
{
|
||||
key_is_new = 1;
|
||||
@@ -261,8 +251,9 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
||||
}
|
||||
else
|
||||
{
|
||||
key_node = push_array(key_stripe->arena, C_KeyNode, 1);
|
||||
key_node = push_array_no_zero(key_stripe->arena, C_KeyNode, 1);
|
||||
}
|
||||
MemoryZeroStruct(key_node);
|
||||
key_node->key = key;
|
||||
DLLPushBack(key_slot->first, key_slot->last, key_node);
|
||||
}
|
||||
@@ -286,7 +277,7 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
||||
U64 root_stripe_idx = root_slot_idx%c_shared->root_stripes_count;
|
||||
C_RootSlot *root_slot = &c_shared->root_slots[root_slot_idx];
|
||||
C_Stripe *root_stripe = &c_shared->root_stripes[root_stripe_idx];
|
||||
MutexScopeW(root_stripe->rw_mutex)
|
||||
RWMutexScope(root_stripe->rw_mutex, 1)
|
||||
{
|
||||
for(C_RootNode *n = root_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
@@ -312,14 +303,13 @@ c_submit_data(C_Key key, Arena **data_arena, String8 data)
|
||||
}
|
||||
|
||||
//- rjf: decrement key ref count of expired hash
|
||||
ProfScope("decrement key ref count of expired hash")
|
||||
if(!u128_match(key_expired_hash, u128_zero()))
|
||||
if(!u128_match(key_expired_hash, u128_zero())) ProfScope("decrement key ref count of expired hash")
|
||||
{
|
||||
U64 old_hash_slot_idx = key_expired_hash.u64[1]%c_shared->blob_slots_count;
|
||||
U64 old_hash_stripe_idx = old_hash_slot_idx%c_shared->blob_stripes_count;
|
||||
C_BlobSlot *old_hash_slot = &c_shared->blob_slots[old_hash_slot_idx];
|
||||
C_Stripe *old_hash_stripe = &c_shared->blob_stripes[old_hash_stripe_idx];
|
||||
MutexScopeR(old_hash_stripe->rw_mutex)
|
||||
RWMutexScope(old_hash_stripe->rw_mutex, 0)
|
||||
{
|
||||
for(C_BlobNode *n = old_hash_slot->first; n != 0; n = n->next)
|
||||
{
|
||||
|
||||
@@ -197,7 +197,6 @@ global C_Shared *c_shared = 0;
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
|
||||
internal U128 c_hash_from_data(String8 data);
|
||||
internal C_ID c_id_make(U64 u64_0, U64 u64_1);
|
||||
internal B32 c_id_match(C_ID a, C_ID b);
|
||||
internal C_Key c_key_make(C_Root root, C_ID id);
|
||||
|
||||
+155
-279
@@ -790,7 +790,7 @@ internal DI_Key
|
||||
ctrl_dbgi_key_from_module(CTRL_Entity *module)
|
||||
{
|
||||
CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {debug_info_path->string, debug_info_path->timestamp};
|
||||
DI_Key dbgi_key = di_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp);
|
||||
return dbgi_key;
|
||||
}
|
||||
|
||||
@@ -979,7 +979,7 @@ internal void
|
||||
ctrl_entity_string_release(CTRL_EntityCtxRWStore *store, String8 string)
|
||||
{
|
||||
U64 bucket_num = ctrl_name_bucket_num_from_string_size(string.size);
|
||||
if(1 <= bucket_num && bucket_num <= ArrayCount(rd_name_bucket_chunk_sizes))
|
||||
if(1 <= bucket_num && bucket_num <= ArrayCount(ctrl_entity_string_bucket_chunk_sizes))
|
||||
{
|
||||
U64 bucket_idx = bucket_num-1;
|
||||
CTRL_EntityStringChunkNode *node = (CTRL_EntityStringChunkNode *)string.str;
|
||||
@@ -1176,7 +1176,7 @@ ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind)
|
||||
}
|
||||
|
||||
internal CTRL_EntityList
|
||||
ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key *dbgi_key)
|
||||
ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key dbgi_key)
|
||||
{
|
||||
CTRL_EntityList list = {0};
|
||||
CTRL_EntityArray all_modules = ctrl_entity_array_from_kind(ctx, CTRL_EntityKind_Module);
|
||||
@@ -1184,7 +1184,7 @@ ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key *dbgi_key)
|
||||
{
|
||||
CTRL_Entity *module = all_modules.v[idx];
|
||||
DI_Key module_dbgi_key = ctrl_dbgi_key_from_module(module);
|
||||
if(di_key_match(&module_dbgi_key, dbgi_key))
|
||||
if(di_key_match(module_dbgi_key, dbgi_key))
|
||||
{
|
||||
ctrl_entity_list_push(arena, &list, module);
|
||||
}
|
||||
@@ -2756,7 +2756,7 @@ internal CTRL_CallStack
|
||||
ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *base_unwind)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
Access *access = access_open();
|
||||
Arch arch = process->arch;
|
||||
CTRL_CallStack result = {0};
|
||||
{
|
||||
@@ -2779,7 +2779,7 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas
|
||||
CTRL_Entity *module = ctrl_module_from_process_vaddr(process, rip_vaddr);
|
||||
U64 rip_voff = ctrl_voff_from_vaddr(module, rip_vaddr);
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
|
||||
RDI_Scope *scope = rdi_scope_from_voff(rdi, rip_voff);
|
||||
|
||||
// rjf: build inline frames (minus parent & inline depth)
|
||||
@@ -2841,7 +2841,7 @@ ctrl_call_stack_from_unwind(Arena *arena, CTRL_Entity *process, CTRL_Unwind *bas
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(di_scope);
|
||||
access_close(access);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
@@ -3084,12 +3084,15 @@ ctrl_thread__entry_point(void *p)
|
||||
}
|
||||
|
||||
//- rjf: reset per-message state
|
||||
arena_clear(ctrl_state->ctrl_thread_msg_process_arena);
|
||||
ctrl_state->module_req_cache_slots_count = 1024;
|
||||
ctrl_state->module_req_cache_slots = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode *, ctrl_state->module_req_cache_slots_count);
|
||||
MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_files);
|
||||
MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_symbols);
|
||||
MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters);
|
||||
ProfScope("reset per-message state")
|
||||
{
|
||||
arena_clear(ctrl_state->ctrl_thread_msg_process_arena);
|
||||
ctrl_state->module_req_cache_slots_count = 4096;
|
||||
ctrl_state->module_req_cache_slots = push_array(ctrl_state->ctrl_thread_msg_process_arena, CTRL_ModuleReqCacheNode *, ctrl_state->module_req_cache_slots_count);
|
||||
MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_files);
|
||||
MemoryZeroStruct(&ctrl_state->msg_user_bp_touched_symbols);
|
||||
MemoryCopyArray(ctrl_state->exception_code_filters, msg->exception_code_filters);
|
||||
}
|
||||
|
||||
//- rjf: gather all touched symbols by user breakpoints
|
||||
{
|
||||
@@ -3185,16 +3188,16 @@ ctrl_thread__entry_point(void *p)
|
||||
String8 path = msg->path;
|
||||
CTRL_Entity *module = ctrl_entity_from_handle(entity_ctx, msg->entity);
|
||||
CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key old_dbgi_key = {debug_info_path->string, debug_info_path->timestamp};
|
||||
di_close(&old_dbgi_key);
|
||||
DI_Key old_dbgi_key = di_key_from_path_timestamp(debug_info_path->string, debug_info_path->timestamp);
|
||||
di_close(old_dbgi_key);
|
||||
MutexScopeW(ctrl_state->ctrl_thread_entity_ctx_rw_mutex)
|
||||
{
|
||||
ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path_normalized_from_string(scratch.arena, path));
|
||||
}
|
||||
U64 new_dbgi_timestamp = os_properties_from_file_path(path).modified;
|
||||
debug_info_path->timestamp = new_dbgi_timestamp;
|
||||
DI_Key new_dbgi_key = {debug_info_path->string, new_dbgi_timestamp};
|
||||
di_open(&new_dbgi_key);
|
||||
DI_Key new_dbgi_key = di_key_from_path_timestamp(debug_info_path->string, new_dbgi_timestamp);
|
||||
di_open(new_dbgi_key);
|
||||
CTRL_EventList evts = {0};
|
||||
CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts);
|
||||
evt->kind = CTRL_EventKind_ModuleDebugInfoPathChange;
|
||||
@@ -3259,12 +3262,12 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_EvalScope *
|
||||
if(user_bps->first == 0) { return; }
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
DI_Scope *di_scope = eval_scope->di_scope;
|
||||
Access *access = eval_scope->access;
|
||||
CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx;
|
||||
CTRL_Entity *module_entity = ctrl_entity_from_handle(entity_ctx, module);
|
||||
CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {debug_info_path_entity->string, debug_info_path_entity->timestamp};
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0);
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module_entity);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
|
||||
U64 base_vaddr = module_entity->vaddr_range.min;
|
||||
for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next)
|
||||
{
|
||||
@@ -3396,11 +3399,12 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
U32 pdb_dbg_time = 0;
|
||||
U32 pdb_dbg_age = 0;
|
||||
Guid pdb_dbg_guid = {0};
|
||||
String8 pdb_dbg_path = str8_zero();
|
||||
String8 pdb_dbg_path = {0};
|
||||
U32 rdi_dbg_time = 0;
|
||||
Guid rdi_dbg_guid = {0};
|
||||
String8 rdi_dbg_path = str8_zero();
|
||||
String8 raddbg_data = str8_zero();
|
||||
String8 exe_dbg_path = {0};
|
||||
String8 rdi_dbg_path = {0};
|
||||
String8 raddbg_data = {0};
|
||||
Rng1U64 raddbg_section_voff_range = r1u64(0, 0);
|
||||
Rng1U64 raddbg_is_attached_section_voff_range = r1u64(0, 0);
|
||||
ProfScope("unpack relevant PE info")
|
||||
@@ -3450,6 +3454,8 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
U32 data_dir_count = 0;
|
||||
if(opt_ext_size > 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
// rjf: read magic number
|
||||
U16 opt_ext_magic = 0;
|
||||
dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min, &opt_ext_magic);
|
||||
@@ -3520,6 +3526,12 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: extract sections
|
||||
U64 sec_array_off = opt_ext_off_range.max;
|
||||
U64 sec_count = file_header.section_count;
|
||||
COFF_SectionHeader *sec = push_array(scratch.arena, COFF_SectionHeader, sec_count);
|
||||
dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec);
|
||||
|
||||
// rjf: grab entry point vaddr
|
||||
entry_point_voff = entry_point;
|
||||
|
||||
@@ -3586,13 +3598,18 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: look for DWARF debug info
|
||||
{
|
||||
U64 symbol_array_off = file_header.symbol_table_foff;
|
||||
U64 symbol_count = file_header.symbol_count;
|
||||
if(symbol_array_off != 0)
|
||||
{
|
||||
exe_dbg_path = path;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: extract copy of module's raddbg data
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
U64 sec_array_off = opt_ext_off_range.max;
|
||||
U64 sec_count = file_header.section_count;
|
||||
COFF_SectionHeader *sec = push_array(scratch.arena, COFF_SectionHeader, sec_count);
|
||||
dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec);
|
||||
for EachIndex(idx, sec_count)
|
||||
{
|
||||
String8 section_name = str8_cstring((char *)sec[idx].name);
|
||||
@@ -3611,7 +3628,6 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
raddbg_data.str = push_array(arena, U8, raddbg_data.size);
|
||||
dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + raddbg_section_voff_range.min,
|
||||
vaddr_range.min + raddbg_section_voff_range.max), raddbg_data.str);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
// rjf: if we have a "raddbg is attached" section, mark the first byte as 1, to signify attachment
|
||||
@@ -3620,6 +3636,8 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
U8 new_value = 1;
|
||||
dmn_process_write_struct(process.dmn_handle, vaddr_range.min + raddbg_is_attached_section_voff_range.min, &new_value);
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3646,6 +3664,10 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, rdi_dbg_path);
|
||||
str8_list_push(scratch.arena, &dbg_path_candidates, rdi_dbg_path);
|
||||
}
|
||||
if(exe_dbg_path.size != 0)
|
||||
{
|
||||
str8_list_push(scratch.arena, &dbg_path_candidates, path);
|
||||
}
|
||||
if(pdb_dbg_path.size != 0)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, pdb_dbg_path);
|
||||
@@ -3828,7 +3850,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
if(!should_filter_event && ev->code == 0xc0000005 &&
|
||||
(spoof == 0 || ev->instruction_pointer != spoof->new_ip_value))
|
||||
{
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
Access *access = access_open();
|
||||
CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, ev->process));
|
||||
CTRL_Entity *module = &ctrl_entity_nil;
|
||||
for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next)
|
||||
@@ -3844,9 +3866,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
// rjf: determine base address of asan shadow space
|
||||
U64 asan_shadow_base_vaddr = 0;
|
||||
B32 asan_shadow_variable_exists_but_is_zero = 0;
|
||||
CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp};
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, max_U64);
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, max_U64);
|
||||
RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_GlobalVariables);
|
||||
{
|
||||
RDI_ParsedNameMap map = {0};
|
||||
@@ -3888,7 +3909,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
}
|
||||
}
|
||||
|
||||
di_scope_close(di_scope);
|
||||
access_close(access);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
@@ -4057,8 +4078,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
out_evt2->parent = process_handle;
|
||||
out_evt2->timestamp = debug_info_timestamp;
|
||||
out_evt2->string = initial_debug_info_path;
|
||||
DI_Key initial_dbgi_key = {initial_debug_info_path, debug_info_timestamp};
|
||||
di_open(&initial_dbgi_key);
|
||||
DI_Key initial_dbgi_key = di_key_from_path_timestamp(initial_debug_info_path, debug_info_timestamp);
|
||||
di_open(initial_dbgi_key);
|
||||
}break;
|
||||
case DMN_EventKind_ExitProcess:
|
||||
{
|
||||
@@ -4090,12 +4111,8 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
out_evt->msg_id = msg->msg_id;
|
||||
out_evt->entity = module_handle;
|
||||
out_evt->string = module_path;
|
||||
CTRL_Entity *debug_info_path_ent = ctrl_entity_child_from_kind(module_ent, CTRL_EntityKind_DebugInfoPath);
|
||||
if(debug_info_path_ent != &ctrl_entity_nil)
|
||||
{
|
||||
DI_Key dbgi_key = {debug_info_path_ent->string, debug_info_path_ent->timestamp};
|
||||
di_close(&dbgi_key);
|
||||
}
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module_ent);
|
||||
di_close(dbgi_key);
|
||||
}break;
|
||||
case DMN_EventKind_DebugString:
|
||||
{
|
||||
@@ -4169,187 +4186,6 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
ctrl_state->dbg_dir_root = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
|
||||
}
|
||||
|
||||
//- rjf: when a new module is loaded, pre-emptively try to open all adjacent
|
||||
// debug infos. with debug events, we learn about loaded modules serially,
|
||||
// and we need to completely load debug info before continuing. for massive
|
||||
// projects, this is a problem, because completely loading debug info isn't a
|
||||
// trivial cost, and there are often 1000s of DLLs.
|
||||
//
|
||||
// an imperfect but usually reasonable heuristic is to look at adjacent
|
||||
// debug info files, in the same or under the directory as the initially
|
||||
// loaded, and pre-emptively convert all of them (which for us is the
|
||||
// heaviest part of debug info loading, if native RDI is not used).
|
||||
//
|
||||
// only do this on the first ever loaded module, *or* once we get beyond 256
|
||||
// modules (a very bad heuristic that may or may not inform us that we are
|
||||
// dealing with insane-town projects)
|
||||
//
|
||||
if(0 &&
|
||||
event->kind == DMN_EventKind_LoadModule &&
|
||||
(entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] > 256 ||
|
||||
entity_ctx->entity_kind_counts[CTRL_EntityKind_Module] == 1))
|
||||
{
|
||||
//- rjf: unpack event
|
||||
CTRL_Handle process_handle = ctrl_handle_make(CTRL_MachineID_Local, event->process);
|
||||
CTRL_Handle loaded_module_handle = ctrl_handle_make(CTRL_MachineID_Local, event->module);
|
||||
CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, process_handle);
|
||||
CTRL_Entity *loaded_module = ctrl_entity_from_handle(entity_ctx, loaded_module_handle);
|
||||
|
||||
//- rjf: for each module, use its full path as the start to a new limited recursive
|
||||
// directory search. cache each directory once traversed in the dbg_dir tree. if any
|
||||
// node is not cached, then scan it & pre-emptively convert debug info.
|
||||
ProfScope("pre-emptively load adjacent debug info for %.*s", str8_varg(loaded_module->string))
|
||||
{
|
||||
//- rjf: calculate seed path
|
||||
DI_Key loaded_di_key = ctrl_dbgi_key_from_module(loaded_module);
|
||||
String8 loaded_di_name = str8_skip_last_slash(loaded_di_key.path);
|
||||
String8 debug_info_ext = str8_skip_last_dot(loaded_di_key.path);
|
||||
String8 seed_folder_path = str8_chop_last_slash(loaded_di_key.path);
|
||||
if(seed_folder_path.size == 0)
|
||||
{
|
||||
String8 module_path = loaded_module->string;
|
||||
seed_folder_path = str8_chop_last_slash(module_path);
|
||||
}
|
||||
|
||||
//- rjf: split seed path
|
||||
String8List seed_path_parts = str8_split_path(scratch.arena, seed_folder_path);
|
||||
|
||||
//- rjf: find parent dir node for this module's debug info; build tree leading to this dir
|
||||
CTRL_DbgDirNode *parent_dir_node = ctrl_state->dbg_dir_root;
|
||||
for(String8Node *n = seed_path_parts.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 name = n->string;
|
||||
CTRL_DbgDirNode *next_child = 0;
|
||||
for(CTRL_DbgDirNode *child = parent_dir_node->first; child != 0; child = child->next)
|
||||
{
|
||||
if(str8_match(child->name, name, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
next_child = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(next_child == 0)
|
||||
{
|
||||
next_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
|
||||
DLLPushBack(parent_dir_node->first, parent_dir_node->last, next_child);
|
||||
next_child->parent = parent_dir_node;
|
||||
next_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, name);
|
||||
parent_dir_node->child_count += 1;
|
||||
}
|
||||
parent_dir_node = next_child;
|
||||
}
|
||||
|
||||
//- rjf: count modules
|
||||
{
|
||||
parent_dir_node->module_direct_count += 1;
|
||||
}
|
||||
|
||||
//- rjf: iterate from dir node up its ancestor chain - do recursive
|
||||
// searches if this is an ancestor of loaded modules, it has not been
|
||||
// searched yet, but it has >4 child branches, meaning it looks like
|
||||
// project directory
|
||||
//
|
||||
DI_KeyList preemptively_loaded_keys = {0};
|
||||
for(CTRL_DbgDirNode *dir_node = parent_dir_node; dir_node != 0; dir_node = dir_node->parent)
|
||||
{
|
||||
if(dir_node->search_count == 0 && dir_node->module_direct_count >= 1)
|
||||
{
|
||||
//- rjf: form full path of this directory node
|
||||
String8List dir_node_path_parts = {0};
|
||||
for(CTRL_DbgDirNode *n = dir_node; n != 0; n = n->parent)
|
||||
{
|
||||
if(n->name.size != 0)
|
||||
{
|
||||
str8_list_push_front(scratch.arena, &dir_node_path_parts, n->name);
|
||||
}
|
||||
}
|
||||
String8 dir_node_path = str8_list_join(scratch.arena, &dir_node_path_parts, &(StringJoin){.sep = str8_lit("/")});
|
||||
|
||||
//- rjf: iterate downwards from this directory recursively, locate
|
||||
// debug infos, and pre-emptively convert
|
||||
typedef struct Task Task;
|
||||
struct Task
|
||||
{
|
||||
Task *next;
|
||||
CTRL_DbgDirNode *node;
|
||||
String8 path;
|
||||
};
|
||||
Task start_task = {0, dir_node, dir_node_path};
|
||||
Task *first_task = &start_task;
|
||||
Task *last_task = first_task;
|
||||
U64 task_count = 0;
|
||||
for(Task *t = first_task; t != 0; t = t->next)
|
||||
{
|
||||
ProfBegin("search task %.*s", str8_varg(t->path));
|
||||
|
||||
// rjf: increment search counter
|
||||
t->node->search_count += 1;
|
||||
|
||||
// rjf: iterate this directory. if debug infos are encountered,
|
||||
// kick off pre-emptive conversion, and gather key. if folders
|
||||
// are encountered, then add them to the tree, and kick off a
|
||||
// sub-search if needed.
|
||||
OS_FileIter *it = os_file_iter_begin(scratch.arena, t->path, 0);
|
||||
U64 idx = 0;
|
||||
for(OS_FileInfo info = {0}; idx < 16384 && os_file_iter_next(scratch.arena, it, &info); idx += 1)
|
||||
{
|
||||
// rjf: folder -> do sub-search if not duplicative
|
||||
if(info.props.flags & FilePropertyFlag_IsFolder && task_count < 16384 && !str8_match(str8_prefix(info.name, 1), str8_lit("."), 0))
|
||||
{
|
||||
CTRL_DbgDirNode *existing_dir_child = 0;
|
||||
for(CTRL_DbgDirNode *child = t->node->first; child != 0; child = child->next)
|
||||
{
|
||||
if(str8_match(child->name, info.name, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
existing_dir_child = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(existing_dir_child == 0)
|
||||
{
|
||||
existing_dir_child = push_array(ctrl_state->dbg_dir_arena, CTRL_DbgDirNode, 1);
|
||||
DLLPushBack(t->node->first, t->node->last, existing_dir_child);
|
||||
existing_dir_child->parent = t->node;
|
||||
existing_dir_child->name = push_str8_copy(ctrl_state->dbg_dir_arena, info.name);
|
||||
t->node->child_count += 1;
|
||||
}
|
||||
if(existing_dir_child->search_count == 0)
|
||||
{
|
||||
Task *task = push_array(scratch.arena, Task, 1);
|
||||
task->node = existing_dir_child;
|
||||
task->path = push_str8f(scratch.arena, "%S/%S", t->path, info.name);
|
||||
SLLQueuePush(first_task, last_task, task);
|
||||
task_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: debug info file -> kick off open
|
||||
else if(preemptively_loaded_keys.count < 4096 &&
|
||||
!(info.props.flags & FilePropertyFlag_IsFolder) &&
|
||||
str8_match(str8_skip_last_dot(info.name), debug_info_ext, StringMatchFlag_CaseInsensitive) &&
|
||||
!str8_match(loaded_di_name, info.name, StringMatchFlag_CaseInsensitive))
|
||||
{
|
||||
DI_Key key = {push_str8f(scratch.arena, "%S/%S", t->path, info.name), info.props.modified};
|
||||
di_open(&key);
|
||||
di_key_list_push(scratch.arena, &preemptively_loaded_keys, &key);
|
||||
if(preemptively_loaded_keys.count >= Max(1, async_thread_count()/2))
|
||||
{
|
||||
for(DI_KeyNode *n = preemptively_loaded_keys.first; n != 0; n = n->next)
|
||||
{
|
||||
di_close(&n->v);
|
||||
}
|
||||
MemoryZeroStruct(&preemptively_loaded_keys);
|
||||
}
|
||||
}
|
||||
}
|
||||
os_file_iter_end(it);
|
||||
ProfEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: out of queued up demon events -> clear event arena
|
||||
if(ctrl_state->first_dmn_event_node == 0)
|
||||
{
|
||||
@@ -4364,8 +4200,23 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg,
|
||||
|
||||
//- rjf: eval helpers
|
||||
|
||||
internal U64
|
||||
ctrl_eval_space_gen(E_Space space)
|
||||
{
|
||||
U64 result = 0;
|
||||
switch(space.kind)
|
||||
{
|
||||
default:{}break;
|
||||
case CTRL_EvalSpaceKind_Entity:
|
||||
{
|
||||
result = ctrl_mem_gen();
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal B32
|
||||
ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
|
||||
ctrl_eval_space_read(E_Space space, void *out, Rng1U64 range)
|
||||
{
|
||||
B32 result = 0;
|
||||
switch(space.kind)
|
||||
@@ -4399,12 +4250,6 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
|
||||
}break;
|
||||
}
|
||||
}break;
|
||||
|
||||
//- rjf: meta evaluations
|
||||
case CTRL_EvalSpaceKind_Meta:
|
||||
{
|
||||
|
||||
}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -4414,9 +4259,10 @@ ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range)
|
||||
internal CTRL_EvalScope *
|
||||
ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, CTRL_Entity *thread)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
CTRL_EntityCtx *entity_ctx = &ctrl_state->ctrl_thread_entity_store->ctx;
|
||||
CTRL_EvalScope *scope = push_array(arena, CTRL_EvalScope, 1);
|
||||
scope->di_scope = di_scope_open();
|
||||
scope->access = access_open();
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: unpack thread
|
||||
@@ -4452,25 +4298,28 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C
|
||||
mod = mod->next)
|
||||
{
|
||||
if(mod->kind != CTRL_EntityKind_Module) { continue; }
|
||||
CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp};
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(mod);
|
||||
|
||||
//- rjf: try to obtain this module's RDI
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, 1, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope->access, dbgi_key, 0, 0);
|
||||
|
||||
//- rjf: if this RDI is not yet ready => determine if we need to wait for it
|
||||
//
|
||||
// (we *always* wait for the initial module)
|
||||
//
|
||||
B32 rdi_is_necessary = 1;
|
||||
if(rdi == &rdi_parsed_nil) ProfScope("determine if RDI is necessary")
|
||||
if(user_bps->count == 0)
|
||||
{
|
||||
rdi_is_necessary = 0;
|
||||
}
|
||||
else if(rdi == &rdi_parsed_nil) ProfScope("determine if RDI is necessary")
|
||||
{
|
||||
// rjf: find cached result
|
||||
U64 hash = ctrl_hash_from_handle(mod->handle);
|
||||
U64 slot_idx = hash%ctrl_state->module_req_cache_slots_count;
|
||||
CTRL_ModuleReqCacheNode *slot = ctrl_state->module_req_cache_slots[slot_idx];
|
||||
CTRL_ModuleReqCacheNode *node = 0;
|
||||
for(CTRL_ModuleReqCacheNode *n = slot; slot != 0; slot = slot->next)
|
||||
for(CTRL_ModuleReqCacheNode *n = slot; n != 0; n = n->next)
|
||||
{
|
||||
if(ctrl_handle_match(n->module, mod->handle))
|
||||
{
|
||||
@@ -4488,7 +4337,9 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C
|
||||
// rjf: not cached -> compute & store
|
||||
else ProfScope("cache miss")
|
||||
{
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, dbgi_key.path);
|
||||
CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(mod, CTRL_EntityKind_DebugInfoPath);
|
||||
OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, debug_info_path->string);
|
||||
ProfScope("determine if %.*s is necessary", str8_varg(debug_info_path->string))
|
||||
{
|
||||
//- rjf: determine if file is PDB
|
||||
B32 file_is_pdb = 0;
|
||||
@@ -4536,13 +4387,14 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C
|
||||
}
|
||||
|
||||
//- rjf: if this RDI is necessary, but we do not have it => wait for it forever
|
||||
if(rdi == &rdi_parsed_nil && rdi_is_necessary)
|
||||
if(rdi == &rdi_parsed_nil && rdi_is_necessary) ProfScope("RDI is necessary -> wait")
|
||||
{
|
||||
rdi = di_rdi_from_key(scope->di_scope, &dbgi_key, 1, max_U64);
|
||||
rdi = di_rdi_from_key(scope->access, dbgi_key, 1, max_U64);
|
||||
}
|
||||
|
||||
//- rjf: fill evaluation module info
|
||||
eval_modules[eval_module_idx].arch = arch;
|
||||
eval_modules[eval_module_idx].dbgi_key = dbgi_key;
|
||||
eval_modules[eval_module_idx].rdi = rdi;
|
||||
eval_modules[eval_module_idx].vaddr_range = mod->vaddr_range;
|
||||
eval_modules[eval_module_idx].space = e_space_make(CTRL_EvalSpaceKind_Entity);
|
||||
@@ -4581,6 +4433,7 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C
|
||||
ctx->primary_module = eval_modules_primary;
|
||||
|
||||
//- rjf: fill space hooks
|
||||
ctx->space_gen = ctrl_eval_space_gen;
|
||||
ctx->space_read = ctrl_eval_space_read;
|
||||
}
|
||||
e_select_base_ctx(&scope->base_ctx);
|
||||
@@ -4606,7 +4459,6 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C
|
||||
//
|
||||
{
|
||||
E_InterpretCtx *ctx = &scope->interpret_ctx;
|
||||
ctx->space_read = ctrl_eval_space_read;
|
||||
ctx->primary_space = eval_modules_primary->space;
|
||||
ctx->reg_arch = eval_modules_primary->arch;
|
||||
ctx->reg_space = e_space_make(CTRL_EvalSpaceKind_Entity);
|
||||
@@ -4619,13 +4471,14 @@ ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, C
|
||||
}
|
||||
e_select_interpret_ctx(&scope->interpret_ctx, eval_modules_primary->rdi, thread_rip_voff);
|
||||
|
||||
ProfEnd();
|
||||
return scope;
|
||||
}
|
||||
|
||||
internal void
|
||||
ctrl_thread__eval_scope_end(CTRL_EvalScope *scope)
|
||||
{
|
||||
di_scope_close(scope->di_scope);
|
||||
access_close(scope->access);
|
||||
}
|
||||
|
||||
//- rjf: log flusher
|
||||
@@ -5351,15 +5204,14 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
if(msg->run_flags & CTRL_RunFlag_StopOnEntryPoint && !launch_done_first_module && event->kind == DMN_EventKind_HandshakeComplete)
|
||||
{
|
||||
launch_done_first_module = 1;
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
Access *access = access_open();
|
||||
|
||||
//- rjf: unpack process/module info
|
||||
CTRL_Entity *process = ctrl_entity_from_handle(entity_ctx, ctrl_handle_make(CTRL_MachineID_Local, event->process));
|
||||
CTRL_Entity *module = ctrl_entity_child_from_kind(process, CTRL_EntityKind_Module);
|
||||
U64 module_base_vaddr = module->vaddr_range.min;
|
||||
CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath);
|
||||
DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp};
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, max_U64);
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, max_U64);
|
||||
RDI_NameMap *unparsed_map = rdi_element_from_name_idx(rdi, NameMaps, RDI_NameMapKind_Procedures);
|
||||
RDI_ParsedNameMap map = {0};
|
||||
rdi_parsed_from_name_map(rdi, unparsed_map, &map);
|
||||
@@ -5572,7 +5424,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
//- rjf: found entry points -> add to joined traps
|
||||
dmn_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &entry_traps);
|
||||
|
||||
di_scope_close(di_scope);
|
||||
access_close(access);
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
@@ -6134,7 +5986,7 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg)
|
||||
//~ rjf: Process Memory Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact
|
||||
ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out)
|
||||
ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
|
||||
{
|
||||
AC_Artifact artifact = {0};
|
||||
{
|
||||
@@ -6158,23 +6010,23 @@ ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry
|
||||
}
|
||||
|
||||
//- rjf: do read
|
||||
U64 range_size = 0;
|
||||
U64 range_size = dim_1u64(vaddr_range_clamped);
|
||||
Arena *range_arena = 0;
|
||||
void *range_base = 0;
|
||||
U64 zero_terminated_size = 0;
|
||||
U64 pre_read_mem_gen = ctrl_mem_gen();
|
||||
B32 pre_run_state = ins_atomic_u64_eval(&ctrl_state->ctrl_thread_run_state);
|
||||
if(range_size != 0)
|
||||
{
|
||||
range_size = dim_1u64(vaddr_range_clamped);
|
||||
// rjf: set up arena
|
||||
U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process
|
||||
U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, page_size);
|
||||
range_arena = arena_alloc(.reserve_size = range_size+ARENA_HEADER_SIZE, .commit_size = range_size+ARENA_HEADER_SIZE);
|
||||
if(range_arena == 0)
|
||||
{
|
||||
range_size = 0;
|
||||
}
|
||||
else
|
||||
|
||||
// rjf: if we got an arena -> push buffer & read
|
||||
if(range_arena != 0)
|
||||
{
|
||||
// rjf: read as much as possible
|
||||
range_base = push_array_no_zero(range_arena, U8, range_size);
|
||||
U64 bytes_read = 0;
|
||||
U64 retry_count = 0;
|
||||
@@ -6199,19 +6051,24 @@ ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: if we read nothing, release arena
|
||||
if(bytes_read == 0)
|
||||
{
|
||||
arena_release(range_arena);
|
||||
range_base = 0;
|
||||
range_size = 0;
|
||||
range_arena = 0;
|
||||
}
|
||||
|
||||
// rjf: if we only got a partial read, zero the rest
|
||||
else if(bytes_read < range_size)
|
||||
{
|
||||
MemoryZero((U8 *)range_base + bytes_read, range_size-bytes_read);
|
||||
}
|
||||
zero_terminated_size = range_size;
|
||||
if(zero_terminated)
|
||||
|
||||
// rjf: determine final size; zero terminate if needed; pop any unneeded bytes if zero-terminating
|
||||
zero_terminated_size = bytes_read;
|
||||
if(zero_terminated && range_base != 0)
|
||||
{
|
||||
for(U64 idx = 0; idx < bytes_read; idx += 1)
|
||||
{
|
||||
@@ -6235,19 +6092,25 @@ ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry
|
||||
content_key.id.u128[0] = u128_hash_from_str8(key);
|
||||
}
|
||||
|
||||
//- rjf: read successful -> submit to hash store
|
||||
U128 hash = {0};
|
||||
if(range_base != 0 && pre_read_mem_gen == post_read_mem_gen)
|
||||
//- rjf: determine if we have any history for this key
|
||||
B32 key_has_history = 0;
|
||||
{
|
||||
hash = c_submit_data(content_key, &range_arena, str8((U8*)range_base, zero_terminated_size));
|
||||
}
|
||||
else if(range_arena != 0)
|
||||
{
|
||||
arena_release(range_arena);
|
||||
retry_out[0] = 1;
|
||||
U128 last_hash = c_hash_from_key(content_key, 0);
|
||||
if(!u128_match(last_hash, u128_zero()))
|
||||
{
|
||||
key_has_history = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: wakeup on new reads
|
||||
//- rjf: read successful, OR we have no history -> submit to hash store
|
||||
U128 hash = {0};
|
||||
if((zero_terminated_size > 0 || !key_has_history) && range_base != 0 && range_size != 0 && pre_read_mem_gen == post_read_mem_gen)
|
||||
{
|
||||
hash = c_submit_data(content_key, &range_arena, str8((U8 *)range_base, zero_terminated_size));
|
||||
gen_out[0] = pre_read_mem_gen;
|
||||
}
|
||||
|
||||
//- rjf: wakeup on new submissions
|
||||
if(!u128_match(u128_zero(), hash))
|
||||
{
|
||||
if(ctrl_state->wakeup_hook != 0)
|
||||
@@ -6256,6 +6119,18 @@ ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: always release leftover arenas
|
||||
if(range_arena != 0)
|
||||
{
|
||||
arena_release(range_arena);
|
||||
}
|
||||
|
||||
//- rjf: retry on mem gen "tearing", and if the range is non-empty
|
||||
if(pre_read_mem_gen != post_read_mem_gen && range_size != 0)
|
||||
{
|
||||
retry_out[0] = 1;
|
||||
}
|
||||
|
||||
//- rjf: bundle content key as artifact
|
||||
StaticAssert(sizeof(content_key) == sizeof(artifact), artifact_key_size_check);
|
||||
MemoryCopyStruct(&artifact, &content_key);
|
||||
@@ -6272,20 +6147,21 @@ ctrl_memory_artifact_destroy(AC_Artifact artifact)
|
||||
}
|
||||
|
||||
internal C_Key
|
||||
ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale)
|
||||
ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
#pragma pack(push, 1)
|
||||
struct
|
||||
{
|
||||
CTRL_Handle process;
|
||||
Rng1U64 vaddr_range;
|
||||
B32 zero_terminated;
|
||||
B32 _padding_;
|
||||
} key_data = {process, vaddr_range, zero_terminated};
|
||||
#pragma pack(pop)
|
||||
String8 key = str8_struct(&key_data);
|
||||
Access *access = access_open();
|
||||
AC_Artifact artifact = ac_artifact_from_key(access, key, ctrl_memory_artifact_create, ctrl_memory_artifact_destroy, endt_us,
|
||||
.flags = AC_Flag_HighPriority,
|
||||
.flags = AC_Flag_HighPriority | (wait_for_fresh ? AC_Flag_WaitForFresh : 0),
|
||||
.gen = ctrl_mem_gen(),
|
||||
.slots_count = 2048,
|
||||
.stale_out = out_is_stale,
|
||||
@@ -6300,7 +6176,7 @@ ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32
|
||||
//- rjf: process memory reading helpers
|
||||
|
||||
internal CTRL_ProcessMemorySlice
|
||||
ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us)
|
||||
ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, B32 wait_for_fresh, U64 endt_us)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
CTRL_ProcessMemorySlice result = {0};
|
||||
@@ -6326,7 +6202,7 @@ ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rn
|
||||
{
|
||||
U64 page_base_vaddr = page_range.min + page_idx*page_size;
|
||||
B32 page_is_stale = 0;
|
||||
C_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, endt_us, &page_is_stale);
|
||||
C_Key page_key = ctrl_key_from_process_vaddr_range(process, r1u64(page_base_vaddr, page_base_vaddr+page_size), 0, wait_for_fresh, endt_us, &page_is_stale);
|
||||
U128 page_hash = c_hash_from_key(page_key, 0);
|
||||
U128 page_last_hash = c_hash_from_key(page_key, 1);
|
||||
result.stale = (result.stale || page_is_stale);
|
||||
@@ -6447,7 +6323,7 @@ ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out,
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
U64 needed_size = dim_1u64(range);
|
||||
CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, range, endt_us);
|
||||
CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, range, 0, endt_us);
|
||||
B32 good = (slice.data.size >= needed_size && !slice.any_byte_bad);
|
||||
if(good)
|
||||
{
|
||||
@@ -6480,15 +6356,15 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src)
|
||||
// time.
|
||||
if(result)
|
||||
{
|
||||
U64 endt_us = os_now_microseconds()+5000;
|
||||
U64 endt_us = os_now_microseconds()+10000;
|
||||
U64 page_size = os_get_system_info()->page_size; // TODO(rjf): @page_size_from_process
|
||||
Rng1U64 page_range = r1u64(range.min/page_size, range.max/page_size);
|
||||
Rng1U64 page_range = r1u64(range.min/page_size, (range.max+page_size-1)/page_size);
|
||||
for EachInRange(page_idx, page_range)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, r1u64(page_idx*page_size, (page_idx+1)*page_size), endt_us);
|
||||
CTRL_ProcessMemorySlice slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process, r1u64(page_idx*page_size, (page_idx+1)*page_size), 1, endt_us);
|
||||
scratch_end(scratch);
|
||||
if(os_now_microseconds() >= endt_us)
|
||||
if(!slice.stale || os_now_microseconds() >= endt_us)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -6503,7 +6379,7 @@ ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src)
|
||||
//~ rjf: Call Stack Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact
|
||||
ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out)
|
||||
ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
|
||||
{
|
||||
AC_Artifact artifact = {0};
|
||||
{
|
||||
@@ -6699,7 +6575,7 @@ ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_
|
||||
//~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact
|
||||
ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out)
|
||||
ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
Access *access = access_open();
|
||||
|
||||
+11
-10
@@ -357,7 +357,7 @@ typedef U64 CTRL_EvalSpaceKind;
|
||||
enum
|
||||
{
|
||||
CTRL_EvalSpaceKind_Entity = E_SpaceKind_FirstUserDefined,
|
||||
CTRL_EvalSpaceKind_Meta,
|
||||
CTRL_EvalSpaceKind_FirstUserDefined,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -650,7 +650,7 @@ struct CTRL_DbgDirNode
|
||||
typedef struct CTRL_EvalScope CTRL_EvalScope;
|
||||
struct CTRL_EvalScope
|
||||
{
|
||||
DI_Scope *di_scope;
|
||||
Access *access;
|
||||
E_BaseCtx base_ctx;
|
||||
E_IRCtx ir_ctx;
|
||||
E_InterpretCtx interpret_ctx;
|
||||
@@ -877,7 +877,7 @@ internal void ctrl_entity_equip_string(CTRL_EntityCtxRWStore *store, CTRL_Entity
|
||||
//- rjf: accelerated entity context lookups
|
||||
internal CTRL_EntityCtxLookupAccel *ctrl_thread_entity_ctx_lookup_accel(void);
|
||||
internal CTRL_EntityArray ctrl_entity_array_from_kind(CTRL_EntityCtx *ctx, CTRL_EntityKind kind);
|
||||
internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key *dbgi_key);
|
||||
internal CTRL_EntityList ctrl_modules_from_dbgi_key(Arena *arena, CTRL_EntityCtx *ctx, DI_Key dbgi_key);
|
||||
internal CTRL_Entity *ctrl_thread_from_id(CTRL_EntityCtx *ctx, U64 id);
|
||||
|
||||
//- rjf: applying events to entity caches
|
||||
@@ -980,8 +980,9 @@ internal void ctrl_thread__module_close(CTRL_Handle process, CTRL_Handle module,
|
||||
//- rjf: attached process running/event gathering
|
||||
internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof);
|
||||
|
||||
//- rjf: eval helpers
|
||||
internal B32 ctrl_eval_space_read(void *u, E_Space space, void *out, Rng1U64 vaddr_range);
|
||||
//- rjf: eval helpers
|
||||
internal U64 ctrl_eval_space_gen(E_Space space);
|
||||
internal B32 ctrl_eval_space_read(E_Space space, void *out, Rng1U64 vaddr_range);
|
||||
|
||||
//- rjf: control thread eval scopes
|
||||
internal CTRL_EvalScope *ctrl_thread__eval_scope_begin(Arena *arena, CTRL_UserBreakpointList *user_bps, CTRL_Entity *thread);
|
||||
@@ -1002,12 +1003,12 @@ internal void ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg);
|
||||
////////////////////////////////
|
||||
//~ rjf: Process Memory Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact ctrl_memory_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out);
|
||||
internal AC_Artifact ctrl_memory_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
internal void ctrl_memory_artifact_destroy(AC_Artifact artifact);
|
||||
internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, U64 endt_us, B32 *out_is_stale);
|
||||
internal C_Key ctrl_key_from_process_vaddr_range(CTRL_Handle process, Rng1U64 vaddr_range, B32 zero_terminated, B32 wait_for_fresh, U64 endt_us, B32 *out_is_stale);
|
||||
|
||||
//- rjf: process memory reading helpers
|
||||
internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, U64 endt_us);
|
||||
internal CTRL_ProcessMemorySlice ctrl_process_memory_slice_from_vaddr_range(Arena *arena, CTRL_Handle process, Rng1U64 range, B32 wait_for_fresh, U64 endt_us);
|
||||
internal B32 ctrl_process_memory_read(CTRL_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us);
|
||||
#define ctrl_process_memory_read_struct(process, vaddr, is_stale_out, ptr, endt_us) ctrl_process_memory_read((process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us))
|
||||
|
||||
@@ -1017,14 +1018,14 @@ internal B32 ctrl_process_write(CTRL_Handle process, Rng1U64 range, void *src);
|
||||
////////////////////////////////
|
||||
//~ rjf: Call Stack Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out);
|
||||
internal AC_Artifact ctrl_call_stack_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
internal void ctrl_call_stack_artifact_destroy(AC_Artifact artifact);
|
||||
internal CTRL_CallStack ctrl_call_stack_from_thread(Access *access, CTRL_Handle thread_handle, B32 high_priority, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Call Stack Tree Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out);
|
||||
internal AC_Artifact ctrl_call_stack_tree_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
internal void ctrl_call_stack_tree_artifact_destroy(AC_Artifact artifact);
|
||||
internal CTRL_CallStackTree ctrl_call_stack_tree(Access *access, U64 endt_us);
|
||||
|
||||
|
||||
+105
-155
@@ -152,7 +152,6 @@ d_line_list_copy(Arena *arena, D_LineList *list)
|
||||
D_LineNode *dst_n = push_array(arena, D_LineNode, 1);
|
||||
MemoryCopyStruct(dst_n, src_n);
|
||||
dst_n->v.file_path = push_str8_copy(arena, dst_n->v.file_path);
|
||||
dst_n->v.dbgi_key = di_key_copy(arena, &src_n->v.dbgi_key);
|
||||
SLLQueuePush(dst.first, dst.last, dst_n);
|
||||
dst.count += 1;
|
||||
}
|
||||
@@ -291,11 +290,11 @@ d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind, D_CmdParams *
|
||||
// - for any instructions which may change the stack pointer, traps are placed
|
||||
// at them with the "save-stack-pointer | single-step-after" behaviors.
|
||||
|
||||
internal CTRL_TrapList
|
||||
internal D_TrapNet
|
||||
d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
CTRL_TrapList result = {0};
|
||||
D_TrapNet result = {0};
|
||||
|
||||
// rjf: thread => unpacked info
|
||||
CTRL_Entity *process = ctrl_entity_ancestor_from_kind(thread, CTRL_EntityKind_Process);
|
||||
@@ -306,13 +305,15 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread)
|
||||
String8 machine_code = {0};
|
||||
{
|
||||
Rng1U64 rng = r1u64(ip_vaddr, ip_vaddr+max_instruction_size_from_arch(arch));
|
||||
CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, rng, os_now_microseconds()+5000);
|
||||
CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, rng, 0, os_now_microseconds()+5000);
|
||||
machine_code = machine_code_slice.data;
|
||||
}
|
||||
|
||||
// rjf: build traps if machine code was read successfully
|
||||
if(machine_code.size != 0)
|
||||
{
|
||||
result.good_read = 1;
|
||||
|
||||
// rjf: decode instruction
|
||||
DASM_Inst inst = dasm_inst_from_code(scratch.arena, arch, ip_vaddr, machine_code, DASM_Syntax_Intel);
|
||||
|
||||
@@ -320,7 +321,7 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread)
|
||||
if(inst.flags & DASM_InstFlag_Call || inst.flags & DASM_InstFlag_Repeats)
|
||||
{
|
||||
CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, ip_vaddr+inst.size};
|
||||
ctrl_trap_list_push(arena, &result, &trap);
|
||||
ctrl_trap_list_push(arena, &result.traps, &trap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,12 +329,12 @@ d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CTRL_TrapList
|
||||
internal D_TrapNet
|
||||
d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
log_infof("step_over_line:\n{\n");
|
||||
CTRL_TrapList result = {0};
|
||||
D_TrapNet result = {0};
|
||||
|
||||
// rjf: thread => info
|
||||
Arch arch = thread->arch;
|
||||
@@ -342,13 +343,13 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
CTRL_Entity *module = ctrl_module_from_process_vaddr(process, ip_vaddr);
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module);
|
||||
log_infof("ip_vaddr: 0x%I64x\n", ip_vaddr);
|
||||
log_infof("dbgi_key: {%S, 0x%I64x}\n", dbgi_key.path, dbgi_key.min_timestamp);
|
||||
log_infof("dbgi_key: {0x%I64x, 0x%I64x}\n", dbgi_key.u64[0], dbgi_key.u64[1]);
|
||||
|
||||
// rjf: ip => line vaddr range
|
||||
Rng1U64 line_vaddr_rng = {0};
|
||||
{
|
||||
U64 ip_voff = ctrl_voff_from_vaddr(module, ip_vaddr);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, ip_voff);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, ip_voff);
|
||||
Rng1U64 line_voff_rng = {0};
|
||||
if(lines.first != 0)
|
||||
{
|
||||
@@ -366,7 +367,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
// is enabled. This is enabled by default normally.
|
||||
{
|
||||
U64 opl_line_voff_rng = ctrl_voff_from_vaddr(module, line_vaddr_rng.max);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, opl_line_voff_rng);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, opl_line_voff_rng);
|
||||
if(lines.first != 0 && (lines.first->v.pt.line == 0xf00f00 || lines.first->v.pt.line == 0xfeefee))
|
||||
{
|
||||
line_vaddr_rng.max = ctrl_vaddr_from_voff(module, lines.first->v.voff_range.max);
|
||||
@@ -381,9 +382,9 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
B32 good_machine_code = 0;
|
||||
if(good_line_info)
|
||||
{
|
||||
CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+50000);
|
||||
CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, 0, os_now_microseconds()+50000);
|
||||
machine_code = machine_code_slice.data;
|
||||
good_machine_code = (machine_code.size == dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad);
|
||||
good_machine_code = (machine_code.size >= dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad);
|
||||
LogInfoNamedBlockF("machine_code_slice")
|
||||
{
|
||||
log_infof("stale: %i\n", machine_code_slice.stale);
|
||||
@@ -470,7 +471,7 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
if(add)
|
||||
{
|
||||
CTRL_Trap trap = {flags, trap_addr};
|
||||
ctrl_trap_list_push(arena, &result, &trap);
|
||||
ctrl_trap_list_push(arena, &result.traps, &trap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,11 +479,18 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
if(good_line_info && good_machine_code)
|
||||
{
|
||||
CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max};
|
||||
ctrl_trap_list_push(arena, &result, &trap);
|
||||
ctrl_trap_list_push(arena, &result.traps, &trap);
|
||||
}
|
||||
|
||||
// rjf: store goodness
|
||||
if(good_machine_code)
|
||||
{
|
||||
result.good_line_info = good_line_info;
|
||||
result.good_read = good_machine_code;
|
||||
}
|
||||
|
||||
// rjf: log
|
||||
LogInfoNamedBlockF("traps") for(CTRL_TrapNode *n = result.first; n != 0; n = n->next)
|
||||
LogInfoNamedBlockF("traps") for(CTRL_TrapNode *n = result.traps.first; n != 0; n = n->next)
|
||||
{
|
||||
log_infof("{flags:0x%x, vaddr:0x%I64x}\n", n->v.flags, n->v.vaddr);
|
||||
}
|
||||
@@ -492,11 +500,11 @@ d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread)
|
||||
return result;
|
||||
}
|
||||
|
||||
internal CTRL_TrapList
|
||||
internal D_TrapNet
|
||||
d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
CTRL_TrapList result = {0};
|
||||
D_TrapNet result = {0};
|
||||
|
||||
// rjf: thread => info
|
||||
Arch arch = thread->arch;
|
||||
@@ -509,7 +517,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
Rng1U64 line_vaddr_rng = {0};
|
||||
{
|
||||
U64 ip_voff = ctrl_voff_from_vaddr(module, ip_vaddr);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, ip_voff);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, ip_voff);
|
||||
Rng1U64 line_voff_rng = {0};
|
||||
if(lines.first != 0)
|
||||
{
|
||||
@@ -524,7 +532,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
// is enabled. This is enabled by default normally.
|
||||
{
|
||||
U64 opl_line_voff_rng = ctrl_voff_from_vaddr(module, line_vaddr_rng.max);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &dbgi_key, opl_line_voff_rng);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, dbgi_key, opl_line_voff_rng);
|
||||
if(lines.first != 0 && (lines.first->v.pt.line == 0xf00f00 || lines.first->v.pt.line == 0xfeefee))
|
||||
{
|
||||
line_vaddr_rng.max = ctrl_vaddr_from_voff(module, lines.first->v.voff_range.max);
|
||||
@@ -539,9 +547,9 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
B32 good_machine_code = 0;
|
||||
if(good_line_info)
|
||||
{
|
||||
CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, os_now_microseconds()+5000);
|
||||
CTRL_ProcessMemorySlice machine_code_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, line_vaddr_rng, 0, os_now_microseconds()+5000);
|
||||
machine_code = machine_code_slice.data;
|
||||
good_machine_code = (machine_code.size == dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad);
|
||||
good_machine_code = (machine_code.size >= dim_1u64(line_vaddr_rng) && !machine_code_slice.any_byte_bad);
|
||||
}
|
||||
|
||||
// rjf: machine code => ctrl flow analysis
|
||||
@@ -587,7 +595,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
CTRL_Entity *jump_dest_module = ctrl_module_from_process_vaddr(process, jump_dest_vaddr);
|
||||
U64 jump_dest_voff = ctrl_voff_from_vaddr(jump_dest_module, jump_dest_vaddr);
|
||||
DI_Key jump_dest_dbgi_key = ctrl_dbgi_key_from_module(jump_dest_module);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, &jump_dest_dbgi_key, jump_dest_voff);
|
||||
D_LineList lines = d_lines_from_dbgi_key_voff(scratch.arena, jump_dest_dbgi_key, jump_dest_voff);
|
||||
if(lines.count == 0)
|
||||
{
|
||||
add = 0;
|
||||
@@ -626,7 +634,7 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
if(add)
|
||||
{
|
||||
CTRL_Trap trap = {flags, trap_addr};
|
||||
ctrl_trap_list_push(arena, &result, &trap);
|
||||
ctrl_trap_list_push(arena, &result.traps, &trap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,7 +642,13 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
if(good_line_info && good_machine_code)
|
||||
{
|
||||
CTRL_Trap trap = {CTRL_TrapFlag_EndStepping, line_vaddr_rng.max};
|
||||
ctrl_trap_list_push(arena, &result, &trap);
|
||||
ctrl_trap_list_push(arena, &result.traps, &trap);
|
||||
}
|
||||
|
||||
// rjf: store goodness
|
||||
{
|
||||
result.good_line_info = good_line_info;
|
||||
result.good_read = good_machine_code;
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
@@ -644,97 +658,14 @@ d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread)
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
//- rjf: symbol -> voff lookups
|
||||
|
||||
internal U64
|
||||
d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
U64 result = 0;
|
||||
{
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
RDI_NameMapKind name_map_kinds[] =
|
||||
{
|
||||
RDI_NameMapKind_GlobalVariables,
|
||||
RDI_NameMapKind_Procedures,
|
||||
};
|
||||
if(rdi != &rdi_parsed_nil)
|
||||
{
|
||||
for(U64 name_map_kind_idx = 0;
|
||||
name_map_kind_idx < ArrayCount(name_map_kinds);
|
||||
name_map_kind_idx += 1)
|
||||
{
|
||||
RDI_NameMapKind name_map_kind = name_map_kinds[name_map_kind_idx];
|
||||
RDI_NameMap *name_map = rdi_element_from_name_idx(rdi, NameMaps, name_map_kind);
|
||||
RDI_ParsedNameMap parsed_name_map = {0};
|
||||
rdi_parsed_from_name_map(rdi, name_map, &parsed_name_map);
|
||||
RDI_NameMapNode *node = rdi_name_map_lookup(rdi, &parsed_name_map, symbol_name.str, symbol_name.size);
|
||||
|
||||
// rjf: node -> num
|
||||
U64 entity_num = 0;
|
||||
if(node != 0)
|
||||
{
|
||||
switch(node->match_count)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
entity_num = node->match_idx_or_idx_run_first + 1;
|
||||
}break;
|
||||
default:
|
||||
{
|
||||
U32 num = 0;
|
||||
U32 *run = rdi_matches_from_map_node(rdi, node, &num);
|
||||
if(num != 0)
|
||||
{
|
||||
entity_num = run[0]+1;
|
||||
}
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: num -> voff
|
||||
U64 voff = 0;
|
||||
if(entity_num != 0) switch(name_map_kind)
|
||||
{
|
||||
default:{}break;
|
||||
case RDI_NameMapKind_GlobalVariables:
|
||||
{
|
||||
RDI_GlobalVariable *global_var = rdi_element_from_name_idx(rdi, GlobalVariables, entity_num-1);
|
||||
voff = global_var->voff;
|
||||
}break;
|
||||
case RDI_NameMapKind_Procedures:
|
||||
{
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, entity_num-1);
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(rdi, Scopes, procedure->root_scope_idx);
|
||||
voff = *rdi_element_from_name_idx(rdi, ScopeVOffData, scope->voff_range_first);
|
||||
}break;
|
||||
}
|
||||
|
||||
// rjf: nonzero voff -> break
|
||||
if(voff != 0)
|
||||
{
|
||||
result = voff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(scope);
|
||||
scratch_end(scratch);
|
||||
ProfEnd();
|
||||
return result;
|
||||
}
|
||||
|
||||
//- rjf: voff -> line info
|
||||
|
||||
internal D_LineList
|
||||
d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
|
||||
d_lines_from_dbgi_key_voff(Arena *arena, DI_Key dbgi_key, U64 voff)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
Access *access = access_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0);
|
||||
D_LineList result = {0};
|
||||
{
|
||||
//- rjf: gather line tables
|
||||
@@ -799,7 +730,7 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
|
||||
}
|
||||
n->v.pt = txt_pt(line->line_num, column ? column->col_first : 1);
|
||||
n->v.voff_range = r1u64(parsed_line_table.voffs[line_info_idx], parsed_line_table.voffs[line_info_idx+1]);
|
||||
n->v.dbgi_key = *dbgi_key;
|
||||
n->v.dbgi_key = dbgi_key;
|
||||
if(line_table_n == top_line_table)
|
||||
{
|
||||
shallowest_voff_range = n->v.voff_range;
|
||||
@@ -813,7 +744,7 @@ d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff)
|
||||
n->v.voff_range = intersect_1u64(n->v.voff_range, shallowest_voff_range);
|
||||
}
|
||||
}
|
||||
di_scope_close(scope);
|
||||
access_close(access);
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
@@ -829,11 +760,11 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key,
|
||||
{
|
||||
array.count = dim_1s64(line_num_range)+1;
|
||||
array.v = push_array(arena, D_LineList, array.count);
|
||||
di_key_list_push(arena, &array.dbgi_keys, &dbgi_key);
|
||||
di_key_list_push(arena, &array.dbgi_keys, dbgi_key);
|
||||
}
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
Access *access = access_open();
|
||||
String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path);
|
||||
for(String8Node *override_n = overrides.first;
|
||||
override_n != 0;
|
||||
@@ -843,7 +774,7 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key,
|
||||
String8 file_path_normalized = lower_from_str8(scratch.arena, path_normalized_from_string(scratch.arena, file_path));
|
||||
|
||||
// rjf: binary -> rdi
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 1, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
|
||||
|
||||
// rjf: file_path_normalized * rdi -> src_id
|
||||
B32 good_src_id = 0;
|
||||
@@ -911,7 +842,7 @@ d_lines_array_from_dbgi_key_file_path_line_range(Arena *arena, DI_Key dbgi_key,
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(scope);
|
||||
access_close(access);
|
||||
scratch_end(scratch);
|
||||
return array;
|
||||
}
|
||||
@@ -926,8 +857,7 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
}
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
U64 *lines_num_voffs = push_array(scratch.arena, U64, array.count);
|
||||
DI_Scope *scope = di_scope_open();
|
||||
DI_KeyList dbgi_keys = d_push_active_dbgi_key_list(scratch.arena);
|
||||
DI_KeyArray dbgi_keys = di_push_all_loaded_keys(scratch.arena);
|
||||
String8List overrides = rd_possible_overrides_from_file_path(scratch.arena, file_path);
|
||||
for(String8Node *override_n = overrides.first;
|
||||
override_n != 0;
|
||||
@@ -935,13 +865,13 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
{
|
||||
String8 file_path = override_n->string;
|
||||
String8 file_path_normalized = lower_from_str8(scratch.arena, file_path);
|
||||
for(DI_KeyNode *dbgi_key_n = dbgi_keys.first;
|
||||
dbgi_key_n != 0;
|
||||
dbgi_key_n = dbgi_key_n->next)
|
||||
for EachIndex(idx, dbgi_keys.count)
|
||||
{
|
||||
Access *access = access_open();
|
||||
|
||||
// rjf: binary -> rdi
|
||||
DI_Key key = dbgi_key_n->v;
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 1, 0);
|
||||
DI_Key key = dbgi_keys.v[idx];
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, key, 1, 0);
|
||||
|
||||
// rjf: file_path_normalized * rdi -> src_id
|
||||
B32 good_src_id = 0;
|
||||
@@ -1012,11 +942,12 @@ d_lines_array_from_file_path_line_range(Arena *arena, String8 file_path, Rng1S64
|
||||
// rjf: good src id -> push to relevant dbgi keys
|
||||
if(good_src_id)
|
||||
{
|
||||
di_key_list_push(arena, &array.dbgi_keys, &key);
|
||||
di_key_list_push(arena, &array.dbgi_keys, key);
|
||||
}
|
||||
|
||||
access_close(access);
|
||||
}
|
||||
}
|
||||
di_scope_close(scope);
|
||||
scratch_end(scratch);
|
||||
return array;
|
||||
}
|
||||
@@ -1065,7 +996,7 @@ d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64
|
||||
U64 tls_index = 0;
|
||||
if(addr_size != 0)
|
||||
{
|
||||
CTRL_ProcessMemorySlice tls_index_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, tls_vaddr_range, 0);
|
||||
CTRL_ProcessMemorySlice tls_index_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, tls_vaddr_range, 0, 0);
|
||||
if(tls_index_slice.data.size >= addr_size)
|
||||
{
|
||||
tls_index = *(U64 *)tls_index_slice.data.str;
|
||||
@@ -1078,13 +1009,13 @@ d_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64
|
||||
U64 thread_info_addr = root_vaddr;
|
||||
U64 tls_addr_off = tls_index*addr_size;
|
||||
U64 tls_addr_array = 0;
|
||||
CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0);
|
||||
CTRL_ProcessMemorySlice tls_addr_array_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(thread_info_addr, thread_info_addr+addr_size), 0, 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_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0);
|
||||
CTRL_ProcessMemorySlice result_slice = ctrl_process_memory_slice_from_vaddr_range(scratch.arena, process->handle, r1u64(tls_addr_array + tls_addr_off, tls_addr_array + tls_addr_off + addr_size), 0, 0);
|
||||
String8 result_data = result_slice.data;
|
||||
if(result_data.size >= 8)
|
||||
{
|
||||
@@ -1184,7 +1115,7 @@ d_push_active_dbgi_key_list(Arena *arena)
|
||||
{
|
||||
CTRL_Entity *module = modules.v[idx];
|
||||
DI_Key key = ctrl_dbgi_key_from_module(module);
|
||||
di_key_list_push(arena, &dbgis, &key);
|
||||
di_key_list_push(arena, &dbgis, key);
|
||||
}
|
||||
return dbgis;
|
||||
}
|
||||
@@ -1271,7 +1202,7 @@ d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 ro
|
||||
}
|
||||
|
||||
internal E_String2NumMap *
|
||||
d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
E_String2NumMap *map = &e_string2num_map_nil;
|
||||
@@ -1287,13 +1218,13 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
{
|
||||
break;
|
||||
}
|
||||
U64 hash = di_hash_from_key(dbgi_key);
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&dbgi_key));
|
||||
U64 slot_idx = hash % cache->table_size;
|
||||
D_RunLocalsCacheSlot *slot = &cache->table[slot_idx];
|
||||
D_RunLocalsCacheNode *node = 0;
|
||||
for(D_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next)
|
||||
{
|
||||
if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff)
|
||||
if(di_key_match(n->dbgi_key, dbgi_key) && n->voff == voff)
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
@@ -1301,18 +1232,18 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
DI_Scope *scope = di_scope_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
Access *access = access_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0);
|
||||
E_String2NumMap *map = e_push_locals_map_from_rdi_voff(cache->arena, rdi, voff);
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
node = push_array(cache->arena, D_RunLocalsCacheNode, 1);
|
||||
node->dbgi_key = di_key_copy(cache->arena, dbgi_key);
|
||||
node->dbgi_key = dbgi_key;
|
||||
node->voff = voff;
|
||||
node->locals_map = map;
|
||||
SLLQueuePush_N(slot->first, slot->last, node, hash_next);
|
||||
}
|
||||
di_scope_close(scope);
|
||||
access_close(access);
|
||||
}
|
||||
if(node != 0 && node->locals_map->slots_count != 0)
|
||||
{
|
||||
@@ -1325,7 +1256,7 @@ d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
}
|
||||
|
||||
internal E_String2NumMap *
|
||||
d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
E_String2NumMap *map = &e_string2num_map_nil;
|
||||
@@ -1341,13 +1272,13 @@ d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
{
|
||||
break;
|
||||
}
|
||||
U64 hash = di_hash_from_key(dbgi_key);
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&dbgi_key));
|
||||
U64 slot_idx = hash % cache->table_size;
|
||||
D_RunLocalsCacheSlot *slot = &cache->table[slot_idx];
|
||||
D_RunLocalsCacheNode *node = 0;
|
||||
for(D_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next)
|
||||
{
|
||||
if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff)
|
||||
if(di_key_match(n->dbgi_key, dbgi_key) && n->voff == voff)
|
||||
{
|
||||
node = n;
|
||||
break;
|
||||
@@ -1355,18 +1286,18 @@ d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff)
|
||||
}
|
||||
if(node == 0)
|
||||
{
|
||||
DI_Scope *scope = di_scope_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 1, 0);
|
||||
Access *access = access_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 1, 0);
|
||||
E_String2NumMap *map = e_push_member_map_from_rdi_voff(cache->arena, rdi, voff);
|
||||
if(map->slots_count != 0)
|
||||
{
|
||||
node = push_array(cache->arena, D_RunLocalsCacheNode, 1);
|
||||
node->dbgi_key = di_key_copy(cache->arena, dbgi_key);
|
||||
node->dbgi_key = dbgi_key;
|
||||
node->voff = voff;
|
||||
node->locals_map = map;
|
||||
SLLQueuePush_N(slot->first, slot->last, node, hash_next);
|
||||
}
|
||||
di_scope_close(scope);
|
||||
access_close(access);
|
||||
}
|
||||
if(node != 0 && node->locals_map->slots_count != 0)
|
||||
{
|
||||
@@ -1674,6 +1605,7 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
//////////////////////////////
|
||||
//- rjf: process top-level commands
|
||||
//
|
||||
D_CmdList deferred_cmds = {0};
|
||||
CTRL_MsgList ctrl_msgs = {0};
|
||||
ProfScope("process top-level commands")
|
||||
{
|
||||
@@ -1875,15 +1807,14 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
}
|
||||
else
|
||||
{
|
||||
B32 good = 1;
|
||||
CTRL_TrapList traps = {0};
|
||||
D_TrapNet trap_net = {0};
|
||||
switch(cmd->kind)
|
||||
{
|
||||
default: break;
|
||||
case D_CmdKind_StepIntoInst: {}break;
|
||||
case D_CmdKind_StepOverInst: {traps = d_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break;
|
||||
case D_CmdKind_StepIntoLine: {traps = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break;
|
||||
case D_CmdKind_StepOverLine: {traps = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break;
|
||||
case D_CmdKind_StepIntoInst: {trap_net.good_read = 1;}break;
|
||||
case D_CmdKind_StepOverInst: {trap_net = d_trap_net_from_thread__step_over_inst(scratch.arena, thread);}break;
|
||||
case D_CmdKind_StepIntoLine: {trap_net = d_trap_net_from_thread__step_into_line(scratch.arena, thread);}break;
|
||||
case D_CmdKind_StepOverLine: {trap_net = d_trap_net_from_thread__step_over_line(scratch.arena, thread);}break;
|
||||
case D_CmdKind_StepOut:
|
||||
{
|
||||
Access *access = access_open();
|
||||
@@ -1896,32 +1827,43 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
{
|
||||
U64 vaddr = regs_rip_from_arch_block(thread->arch, callstack.concrete_frames[1]->regs);
|
||||
CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr};
|
||||
ctrl_trap_list_push(scratch.arena, &traps, &trap);
|
||||
ctrl_trap_list_push(scratch.arena, &trap_net.traps, &trap);
|
||||
trap_net.good_read = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_user_error(str8_lit("Could not find the return address of the current callstack frame successfully."));
|
||||
good = 0;
|
||||
}
|
||||
|
||||
access_close(access);
|
||||
}break;
|
||||
}
|
||||
if(good && traps.count != 0)
|
||||
B32 good_trap_net = (trap_net.good_read || !trap_net.good_line_info);
|
||||
if(good_trap_net && trap_net.traps.count != 0)
|
||||
{
|
||||
need_run = 1;
|
||||
run_kind = D_RunKind_Step;
|
||||
run_thread = thread;
|
||||
run_flags = 0;
|
||||
run_traps = traps;
|
||||
run_traps = trap_net.traps;
|
||||
}
|
||||
if(good && traps.count == 0)
|
||||
else if(good_trap_net && trap_net.traps.count == 0)
|
||||
{
|
||||
need_run = 1;
|
||||
run_kind = D_RunKind_SingleStep;
|
||||
run_thread = thread;
|
||||
run_flags = 0;
|
||||
run_traps = traps;
|
||||
run_traps = trap_net.traps;
|
||||
}
|
||||
else if(!good_trap_net && params->retry_idx < 100)
|
||||
{
|
||||
D_CmdParams params_copy = *params;
|
||||
params_copy.retry_idx += 1;
|
||||
d_cmd_list_push_new(scratch.arena, &deferred_cmds, cmd->kind, ¶ms_copy);
|
||||
}
|
||||
else if(!good_trap_net)
|
||||
{
|
||||
log_user_error(str8_lit("Could not successfully step."));
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -2180,6 +2122,14 @@ d_tick(Arena *arena, D_TargetArray *targets, D_BreakpointArray *breakpoints, D_P
|
||||
MemoryZeroStruct(&d_state->cmds);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: push deferred commands
|
||||
//
|
||||
for EachNode(n, D_CmdNode, deferred_cmds.first)
|
||||
{
|
||||
d_cmd_list_push_new(d_state->cmds_arena, &d_state->cmds, n->cmd.kind, &n->cmd.params);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: push new control messages to queue - try to send queue to control,
|
||||
// clear queue if successful (if not, we'll just keep them around until
|
||||
|
||||
@@ -69,6 +69,17 @@ struct D_PathMapArray
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Trap Nets
|
||||
|
||||
typedef struct D_TrapNet D_TrapNet;
|
||||
struct D_TrapNet
|
||||
{
|
||||
CTRL_TrapList traps;
|
||||
B32 good_line_info;
|
||||
B32 good_read;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Tick Output Types
|
||||
|
||||
@@ -187,6 +198,7 @@ struct D_CmdParams
|
||||
U32 pid;
|
||||
U32 rgba;
|
||||
D_TargetArray targets;
|
||||
U64 retry_idx;
|
||||
};
|
||||
|
||||
typedef struct D_Cmd D_Cmd;
|
||||
@@ -358,18 +370,15 @@ internal void d_cmd_list_push_new(Arena *arena, D_CmdList *cmds, D_CmdKind kind,
|
||||
////////////////////////////////
|
||||
//~ rjf: Stepping "Trap Net" Builders
|
||||
|
||||
internal CTRL_TrapList d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread);
|
||||
internal CTRL_TrapList d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread);
|
||||
internal CTRL_TrapList d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread);
|
||||
internal D_TrapNet d_trap_net_from_thread__step_over_inst(Arena *arena, CTRL_Entity *thread);
|
||||
internal D_TrapNet d_trap_net_from_thread__step_over_line(Arena *arena, CTRL_Entity *thread);
|
||||
internal D_TrapNet d_trap_net_from_thread__step_into_line(Arena *arena, CTRL_Entity *thread);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
//- rjf: symbol -> voff lookups
|
||||
internal U64 d_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name);
|
||||
|
||||
//- rjf: voff -> line info
|
||||
internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff);
|
||||
internal D_LineList d_lines_from_dbgi_key_voff(Arena *arena, DI_Key dbgi_key, U64 voff);
|
||||
|
||||
//- rjf: file:line -> line info
|
||||
// TODO(rjf): this depends on file path maps, needs to move
|
||||
@@ -408,8 +417,8 @@ internal DI_KeyList d_push_active_dbgi_key_list(Arena *arena);
|
||||
internal U64 d_query_cached_rip_from_thread(CTRL_Entity *thread);
|
||||
internal U64 d_query_cached_rip_from_thread_unwind(CTRL_Entity *thread, U64 unwind_count);
|
||||
internal U64 d_query_cached_tls_base_vaddr_from_process_root_rip(CTRL_Entity *process, U64 root_vaddr, U64 rip_vaddr);
|
||||
internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff);
|
||||
internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff);
|
||||
internal E_String2NumMap *d_query_cached_locals_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
|
||||
internal E_String2NumMap *d_query_cached_member_map_from_dbgi_key_voff(DI_Key dbgi_key, U64 voff);
|
||||
|
||||
//- rjf: top-level command dispatch
|
||||
internal void d_push_cmd(D_CmdKind kind, D_CmdParams *params);
|
||||
|
||||
+1426
-1732
File diff suppressed because it is too large
Load Diff
+242
-366
@@ -5,13 +5,12 @@
|
||||
#define DBG_INFO_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Cache Key Type
|
||||
//~ rjf: Unique Debug Info Key
|
||||
|
||||
typedef struct DI_Key DI_Key;
|
||||
struct DI_Key
|
||||
{
|
||||
String8 path;
|
||||
U64 min_timestamp;
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
typedef struct DI_KeyNode DI_KeyNode;
|
||||
@@ -37,14 +36,182 @@ struct DI_KeyArray
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Event Types
|
||||
//~ rjf: Debug Info Path / Timestamp => Key Cache Types
|
||||
|
||||
typedef struct DI_KeyPathNode DI_KeyPathNode;
|
||||
struct DI_KeyPathNode
|
||||
{
|
||||
DI_KeyPathNode *next;
|
||||
DI_KeyPathNode *prev;
|
||||
String8 path;
|
||||
U64 min_timestamp;
|
||||
DI_Key key;
|
||||
};
|
||||
|
||||
typedef struct DI_KeySlot DI_KeySlot;
|
||||
struct DI_KeySlot
|
||||
{
|
||||
DI_KeyPathNode *first;
|
||||
DI_KeyPathNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Cache Types
|
||||
|
||||
typedef struct DI_Node DI_Node;
|
||||
struct DI_Node
|
||||
{
|
||||
// rjf: links
|
||||
DI_Node *next;
|
||||
DI_Node *prev;
|
||||
|
||||
// rjf: key
|
||||
DI_Key key;
|
||||
|
||||
// rjf: value
|
||||
OS_Handle file;
|
||||
OS_Handle file_map;
|
||||
void *file_base;
|
||||
FileProperties file_props;
|
||||
Arena *arena;
|
||||
RDI_Parsed rdi;
|
||||
|
||||
// rjf: metadata
|
||||
AccessPt access_pt;
|
||||
U64 refcount;
|
||||
U64 batch_request_counts[2];
|
||||
U64 working_count;
|
||||
U64 completion_count;
|
||||
};
|
||||
|
||||
typedef struct DI_Slot DI_Slot;
|
||||
struct DI_Slot
|
||||
{
|
||||
DI_Node *first;
|
||||
DI_Node *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Requests
|
||||
|
||||
typedef struct DI_Request DI_Request;
|
||||
struct DI_Request
|
||||
{
|
||||
DI_Key key;
|
||||
};
|
||||
|
||||
typedef struct DI_RequestNode DI_RequestNode;
|
||||
struct DI_RequestNode
|
||||
{
|
||||
DI_RequestNode *next;
|
||||
DI_Request v;
|
||||
};
|
||||
|
||||
typedef struct DI_RequestBatch DI_RequestBatch;
|
||||
struct DI_RequestBatch
|
||||
{
|
||||
Mutex mutex;
|
||||
Arena *arena;
|
||||
DI_RequestNode *first;
|
||||
DI_RequestNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Load Tasks
|
||||
|
||||
typedef enum DI_LoadTaskStatus
|
||||
{
|
||||
DI_LoadTaskStatus_Null,
|
||||
DI_LoadTaskStatus_Active,
|
||||
DI_LoadTaskStatus_Done,
|
||||
}
|
||||
DI_LoadTaskStatus;
|
||||
|
||||
typedef struct DI_LoadTask DI_LoadTask;
|
||||
struct DI_LoadTask
|
||||
{
|
||||
DI_LoadTask *next;
|
||||
DI_LoadTask *prev;
|
||||
|
||||
DI_Key key;
|
||||
DI_LoadTaskStatus status;
|
||||
|
||||
B32 og_analyzed;
|
||||
B32 og_is_rdi;
|
||||
U64 og_size;
|
||||
|
||||
B32 rdi_analyzed;
|
||||
B32 rdi_is_stale;
|
||||
|
||||
U64 thread_count;
|
||||
OS_Handle process;
|
||||
};
|
||||
|
||||
typedef struct DI_LoadCompletion DI_LoadCompletion;
|
||||
struct DI_LoadCompletion
|
||||
{
|
||||
DI_LoadCompletion *next;
|
||||
U64 code;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Types
|
||||
|
||||
typedef struct DI_SearchItem DI_SearchItem;
|
||||
struct DI_SearchItem
|
||||
{
|
||||
U64 idx;
|
||||
DI_Key key;
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunk DI_SearchItemChunk;
|
||||
struct DI_SearchItemChunk
|
||||
{
|
||||
DI_SearchItemChunk *next;
|
||||
U64 base_idx;
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunkList DI_SearchItemChunkList;
|
||||
struct DI_SearchItemChunkList
|
||||
{
|
||||
DI_SearchItemChunk *first;
|
||||
DI_SearchItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemArray DI_SearchItemArray;
|
||||
struct DI_SearchItemArray
|
||||
{
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Match Types
|
||||
|
||||
typedef struct DI_Match DI_Match;
|
||||
struct DI_Match
|
||||
{
|
||||
DI_Key key;
|
||||
RDI_SectionKind section_kind;
|
||||
U32 idx;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Events
|
||||
|
||||
typedef enum DI_EventKind
|
||||
{
|
||||
DI_EventKind_Null,
|
||||
DI_EventKind_ConversionStarted,
|
||||
DI_EventKind_ConversionEnded,
|
||||
DI_EventKind_ConversionFailureUnsupportedFormat,
|
||||
DI_EventKind_COUNT
|
||||
}
|
||||
DI_EventKind;
|
||||
@@ -72,418 +239,127 @@ struct DI_EventList
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Cache Types
|
||||
|
||||
typedef struct DI_StringChunkNode DI_StringChunkNode;
|
||||
struct DI_StringChunkNode
|
||||
{
|
||||
DI_StringChunkNode *next;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct DI_Node DI_Node;
|
||||
struct DI_Node
|
||||
{
|
||||
// rjf: links
|
||||
DI_Node *next;
|
||||
DI_Node *prev;
|
||||
|
||||
// rjf: metadata
|
||||
U64 ref_count;
|
||||
U64 touch_count;
|
||||
U64 is_working;
|
||||
|
||||
// rjf: key
|
||||
DI_Key key;
|
||||
|
||||
// rjf: file handles
|
||||
OS_Handle file;
|
||||
OS_Handle file_map;
|
||||
void *file_base;
|
||||
FileProperties file_props;
|
||||
|
||||
// rjf: parse artifacts
|
||||
Arena *arena;
|
||||
RDI_Parsed rdi;
|
||||
B32 parse_done;
|
||||
};
|
||||
|
||||
typedef struct DI_Slot DI_Slot;
|
||||
struct DI_Slot
|
||||
{
|
||||
DI_Node *first;
|
||||
DI_Node *last;
|
||||
};
|
||||
|
||||
typedef struct DI_Stripe DI_Stripe;
|
||||
struct DI_Stripe
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Node *free_node;
|
||||
DI_StringChunkNode *free_string_chunks[8];
|
||||
RWMutex rw_mutex;
|
||||
CondVar cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Cache Types
|
||||
|
||||
typedef struct DI_SearchItem DI_SearchItem;
|
||||
struct DI_SearchItem
|
||||
{
|
||||
U64 idx;
|
||||
U64 dbgi_idx;
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunk DI_SearchItemChunk;
|
||||
struct DI_SearchItemChunk
|
||||
{
|
||||
DI_SearchItemChunk *next;
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemChunkList DI_SearchItemChunkList;
|
||||
struct DI_SearchItemChunkList
|
||||
{
|
||||
DI_SearchItemChunk *first;
|
||||
DI_SearchItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchItemArray DI_SearchItemArray;
|
||||
struct DI_SearchItemArray
|
||||
{
|
||||
DI_SearchItem *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchParams DI_SearchParams;
|
||||
struct DI_SearchParams
|
||||
{
|
||||
RDI_SectionKind target;
|
||||
DI_KeyArray dbgi_keys;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchBucket DI_SearchBucket;
|
||||
struct DI_SearchBucket
|
||||
{
|
||||
Arena *arena;
|
||||
String8 query;
|
||||
U64 params_hash;
|
||||
DI_SearchParams params;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchNode DI_SearchNode;
|
||||
struct DI_SearchNode
|
||||
{
|
||||
DI_SearchNode *next;
|
||||
DI_SearchNode *prev;
|
||||
U128 key;
|
||||
U64 scope_refcount;
|
||||
U64 work_refcount;
|
||||
U64 last_update_tick_idx;
|
||||
U64 bucket_read_gen;
|
||||
U64 bucket_write_gen;
|
||||
U64 bucket_items_gen;
|
||||
DI_SearchBucket buckets[6];
|
||||
DI_SearchItemArray items;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchSlot DI_SearchSlot;
|
||||
struct DI_SearchSlot
|
||||
{
|
||||
DI_SearchNode *first;
|
||||
DI_SearchNode *last;
|
||||
};
|
||||
|
||||
typedef struct DI_SearchStripe DI_SearchStripe;
|
||||
struct DI_SearchStripe
|
||||
{
|
||||
Arena *arena;
|
||||
DI_SearchNode *free_node;
|
||||
RWMutex rw_mutex;
|
||||
CondVar cv;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scoped Access Types
|
||||
|
||||
typedef struct DI_Touch DI_Touch;
|
||||
struct DI_Touch
|
||||
{
|
||||
DI_Touch *next;
|
||||
DI_Node *node;
|
||||
DI_Stripe *stripe;
|
||||
DI_SearchNode *search_node;
|
||||
DI_SearchStripe *search_stripe;
|
||||
};
|
||||
|
||||
typedef struct DI_Scope DI_Scope;
|
||||
struct DI_Scope
|
||||
{
|
||||
DI_Scope *next;
|
||||
DI_Scope *prev;
|
||||
DI_Touch *first_touch;
|
||||
DI_Touch *last_touch;
|
||||
};
|
||||
|
||||
typedef struct DI_TCTX DI_TCTX;
|
||||
struct DI_TCTX
|
||||
{
|
||||
Arena *arena;
|
||||
DI_Scope *first_scope;
|
||||
DI_Scope *last_scope;
|
||||
DI_Scope *free_scope;
|
||||
DI_Touch *free_touch;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Thread State Types
|
||||
|
||||
typedef struct DI_SearchThread DI_SearchThread;
|
||||
struct DI_SearchThread
|
||||
{
|
||||
Thread thread;
|
||||
Mutex ring_mutex;
|
||||
CondVar ring_cv;
|
||||
U64 ring_size;
|
||||
U8 *ring_base;
|
||||
U64 ring_write_pos;
|
||||
U64 ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Match Cache State Types
|
||||
|
||||
typedef struct DI_Match DI_Match;
|
||||
struct DI_Match
|
||||
{
|
||||
U64 dbgi_idx;
|
||||
RDI_SectionKind section;
|
||||
U32 idx;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNode DI_MatchNode;
|
||||
struct DI_MatchNode
|
||||
{
|
||||
DI_MatchNode *next;
|
||||
DI_Match v;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNameNode DI_MatchNameNode;
|
||||
struct DI_MatchNameNode
|
||||
{
|
||||
// rjf: synchronously written by usage code
|
||||
DI_MatchNameNode *next;
|
||||
DI_MatchNameNode *prev;
|
||||
DI_MatchNameNode *lru_next;
|
||||
DI_MatchNameNode *lru_prev;
|
||||
U64 alloc_gen;
|
||||
U64 first_gen_touched;
|
||||
U64 last_gen_touched;
|
||||
U64 req_params_hash;
|
||||
U64 req_count;
|
||||
String8 name;
|
||||
U64 hash;
|
||||
|
||||
// rjf: atomically written by match work
|
||||
U64 cmp_count;
|
||||
U64 cmp_params_hash;
|
||||
DI_Match primary_match;
|
||||
// DI_MatchNode *first_alt_match;
|
||||
// DI_MatchNode *last_alt_match;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchNameSlot DI_MatchNameSlot;
|
||||
struct DI_MatchNameSlot
|
||||
{
|
||||
DI_MatchNameNode *first;
|
||||
DI_MatchNameNode *last;
|
||||
};
|
||||
|
||||
typedef struct DI_MatchStore DI_MatchStore;
|
||||
struct DI_MatchStore
|
||||
{
|
||||
Arena *arena;
|
||||
U64 gen;
|
||||
Arena *gen_arenas[2];
|
||||
|
||||
// rjf: parameters
|
||||
Arena *params_arena;
|
||||
RWMutex params_rw_mutex;
|
||||
U64 params_hash;
|
||||
DI_KeyArray params_keys;
|
||||
|
||||
// rjf: match cache
|
||||
U64 match_name_slots_count;
|
||||
DI_MatchNameSlot *match_name_slots;
|
||||
DI_MatchNameNode *first_free_match_name;
|
||||
DI_Match *first_free_match;
|
||||
DI_MatchNameNode *first_lru_match_name;
|
||||
DI_MatchNameNode *last_lru_match_name;
|
||||
U64 active_match_name_nodes_count;
|
||||
RWMutex match_rw_mutex;
|
||||
CondVar match_cv;
|
||||
|
||||
// rjf: user -> match work ring buffer
|
||||
CondVar u2m_ring_cv;
|
||||
Mutex u2m_ring_mutex;
|
||||
U64 u2m_ring_size;
|
||||
U8 *u2m_ring_base;
|
||||
U64 u2m_ring_write_pos;
|
||||
U64 u2m_ring_read_pos;
|
||||
|
||||
// rjf: match -> user work ring buffer
|
||||
CondVar m2u_ring_cv;
|
||||
Mutex m2u_ring_mutex;
|
||||
U64 m2u_ring_size;
|
||||
U8 *m2u_ring_base;
|
||||
U64 m2u_ring_write_pos;
|
||||
U64 m2u_ring_read_pos;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State Types
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct DI_Shared DI_Shared;
|
||||
struct DI_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
U64 load_gen;
|
||||
U64 load_count;
|
||||
|
||||
// rjf: key -> path cache
|
||||
U64 key2path_slots_count;
|
||||
DI_KeySlot *key2path_slots;
|
||||
StripeArray key2path_stripes;
|
||||
|
||||
// rjf: path -> key cache
|
||||
U64 path2key_slots_count;
|
||||
DI_KeySlot *path2key_slots;
|
||||
StripeArray path2key_stripes;
|
||||
|
||||
// rjf: debug info cache
|
||||
U64 slots_count;
|
||||
DI_Slot *slots;
|
||||
U64 stripes_count;
|
||||
DI_Stripe *stripes;
|
||||
StripeArray stripes;
|
||||
|
||||
// rjf: search cache
|
||||
U64 search_slots_count;
|
||||
DI_SearchSlot *search_slots;
|
||||
U64 search_stripes_count;
|
||||
DI_SearchStripe *search_stripes;
|
||||
// rjf: requests
|
||||
DI_RequestBatch req_batches[2]; // [0] -> high priority, [1] -> low priority
|
||||
|
||||
// rjf: user -> parse ring
|
||||
Mutex u2p_ring_mutex;
|
||||
CondVar u2p_ring_cv;
|
||||
U64 u2p_ring_size;
|
||||
U8 *u2p_ring_base;
|
||||
U64 u2p_ring_write_pos;
|
||||
U64 u2p_ring_read_pos;
|
||||
// rjf: conversion tasks
|
||||
DI_LoadTask *first_load_task[2];
|
||||
DI_LoadTask *last_load_task[2];
|
||||
DI_LoadTask *free_load_task;
|
||||
U64 conversion_process_count;
|
||||
U64 conversion_thread_count;
|
||||
|
||||
// rjf: parse -> user event ring
|
||||
Mutex p2u_ring_mutex;
|
||||
CondVar p2u_ring_cv;
|
||||
U64 p2u_ring_size;
|
||||
U8 *p2u_ring_base;
|
||||
U64 p2u_ring_write_pos;
|
||||
U64 p2u_ring_read_pos;
|
||||
// rjf: conversion completion receiving thread
|
||||
U64 conversion_completion_code;
|
||||
String8 conversion_completion_lock_semaphore_name;
|
||||
String8 conversion_completion_signal_semaphore_name;
|
||||
String8 conversion_completion_shared_memory_name;
|
||||
Semaphore conversion_completion_lock_semaphore;
|
||||
Semaphore conversion_completion_signal_semaphore;
|
||||
OS_Handle conversion_completion_shared_memory;
|
||||
U64 *conversion_completion_shared_memory_base;
|
||||
Thread conversion_completion_signal_receiver_thread;
|
||||
|
||||
// rjf: search threads
|
||||
U64 search_threads_count;
|
||||
DI_SearchThread *search_threads;
|
||||
Thread search_evictor_thread;
|
||||
// rjf: completion batch
|
||||
Mutex completion_mutex;
|
||||
Arena *completion_arena;
|
||||
DI_LoadCompletion *first_completion;
|
||||
DI_LoadCompletion *last_completion;
|
||||
|
||||
// rjf: events
|
||||
Mutex event_mutex;
|
||||
Arena *event_arena;
|
||||
DI_EventList events;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DI_Shared *di_shared = 0;
|
||||
thread_static DI_TCTX *di_tctx = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Basic Helpers
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal U64 di_hash_from_seed_string(U64 seed, String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags);
|
||||
internal U64 di_hash_from_key(DI_Key *k);
|
||||
internal DI_Key di_key_zero(void);
|
||||
internal B32 di_key_match(DI_Key *a, DI_Key *b);
|
||||
internal DI_Key di_key_copy(Arena *arena, DI_Key *src);
|
||||
internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src);
|
||||
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key);
|
||||
internal B32 di_key_match(DI_Key a, DI_Key b);
|
||||
internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key key);
|
||||
internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list);
|
||||
internal DI_KeyArray di_key_array_copy(Arena *arena, DI_KeyArray *src);
|
||||
internal DI_SearchParams di_search_params_copy(Arena *arena, DI_SearchParams *src);
|
||||
internal U64 di_hash_from_search_params(DI_SearchParams *params);
|
||||
internal void di_search_item_chunk_list_concat_in_place(DI_SearchItemChunkList *dst, DI_SearchItemChunkList *to_push);
|
||||
internal U64 di_search_item_num_from_array_element_idx__linear_search(DI_SearchItemArray *array, U64 element_idx);
|
||||
internal String8 di_search_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, RDI_SectionKind target, U64 element_idx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void di_init(void);
|
||||
internal void di_init(CmdLine *cmdline);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Scope Functions
|
||||
//~ rjf: Path * Timestamp Cache Submission & Lookup
|
||||
|
||||
internal DI_Scope *di_scope_open(void);
|
||||
internal void di_scope_close(DI_Scope *scope);
|
||||
internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Stripe *stripe, DI_Node *node);
|
||||
internal void di_scope_touch_search_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_SearchStripe *stripe, DI_SearchNode *node);
|
||||
internal DI_Key di_key_from_path_timestamp(String8 path, U64 min_timestamp);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Slot Functions
|
||||
//~ rjf: Debug Info Opening / Closing
|
||||
|
||||
internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key);
|
||||
internal void di_open(DI_Key key);
|
||||
internal void di_close(DI_Key key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Per-Stripe Functions
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
internal U64 di_string_bucket_idx_from_string_size(U64 size);
|
||||
internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string);
|
||||
internal U64 di_load_gen(void);
|
||||
internal U64 di_load_count(void);
|
||||
internal DI_KeyArray di_push_all_loaded_keys(Arena *arena);
|
||||
internal RDI_Parsed *di_rdi_from_key(Access *access, DI_Key key, B32 high_priority, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Opening/Closing
|
||||
//~ rjf: Events
|
||||
|
||||
internal void di_open(DI_Key *key);
|
||||
internal void di_close(DI_Key *key);
|
||||
internal DI_EventList di_get_events(Arena *arena);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Cache Lookups
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, B32 high_priority, U64 endt_us);
|
||||
internal void di_async_tick(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Cache Lookups
|
||||
//~ rjf: Conversion Completion Signal Receiver Thread
|
||||
|
||||
internal DI_SearchItemArray di_search_items_from_key_params_query(DI_Scope *scope, U128 key, DI_SearchParams *params, String8 query, U64 endt_us, B32 *stale_out);
|
||||
internal void di_signal_completion(void);
|
||||
internal void di_conversion_completion_signal_receiver_thread_entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Parse Work
|
||||
//~ rjf: Search Artifact Cache Hooks / Lookups
|
||||
|
||||
internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us);
|
||||
internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key);
|
||||
|
||||
internal void di_p2u_push_event(DI_Event *event);
|
||||
internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us);
|
||||
|
||||
ASYNC_WORK_DEF(di_parse_work);
|
||||
internal AC_Artifact di_search_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
internal void di_search_artifact_destroy(AC_Artifact artifact);
|
||||
internal DI_SearchItemArray di_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us, B32 *stale_out);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Threads
|
||||
//~ rjf: Match Artifact Cache Hooks / Lookups
|
||||
|
||||
internal B32 di_u2s_enqueue_req(U128 key, U64 endt_us);
|
||||
internal U128 di_u2s_dequeue_req(U64 thread_idx);
|
||||
|
||||
ASYNC_WORK_DEF(di_search_work);
|
||||
internal int di_qsort_compare_search_items(DI_SearchItem *a, DI_SearchItem *b);
|
||||
internal void di_search_thread__entry_point(void *p);
|
||||
|
||||
internal void di_search_evictor_thread__entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Match Store
|
||||
|
||||
internal DI_MatchStore *di_match_store_alloc(void);
|
||||
internal void di_match_store_begin(DI_MatchStore *store, DI_KeyArray keys);
|
||||
internal DI_Match di_match_from_name(DI_MatchStore *store, String8 name, U64 endt_us);
|
||||
ASYNC_WORK_DEF(di_match_work);
|
||||
internal AC_Artifact di_match_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
internal DI_Match di_match_from_string(String8 string, U64 index, DI_Key preferred_dbgi_key, U64 endt_us);
|
||||
|
||||
#endif // DBG_INFO_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,281 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef DBG_INFO2_H
|
||||
#define DBG_INFO2_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Unique Debug Info Key
|
||||
|
||||
typedef struct DI2_Key DI2_Key;
|
||||
struct DI2_Key
|
||||
{
|
||||
U64 u64[2];
|
||||
};
|
||||
|
||||
typedef struct DI2_KeyNode DI2_KeyNode;
|
||||
struct DI2_KeyNode
|
||||
{
|
||||
DI2_KeyNode *next;
|
||||
DI2_Key v;
|
||||
};
|
||||
|
||||
typedef struct DI2_KeyList DI2_KeyList;
|
||||
struct DI2_KeyList
|
||||
{
|
||||
DI2_KeyNode *first;
|
||||
DI2_KeyNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct DI2_KeyArray DI2_KeyArray;
|
||||
struct DI2_KeyArray
|
||||
{
|
||||
DI2_Key *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Path / Timestamp => Key Cache Types
|
||||
|
||||
typedef struct DI2_KeyPathNode DI2_KeyPathNode;
|
||||
struct DI2_KeyPathNode
|
||||
{
|
||||
DI2_KeyPathNode *next;
|
||||
DI2_KeyPathNode *prev;
|
||||
String8 path;
|
||||
U64 min_timestamp;
|
||||
DI2_Key key;
|
||||
};
|
||||
|
||||
typedef struct DI2_KeySlot DI2_KeySlot;
|
||||
struct DI2_KeySlot
|
||||
{
|
||||
DI2_KeyPathNode *first;
|
||||
DI2_KeyPathNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Cache Types
|
||||
|
||||
typedef struct DI2_Node DI2_Node;
|
||||
struct DI2_Node
|
||||
{
|
||||
// rjf: links
|
||||
DI2_Node *next;
|
||||
DI2_Node *prev;
|
||||
|
||||
// rjf: key
|
||||
DI2_Key key;
|
||||
|
||||
// rjf: value
|
||||
OS_Handle file;
|
||||
OS_Handle file_map;
|
||||
void *file_base;
|
||||
FileProperties file_props;
|
||||
Arena *arena;
|
||||
RDI_Parsed rdi;
|
||||
|
||||
// rjf: metadata
|
||||
AccessPt access_pt;
|
||||
U64 refcount;
|
||||
U64 batch_request_counts[2];
|
||||
U64 working_count;
|
||||
U64 completion_count;
|
||||
};
|
||||
|
||||
typedef struct DI2_Slot DI2_Slot;
|
||||
struct DI2_Slot
|
||||
{
|
||||
DI2_Node *first;
|
||||
DI2_Node *last;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Requests
|
||||
|
||||
typedef struct DI2_Request DI2_Request;
|
||||
struct DI2_Request
|
||||
{
|
||||
DI2_Key key;
|
||||
};
|
||||
|
||||
typedef struct DI2_RequestNode DI2_RequestNode;
|
||||
struct DI2_RequestNode
|
||||
{
|
||||
DI2_RequestNode *next;
|
||||
DI2_Request v;
|
||||
};
|
||||
|
||||
typedef struct DI2_RequestBatch DI2_RequestBatch;
|
||||
struct DI2_RequestBatch
|
||||
{
|
||||
Mutex mutex;
|
||||
Arena *arena;
|
||||
DI2_RequestNode *first;
|
||||
DI2_RequestNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Load Tasks
|
||||
|
||||
typedef enum DI2_LoadTaskStatus
|
||||
{
|
||||
DI2_LoadTaskStatus_Null,
|
||||
DI2_LoadTaskStatus_Active,
|
||||
DI2_LoadTaskStatus_Done,
|
||||
}
|
||||
DI2_LoadTaskStatus;
|
||||
|
||||
typedef struct DI2_LoadTask DI2_LoadTask;
|
||||
struct DI2_LoadTask
|
||||
{
|
||||
DI2_LoadTask *next;
|
||||
DI2_LoadTask *prev;
|
||||
|
||||
DI2_Key key;
|
||||
DI2_LoadTaskStatus status;
|
||||
|
||||
B32 og_analyzed;
|
||||
B32 og_is_rdi;
|
||||
U64 og_size;
|
||||
|
||||
B32 rdi_analyzed;
|
||||
B32 rdi_is_stale;
|
||||
|
||||
U64 thread_count;
|
||||
OS_Handle process;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Types
|
||||
|
||||
typedef struct DI2_SearchItem DI2_SearchItem;
|
||||
struct DI2_SearchItem
|
||||
{
|
||||
U64 idx;
|
||||
DI2_Key key;
|
||||
U64 missed_size;
|
||||
FuzzyMatchRangeList match_ranges;
|
||||
};
|
||||
|
||||
typedef struct DI2_SearchItemChunk DI2_SearchItemChunk;
|
||||
struct DI2_SearchItemChunk
|
||||
{
|
||||
DI2_SearchItemChunk *next;
|
||||
U64 base_idx;
|
||||
DI2_SearchItem *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
|
||||
typedef struct DI2_SearchItemChunkList DI2_SearchItemChunkList;
|
||||
struct DI2_SearchItemChunkList
|
||||
{
|
||||
DI2_SearchItemChunk *first;
|
||||
DI2_SearchItemChunk *last;
|
||||
U64 chunk_count;
|
||||
U64 total_count;
|
||||
};
|
||||
|
||||
typedef struct DI2_SearchItemArray DI2_SearchItemArray;
|
||||
struct DI2_SearchItemArray
|
||||
{
|
||||
DI2_SearchItem *v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Shared State
|
||||
|
||||
typedef struct DI2_Shared DI2_Shared;
|
||||
struct DI2_Shared
|
||||
{
|
||||
Arena *arena;
|
||||
U64 load_gen;
|
||||
|
||||
// rjf: key -> path cache
|
||||
U64 key2path_slots_count;
|
||||
DI2_KeySlot *key2path_slots;
|
||||
StripeArray key2path_stripes;
|
||||
|
||||
// rjf: path -> key cache
|
||||
U64 path2key_slots_count;
|
||||
DI2_KeySlot *path2key_slots;
|
||||
StripeArray path2key_stripes;
|
||||
|
||||
// rjf: debug info cache
|
||||
U64 slots_count;
|
||||
DI2_Slot *slots;
|
||||
StripeArray stripes;
|
||||
|
||||
// rjf: requests
|
||||
DI2_RequestBatch req_batches[2]; // [0] -> high priority, [1] -> low priority
|
||||
|
||||
// rjf: conversion tasks
|
||||
DI2_LoadTask *first_load_task;
|
||||
DI2_LoadTask *last_load_task;
|
||||
DI2_LoadTask *free_load_task;
|
||||
U64 conversion_process_count;
|
||||
U64 conversion_thread_count;
|
||||
|
||||
// rjf: conversion completion receiving thread
|
||||
String8 conversion_completion_signal_semaphore_name;
|
||||
Semaphore conversion_completion_signal_semaphore;
|
||||
Thread conversion_completion_signal_receiver_thread;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
global DI2_Shared *di2_shared = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Helpers
|
||||
|
||||
internal DI2_Key di2_key_zero(void);
|
||||
internal B32 di2_key_match(DI2_Key a, DI2_Key b);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Layer Initialization
|
||||
|
||||
internal void di2_init(CmdLine *cmdline);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Path * Timestamp Cache Submission & Lookup
|
||||
|
||||
internal DI2_Key di2_key_from_path_timestamp(String8 path, U64 min_timestamp);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Opening / Closing
|
||||
|
||||
internal void di2_open(DI2_Key key);
|
||||
internal void di2_close(DI2_Key key);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Debug Info Lookups
|
||||
|
||||
internal U64 di2_load_gen(void);
|
||||
internal DI2_KeyArray di2_push_all_loaded_keys(Arena *arena);
|
||||
internal RDI_Parsed *di2_rdi_from_key(Access *access, DI2_Key key, B32 high_priority, U64 endt_us);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Asynchronous Tick
|
||||
|
||||
internal void di2_async_tick(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Conversion Completion Signal Receiver Thread
|
||||
|
||||
internal void di2_signal_completion(void);
|
||||
internal void di2_conversion_completion_signal_receiver_thread_entry_point(void *p);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Search Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact di2_search_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out);
|
||||
internal void di2_search_artifact_destroy(AC_Artifact artifact);
|
||||
internal DI2_SearchItemArray di2_search_item_array_from_target_query(Access *access, RDI_SectionKind target, String8 query, U64 endt_us);
|
||||
|
||||
#endif // DBG_INFO2_H
|
||||
@@ -279,7 +279,7 @@ struct DMN_LNX_State
|
||||
Arena *arena;
|
||||
|
||||
// rjf: access locking mechanism
|
||||
OS_Handle access_mutex;
|
||||
Mutex access_mutex;
|
||||
B32 access_run_state;
|
||||
|
||||
// rjf: deferred events
|
||||
|
||||
@@ -322,7 +322,9 @@ dmn_w32_process_read(HANDLE process, Rng1U64 range, void *dst)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
log_infof("'Win32 ReadProcessMemory failure': { [0x%I64x, 0x%I64x), code: %i }\n", range.min, range.max, error);
|
||||
bytes_read += actual_read;
|
||||
// NOTE(rjf): I have discovered that `actual_read` is *NOT* guaranteed to have
|
||||
// a usable value if `ReadProcessMemory` fails!
|
||||
// bytes_read += actual_read;
|
||||
(void)error;
|
||||
break;
|
||||
}
|
||||
@@ -2882,7 +2884,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
{
|
||||
single_step_thread_ctx = 0;
|
||||
}
|
||||
if(ctx != 0)
|
||||
if(single_step_thread_ctx != 0)
|
||||
{
|
||||
U64 rflags = single_step_thread_ctx->EFlags|0x2;
|
||||
U64 new_rflags = rflags & ~0x100;
|
||||
|
||||
+4
-8
@@ -185,7 +185,7 @@ dasm_params_match(DASM_Params *a, DASM_Params *b)
|
||||
a->style_flags == b->style_flags &&
|
||||
a->syntax == b->syntax &&
|
||||
a->base_vaddr == b->base_vaddr &&
|
||||
di_key_match(&a->dbgi_key, &b->dbgi_key));
|
||||
di_key_match(a->dbgi_key, b->dbgi_key));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -266,14 +266,13 @@ struct DASM_Artifact
|
||||
};
|
||||
|
||||
internal AC_Artifact
|
||||
dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out)
|
||||
dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
|
||||
{
|
||||
DASM_Artifact *artifact = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
Access *access = access_open();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
|
||||
//- rjf: unpack key
|
||||
U128 hash = {0};
|
||||
@@ -281,15 +280,14 @@ dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out)
|
||||
U64 key_read_off = 0;
|
||||
key_read_off += str8_deserial_read_struct(key, key_read_off, &hash);
|
||||
key_read_off += str8_deserial_read_struct(key, key_read_off, ¶ms);
|
||||
params.dbgi_key.path.str = key.str + key_read_off;
|
||||
String8 data = c_data_from_hash(access, hash);
|
||||
|
||||
//- rjf: get dbg info
|
||||
B32 stale = 0;
|
||||
RDI_Parsed *rdi = &rdi_parsed_nil;
|
||||
if(params.dbgi_key.path.size != 0)
|
||||
if(!di_key_match(params.dbgi_key, di_key_zero()))
|
||||
{
|
||||
rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, 1, 0);
|
||||
rdi = di_rdi_from_key(access, params.dbgi_key, 0, 0);
|
||||
stale = (stale || (rdi == &rdi_parsed_nil));
|
||||
}
|
||||
|
||||
@@ -483,7 +481,6 @@ dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out)
|
||||
artifact->data_hash = hash;
|
||||
}
|
||||
|
||||
di_scope_close(di_scope);
|
||||
access_close(access);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
@@ -514,7 +511,6 @@ dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params)
|
||||
String8List key_parts = {0};
|
||||
str8_list_push(scratch.arena, &key_parts, str8_struct(&hash));
|
||||
str8_list_push(scratch.arena, &key_parts, str8_struct(params));
|
||||
str8_list_push(scratch.arena, &key_parts, params->dbgi_key.path);
|
||||
String8 key = str8_list_join(scratch.arena, &key_parts, 0);
|
||||
|
||||
// rjf: get info
|
||||
|
||||
+1
-1
@@ -197,7 +197,7 @@ internal U64 dasm_line_array_code_off_from_idx(DASM_LineArray *array, U64 idx);
|
||||
////////////////////////////////
|
||||
//~ rjf: Artifact Cache Hooks / Lookups
|
||||
|
||||
internal AC_Artifact dasm_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out);
|
||||
internal AC_Artifact dasm_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
internal void dasm_artifact_destroy(AC_Artifact artifact);
|
||||
internal DASM_Info dasm_info_from_hash_params(Access *access, U128 hash, DASM_Params *params);
|
||||
internal DASM_Info dasm_info_from_key_params(Access *access, C_Key key, DASM_Params *params, U128 *hash_out);
|
||||
|
||||
@@ -69,6 +69,31 @@ dw_reg_pos_from_code(Arch arch, DW_Reg reg_code)
|
||||
return max_U64;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_reg_count_from_arch(Arch arch)
|
||||
{
|
||||
switch (arch) {
|
||||
default: { NotImplemented; } // fall-through
|
||||
case Arch_Null: return 0;
|
||||
case Arch_x86: return DW_RegX86_Last;
|
||||
case Arch_x64: return DW_RegX64_Last;
|
||||
}
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_reg_max_size_from_arch(Arch arch)
|
||||
{
|
||||
local_persist U64 max_size = 0;
|
||||
if (max_size == 0) {
|
||||
U64 max_idx = dw_reg_count_from_arch(arch);
|
||||
for EachIndex(reg_idx, max_idx) {
|
||||
U64 reg_size = dw_reg_size_from_code(arch, reg_idx);
|
||||
max_size = Max(max_size, reg_size);
|
||||
}
|
||||
}
|
||||
return max_size;
|
||||
}
|
||||
|
||||
internal DW_AttribClass
|
||||
dw_attrib_class_from_attrib_v2(DW_AttribKind k)
|
||||
{
|
||||
@@ -386,9 +411,130 @@ dw_pick_default_lower_bound(DW_Language lang)
|
||||
return lower_bound;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_operand_count_from_expr_op(DW_ExprOp op)
|
||||
{
|
||||
switch (op) {
|
||||
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) case _ID: return _OPER_COUNT;
|
||||
DW_Expr_V3_XList(X)
|
||||
DW_Expr_V4_XList(X)
|
||||
DW_Expr_V5_XList(X)
|
||||
DW_Expr_GNU_XList(X)
|
||||
#undef X
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_pop_count_from_expr_op(DW_ExprOp op)
|
||||
{
|
||||
switch (op) {
|
||||
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) case _ID: return _POP_COUNT;
|
||||
DW_Expr_V3_XList(X)
|
||||
DW_Expr_V4_XList(X)
|
||||
DW_Expr_V5_XList(X)
|
||||
DW_Expr_GNU_XList(X)
|
||||
#undef X
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_push_count_from_expr_op(DW_ExprOp op)
|
||||
{
|
||||
switch (op) {
|
||||
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) case _ID: return _PUSH_COUNT;
|
||||
DW_Expr_V3_XList(X)
|
||||
DW_Expr_V4_XList(X)
|
||||
DW_Expr_V5_XList(X)
|
||||
DW_Expr_GNU_XList(X)
|
||||
#undef X
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_operand_count_from_cfa_opcode(DW_CFA_Opcode opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return ArrayCount(t)-1; }
|
||||
DW_CFA_Kind_XList(X)
|
||||
#undef X
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_is_cfa_expr_opcode_invalid(DW_ExprOp opcode)
|
||||
{
|
||||
B32 is_invalid = 0;
|
||||
switch (opcode) {
|
||||
case DW_ExprOp_Addrx:
|
||||
case DW_ExprOp_Call2:
|
||||
case DW_ExprOp_Call4:
|
||||
case DW_ExprOp_CallRef:
|
||||
case DW_ExprOp_ConstType:
|
||||
case DW_ExprOp_Constx:
|
||||
case DW_ExprOp_Convert:
|
||||
case DW_ExprOp_DerefType:
|
||||
case DW_ExprOp_RegvalType:
|
||||
case DW_ExprOp_Reinterpret:
|
||||
case DW_ExprOp_PushObjectAddress:
|
||||
case DW_ExprOp_CallFrameCfa: {
|
||||
is_invalid = 1;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
return is_invalid;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_is_new_row_cfa_opcode(DW_CFA_Opcode opcode)
|
||||
{
|
||||
B32 is_new_row_op = 0;
|
||||
switch (opcode) {
|
||||
case DW_CFA_SetLoc:
|
||||
case DW_CFA_AdvanceLoc:
|
||||
case DW_CFA_AdvanceLoc1:
|
||||
case DW_CFA_AdvanceLoc2:
|
||||
case DW_CFA_AdvanceLoc4: {
|
||||
is_new_row_op = 1;
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
return is_new_row_op;
|
||||
}
|
||||
|
||||
internal DW_CFA_OperandType *
|
||||
dw_operand_types_from_cfa_op(DW_CFA_Opcode opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
#define X(_N, _ID, ...) case _ID: { local_persist DW_CFA_OperandType t[] = { DW_CFA_OperandType_Null, __VA_ARGS__ }; return &t[0] + 1; }
|
||||
DW_CFA_Kind_XList(X)
|
||||
#undef X
|
||||
default: { NotImplemented; } break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Enum
|
||||
|
||||
internal String8
|
||||
dw_string_from_format(DW_Format format)
|
||||
{
|
||||
switch (format) {
|
||||
case DW_Format_Null: return str8_zero();
|
||||
case DW_Format_32Bit: return str8_lit("DWARF32");
|
||||
case DW_Format_64Bit: return str8_lit("DWARF64");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op)
|
||||
{
|
||||
@@ -659,3 +805,15 @@ dw_string_from_register(Arena *arena, Arch arch, U64 reg_id)
|
||||
}
|
||||
return reg_str;
|
||||
}
|
||||
|
||||
internal String8
|
||||
dw_string_from_cfa_opcode(DW_CFA_Opcode opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
#define X(_NAME, _ID, ...) case _ID: return str8_lit(Stringify(_NAME));
|
||||
DW_CFA_Kind_XList(X)
|
||||
#undef X
|
||||
default: InvalidPath; break;
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
+254
-234
@@ -1337,258 +1337,260 @@ typedef enum DW_LNCTEnum
|
||||
DW_LNCT_UserHi = 0x3fff
|
||||
} DW_LNCTEnum;
|
||||
|
||||
#define DW_CFA_Kind1_XList(X) \
|
||||
X(Nop, 0x0) \
|
||||
X(SetLoc, 0x1) \
|
||||
X(AdvanceLoc1, 0x2) \
|
||||
X(AdvanceLoc2, 0x3) \
|
||||
X(AdvanceLoc4, 0x4) \
|
||||
X(OffsetExt, 0x5) \
|
||||
X(RestoreExt, 0x6) \
|
||||
X(Undefined, 0x7) \
|
||||
X(SameValue, 0x8) \
|
||||
X(Register, 0x9) \
|
||||
X(RememberState, 0xA) \
|
||||
X(RestoreState, 0xB) \
|
||||
X(DefCfa, 0xC) \
|
||||
X(DefCfaRegister, 0xD) \
|
||||
X(DefCfaOffset, 0xE) \
|
||||
X(DefCfaExpr, 0xF) \
|
||||
X(Expr, 0x10) \
|
||||
X(OffsetExtSf, 0x11) \
|
||||
X(DefCfaSf, 0x12) \
|
||||
X(DefCfaOffsetSf, 0x13) \
|
||||
X(ValOffset, 0x14) \
|
||||
X(ValOffsetSf, 0x15) \
|
||||
X(ValExpr, 0x16)
|
||||
////////////////////////////////
|
||||
// CFA
|
||||
|
||||
#define DW_CFA_Kind2_XList(X) \
|
||||
X(AdvanceLoc, 0x40) \
|
||||
X(Offset, 0x80) \
|
||||
X(Restore, 0xC0)
|
||||
|
||||
typedef U8 DW_CFA;
|
||||
typedef enum DW_CFAEnum
|
||||
typedef enum
|
||||
{
|
||||
#define X(_N, _ID) DW_CFA_##_N = _ID,
|
||||
DW_CFA_Kind1_XList(X)
|
||||
DW_CFA_Kind2_XList(X)
|
||||
DW_CFA_OperandType_Null,
|
||||
DW_CFA_OperandType_Value,
|
||||
DW_CFA_OperandType_Register,
|
||||
DW_CFA_OperandType_Expression,
|
||||
} DW_CFA_OperandType;
|
||||
|
||||
// (opcode name, opcode id, operand count, operand types)
|
||||
#define DW_CFA_Kind_XList(X) \
|
||||
X(Nop, 0x0) \
|
||||
X(SetLoc, 0x1, DW_CFA_OperandType_Value) \
|
||||
X(AdvanceLoc1, 0x2, DW_CFA_OperandType_Value) \
|
||||
X(AdvanceLoc2, 0x3, DW_CFA_OperandType_Value) \
|
||||
X(AdvanceLoc4, 0x4, DW_CFA_OperandType_Value) \
|
||||
X(OffsetExt, 0x5, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
|
||||
X(RestoreExt, 0x6) \
|
||||
X(Undefined, 0x7, DW_CFA_OperandType_Register) \
|
||||
X(SameValue, 0x8, DW_CFA_OperandType_Register) \
|
||||
X(Register, 0x9, DW_CFA_OperandType_Register) \
|
||||
X(RememberState, 0xa) \
|
||||
X(RestoreState, 0xb) \
|
||||
X(DefCfa, 0xc, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
|
||||
X(DefCfaRegister, 0xd, DW_CFA_OperandType_Register) \
|
||||
X(DefCfaOffset, 0xe, DW_CFA_OperandType_Value) \
|
||||
X(DefCfaExpr, 0xf, DW_CFA_OperandType_Expression) \
|
||||
X(Expr, 0x10, DW_CFA_OperandType_Expression) \
|
||||
X(OffsetExtSf, 0x11, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
|
||||
X(DefCfaSf, 0x12, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
|
||||
X(DefCfaOffsetSf, 0x13, DW_CFA_OperandType_Value) \
|
||||
X(ValOffset, 0x14, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
|
||||
X(ValOffsetSf, 0x15, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
|
||||
X(ValExpr, 0x16, DW_CFA_OperandType_Register, DW_CFA_OperandType_Expression) \
|
||||
X(AdvanceLoc, 0x40, DW_CFA_OperandType_Value) \
|
||||
X(Offset, 0x80, DW_CFA_OperandType_Register, DW_CFA_OperandType_Value) \
|
||||
X(Restore, 0xc0, DW_CFA_OperandType_Register)
|
||||
|
||||
#define DW_CFA_OperandMax 2
|
||||
#define DW_CFA_Mask_OpcodeHi 0xc0
|
||||
#define DW_CFA_Mask_Operand 0x3f
|
||||
|
||||
typedef U8 DW_CFA_Opcode;
|
||||
typedef enum DW_CFA_Enum
|
||||
{
|
||||
#define X(_N, _ID, ...) DW_CFA_##_N = _ID,
|
||||
DW_CFA_Kind_XList(X)
|
||||
#undef X
|
||||
|
||||
DW_CFA_OplKind1 = DW_CFA_ValExpr,
|
||||
DW_CFA_OplKind2 = DW_CFA_Restore,
|
||||
} DW_CFAEnum;
|
||||
|
||||
typedef U8 DW_CFAMask;
|
||||
enum
|
||||
{
|
||||
// kind1: opcode: [0,5] zeroes:[6,7]; kind2: operand:[0,5] opcode:[6,7]
|
||||
DW_CFAMask_OpcodeHi = 0xC0,
|
||||
DW_CFAMask_Operand = 0x3F,
|
||||
DW_CFAMask_Count = 2
|
||||
};
|
||||
} DW_CFA_Enum;
|
||||
|
||||
////////////////////////////////
|
||||
// Expression Opcodes
|
||||
|
||||
#define DW_Expr_V3_XList(X) \
|
||||
X(Null, 0x00) \
|
||||
X(Addr, 0x03) \
|
||||
X(Deref, 0x06) \
|
||||
X(Const1U, 0x08) \
|
||||
X(Const1S, 0x09) \
|
||||
X(Const2U, 0x0a) \
|
||||
X(Const2S, 0x0b) \
|
||||
X(Const4U, 0x0c) \
|
||||
X(Const4S, 0x0d) \
|
||||
X(Const8U, 0x0e) \
|
||||
X(Const8S, 0x0f) \
|
||||
X(ConstU, 0x10) \
|
||||
X(ConstS, 0x11) \
|
||||
X(Dup, 0x12) \
|
||||
X(Drop, 0x13) \
|
||||
X(Over, 0x14) \
|
||||
X(Pick, 0x15) \
|
||||
X(Swap, 0x16) \
|
||||
X(Rot, 0x17) \
|
||||
X(XDeref, 0x18) \
|
||||
X(Abs, 0x19) \
|
||||
X(And, 0x1a) \
|
||||
X(Div, 0x1b) \
|
||||
X(Minus, 0x1c) \
|
||||
X(Mod, 0x1d) \
|
||||
X(Mul, 0x1e) \
|
||||
X(Neg, 0x1f) \
|
||||
X(Not, 0x20) \
|
||||
X(Or, 0x21) \
|
||||
X(Plus, 0x22) \
|
||||
X(PlusUConst, 0x23) \
|
||||
X(Shl, 0x24) \
|
||||
X(Shr, 0x25) \
|
||||
X(Shra, 0x26) \
|
||||
X(Xor, 0x27) \
|
||||
X(Skip, 0x2f) \
|
||||
X(Bra, 0x28) \
|
||||
X(Eq, 0x29) \
|
||||
X(Ge, 0x2a) \
|
||||
X(Gt, 0x2b) \
|
||||
X(Le, 0x2c) \
|
||||
X(Lt, 0x2d) \
|
||||
X(Ne, 0x2e) \
|
||||
X(Lit0, 0x30) \
|
||||
X(Lit1, 0x31) \
|
||||
X(Lit2, 0x32) \
|
||||
X(Lit3, 0x33) \
|
||||
X(Lit4, 0x34) \
|
||||
X(Lit5, 0x35) \
|
||||
X(Lit6, 0x36) \
|
||||
X(Lit7, 0x37) \
|
||||
X(Lit8, 0x38) \
|
||||
X(Lit9, 0x39) \
|
||||
X(Lit10, 0x3a) \
|
||||
X(Lit11, 0x3b) \
|
||||
X(Lit12, 0x3c) \
|
||||
X(Lit13, 0x3d) \
|
||||
X(Lit14, 0x3e) \
|
||||
X(Lit15, 0x3f) \
|
||||
X(Lit16, 0x40) \
|
||||
X(Lit17, 0x41) \
|
||||
X(Lit18, 0x42) \
|
||||
X(Lit19, 0x43) \
|
||||
X(Lit20, 0x44) \
|
||||
X(Lit21, 0x45) \
|
||||
X(Lit22, 0x46) \
|
||||
X(Lit23, 0x47) \
|
||||
X(Lit24, 0x48) \
|
||||
X(Lit25, 0x49) \
|
||||
X(Lit26, 0x4a) \
|
||||
X(Lit27, 0x4b) \
|
||||
X(Lit28, 0x4c) \
|
||||
X(Lit29, 0x4d) \
|
||||
X(Lit30, 0x4e) \
|
||||
X(Lit31, 0x4f) \
|
||||
X(Reg0, 0x50) \
|
||||
X(Reg1, 0x51) \
|
||||
X(Reg2, 0x52) \
|
||||
X(Reg3, 0x53) \
|
||||
X(Reg4, 0x54) \
|
||||
X(Reg5, 0x55) \
|
||||
X(Reg6, 0x56) \
|
||||
X(Reg7, 0x57) \
|
||||
X(Reg8, 0x58) \
|
||||
X(Reg9, 0x59) \
|
||||
X(Reg10, 0x5a) \
|
||||
X(Reg11, 0x5b) \
|
||||
X(Reg12, 0x5c) \
|
||||
X(Reg13, 0x5d) \
|
||||
X(Reg14, 0x5e) \
|
||||
X(Reg15, 0x5f) \
|
||||
X(Reg16, 0x60) \
|
||||
X(Reg17, 0x61) \
|
||||
X(Reg18, 0x62) \
|
||||
X(Reg19, 0x63) \
|
||||
X(Reg20, 0x64) \
|
||||
X(Reg21, 0x65) \
|
||||
X(Reg22, 0x66) \
|
||||
X(Reg23, 0x67) \
|
||||
X(Reg24, 0x68) \
|
||||
X(Reg25, 0x69) \
|
||||
X(Reg26, 0x6a) \
|
||||
X(Reg27, 0x6b) \
|
||||
X(Reg28, 0x6c) \
|
||||
X(Reg29, 0x6d) \
|
||||
X(Reg30, 0x6e) \
|
||||
X(Reg31, 0x6f) \
|
||||
X(BReg0, 0x70) \
|
||||
X(BReg1, 0x71) \
|
||||
X(BReg2, 0x72) \
|
||||
X(BReg3, 0x73) \
|
||||
X(BReg4, 0x74) \
|
||||
X(BReg5, 0x75) \
|
||||
X(BReg6, 0x76) \
|
||||
X(BReg7, 0x77) \
|
||||
X(BReg8, 0x78) \
|
||||
X(BReg9, 0x79) \
|
||||
X(BReg10, 0x7a) \
|
||||
X(BReg11, 0x7b) \
|
||||
X(BReg12, 0x7c) \
|
||||
X(BReg13, 0x7d) \
|
||||
X(BReg14, 0x7e) \
|
||||
X(BReg15, 0x7f) \
|
||||
X(BReg16, 0x80) \
|
||||
X(BReg17, 0x81) \
|
||||
X(BReg18, 0x82) \
|
||||
X(BReg19, 0x83) \
|
||||
X(BReg20, 0x84) \
|
||||
X(BReg21, 0x85) \
|
||||
X(BReg22, 0x86) \
|
||||
X(BReg23, 0x87) \
|
||||
X(BReg24, 0x88) \
|
||||
X(BReg25, 0x89) \
|
||||
X(BReg26, 0x8a) \
|
||||
X(BReg27, 0x8b) \
|
||||
X(BReg28, 0x8c) \
|
||||
X(BReg29, 0x8d) \
|
||||
X(BReg30, 0x8e) \
|
||||
X(BReg31, 0x8f) \
|
||||
X(RegX, 0x90) \
|
||||
X(FBReg, 0x91) \
|
||||
X(BRegX, 0x92) \
|
||||
X(Piece, 0x93) \
|
||||
X(DerefSize, 0x94) \
|
||||
X(XDerefSize, 0x95) \
|
||||
X(Nop, 0x96) \
|
||||
X(PushObjectAddress, 0x97) \
|
||||
X(Call2, 0x98) \
|
||||
X(Call4, 0x99) \
|
||||
X(CallRef, 0x9a) \
|
||||
X(FormTlsAddress, 0x9b) \
|
||||
X(CallFrameCfa, 0x9c) \
|
||||
X(BitPiece, 0x9d)
|
||||
// (opcode name, opcode id, operand count, pop count, push count)
|
||||
#define DW_Expr_V3_XList(X) \
|
||||
X(Null, 0x00, 0, 0, 0) \
|
||||
X(Addr, 0x03, 1, 0, 1) \
|
||||
X(Deref, 0x06, 0, 1, 1) \
|
||||
X(Const1U, 0x08, 1, 0, 1) \
|
||||
X(Const1S, 0x09, 1, 0, 1) \
|
||||
X(Const2U, 0x0a, 1, 0, 1) \
|
||||
X(Const2S, 0x0b, 1, 0, 1) \
|
||||
X(Const4U, 0x0c, 1, 0, 1) \
|
||||
X(Const4S, 0x0d, 1, 0, 1) \
|
||||
X(Const8U, 0x0e, 1, 0, 1) \
|
||||
X(Const8S, 0x0f, 1, 0, 1) \
|
||||
X(ConstU, 0x10, 1, 0, 1) \
|
||||
X(ConstS, 0x11, 1, 0, 1) \
|
||||
X(Dup, 0x12, 0, 0, 1) \
|
||||
X(Drop, 0x13, 0, 1, 0) \
|
||||
X(Over, 0x14, 0, 0, 1) \
|
||||
X(Pick, 0x15, 1, 0, 1) \
|
||||
X(Swap, 0x16, 0, 0, 0) \
|
||||
X(Rot, 0x17, 0, 0, 0) \
|
||||
X(XDeref, 0x18, 0, 2, 1) \
|
||||
X(Abs, 0x19, 0, 1, 1) \
|
||||
X(And, 0x1a, 0, 2, 1) \
|
||||
X(Div, 0x1b, 0, 2, 1) \
|
||||
X(Minus, 0x1c, 0, 2, 1) \
|
||||
X(Mod, 0x1d, 0, 2, 1) \
|
||||
X(Mul, 0x1e, 0, 2, 1) \
|
||||
X(Neg, 0x1f, 0, 1, 1) \
|
||||
X(Not, 0x20, 0, 1, 1) \
|
||||
X(Or, 0x21, 0, 2, 1) \
|
||||
X(Plus, 0x22, 0, 2, 1) \
|
||||
X(PlusUConst, 0x23, 1, 1, 1) \
|
||||
X(Shl, 0x24, 0, 2, 1) \
|
||||
X(Shr, 0x25, 0, 2, 1) \
|
||||
X(Shra, 0x26, 0, 2, 1) \
|
||||
X(Xor, 0x27, 0, 2, 1) \
|
||||
X(Bra, 0x28, 1, 1, 0) \
|
||||
X(Eq, 0x29, 0, 2, 1) \
|
||||
X(Ge, 0x2a, 0, 2, 1) \
|
||||
X(Gt, 0x2b, 0, 2, 1) \
|
||||
X(Le, 0x2c, 0, 2, 1) \
|
||||
X(Lt, 0x2d, 0, 2, 1) \
|
||||
X(Ne, 0x2e, 0, 2, 1) \
|
||||
X(Skip, 0x2f, 1, 0, 0) \
|
||||
X(Lit0, 0x30, 0, 0, 0) \
|
||||
X(Lit1, 0x31, 0, 0, 0) \
|
||||
X(Lit2, 0x32, 0, 0, 0) \
|
||||
X(Lit3, 0x33, 0, 0, 0) \
|
||||
X(Lit4, 0x34, 0, 0, 0) \
|
||||
X(Lit5, 0x35, 0, 0, 0) \
|
||||
X(Lit6, 0x36, 0, 0, 0) \
|
||||
X(Lit7, 0x37, 0, 0, 0) \
|
||||
X(Lit8, 0x38, 0, 0, 0) \
|
||||
X(Lit9, 0x39, 0, 0, 0) \
|
||||
X(Lit10, 0x3a, 0, 0, 0) \
|
||||
X(Lit11, 0x3b, 0, 0, 0) \
|
||||
X(Lit12, 0x3c, 0, 0, 0) \
|
||||
X(Lit13, 0x3d, 0, 0, 0) \
|
||||
X(Lit14, 0x3e, 0, 0, 0) \
|
||||
X(Lit15, 0x3f, 0, 0, 0) \
|
||||
X(Lit16, 0x40, 0, 0, 0) \
|
||||
X(Lit17, 0x41, 0, 0, 0) \
|
||||
X(Lit18, 0x42, 0, 0, 0) \
|
||||
X(Lit19, 0x43, 0, 0, 0) \
|
||||
X(Lit20, 0x44, 0, 0, 0) \
|
||||
X(Lit21, 0x45, 0, 0, 0) \
|
||||
X(Lit22, 0x46, 0, 0, 0) \
|
||||
X(Lit23, 0x47, 0, 0, 0) \
|
||||
X(Lit24, 0x48, 0, 0, 0) \
|
||||
X(Lit25, 0x49, 0, 0, 0) \
|
||||
X(Lit26, 0x4a, 0, 0, 0) \
|
||||
X(Lit27, 0x4b, 0, 0, 0) \
|
||||
X(Lit28, 0x4c, 0, 0, 0) \
|
||||
X(Lit29, 0x4d, 0, 0, 0) \
|
||||
X(Lit30, 0x4e, 0, 0, 0) \
|
||||
X(Lit31, 0x4f, 0, 0, 0) \
|
||||
X(Reg0, 0x50, 0, 0, 1) \
|
||||
X(Reg1, 0x51, 0, 0, 1) \
|
||||
X(Reg2, 0x52, 0, 0, 1) \
|
||||
X(Reg3, 0x53, 0, 0, 1) \
|
||||
X(Reg4, 0x54, 0, 0, 1) \
|
||||
X(Reg5, 0x55, 0, 0, 1) \
|
||||
X(Reg6, 0x56, 0, 0, 1) \
|
||||
X(Reg7, 0x57, 0, 0, 1) \
|
||||
X(Reg8, 0x58, 0, 0, 1) \
|
||||
X(Reg9, 0x59, 0, 0, 1) \
|
||||
X(Reg10, 0x5a, 0, 0, 1) \
|
||||
X(Reg11, 0x5b, 0, 0, 1) \
|
||||
X(Reg12, 0x5c, 0, 0, 1) \
|
||||
X(Reg13, 0x5d, 0, 0, 1) \
|
||||
X(Reg14, 0x5e, 0, 0, 1) \
|
||||
X(Reg15, 0x5f, 0, 0, 1) \
|
||||
X(Reg16, 0x60, 0, 0, 1) \
|
||||
X(Reg17, 0x61, 0, 0, 1) \
|
||||
X(Reg18, 0x62, 0, 0, 1) \
|
||||
X(Reg19, 0x63, 0, 0, 1) \
|
||||
X(Reg20, 0x64, 0, 0, 1) \
|
||||
X(Reg21, 0x65, 0, 0, 1) \
|
||||
X(Reg22, 0x66, 0, 0, 1) \
|
||||
X(Reg23, 0x67, 0, 0, 1) \
|
||||
X(Reg24, 0x68, 0, 0, 1) \
|
||||
X(Reg25, 0x69, 0, 0, 1) \
|
||||
X(Reg26, 0x6a, 0, 0, 1) \
|
||||
X(Reg27, 0x6b, 0, 0, 1) \
|
||||
X(Reg28, 0x6c, 0, 0, 1) \
|
||||
X(Reg29, 0x6d, 0, 0, 1) \
|
||||
X(Reg30, 0x6e, 0, 0, 1) \
|
||||
X(Reg31, 0x6f, 0, 0, 1) \
|
||||
X(BReg0, 0x70, 1, 0, 1) \
|
||||
X(BReg1, 0x71, 1, 0, 1) \
|
||||
X(BReg2, 0x72, 1, 0, 1) \
|
||||
X(BReg3, 0x73, 1, 0, 1) \
|
||||
X(BReg4, 0x74, 1, 0, 1) \
|
||||
X(BReg5, 0x75, 1, 0, 1) \
|
||||
X(BReg6, 0x76, 1, 0, 1) \
|
||||
X(BReg7, 0x77, 1, 0, 1) \
|
||||
X(BReg8, 0x78, 1, 0, 1) \
|
||||
X(BReg9, 0x79, 1, 0, 1) \
|
||||
X(BReg10, 0x7a, 1, 0, 1) \
|
||||
X(BReg11, 0x7b, 1, 0, 1) \
|
||||
X(BReg12, 0x7c, 1, 0, 1) \
|
||||
X(BReg13, 0x7d, 1, 0, 1) \
|
||||
X(BReg14, 0x7e, 1, 0, 1) \
|
||||
X(BReg15, 0x7f, 1, 0, 1) \
|
||||
X(BReg16, 0x80, 1, 0, 1) \
|
||||
X(BReg17, 0x81, 1, 0, 1) \
|
||||
X(BReg18, 0x82, 1, 0, 1) \
|
||||
X(BReg19, 0x83, 1, 0, 1) \
|
||||
X(BReg20, 0x84, 1, 0, 1) \
|
||||
X(BReg21, 0x85, 1, 0, 1) \
|
||||
X(BReg22, 0x86, 1, 0, 1) \
|
||||
X(BReg23, 0x87, 1, 0, 1) \
|
||||
X(BReg24, 0x88, 1, 0, 1) \
|
||||
X(BReg25, 0x89, 1, 0, 1) \
|
||||
X(BReg26, 0x8a, 1, 0, 1) \
|
||||
X(BReg27, 0x8b, 1, 0, 1) \
|
||||
X(BReg28, 0x8c, 1, 0, 1) \
|
||||
X(BReg29, 0x8d, 1, 0, 1) \
|
||||
X(BReg30, 0x8e, 1, 0, 1) \
|
||||
X(BReg31, 0x8f, 1, 0, 1) \
|
||||
X(RegX, 0x90, 1, 0, 1) \
|
||||
X(FBReg, 0x91, 1, 0, 1) \
|
||||
X(BRegX, 0x92, 2, 0, 1) \
|
||||
X(Piece, 0x93, 1, 0, 0) \
|
||||
X(DerefSize, 0x94, 1, 1, 1) \
|
||||
X(XDerefSize, 0x95, 1, 2, 1) \
|
||||
X(Nop, 0x96, 0, 0, 0) \
|
||||
X(PushObjectAddress, 0x97, 0, 0, 1) \
|
||||
X(Call2, 0x98, 1, 0, 0) \
|
||||
X(Call4, 0x99, 1, 0, 0) \
|
||||
X(CallRef, 0x9a, 1, 0, 0) \
|
||||
X(FormTlsAddress, 0x9b, 0, 0, 1) \
|
||||
X(CallFrameCfa, 0x9c, 0, 0, 1) \
|
||||
X(BitPiece, 0x9d, 2, 0, 0)
|
||||
|
||||
#define DW_Expr_V4_XList(X) \
|
||||
X(ImplicitValue, 0x9e) \
|
||||
X(StackValue, 0x9f)
|
||||
#define DW_Expr_V4_XList(X) \
|
||||
X(ImplicitValue, 0x9e, 2, 0, 1) \
|
||||
X(StackValue, 0x9f, 0, 0, 0)
|
||||
|
||||
#define DW_Expr_V5_XList(X) \
|
||||
X(ImplicitPointer, 0xa0) \
|
||||
X(Addrx, 0xa1) \
|
||||
X(Constx, 0xa2) \
|
||||
X(EntryValue, 0xa3) \
|
||||
X(ConstType, 0xa4) \
|
||||
X(RegvalType, 0xa5) \
|
||||
X(DerefType, 0xa6) \
|
||||
X(XderefType, 0xa7) \
|
||||
X(Convert, 0xa8) \
|
||||
X(ReInterpret, 0xa9)
|
||||
#define DW_Expr_V5_XList(X) \
|
||||
X(ImplicitPointer, 0xa0, 2, 0, 1) \
|
||||
X(Addrx, 0xa1, 1, 0, 1) \
|
||||
X(Constx, 0xa2, 1, 0, 1) \
|
||||
X(EntryValue, 0xa3, 2, 0, 0) \
|
||||
X(ConstType, 0xa4, 3, 0, 1) \
|
||||
X(RegvalType, 0xa5, 2, 0, 1) \
|
||||
X(DerefType, 0xa6, 2, 1, 1) \
|
||||
X(XDerefType, 0xa7, 2, 2, 1) \
|
||||
X(Convert, 0xa8, 1, 1, 1) \
|
||||
X(Reinterpret, 0xa9, 1, 1, 1)
|
||||
|
||||
#define DW_Expr_GNU_XList(X) \
|
||||
X(GNU_PushTlsAddress, 0xe0) \
|
||||
X(GNU_UnInit, 0xf0) \
|
||||
X(GNU_ImplicitPointer, 0xf2) \
|
||||
X(GNU_EntryValue, 0xf3) \
|
||||
X(GNU_ConstType, 0xf4) \
|
||||
X(GNU_RegvalType, 0xf5) \
|
||||
X(GNU_DerefType, 0xf6) \
|
||||
X(GNU_Convert, 0xf7) \
|
||||
X(GNU_ParameterRef, 0xfa) \
|
||||
X(GNU_AddrIndex, 0xfb) \
|
||||
X(GNU_ConstIndex, 0xfc)
|
||||
#define DW_Expr_GNU_XList(X) \
|
||||
X(GNU_PushTlsAddress, 0xe0, 0, 0, 1) \
|
||||
X(GNU_UnInit, 0xf0, 0, 0, 0) \
|
||||
X(GNU_ImplicitPointer, 0xf2, 2, 0, 1) \
|
||||
X(GNU_EntryValue, 0xf3, 2, 0, 0) \
|
||||
X(GNU_ConstType, 0xf4, 3, 0, 1) \
|
||||
X(GNU_RegvalType, 0xf5, 2, 0, 1) \
|
||||
X(GNU_DerefType, 0xf6, 2, 1, 1) \
|
||||
X(GNU_Convert, 0xf7, 1, 1, 1) \
|
||||
X(GNU_ParameterRef, 0xfa, 1, 0, 0) \
|
||||
X(GNU_AddrIndex, 0xfb, 0, 0, 1) \
|
||||
X(GNU_ConstIndex, 0xfc, 1, 0, 1)
|
||||
|
||||
typedef U64 DW_ExprOp;
|
||||
typedef U8 DW_ExprOp;
|
||||
typedef enum DW_ExprOpEnum
|
||||
{
|
||||
#define X(_N, _ID) DW_ExprOp_##_N = _ID,
|
||||
#define X(_N, _ID, _OPER_COUNT, _POP_COUNT, _PUSH_COUNT) DW_ExprOp_##_N = _ID,
|
||||
DW_Expr_V3_XList(X)
|
||||
DW_Expr_V4_XList(X)
|
||||
DW_Expr_V5_XList(X)
|
||||
DW_Expr_GNU_XList(X)
|
||||
DW_Expr_V4_XList(X)
|
||||
DW_Expr_V5_XList(X)
|
||||
DW_Expr_GNU_XList(X)
|
||||
#undef X
|
||||
} DW_ExprOpEnum;
|
||||
|
||||
//- Regs
|
||||
|
||||
#define DW_Regs_X86_XList(X) \
|
||||
#define DW_Regs_X86_XList(X) \
|
||||
X(Eax, 0, eax, 0, 4) \
|
||||
X(Ecx, 1, ecx, 0, 4) \
|
||||
X(Edx, 2, edx, 0, 4) \
|
||||
@@ -1636,7 +1638,7 @@ X(Gs, 45, gs, 0, 2) \
|
||||
X(Tr, 48, nil, 0, 0) \
|
||||
X(Ldtr, 49, nil, 0, 0)
|
||||
|
||||
#define DW_Regs_X64_XList(X) \
|
||||
#define DW_Regs_X64_XList(X) \
|
||||
X(Rax, 0, rax, 0, 8) \
|
||||
X(Rdx, 1, rdx, 0, 8) \
|
||||
X(Rcx, 2, rcx, 0, 8) \
|
||||
@@ -1722,6 +1724,7 @@ typedef enum DW_RegX86Enum
|
||||
#define X(_N,_ID,...) DW_RegX86_##_N = _ID,
|
||||
DW_Regs_X86_XList(X)
|
||||
#undef X
|
||||
DW_RegX86_Last
|
||||
} DW_RegX86Enum;
|
||||
|
||||
typedef DW_Reg DW_RegX64;
|
||||
@@ -1730,6 +1733,7 @@ typedef enum DW_RegX64Enum
|
||||
#define X(_N,_ID,...) DW_RegX64_##_N = _ID,
|
||||
DW_Regs_X64_XList(X)
|
||||
#undef X
|
||||
DW_RegX64_Last
|
||||
} DW_RegX64Enum;
|
||||
|
||||
////////////////////////////////
|
||||
@@ -1740,6 +1744,8 @@ internal U64 dw_reg_size_from_code_x64(DW_Reg reg_code);
|
||||
internal U64 dw_reg_pos_from_code_x64(DW_Reg reg_code);
|
||||
internal U64 dw_reg_size_from_code(Arch arch, DW_Reg reg_code);
|
||||
internal U64 dw_reg_pos_from_code(Arch arch, DW_Reg reg_code);
|
||||
internal U64 dw_reg_max_size_from_arch(Arch arch);
|
||||
internal U64 dw_reg_count_from_arch(Arch arch);
|
||||
|
||||
//- Attrib Class Encodings
|
||||
|
||||
@@ -1779,9 +1785,22 @@ internal DW_AttribClass dw_pick_attrib_value_class(DW_Version ver, DW_Ext ext, B
|
||||
|
||||
internal U64 dw_pick_default_lower_bound(DW_Language lang);
|
||||
|
||||
internal U64 dw_operand_count_from_expr_op(DW_ExprOp op);
|
||||
internal U64 dw_pop_count_from_expr_op(DW_ExprOp op);
|
||||
internal U64 dw_push_count_from_expr_op(DW_ExprOp op);
|
||||
|
||||
////////////////////////////////
|
||||
//~ CFA
|
||||
|
||||
internal U64 dw_operand_count_from_cfa_opcode(DW_CFA_Opcode opcode);
|
||||
internal B32 dw_is_cfa_expr_opcode_invalid(DW_ExprOp opcode);
|
||||
internal B32 dw_is_new_row_cfa_opcode(DW_CFA_Opcode opcode);
|
||||
internal DW_CFA_OperandType * dw_operand_types_from_cfa_op(DW_CFA_Opcode opcode);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: String <=> Enum
|
||||
|
||||
internal String8 dw_string_from_format(DW_Format format);
|
||||
internal String8 dw_string_from_expr_op(Arena *arena, DW_Version ver, DW_Ext ext, DW_ExprOp op);
|
||||
internal String8 dw_string_from_tag_kind(Arena *arena, DW_TagKind kind);
|
||||
internal String8 dw_string_from_attrib_kind(Arena *arena, DW_Version ver, DW_Ext ext, DW_AttribKind kind);
|
||||
@@ -1797,5 +1816,6 @@ internal String8 dw_string_from_loc_list_entry_kind(Arena *arena, DW_LLE kind);
|
||||
internal String8 dw_string_from_section_kind(Arena *arena, DW_SectionKind kind);
|
||||
internal String8 dw_string_from_rng_list_entry_kind(Arena *arena, DW_RLE kind);
|
||||
internal String8 dw_string_from_register(Arena *arena, Arch arch, U64 reg_id);
|
||||
internal String8 dw_string_from_cfa_opcode(DW_CFA_Opcode opcode);
|
||||
|
||||
#endif // DWARF_H
|
||||
|
||||
+9
-13
@@ -2,28 +2,24 @@
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal B32
|
||||
dw_is_dwarf_present_coff_section_table(String8 raw_image,
|
||||
String8 string_table,
|
||||
U64 section_count,
|
||||
COFF_SectionHeader *section_table)
|
||||
dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table)
|
||||
{
|
||||
B32 is_dwarf_present = 0;
|
||||
|
||||
for (U64 i = 0; i < section_count; ++i) {
|
||||
COFF_SectionHeader *header = §ion_table[i];
|
||||
String8 name = coff_name_from_section_header(string_table, header);
|
||||
|
||||
for EachIndex(idx, section_count)
|
||||
{
|
||||
COFF_SectionHeader *header = §ion_table[idx];
|
||||
String8 name = coff_name_from_section_header(string_table, header);
|
||||
DW_SectionKind s = dw_section_kind_from_string(name);
|
||||
if (s == DW_Section_Null) {
|
||||
if(s == DW_Section_Null)
|
||||
{
|
||||
s = dw_section_dwo_kind_from_string(name);
|
||||
}
|
||||
|
||||
is_dwarf_present = s != DW_Section_Null;
|
||||
if (is_dwarf_present) {
|
||||
if(is_dwarf_present)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return is_dwarf_present;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#ifndef DWARF_COFF_H
|
||||
#define DWARF_COFF_H
|
||||
|
||||
internal B32 dw_is_dwarf_present_coff_section_table(String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||
internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||
internal DW_Input dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table);
|
||||
|
||||
#endif // DWARF_COFF_H
|
||||
|
||||
+562
-377
File diff suppressed because it is too large
Load Diff
+20
-19
@@ -7,21 +7,22 @@
|
||||
////////////////////////////////
|
||||
//~ rjf: Dump Subset Types
|
||||
|
||||
#define DW_DumpSubset_XList \
|
||||
X(DebugInfo, debug_info, "DEBUG INFO")\
|
||||
X(DebugAbbrev, debug_abbrev, "DEBUG ABBREV")\
|
||||
X(DebugLine, debug_line, "DEBUG LINE")\
|
||||
X(DebugStr, debug_str, "DEBUG STR")\
|
||||
X(DebugLoc, debug_loc, "DEBUG LOC")\
|
||||
X(DebugRanges, debug_ranges, "DEBUG RANGES")\
|
||||
X(DebugARanges, debug_aranges, "DEBUG ARANGES")\
|
||||
X(DebugAddr, debug_addr, "DEBUG ADDR")\
|
||||
X(DebugLocLists, debug_loclists, "DEBUG LOCLISTS")\
|
||||
X(DebugRngLists, debug_rnglists, "DEBUG RNGLISTS")\
|
||||
X(DebugPubNames, debug_pubnames, "DEBUG PUBNAMES")\
|
||||
X(DebugPubTypes, debug_pubtypes, "DEBUG PUBTYPES")\
|
||||
X(DebugLineStr, debug_linestr, "DEBUG LINESTR")\
|
||||
X(DebugStrOffsets, debug_stroff, "DEBUG STROFF")\
|
||||
#define DW_DumpSubset_XList \
|
||||
X(DebugInfo, debug_info, "DEBUG INFO") \
|
||||
X(DebugAbbrev, debug_abbrev, "DEBUG ABBREV") \
|
||||
X(DebugLine, debug_line, "DEBUG LINE") \
|
||||
X(DebugStr, debug_str, "DEBUG STR") \
|
||||
X(DebugLoc, debug_loc, "DEBUG LOC") \
|
||||
X(DebugRanges, debug_ranges, "DEBUG RANGES") \
|
||||
X(DebugARanges, debug_aranges, "DEBUG ARANGES") \
|
||||
X(DebugAddr, debug_addr, "DEBUG ADDR") \
|
||||
X(DebugLocLists, debug_loclists, "DEBUG LOCLISTS") \
|
||||
X(DebugRngLists, debug_rnglists, "DEBUG RNGLISTS") \
|
||||
X(DebugPubNames, debug_pubnames, "DEBUG PUBNAMES") \
|
||||
X(DebugPubTypes, debug_pubtypes, "DEBUG PUBTYPES") \
|
||||
X(DebugLineStr, debug_linestr, "DEBUG LINESTR") \
|
||||
X(DebugStrOffsets, debug_stroff, "DEBUG STROFF") \
|
||||
X(DebugFrame, debug_frame, "DEBUG FRAME") \
|
||||
|
||||
typedef enum DW_DumpSubset
|
||||
{
|
||||
@@ -57,15 +58,15 @@ read_only global String8 dw_name_title_from_dump_subset_table[] =
|
||||
////////////////////////////////
|
||||
//~ rjf: Stringification Helpers
|
||||
|
||||
internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, U64 reg_idx, S64 reg_off);
|
||||
internal String8 dw_string_from_reg_off(Arena *arena, Arch arch, DW_Reg reg_idx, S64 reg_off);
|
||||
internal String8List dw_string_list_from_expression (Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
||||
internal String8 dw_single_line_string_from_expression(Arena *arena, String8 raw_data, U64 cu_base, U64 address_size, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
||||
internal String8 dw_string_from_eh_ptr_enc (Arena *arena, DW_EhPtrEnc enc);
|
||||
internal String8 dw_string_from_eh_ptr_enc (Arena *arena, EH_PtrEnc enc);
|
||||
|
||||
#if 0
|
||||
internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
||||
internal void dw_string_from_cfi_program (Arena *arena, String8List *out, String8 indent, String8 raw_data, DW_CIE *cie, EH_PtrCtx *ptr_ctx, Arch arch, DW_Version ver, DW_Ext ext, DW_Format format);
|
||||
|
||||
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, DW_EhPtrCtx *ptr_ctx);
|
||||
internal void dw_print_eh_frame (Arena *arena, String8List *out, String8 indent, String8 raw_eh_frame, Arch arch, DW_Version ver, DW_Ext ext, EH_PtrCtx *ptr_ctx);
|
||||
internal void dw_print_debug_loc (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
||||
internal void dw_print_debug_ranges (Arena *arena, String8List *out, String8 indent, DW_Input *input, Arch arch, ExecutableImageKind image_type, B32 relaxed);
|
||||
internal void dw_print_debug_aranges (Arena *arena, String8List *out, String8 indent, DW_Input *input);
|
||||
|
||||
+688
-2
@@ -982,7 +982,7 @@ internal U64
|
||||
dw_interp_const64(U64 type_byte_size, DW_ATE type_encoding, DW_FormKind form_kind, DW_Form form)
|
||||
{
|
||||
U64 result = max_U64;
|
||||
if (form_kind == DW_Form_Data1 || form_kind == DW_Form_Data2 || form_kind == DW_Form_Data4 || form_kind == DW_Form_Data16) {
|
||||
if (form_kind == DW_Form_Data1 || form_kind == DW_Form_Data2 || form_kind == DW_Form_Data4 || form_kind == DW_Form_Data8 || form_kind == DW_Form_Data16) {
|
||||
if (form.data.size <= sizeof(result)) {
|
||||
if (!dw_try_u64_from_const_value(type_byte_size, type_encoding, form.data, &result)) {
|
||||
Assert(!"unable to decode data");
|
||||
@@ -1007,7 +1007,7 @@ dw_interp_const64(U64 type_byte_size, DW_ATE type_encoding, DW_FormKind form_kin
|
||||
internal U64
|
||||
dw_interp_const_u64(DW_FormKind form_kind, DW_Form form)
|
||||
{
|
||||
return dw_interp_const64(DW_ATE_Unsigned, sizeof(U64), form_kind, form);
|
||||
return dw_interp_const64(sizeof(U64), DW_ATE_Unsigned, form_kind, form);
|
||||
}
|
||||
|
||||
internal U32
|
||||
@@ -3112,3 +3112,689 @@ dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Input *input, DW_Sect
|
||||
return names_table;
|
||||
}
|
||||
|
||||
internal DW_Expr
|
||||
dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data)
|
||||
{
|
||||
DW_Expr expr = {0};
|
||||
for (U64 cursor = 0; cursor < data.size; ) {
|
||||
U64 inst_start = cursor;
|
||||
|
||||
DW_ExprOp opcode = 0;
|
||||
cursor += str8_deserial_read_struct(data, cursor, &opcode);
|
||||
|
||||
DW_ExprOperand operands[4] = {0};
|
||||
switch (opcode) {
|
||||
case DW_ExprOp_Lit0: case DW_ExprOp_Lit1: case DW_ExprOp_Lit2:
|
||||
case DW_ExprOp_Lit3: case DW_ExprOp_Lit4: case DW_ExprOp_Lit5:
|
||||
case DW_ExprOp_Lit6: case DW_ExprOp_Lit7: case DW_ExprOp_Lit8:
|
||||
case DW_ExprOp_Lit9: case DW_ExprOp_Lit10: case DW_ExprOp_Lit11:
|
||||
case DW_ExprOp_Lit12: case DW_ExprOp_Lit13: case DW_ExprOp_Lit14:
|
||||
case DW_ExprOp_Lit15: case DW_ExprOp_Lit16: case DW_ExprOp_Lit17:
|
||||
case DW_ExprOp_Lit18: case DW_ExprOp_Lit19: case DW_ExprOp_Lit20:
|
||||
case DW_ExprOp_Lit21: case DW_ExprOp_Lit22: case DW_ExprOp_Lit23:
|
||||
case DW_ExprOp_Lit24: case DW_ExprOp_Lit25: case DW_ExprOp_Lit26:
|
||||
case DW_ExprOp_Lit27: case DW_ExprOp_Lit28: case DW_ExprOp_Lit29:
|
||||
case DW_ExprOp_Lit30: case DW_ExprOp_Lit31: {
|
||||
// implicit operands
|
||||
} break;
|
||||
case DW_ExprOp_Const1U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8); } break;
|
||||
case DW_ExprOp_Const2U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u16); } break;
|
||||
case DW_ExprOp_Const4U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u32); } break;
|
||||
case DW_ExprOp_Const8U: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].u64); } break;
|
||||
case DW_ExprOp_Const1S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s8); } break;
|
||||
case DW_ExprOp_Const2S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s16); } break;
|
||||
case DW_ExprOp_Const4S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s32); } break;
|
||||
case DW_ExprOp_Const8S: { cursor += str8_deserial_read_struct(data, cursor, &operands[0].s64); } break;
|
||||
case DW_ExprOp_ConstU: { cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); } break;
|
||||
case DW_ExprOp_ConstS: { cursor += str8_deserial_read_sleb128(data, cursor, &operands[0].s64); } break;
|
||||
case DW_ExprOp_Addr: { cursor += str8_deserial_read(data, cursor, &operands[0].u64, addr_size, addr_size); } break;
|
||||
case DW_ExprOp_Reg0: case DW_ExprOp_Reg1: case DW_ExprOp_Reg2:
|
||||
case DW_ExprOp_Reg3: case DW_ExprOp_Reg4: case DW_ExprOp_Reg5:
|
||||
case DW_ExprOp_Reg6: case DW_ExprOp_Reg7: case DW_ExprOp_Reg8:
|
||||
case DW_ExprOp_Reg9: case DW_ExprOp_Reg10: case DW_ExprOp_Reg11:
|
||||
case DW_ExprOp_Reg12: case DW_ExprOp_Reg13: case DW_ExprOp_Reg14:
|
||||
case DW_ExprOp_Reg15: case DW_ExprOp_Reg16: case DW_ExprOp_Reg17:
|
||||
case DW_ExprOp_Reg18: case DW_ExprOp_Reg19: case DW_ExprOp_Reg20:
|
||||
case DW_ExprOp_Reg21: case DW_ExprOp_Reg22: case DW_ExprOp_Reg23:
|
||||
case DW_ExprOp_Reg24: case DW_ExprOp_Reg25: case DW_ExprOp_Reg26:
|
||||
case DW_ExprOp_Reg27: case DW_ExprOp_Reg28: case DW_ExprOp_Reg29:
|
||||
case DW_ExprOp_Reg30: case DW_ExprOp_Reg31: {
|
||||
// implicit operands
|
||||
} break;
|
||||
case DW_ExprOp_RegX: { cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64); } break;
|
||||
case DW_ExprOp_ImplicitValue: {
|
||||
U64 value_size = 0; String8 value = {0};
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &value_size);
|
||||
cursor += str8_deserial_read_block(data, cursor, value_size, &operands[0].block);
|
||||
} break;
|
||||
case DW_ExprOp_Piece: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
} break;
|
||||
case DW_ExprOp_BitPiece: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64);
|
||||
} break;
|
||||
case DW_ExprOp_Pick: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8);
|
||||
} break;
|
||||
case DW_ExprOp_PlusUConst: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
} break;
|
||||
case DW_ExprOp_Skip: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].s16);
|
||||
} break;
|
||||
case DW_ExprOp_Bra: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].s16);
|
||||
} break;
|
||||
case DW_ExprOp_BReg0: case DW_ExprOp_BReg1: case DW_ExprOp_BReg2:
|
||||
case DW_ExprOp_BReg3: case DW_ExprOp_BReg4: case DW_ExprOp_BReg5:
|
||||
case DW_ExprOp_BReg6: case DW_ExprOp_BReg7: case DW_ExprOp_BReg8:
|
||||
case DW_ExprOp_BReg9: case DW_ExprOp_BReg10: case DW_ExprOp_BReg11:
|
||||
case DW_ExprOp_BReg12: case DW_ExprOp_BReg13: case DW_ExprOp_BReg14:
|
||||
case DW_ExprOp_BReg15: case DW_ExprOp_BReg16: case DW_ExprOp_BReg17:
|
||||
case DW_ExprOp_BReg18: case DW_ExprOp_BReg19: case DW_ExprOp_BReg20:
|
||||
case DW_ExprOp_BReg21: case DW_ExprOp_BReg22: case DW_ExprOp_BReg23:
|
||||
case DW_ExprOp_BReg24: case DW_ExprOp_BReg25: case DW_ExprOp_BReg26:
|
||||
case DW_ExprOp_BReg27: case DW_ExprOp_BReg28: case DW_ExprOp_BReg29:
|
||||
case DW_ExprOp_BReg30: case DW_ExprOp_BReg31: {
|
||||
cursor += str8_deserial_read_sleb128(data, cursor, &operands[0].s64);
|
||||
} break;
|
||||
case DW_ExprOp_BRegX: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
cursor += str8_deserial_read_sleb128(data, cursor, &operands[1].s64);
|
||||
} break;
|
||||
case DW_ExprOp_FBReg: {
|
||||
cursor += str8_deserial_read_sleb128(data, cursor, &operands[0].s64);
|
||||
} break;
|
||||
case DW_ExprOp_Deref: {
|
||||
// no operands
|
||||
} break;
|
||||
case DW_ExprOp_DerefSize: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8);
|
||||
} break;
|
||||
case DW_ExprOp_XDerefSize: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8);
|
||||
} break;
|
||||
case DW_ExprOp_Call2: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u16);
|
||||
} break;
|
||||
case DW_ExprOp_Call4: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u32);
|
||||
} break;
|
||||
case DW_ExprOp_CallRef: {
|
||||
cursor += str8_deserial_read_dwarf_uint(data, cursor, format, &operands[0].u64);
|
||||
} break;
|
||||
case DW_ExprOp_ImplicitPointer:
|
||||
case DW_ExprOp_GNU_ImplicitPointer: {
|
||||
cursor += str8_deserial_read_dwarf_uint(data, cursor, format, &operands[0].u64);
|
||||
cursor += str8_deserial_read_sleb128(data, cursor, &operands[1].s64);
|
||||
} break;
|
||||
case DW_ExprOp_Convert:
|
||||
case DW_ExprOp_GNU_Convert: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
} break;
|
||||
case DW_ExprOp_GNU_ParameterRef: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u32);
|
||||
} break;
|
||||
case DW_ExprOp_DerefType:
|
||||
case DW_ExprOp_GNU_DerefType: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8);
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64);
|
||||
} break;
|
||||
case DW_ExprOp_XDerefType: {
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[0].u8);
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64);
|
||||
} break;
|
||||
case DW_ExprOp_ConstType:
|
||||
case DW_ExprOp_GNU_ConstType: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
cursor += str8_deserial_read_struct(data, cursor, &operands[1].u8);
|
||||
cursor += str8_deserial_read_block(data, cursor, operands[1].u8, &operands[2].block);
|
||||
} break;
|
||||
case DW_ExprOp_RegvalType: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[1].u64);
|
||||
} break;
|
||||
case DW_ExprOp_EntryValue:
|
||||
case DW_ExprOp_GNU_EntryValue: {
|
||||
U64 entry_value_expr_size = 0;
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &entry_value_expr_size);
|
||||
cursor += str8_deserial_read_block(data, cursor, entry_value_expr_size, &operands[0].block);
|
||||
} break;
|
||||
case DW_ExprOp_Addrx: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
} break;
|
||||
case DW_ExprOp_Constx: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
} break;
|
||||
case DW_ExprOp_CallFrameCfa:
|
||||
case DW_ExprOp_FormTlsAddress:
|
||||
case DW_ExprOp_PushObjectAddress:
|
||||
case DW_ExprOp_Nop:
|
||||
case DW_ExprOp_Eq:
|
||||
case DW_ExprOp_Ge:
|
||||
case DW_ExprOp_Gt:
|
||||
case DW_ExprOp_Le:
|
||||
case DW_ExprOp_Lt:
|
||||
case DW_ExprOp_Ne:
|
||||
case DW_ExprOp_Shl:
|
||||
case DW_ExprOp_Shr:
|
||||
case DW_ExprOp_Shra:
|
||||
case DW_ExprOp_Xor:
|
||||
case DW_ExprOp_XDeref:
|
||||
case DW_ExprOp_Abs:
|
||||
case DW_ExprOp_And:
|
||||
case DW_ExprOp_Div:
|
||||
case DW_ExprOp_Minus:
|
||||
case DW_ExprOp_Mod:
|
||||
case DW_ExprOp_Mul:
|
||||
case DW_ExprOp_Neg:
|
||||
case DW_ExprOp_Not:
|
||||
case DW_ExprOp_Or:
|
||||
case DW_ExprOp_Plus:
|
||||
case DW_ExprOp_Rot:
|
||||
case DW_ExprOp_Swap:
|
||||
case DW_ExprOp_Dup:
|
||||
case DW_ExprOp_Drop:
|
||||
case DW_ExprOp_Over:
|
||||
case DW_ExprOp_StackValue:
|
||||
case DW_ExprOp_GNU_PushTlsAddress: {
|
||||
// no operands
|
||||
} break;
|
||||
case DW_ExprOp_GNU_AddrIndex: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
} break;
|
||||
case DW_ExprOp_GNU_ConstIndex: {
|
||||
cursor += str8_deserial_read_uleb128(data, cursor, &operands[0].u64);
|
||||
} break;
|
||||
default: { InvalidPath; } break;
|
||||
}
|
||||
|
||||
U64 operand_count = dw_operand_count_from_expr_op(opcode);
|
||||
DW_ExprInst *inst = push_array(arena, DW_ExprInst, 1);
|
||||
inst->opcode = opcode;
|
||||
inst->size = cursor - inst_start;
|
||||
inst->operands = push_array(arena, DW_ExprOperand, operand_count);
|
||||
MemoryCopy(inst->operands, operands, operand_count * sizeof(DW_ExprOperand));
|
||||
|
||||
DLLPushBack(expr.first, expr.last, inst);
|
||||
expr.count += 1;
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
internal void
|
||||
dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n)
|
||||
{
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
}
|
||||
|
||||
internal DW_CFA_InstNode *
|
||||
dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v)
|
||||
{
|
||||
DW_CFA_InstNode *n = push_array(arena, DW_CFA_InstNode, 1);
|
||||
n->v = v;
|
||||
dw_cfa_inst_list_push_node(list, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out)
|
||||
{
|
||||
U64 read_size = 0;
|
||||
if (cie->segment_selector_size) {
|
||||
NotImplemented;
|
||||
} else {
|
||||
read_size = str8_deserial_read(data, 0, ptr_out, cie->address_size, cie->address_size);
|
||||
}
|
||||
return read_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out)
|
||||
{
|
||||
U32 first_four_bytes = 0;
|
||||
str8_deserial_read_struct(data, off, &first_four_bytes);
|
||||
DW_Format format = first_four_bytes == max_U32 ? DW_Format_64Bit : DW_Format_32Bit;
|
||||
|
||||
U64 length = 0;
|
||||
U64 length_size = str8_deserial_read_dwarf_packed_size(data, off, &length);
|
||||
if (length_size == 0) { goto exit; }
|
||||
|
||||
Rng1U64 entry_range = rng_1u64(off, off + length_size + length);
|
||||
String8 entry_data = str8_substr(data, entry_range);
|
||||
U64 id = 0;
|
||||
U64 id_size = str8_deserial_read_dwarf_uint(entry_data, length_size, format, &id);
|
||||
if (id_size == 0) { goto exit; }
|
||||
|
||||
U64 id_type = format == DW_Format_32Bit ? max_U32 : max_U64;
|
||||
desc_out->format = format;
|
||||
desc_out->type = (id == id_type) ? DW_DescriptorEntryType_CIE : DW_DescriptorEntryType_FDE;
|
||||
desc_out->entry_range = entry_range;
|
||||
|
||||
exit:;
|
||||
return length + length_size;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out)
|
||||
{
|
||||
B32 is_parsed = 0;
|
||||
U64 cursor = format == DW_Format_32Bit ? 4 : 12;
|
||||
|
||||
U64 cie_id = 0;
|
||||
U64 cie_id_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_id);
|
||||
if (cie_id_size == 0) { goto exit; }
|
||||
cursor += cie_id_size;
|
||||
|
||||
U8 version = 0;
|
||||
U64 version_size = str8_deserial_read_struct(data, cursor, &version);
|
||||
if (version_size == 0) { goto exit; }
|
||||
cursor += version_size;
|
||||
|
||||
String8 aug_string = {0};
|
||||
U64 aug_string_size = str8_deserial_read_cstr(data, cursor, &aug_string);
|
||||
if (aug_string_size == 0) { goto exit; }
|
||||
cursor += aug_string_size;
|
||||
|
||||
U8 address_size = 0;
|
||||
U8 segment_selector_size = 0;
|
||||
if (version >= DW_Version_4) {
|
||||
U64 address_size_size = str8_deserial_read_struct(data, cursor, &address_size);
|
||||
if (address_size_size == 0) { goto exit; }
|
||||
cursor += address_size_size;
|
||||
|
||||
U64 segment_selector_size_size = str8_deserial_read_struct(data, cursor, &segment_selector_size);
|
||||
if (segment_selector_size_size == 0) { goto exit; }
|
||||
cursor += segment_selector_size;
|
||||
} else {
|
||||
address_size = byte_size_from_arch(arch);
|
||||
}
|
||||
|
||||
U64 code_align_factor = 0;
|
||||
U64 code_align_factor_size = str8_deserial_read_uleb128(data, cursor, &code_align_factor);
|
||||
if (code_align_factor_size == 0) { goto exit; }
|
||||
cursor += code_align_factor_size;
|
||||
|
||||
S64 data_align_factor = 0;
|
||||
U64 data_align_factor_size = str8_deserial_read_sleb128(data, cursor, &data_align_factor);
|
||||
if (data_align_factor_size == 0) { goto exit; }
|
||||
cursor += data_align_factor_size;
|
||||
|
||||
U64 ret_addr_reg = 0;
|
||||
U64 ret_addr_reg_size = 0;
|
||||
if (version == DW_Version_1) { ret_addr_reg_size = str8_deserial_read(data, cursor, &ret_addr_reg, sizeof(U8), sizeof(U8)); }
|
||||
else { ret_addr_reg_size = str8_deserial_read_uleb128(data, cursor, &ret_addr_reg); }
|
||||
if (ret_addr_reg_size == 0) { goto exit; }
|
||||
cursor += ret_addr_reg_size;
|
||||
|
||||
if (aug_string.size > 0) { goto exit; }
|
||||
|
||||
cie_out->insts = str8_skip(data, cursor);
|
||||
cie_out->aug_string = aug_string;
|
||||
cie_out->code_align_factor = code_align_factor;
|
||||
cie_out->data_align_factor = data_align_factor;
|
||||
cie_out->ret_addr_reg = ret_addr_reg;
|
||||
cie_out->format = format;
|
||||
cie_out->version = version;
|
||||
cie_out->address_size = address_size;
|
||||
cie_out->segment_selector_size = segment_selector_size;
|
||||
|
||||
is_parsed = 1;
|
||||
exit:;
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal B32
|
||||
dw_parse_fde(String8 data,
|
||||
DW_Format format,
|
||||
DW_CIEFromOffsetFunc *cie_from_offset_func,
|
||||
void *cie_from_offset_ud,
|
||||
DW_FDE *fde_out)
|
||||
{
|
||||
B32 is_parsed = 0;
|
||||
U64 cursor = format == DW_Format_32Bit ? 4 : 12;
|
||||
|
||||
// extract CIE pointer
|
||||
U64 cie_pointer = 0;
|
||||
U64 cie_pointer_size = str8_deserial_read_dwarf_uint(data, cursor, format, &cie_pointer);
|
||||
if (cie_pointer_size == 0) { goto exit; }
|
||||
cursor += cie_pointer_size;
|
||||
|
||||
// map offset -> CIE
|
||||
DW_CIE *cie = cie_from_offset_func(cie_from_offset_ud, cie_pointer);
|
||||
if (cie == 0) { goto exit; }
|
||||
|
||||
// extract address of first instruction
|
||||
U64 pc_begin = 0;
|
||||
U64 pc_begin_size = dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_begin);
|
||||
if (pc_begin_size == 0) { goto exit; }
|
||||
cursor += pc_begin_size;
|
||||
|
||||
// extract instruction range size
|
||||
U64 pc_range = 0;
|
||||
U64 pc_range_size = dw_read_debug_frame_ptr(str8_skip(data, cursor), cie, &pc_range);
|
||||
if (pc_range_size == 0) { goto exit; }
|
||||
cursor += pc_range_size;
|
||||
|
||||
// parse augmentation data
|
||||
String8 aug_data = str8_substr(data, rng_1u64(cursor, cursor + cie->aug_data.size));
|
||||
cursor += cie->aug_data.size;
|
||||
|
||||
// commit values to out
|
||||
fde_out->format = format;
|
||||
fde_out->cie_pointer = cie_pointer;
|
||||
fde_out->pc_range = rng_1u64(pc_begin, pc_begin + pc_range);
|
||||
fde_out->insts = str8_skip(data, cursor);
|
||||
|
||||
is_parsed = 1;
|
||||
exit:;
|
||||
return is_parsed;
|
||||
}
|
||||
|
||||
internal DW_CFA_ParseErrorCode
|
||||
dw_parse_cfa_inst(String8 data,
|
||||
U64 code_align_factor,
|
||||
S64 data_align_factor,
|
||||
DW_DecodePtr *decode_ptr_func,
|
||||
void *decode_ptr_ud,
|
||||
U64 *bytes_read_out,
|
||||
DW_CFA_Inst *inst_out)
|
||||
{
|
||||
*bytes_read_out = 0;
|
||||
|
||||
DW_CFA_ParseErrorCode error_code = DW_CFA_ParseErrorCode_End;
|
||||
U64 cursor = 0;
|
||||
|
||||
// read opcode
|
||||
DW_CFA_Opcode raw_opcode = 0;
|
||||
U64 raw_opcode_size = str8_deserial_read_struct(data, cursor, &raw_opcode);
|
||||
if (raw_opcode_size == 0) { goto exit; }
|
||||
cursor += raw_opcode_size;
|
||||
|
||||
// decode opcode implicit operand
|
||||
U64 opcode = raw_opcode & ~DW_CFA_Mask_OpcodeHi;
|
||||
U64 implicit_operand = 0;
|
||||
if ((raw_opcode & DW_CFA_Mask_OpcodeHi) != 0) {
|
||||
opcode = raw_opcode & DW_CFA_Mask_OpcodeHi;
|
||||
implicit_operand = raw_opcode & DW_CFA_Mask_Operand;
|
||||
}
|
||||
|
||||
// decode operands
|
||||
DW_CFA_Operand operands[DW_CFA_OperandMax] = {0};
|
||||
switch (opcode) {
|
||||
case DW_CFA_SetLoc: {
|
||||
U64 address_size = decode_ptr_func(str8_skip(data, cursor), decode_ptr_ud, &operands[0].u64);
|
||||
if (address_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += address_size;
|
||||
} break;
|
||||
case DW_CFA_AdvanceLoc: {
|
||||
operands[0].u64 = implicit_operand * code_align_factor;
|
||||
} break;
|
||||
case DW_CFA_AdvanceLoc1: {
|
||||
U8 delta = 0;
|
||||
U64 delta_size = str8_deserial_read_struct(data, cursor, &delta);
|
||||
if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += delta_size;
|
||||
operands[0].u64 = delta * code_align_factor;
|
||||
} break;
|
||||
case DW_CFA_AdvanceLoc2: {
|
||||
U16 delta = 0;
|
||||
U64 delta_size = str8_deserial_read_struct(data, cursor, &delta);
|
||||
if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += delta_size;
|
||||
operands[0].u64 = delta * code_align_factor;
|
||||
} break;
|
||||
case DW_CFA_AdvanceLoc4: {
|
||||
U32 delta = 0;
|
||||
U64 delta_size = str8_deserial_read_struct(data, cursor, &delta);
|
||||
if (delta_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
operands[0].u64 = delta * code_align_factor;
|
||||
} break;
|
||||
case DW_CFA_DefCfa: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
U64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = reg;
|
||||
operands[1].u64 = offset;
|
||||
} break;
|
||||
case DW_CFA_DefCfaSf: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
S64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = reg;
|
||||
operands[1].s64 = offset * data_align_factor;
|
||||
} break;
|
||||
case DW_CFA_DefCfaRegister: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
operands[0].u64 = reg;
|
||||
} break;
|
||||
case DW_CFA_DefCfaOffset: {
|
||||
U64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = offset;
|
||||
} break;
|
||||
case DW_CFA_DefCfaOffsetSf: {
|
||||
U64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = offset * data_align_factor;
|
||||
} break;
|
||||
case DW_CFA_DefCfaExpr: {
|
||||
U64 expr_size = 0;
|
||||
U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size);
|
||||
if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += expr_size_size;
|
||||
|
||||
if (cursor + expr_size > data.size) { goto exit; }
|
||||
String8 expr = str8_prefix(str8_skip(data, cursor), expr_size);
|
||||
|
||||
operands[0].block = expr;
|
||||
cursor += expr_size;
|
||||
} break;
|
||||
case DW_CFA_Undefined: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
operands[0].u64 = reg;
|
||||
} break;
|
||||
case DW_CFA_SameValue: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
operands[0].u64 = reg;
|
||||
} break;
|
||||
case DW_CFA_Offset: {
|
||||
U64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = implicit_operand;
|
||||
operands[1].s64 = (S64)offset * data_align_factor;
|
||||
} break;
|
||||
case DW_CFA_OffsetExt: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
U64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = reg;
|
||||
operands[1].u64 = offset * data_align_factor;
|
||||
} break;
|
||||
case DW_CFA_OffsetExtSf: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
S64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = reg;
|
||||
operands[1].s64 = offset * data_align_factor;
|
||||
} break;
|
||||
case DW_CFA_ValOffset: {
|
||||
U64 val = 0;
|
||||
U64 val_size = str8_deserial_read_uleb128(data, cursor, &val);
|
||||
if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += val_size;
|
||||
|
||||
U64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_uleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = val;
|
||||
operands[1].u64 = offset * data_align_factor;
|
||||
} break;
|
||||
case DW_CFA_ValOffsetSf: {
|
||||
U64 val = 0;
|
||||
U64 val_size = str8_deserial_read_uleb128(data, cursor, &val);
|
||||
if (val_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += val_size;
|
||||
|
||||
S64 offset = 0;
|
||||
U64 offset_size = str8_deserial_read_sleb128(data, cursor, &offset);
|
||||
if (offset_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += offset_size;
|
||||
|
||||
operands[0].u64 = val;
|
||||
operands[1].s64 = offset;
|
||||
} break;
|
||||
case DW_CFA_Register: {
|
||||
U64 dst_reg = 0;
|
||||
U64 dst_reg_size = str8_deserial_read_uleb128(data, cursor, &dst_reg);
|
||||
if (dst_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += dst_reg_size;
|
||||
|
||||
U64 src_reg = 0;
|
||||
U64 src_reg_size = str8_deserial_read_uleb128(data, cursor, &src_reg);
|
||||
if (src_reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += src_reg_size;
|
||||
|
||||
operands[0].u64 = dst_reg;
|
||||
operands[1].u64 = src_reg;
|
||||
} break;
|
||||
case DW_CFA_Expr: {
|
||||
U64 reg = 0;
|
||||
U64 reg_size = str8_deserial_read_uleb128(data, cursor, ®);
|
||||
if (reg_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += reg_size;
|
||||
|
||||
U64 expr_size = 0;
|
||||
U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size);
|
||||
if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += expr_size_size;
|
||||
|
||||
if (cursor + expr_size > data.size) { goto exit; }
|
||||
String8 expr = str8_prefix(str8_skip(data, cursor), expr_size);
|
||||
cursor += expr_size;
|
||||
|
||||
operands[0].block = expr;
|
||||
} break;
|
||||
case DW_CFA_ValExpr: {
|
||||
U64 val = 0;
|
||||
U64 val_size = str8_deserial_read_uleb128(data, cursor, &val);
|
||||
if (val_size == 0) { goto exit; }
|
||||
cursor += val_size;
|
||||
|
||||
U64 expr_size = 0;
|
||||
U64 expr_size_size = str8_deserial_read_uleb128(data, cursor, &expr_size);
|
||||
if (expr_size_size == 0) { error_code = DW_CFA_ParseErrorCode_OutOfData; goto exit; }
|
||||
cursor += expr_size_size;
|
||||
|
||||
if (cursor + expr_size > data.size) { goto exit; }
|
||||
String8 expr = str8_prefix(str8_skip(data, cursor), expr_size);
|
||||
cursor += expr_size;
|
||||
|
||||
operands[0].u64 = val;
|
||||
operands[1].block = expr;
|
||||
} break;
|
||||
case DW_CFA_Restore: {
|
||||
operands[0].u64 = implicit_operand;
|
||||
} break;
|
||||
case DW_CFA_RestoreExt: {} break;
|
||||
case DW_CFA_RememberState: {} break;
|
||||
case DW_CFA_RestoreState: {} break;
|
||||
case DW_CFA_Nop: {} break;
|
||||
default: { NotImplemented; goto exit; } break;
|
||||
}
|
||||
|
||||
// fill out output
|
||||
inst_out->opcode = opcode;
|
||||
MemoryCopyTyped(&inst_out->operands[0], &operands[0], DW_CFA_OperandMax);
|
||||
|
||||
*bytes_read_out = cursor;
|
||||
|
||||
error_code = DW_CFA_ParseErrorCode_NewInst;
|
||||
|
||||
exit:;
|
||||
return error_code;
|
||||
}
|
||||
|
||||
internal DW_CFA_InstList
|
||||
dw_parse_cfa_inst_list(Arena *arena,
|
||||
String8 data,
|
||||
U64 code_align_factor,
|
||||
S64 data_align_factor,
|
||||
DW_DecodePtr *decode_ptr_func,
|
||||
void *decode_ptr_ud)
|
||||
{
|
||||
U64 pos = arena_pos(arena);
|
||||
DW_CFA_InstList list = {0};
|
||||
for (U64 cursor = 0, inst_size;; cursor += inst_size) {
|
||||
DW_CFA_Inst inst = {0};
|
||||
DW_CFA_ParseErrorCode error_code = dw_parse_cfa_inst(str8_skip(data, cursor), code_align_factor, data_align_factor, decode_ptr_func, decode_ptr_ud, &inst_size, &inst);
|
||||
if (error_code == DW_CFA_ParseErrorCode_End) { break; }
|
||||
if (error_code != DW_CFA_ParseErrorCode_NewInst) {
|
||||
MemoryZeroStruct(&list);
|
||||
arena_pop_to(arena, pos);
|
||||
break;
|
||||
}
|
||||
dw_cfa_inst_list_push(arena, &list, inst);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
internal
|
||||
DW_DECODE_PTR(dw_decode_ptr_debug_frame)
|
||||
{
|
||||
return dw_read_debug_frame_ptr(data, ud, ptr_out);
|
||||
}
|
||||
|
||||
|
||||
+132
-21
@@ -319,6 +319,118 @@ typedef struct DW_Reference
|
||||
U64 info_off;
|
||||
} DW_Reference;
|
||||
|
||||
////////////////////////////////
|
||||
//~ Expression
|
||||
|
||||
typedef union DW_ExprOperand
|
||||
{
|
||||
U8 u8;
|
||||
U16 u16;
|
||||
U32 u32;
|
||||
U64 u64;
|
||||
|
||||
S8 s8;
|
||||
S16 s16;
|
||||
S32 s32;
|
||||
S64 s64;
|
||||
|
||||
String8 block;
|
||||
} DW_ExprOperand;
|
||||
|
||||
typedef struct DW_ExprInst
|
||||
{
|
||||
DW_ExprOp opcode;
|
||||
DW_ExprOperand *operands;
|
||||
U64 size;
|
||||
struct DW_ExprInst *next;
|
||||
struct DW_ExprInst *prev;
|
||||
} DW_ExprInst;
|
||||
|
||||
typedef struct DW_Expr
|
||||
{
|
||||
U64 count;
|
||||
DW_ExprInst *first;
|
||||
DW_ExprInst *last;
|
||||
} DW_Expr;
|
||||
|
||||
////////////////////////////////
|
||||
// .debug_frame
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DW_DescriptorEntryType_Null,
|
||||
DW_DescriptorEntryType_CIE,
|
||||
DW_DescriptorEntryType_FDE
|
||||
} DW_DescriptorEntryType;
|
||||
|
||||
typedef struct DW_DescriptorEntry
|
||||
{
|
||||
DW_DescriptorEntryType type;
|
||||
DW_Format format;
|
||||
Rng1U64 entry_range;
|
||||
} DW_DescriptorEntry;
|
||||
|
||||
typedef struct DW_CIE
|
||||
{
|
||||
String8 insts;
|
||||
String8 aug_string;
|
||||
String8 aug_data;
|
||||
U64 code_align_factor;
|
||||
S64 data_align_factor;
|
||||
U64 ret_addr_reg;
|
||||
DW_Format format;
|
||||
U8 version;
|
||||
U8 address_size;
|
||||
U8 segment_selector_size;
|
||||
} DW_CIE;
|
||||
|
||||
typedef struct DW_FDE
|
||||
{
|
||||
DW_Format format;
|
||||
U64 cie_pointer;
|
||||
Rng1U64 pc_range;
|
||||
String8 insts;
|
||||
} DW_FDE;
|
||||
|
||||
typedef union DW_CFA_Operand
|
||||
{
|
||||
U64 u64;
|
||||
S64 s64;
|
||||
String8 block;
|
||||
} DW_CFA_Operand;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DW_CFA_ParseErrorCode_NewInst,
|
||||
DW_CFA_ParseErrorCode_End,
|
||||
DW_CFA_ParseErrorCode_OutOfData
|
||||
} DW_CFA_ParseErrorCode;
|
||||
|
||||
typedef struct DW_CFA_Inst
|
||||
{
|
||||
DW_CFA_Opcode opcode;
|
||||
DW_CFA_Operand operands[DW_CFA_OperandMax];
|
||||
} DW_CFA_Inst;
|
||||
|
||||
typedef struct DW_CFA_InstNode
|
||||
{
|
||||
DW_CFA_Inst v;
|
||||
struct DW_CFA_InstNode *next;
|
||||
} DW_CFA_InstNode;
|
||||
|
||||
typedef struct DW_CFA_InstList
|
||||
{
|
||||
U64 count;
|
||||
DW_CFA_InstNode *first;
|
||||
DW_CFA_InstNode *last;
|
||||
} DW_CFA_InstList;
|
||||
|
||||
#define DW_DECODE_PTR(name) U64 name(String8 data, void *ud, U64 *ptr_out)
|
||||
typedef DW_DECODE_PTR(DW_DecodePtr);
|
||||
|
||||
#define DW_CIE_FROM_OFFSET_FUNC(name) DW_CIE * name(void *ud, U64 offset)
|
||||
typedef DW_CIE_FROM_OFFSET_FUNC(DW_CIEFromOffsetFunc);
|
||||
|
||||
// hasher
|
||||
|
||||
internal U64 dw_hash_from_string(String8 string);
|
||||
@@ -417,27 +529,8 @@ internal DW_TagNode * dw_tag_node_from_info_off(DW_CompUnit *cu, U64 info_off);
|
||||
|
||||
// line info
|
||||
|
||||
internal U64 dw_read_line_file(String8 line_data,
|
||||
U64 line_off,
|
||||
DW_Input *input,
|
||||
DW_Version unit_version,
|
||||
DW_Format unit_format,
|
||||
DW_Ext ext,
|
||||
U64 address_size,
|
||||
DW_ListUnit *str_offsets,
|
||||
U64 enc_count,
|
||||
U64 *enc_arr,
|
||||
DW_LineFile *line_file_out);
|
||||
internal U64 dw_read_line_vm_header(Arena *arena,
|
||||
String8 line_data,
|
||||
U64 line_off,
|
||||
DW_Input *input,
|
||||
String8 cu_dir,
|
||||
String8 cu_name,
|
||||
U8 cu_address_size,
|
||||
DW_ListUnit *cu_str_offsets,
|
||||
DW_LineVMHeader *header_out);
|
||||
|
||||
internal U64 dw_read_line_file(String8 line_data, U64 line_off, DW_Input *input, DW_Version unit_version, DW_Format unit_format, DW_Ext ext, U64 address_size, DW_ListUnit *str_offsets, U64 enc_count, U64 *enc_arr, DW_LineFile *line_file_out);
|
||||
internal U64 dw_read_line_vm_header(Arena *arena, String8 line_data, U64 line_off, DW_Input *input, String8 cu_dir, String8 cu_name, U8 cu_address_size, DW_ListUnit *cu_str_offsets, DW_LineVMHeader *header_out);
|
||||
internal void dw_line_vm_reset(DW_LineVMState *state, B32 default_is_stmt);
|
||||
internal void dw_line_vm_advance(DW_LineVMState *state, U64 advance, U64 min_inst_len, U64 max_ops_for_inst);
|
||||
internal DW_LineSeqNode * dw_push_line_seq(Arena* arena, DW_LineTableParseResult *parsed_tbl);
|
||||
@@ -451,4 +544,22 @@ internal DW_LineTableParseResult dw_parsed_line_table_from_data(Arena *arena, St
|
||||
|
||||
internal DW_PubStringsTable dw_v4_pub_strings_table_from_section_kind(Arena *arena, DW_Input *input, DW_SectionKind section_kind);
|
||||
|
||||
// expression
|
||||
|
||||
internal DW_Expr dw_expr_from_data(Arena *arena, DW_Format format, U64 addr_size, String8 data);
|
||||
|
||||
// debug frame
|
||||
|
||||
internal void dw_cfa_inst_list_push_node(DW_CFA_InstList *list, DW_CFA_InstNode *n);
|
||||
internal DW_CFA_InstNode * dw_cfa_inst_list_push(Arena *arena, DW_CFA_InstList *list, DW_CFA_Inst v);
|
||||
|
||||
internal U64 dw_read_debug_frame_ptr(String8 data, DW_CIE *cie, U64 *ptr_out);
|
||||
|
||||
internal U64 dw_parse_descriptor_entry_header(String8 data, U64 off, DW_DescriptorEntry *desc_out);
|
||||
internal B32 dw_parse_cie(String8 data, DW_Format format, Arch arch, DW_CIE *cie_out);
|
||||
internal B32 dw_parse_fde(String8 data, DW_Format format, DW_CIEFromOffsetFunc *cie_from_offset_func, void *cie_from_offset_ud, DW_FDE *fde_out);
|
||||
|
||||
internal DW_CFA_ParseErrorCode dw_parse_cfa_inst(String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud, U64 *bytes_read_out, DW_CFA_Inst *inst_out);
|
||||
internal DW_CFA_InstList dw_parse_cfa_inst_list(Arena *arena, String8 data, U64 code_align_factor, S64 data_align_factor, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
|
||||
|
||||
#endif // DWARF_PARSE_H
|
||||
|
||||
+261
-1152
File diff suppressed because it is too large
Load Diff
+59
-190
@@ -4,221 +4,90 @@
|
||||
#ifndef DWARF_UNWIND_H
|
||||
#define DWARF_UNWIND_H
|
||||
|
||||
typedef struct DW_UnwindResult
|
||||
typedef enum DW_CFI_RegisterRule
|
||||
{
|
||||
B32 is_invalid;
|
||||
B32 missed_read;
|
||||
U64 missed_read_addr;
|
||||
U64 stack_pointer;
|
||||
} DW_UnwindResult;
|
||||
DW_CFI_RegisterRule_Undefined,
|
||||
DW_CFI_RegisterRule_SameValue,
|
||||
DW_CFI_RegisterRule_Offset,
|
||||
DW_CFI_RegisterRule_ValOffset,
|
||||
DW_CFI_RegisterRule_Register,
|
||||
DW_CFI_RegisterRule_Expression,
|
||||
DW_CFI_RegisterRule_ValExpression,
|
||||
DW_CFI_RegisterRule_Architectural
|
||||
} DW_CFI_RegisterRule;
|
||||
|
||||
// EH: Exception Frames
|
||||
|
||||
typedef U8 DW_EhPtrEnc;
|
||||
enum
|
||||
typedef enum DW_CFA_Rule
|
||||
{
|
||||
DW_EhPtrEnc_TypeMask = 0x0F,
|
||||
DW_EhPtrEnc_Ptr = 0x00, // Pointer sized unsigned value
|
||||
DW_EhPtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value
|
||||
DW_EhPtrEnc_UData2 = 0x02, // Unsigned 16-bit value
|
||||
DW_EhPtrEnc_UData4 = 0x03, // Unsigned 32-bit value
|
||||
DW_EhPtrEnc_UData8 = 0x04, // Unsigned 64-bit value
|
||||
DW_EhPtrEnc_Signed = 0x08, // Signed pointer
|
||||
DW_EhPtrEnc_SLEB128 = 0x09, // Signed LE base-128 value
|
||||
DW_EhPtrEnc_SData2 = 0x0A, // Signed 16-bit value
|
||||
DW_EhPtrEnc_SData4 = 0x0B, // Signed 32-bit value
|
||||
DW_EhPtrEnc_SData8 = 0x0C, // Signed 64-bit value
|
||||
};
|
||||
DW_CFA_Rule_Null,
|
||||
DW_CFA_Rule_RegOff,
|
||||
DW_CFA_Rule_Expression
|
||||
} DW_CFA_Rule;
|
||||
|
||||
enum
|
||||
typedef struct DW_CFA
|
||||
{
|
||||
DW_EhPtrEnc_ModifyMask = 0x70,
|
||||
DW_EhPtrEnc_PcRel = 0x10, // Value is relative to the current program counter.
|
||||
DW_EhPtrEnc_TextRel = 0x20, // Value is relative to the .text section.
|
||||
DW_EhPtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section.
|
||||
DW_EhPtrEnc_FuncRel = 0x40, // Value is relative to the function.
|
||||
DW_EhPtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary.
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DW_EhPtrEnc_Indirect = 0x80, // This flag indicates that value is stored in virtual memory.
|
||||
DW_EhPtrEnc_Omit = 0xFF,
|
||||
};
|
||||
|
||||
typedef struct DW_EhPtrCtx
|
||||
{
|
||||
U64 raw_base_vaddr; // address where pointer is being read
|
||||
U64 text_vaddr; // base address of section with instructions (used for encoding pointer on SH and IA64)
|
||||
U64 data_vaddr; // base address of data section (used for encoding pointer on x86-64)
|
||||
U64 func_vaddr; // base address of function where IP is located
|
||||
} DW_EhPtrCtx;
|
||||
|
||||
// CIE: Common Information Entry
|
||||
typedef struct DW_CIEUnpacked
|
||||
{
|
||||
U8 version;
|
||||
DW_EhPtrEnc lsda_encoding;
|
||||
DW_EhPtrEnc addr_encoding;
|
||||
|
||||
B32 has_augmentation_size;
|
||||
U64 augmentation_size;
|
||||
String8 augmentation;
|
||||
|
||||
U64 code_align_factor;
|
||||
S64 data_align_factor;
|
||||
U64 ret_addr_reg;
|
||||
|
||||
U64 handler_ip;
|
||||
|
||||
Rng1U64 cfi_range;
|
||||
} DW_CIEUnpacked;
|
||||
|
||||
typedef struct DW_CIEUnpackedNode
|
||||
{
|
||||
struct DW_CIEUnpackedNode *next;
|
||||
DW_CIEUnpacked cie;
|
||||
U64 offset;
|
||||
} DW_CIEUnpackedNode;
|
||||
|
||||
// FDE: Frame Description Entry
|
||||
typedef struct DW_FDEUnpacked
|
||||
{
|
||||
Rng1U64 ip_voff_range;
|
||||
U64 lsda_ip;
|
||||
Rng1U64 cfi_range;
|
||||
} DW_FDEUnpacked;
|
||||
|
||||
// CFI: Call Frame Information
|
||||
typedef struct DW_CFIRecords
|
||||
{
|
||||
B32 valid;
|
||||
DW_CIEUnpacked cie;
|
||||
DW_FDEUnpacked fde;
|
||||
} DW_CFIRecords;
|
||||
|
||||
typedef enum DW_CFICFARule{
|
||||
DW_CFI_CFA_Rule_RegOff,
|
||||
DW_CFI_CFA_Rule_Expr,
|
||||
} DW_CFICFARule;
|
||||
|
||||
typedef struct DW_CFICFACell
|
||||
{
|
||||
DW_CFICFARule rule;
|
||||
DW_CFA_Rule rule;
|
||||
union {
|
||||
struct {
|
||||
U64 reg_idx;
|
||||
S64 offset;
|
||||
DW_Reg reg;
|
||||
S64 off;
|
||||
};
|
||||
Rng1U64 expr;
|
||||
String8 expr;
|
||||
};
|
||||
} DW_CFICFACell;
|
||||
} DW_CFA;
|
||||
|
||||
typedef enum DW_CFIRegisterRule
|
||||
typedef struct DW_CFI_Register
|
||||
{
|
||||
DW_CFIRegisterRule_SameValue,
|
||||
DW_CFIRegisterRule_Undefined,
|
||||
DW_CFIRegisterRule_Offset,
|
||||
DW_CFIRegisterRule_ValOffset,
|
||||
DW_CFIRegisterRule_Register,
|
||||
DW_CFIRegisterRule_Expression,
|
||||
DW_CFIRegisterRule_ValExpression,
|
||||
} DW_CFIRegisterRule;
|
||||
|
||||
typedef struct DW_CFICell
|
||||
{
|
||||
DW_CFIRegisterRule rule;
|
||||
DW_CFI_RegisterRule rule;
|
||||
union {
|
||||
S64 n;
|
||||
Rng1U64 expr;
|
||||
S64 n;
|
||||
String8 expr;
|
||||
};
|
||||
} DW_CFICell;
|
||||
} DW_CFI_Register;
|
||||
|
||||
typedef struct DW_CFIRow
|
||||
typedef struct DW_CFA_Row
|
||||
{
|
||||
struct DW_CFIRow *next;
|
||||
DW_CFICell *cells;
|
||||
DW_CFICFACell cfa_cell;
|
||||
} DW_CFIRow;
|
||||
DW_CFA cfa;
|
||||
DW_CFI_Register *regs;
|
||||
struct DW_CFA_Row *next;
|
||||
} DW_CFA_Row;
|
||||
|
||||
typedef struct DW_CFIMachine
|
||||
typedef struct DW_CFI_Unwind
|
||||
{
|
||||
U64 cells_per_row;
|
||||
DW_CIEUnpacked *cie;
|
||||
DW_EhPtrCtx *ptr_ctx;
|
||||
DW_CFIRow *initial_row;
|
||||
U64 fde_ip;
|
||||
} DW_CFIMachine;
|
||||
DW_CFA_InstList insts;
|
||||
DW_CIE *cie;
|
||||
DW_FDE *fde;
|
||||
DW_CFA_Row *initial_row;
|
||||
DW_CFA_Row *row;
|
||||
DW_CFA_InstNode *curr_inst;
|
||||
DW_CFA_Row *free_rows;
|
||||
DW_Reg reg_count;
|
||||
U64 pc;
|
||||
Arch arch;
|
||||
} DW_CFI_Unwind;
|
||||
|
||||
typedef U8 DW_CFADecode;
|
||||
enum
|
||||
{
|
||||
DW_CFADecode_Nop = 0x0,
|
||||
// 1,2,4,8 reserved for literal byte sizes
|
||||
DW_CFADecode_Address = 0x9,
|
||||
DW_CFADecode_ULEB128 = 0xA,
|
||||
DW_CFADecode_SLEB128 = 0xB,
|
||||
};
|
||||
typedef enum {
|
||||
DW_UnwindStatus_Ok,
|
||||
DW_UnwindStatus_Fail,
|
||||
DW_UnwindStatus_Maybe
|
||||
} DW_UnwindStatus;
|
||||
|
||||
typedef U16 DW_CFAControlBits;
|
||||
enum
|
||||
{
|
||||
DW_CFAControlBits_Dec1Mask = 0x00F,
|
||||
DW_CFAControlBits_Dec2Mask = 0x0F0,
|
||||
DW_CFAControlBits_IsReg0 = 0x100,
|
||||
DW_CFAControlBits_IsReg1 = 0x200,
|
||||
DW_CFAControlBits_IsReg2 = 0x400,
|
||||
DW_CFAControlBits_NewRow = 0x800,
|
||||
};
|
||||
#define DW_REG_READ(name) DW_UnwindStatus name(DW_Reg reg_id, void *buffer, U64 buffer_max, void *ud)
|
||||
typedef DW_REG_READ(DW_RegRead);
|
||||
|
||||
global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind1[DW_CFA_OplKind1 + 1];
|
||||
global read_only DW_CFAControlBits dw_unwind__cfa_control_bits_kind2[DW_CFA_OplKind2 + 1];
|
||||
#define DW_REG_WRITE(name) DW_UnwindStatus name(DW_Reg reg_id, void *value, U64 value_size, void *ud)
|
||||
typedef DW_REG_WRITE(DW_RegWrite);
|
||||
|
||||
// register codes for unwinding match the DW_RegX64 register codes
|
||||
#define DW_UNWIND_X64__REG_SLOT_COUNT 17
|
||||
#define DW_MEM_READ(name) DW_UnwindStatus name(U64 addr, U64 size, void *buffer, void *ud)
|
||||
typedef DW_MEM_READ(DW_MemRead);
|
||||
|
||||
////////////////////////////////
|
||||
// x64 Unwind Function
|
||||
|
||||
internal DW_UnwindResult
|
||||
dw_unwind_x64(String8 raw_text,
|
||||
String8 raw_eh_frame,
|
||||
String8 raw_eh_frame_header,
|
||||
Rng1U64 text_vrange,
|
||||
Rng1U64 eh_frame_vrange,
|
||||
Rng1U64 eh_frame_header_vrange,
|
||||
U64 default_image_base,
|
||||
U64 image_base,
|
||||
U64 stack_pointer,
|
||||
DW_RegsX64 *regs,
|
||||
DW_ReadMemorySig *read_memory,
|
||||
void *read_memory_ud);
|
||||
internal DW_CFA_Row * dw_make_cfa_row(Arena *arena, U64 reg_count);
|
||||
internal DW_CFA_Row * dw_copy_cfa_row(Arena *arena, U64 reg_count, DW_CFA_Row *row);
|
||||
|
||||
internal DW_UnwindResult dw_unwind_x64__apply_frame_rules(String8 raw_eh_frame, DW_CFIRow *row, U64 text_base_vaddr, DW_ReadMemorySig *read_memory, void *read_memory_ud, U64 stack_pointer, DW_RegsX64 *regs);
|
||||
|
||||
////////////////////////////////
|
||||
// x64 Unwind Helper Functions
|
||||
|
||||
internal void dw_unwind_init_x64(void);
|
||||
internal U64 dw_unwind_parse_pointer_x64(void *base, Rng1U64 range, DW_EhPtrCtx *ptr_ctx, DW_EhPtrEnc ptr_enc, U64 off, U64 *ptr_out);
|
||||
|
||||
//- eh_frame parsing
|
||||
internal void dw_unwind_parse_cie_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, U64 off, DW_CIEUnpacked *cie_out);
|
||||
internal void dw_unwind_parse_fde_x64(void *base,Rng1U64 range,DW_EhPtrCtx *ptr_ctx, DW_CIEUnpacked *parent_cie, U64 off, DW_FDEUnpacked *fde_out);
|
||||
internal DW_CFIRecords dw_unwind_eh_frame_cfi_from_ip_slow_x64(String8 raw_eh_frame, DW_EhPtrCtx *ptr_ctx, U64 ip_voff);
|
||||
internal DW_CFIRecords dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, DW_EhPtrCtx *ptr_ctx, U64 ip_voff);
|
||||
|
||||
//- cfi machine
|
||||
|
||||
internal DW_CFIMachine dw_unwind_make_machine_x64(U64 cells_per_row, DW_CIEUnpacked *cie, DW_EhPtrCtx *ptr_ctx);
|
||||
internal void dw_unwind_machine_equip_initial_row_x64(DW_CFIMachine *machine, DW_CFIRow *initial_row);
|
||||
internal void dw_unwind_machine_equip_fde_ip_x64(DW_CFIMachine *machine, U64 fde_ip);
|
||||
|
||||
internal DW_CFIRow* dw_unwind_row_alloc_x64(Arena *arena, U64 cells_per_row);
|
||||
internal void dw_unwind_row_zero_x64(DW_CFIRow *row, U64 cells_per_row);
|
||||
internal void dw_unwind_row_copy_x64(DW_CFIRow *dst, DW_CFIRow *src, U64 cells_per_row);
|
||||
|
||||
internal B32 dw_unwind_machine_run_to_ip_x64(void *base, Rng1U64 range, DW_CFIMachine *machine, U64 target_ip, DW_CFIRow *row_out);
|
||||
internal DW_CFI_Unwind * dw_cfi_unwind_init(Arena *arena, Arch arch, DW_CIE *cie, DW_FDE *fde, DW_DecodePtr *decode_ptr_func, void *decode_ptr_ud);
|
||||
internal B32 dw_cfi_next_row(Arena *arena, DW_CFI_Unwind *uw);
|
||||
internal DW_UnwindStatus dw_cfi_apply_register_rules(DW_CFI_Unwind *uw, DW_MemRead *mem_read_func, void *mem_read_ud, DW_RegRead *reg_read_func, void *reg_read_ud, DW_RegWrite *reg_write_func, void *reg_write_ud);
|
||||
|
||||
#endif // DWARF_UNWIND_H
|
||||
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal U64
|
||||
eh_read_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out)
|
||||
{
|
||||
U64 ptr_off = off;
|
||||
|
||||
// align read offset as needed
|
||||
if (encoding == EH_PtrEnc_Aligned) {
|
||||
ptr_off = AlignPow2(ptr_off, ptr_ctx->ptr_align);
|
||||
encoding = EH_PtrEnc_Ptr;
|
||||
}
|
||||
|
||||
// decode pointer value
|
||||
U64 decode_size = 0;
|
||||
U64 raw_ptr_size = 0;
|
||||
U64 raw_ptr = 0;
|
||||
switch (encoding & EH_PtrEnc_TypeMask) {
|
||||
default: { InvalidPath; } break;
|
||||
|
||||
case EH_PtrEnc_Ptr : { raw_ptr_size = 8; } goto ufixed;
|
||||
case EH_PtrEnc_UData2: { raw_ptr_size = 2; } goto ufixed;
|
||||
case EH_PtrEnc_UData4: { raw_ptr_size = 4; } goto ufixed;
|
||||
case EH_PtrEnc_UData8: { raw_ptr_size = 8; } goto ufixed;
|
||||
ufixed: {
|
||||
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||
} break;
|
||||
|
||||
// TODO: Signed is actually just a flag that indicates this int is negavite.
|
||||
// There shouldn't be a read for Signed.
|
||||
// For instance, (EH_PtrEnc_UData2 | EH_PtrEnc_Signed) == EH_PtrEnc_SData etc.
|
||||
case EH_PtrEnc_Signed: { raw_ptr_size = 8; } goto sfixed;
|
||||
|
||||
case EH_PtrEnc_SData2: { raw_ptr_size = 2; } goto sfixed;
|
||||
case EH_PtrEnc_SData4: { raw_ptr_size = 4; } goto sfixed;
|
||||
case EH_PtrEnc_SData8: { raw_ptr_size = 8; } goto sfixed;
|
||||
sfixed: {
|
||||
decode_size += str8_deserial_read(frame_base, ptr_off, &raw_ptr, raw_ptr_size, raw_ptr_size);
|
||||
raw_ptr = extend_sign64(raw_ptr, raw_ptr_size);
|
||||
} break;
|
||||
|
||||
case EH_PtrEnc_ULEB128: { decode_size += str8_deserial_read_uleb128(frame_base, ptr_off, &raw_ptr); } break;
|
||||
case EH_PtrEnc_SLEB128: { decode_size += str8_deserial_read_sleb128(frame_base, ptr_off, (S64*)&raw_ptr); } break;
|
||||
}
|
||||
|
||||
// apply relative bases
|
||||
if (decode_size > 0) {
|
||||
U64 ptr = raw_ptr;
|
||||
switch (encoding & EH_PtrEnc_ModifierMask) {
|
||||
case EH_PtrEnc_PcRel: { ptr = ptr_ctx->raw_base_vaddr + off + raw_ptr; } break;
|
||||
case EH_PtrEnc_TextRel: { ptr = ptr_ctx->text_vaddr + raw_ptr; } break;
|
||||
case EH_PtrEnc_DataRel: { ptr = ptr_ctx->data_vaddr + raw_ptr; } break;
|
||||
case EH_PtrEnc_FuncRel: {
|
||||
Assert(!"TODO: need a sample to verify implementation");
|
||||
ptr = ptr_ctx->func_vaddr + raw_ptr;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (ptr_out) {
|
||||
*ptr_out = raw_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return decode_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out)
|
||||
{
|
||||
// TODO:
|
||||
// Handle "eh" param, it indicates presence of EH Data field.
|
||||
// On 32bit arch it is a 4-byte and on 64-bit 8-byte value.
|
||||
// Reference: https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA/ehframechpt.html
|
||||
// Reference doc doesn't clarify structure for EH Data though
|
||||
|
||||
U64 cursor = 0;
|
||||
|
||||
EH_AugFlags aug_flags = 0;
|
||||
EH_PtrEnc lsda_encoding = EH_PtrEnc_Omit;
|
||||
EH_PtrEnc addr_encoding = EH_PtrEnc_UData8;
|
||||
EH_PtrEnc handler_encoding = EH_PtrEnc_Omit;
|
||||
U64 handler_ip = 0;
|
||||
if (str8_match(str8_prefix(aug_string, 1), str8_lit("z"), 0)) {
|
||||
U64 aug_cursor = 0;
|
||||
for (U8 *ptr = aug_string.str; ptr < (aug_string.str+aug_string.size); ptr += 1) {
|
||||
switch (*ptr) {
|
||||
case 'L': {
|
||||
aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &lsda_encoding);
|
||||
aug_flags |= EH_AugFlag_HasLSDA;
|
||||
} break;
|
||||
case 'P': {
|
||||
aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &handler_encoding);
|
||||
aug_cursor += eh_read_ptr(aug_data, aug_cursor, ptr_ctx, handler_encoding, &handler_ip);
|
||||
aug_flags |= EH_AugFlag_HasHandler;
|
||||
} break;
|
||||
case 'R': {
|
||||
aug_cursor += str8_deserial_read_struct(aug_data, aug_cursor, &addr_encoding);
|
||||
aug_flags |= EH_AugFlag_HasAddrEnc;
|
||||
} break;
|
||||
default: { Assert(!"failed to parse augmentation string"); goto exit; } break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aug_out) {
|
||||
aug_out->handler_ip = handler_ip;
|
||||
aug_out->handler_encoding = handler_encoding;
|
||||
aug_out->lsda_encoding = handler_encoding;
|
||||
aug_out->addr_encoding = addr_encoding;
|
||||
aug_out->flags = aug_flags;
|
||||
}
|
||||
|
||||
exit:;
|
||||
U64 parse_size = cursor;
|
||||
return parse_size;
|
||||
}
|
||||
|
||||
internal U64
|
||||
eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx)
|
||||
{
|
||||
return eh_parse_aug_data(aug_string, data, ptr_ctx, 0);
|
||||
}
|
||||
|
||||
internal U64
|
||||
eh_frame_hdr_search_linear_x64(String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 location)
|
||||
{
|
||||
// Table contains only addresses for first instruction in a function and we cannot
|
||||
// guarantee that result is FDE that corresponds to the input location.
|
||||
// So input location must be cheked against range from FDE header again.
|
||||
|
||||
U64 closest_location = max_U64;
|
||||
U64 closest_address = max_U64;
|
||||
|
||||
U64 cursor = 0;
|
||||
|
||||
U8 version = 0;
|
||||
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &version);
|
||||
|
||||
if (version == 1) {
|
||||
#if 0
|
||||
EH_PtrCtx ptr_ctx = {0};
|
||||
// Set this to base address of .eh_frame_hdr. Entries are relative
|
||||
// to this section for some reason.
|
||||
ptr_ctx.data_vaddr = range.min;
|
||||
// If input location is VMA then set this to address of .text.
|
||||
// Pointer parsing function will adjust "init_location" to correct VMA.
|
||||
ptr_ctx.text_vaddr = 0;
|
||||
#endif
|
||||
|
||||
EH_PtrEnc eh_frame_ptr_enc = 0, fde_count_enc = 0, table_enc = 0;
|
||||
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &eh_frame_ptr_enc);
|
||||
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &fde_count_enc);
|
||||
cursor += str8_deserial_read_struct(raw_eh_frame_hdr, cursor, &table_enc);
|
||||
|
||||
U64 eh_frame_ptr = 0, fde_count = 0;
|
||||
NotImplemented;
|
||||
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, eh_frame_ptr_enc, cursor, &eh_frame_ptr);
|
||||
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, fde_count_enc, cursor, &fde_count);
|
||||
|
||||
for (U64 fde_idx = 0; fde_idx < fde_count; ++fde_idx) {
|
||||
U64 init_location = 0, address = 0;
|
||||
NotImplemented;
|
||||
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &init_location);
|
||||
//cursor += dw_unwind_parse_pointer_x64(raw_eh_frame_hdr.str, rng_1u64(0, raw_eh_frame_hdr.size), ptr_ctx, table_enc, cursor, &address);
|
||||
|
||||
S64 current_delta = (S64)(location - init_location);
|
||||
S64 closest_delta = (S64)(location - closest_location);
|
||||
if (0 <= current_delta && current_delta < closest_delta) {
|
||||
closest_location = init_location;
|
||||
closest_address = address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// address where to find corresponding FDE, this is an absolute offset
|
||||
// into the image file.
|
||||
return closest_address;
|
||||
}
|
||||
|
||||
#if 0
|
||||
internal DW_CFIRecords
|
||||
dw_unwind_eh_frame_hdr_from_ip_fast_x64(String8 raw_eh_frame, String8 raw_eh_frame_hdr, EH_PtrCtx *ptr_ctx, U64 ip_voff)
|
||||
{
|
||||
DW_CFIRecords result = {0};
|
||||
|
||||
// find FDE offset
|
||||
void *eh_frame_hdr = raw_eh_frame.str;
|
||||
U64 fde_offset = dw_search_eh_frame_hdr_linear_x64(raw_eh_frame_hdr, ptr_ctx, ip_voff);
|
||||
|
||||
B32 is_fde_offset_valid = (fde_offset != max_U64);
|
||||
if (is_fde_offset_valid) {
|
||||
U64 fde_read_offset = (fde_offset - ptr_ctx->raw_base_vaddr);
|
||||
|
||||
// read FDE size
|
||||
U64 fde_size = 0;
|
||||
fde_read_offset += str8_deserial_read_dwarf_packed_size(raw_eh_frame, fde_read_offset, &fde_size);
|
||||
|
||||
// read FDE discriminator
|
||||
U32 fde_discrim = 0;
|
||||
fde_read_offset += str8_deserial_read_struct(raw_eh_frame, fde_read_offset, &fde_discrim);
|
||||
|
||||
// compute parent CIE offset
|
||||
U64 cie_read_offset = fde_read_offset - (fde_discrim + sizeof(fde_discrim));
|
||||
|
||||
// read CIE size
|
||||
U64 cie_size = 0;
|
||||
cie_read_offset += str8_deserial_read_dwarf_packed_size(raw_eh_frame, cie_read_offset, &cie_size);
|
||||
|
||||
// read CIE discriminator
|
||||
U32 cie_discrim = max_U32;
|
||||
cie_read_offset += str8_deserial_read_struct(raw_eh_frame, cie_read_offset, &cie_discrim);
|
||||
|
||||
B32 is_fde = (fde_discrim != 0);
|
||||
B32 is_cie = (cie_discrim == 0);
|
||||
if (is_fde && is_cie) {
|
||||
Rng1U64 cie_range = rng_1u64(0, cie_read_offset + (cie_size - sizeof(cie_discrim)));
|
||||
Rng1U64 fde_range = rng_1u64(0, fde_read_offset + (fde_size - sizeof(fde_discrim)));
|
||||
|
||||
// parse CIE
|
||||
DW_CIE cie = {0};
|
||||
dw_unwind_parse_cie_x64(raw_eh_frame.str, cie_range, ptr_ctx, cie_read_offset, &cie);
|
||||
|
||||
// parse FDE
|
||||
DW_FDE fde = {0};
|
||||
NotImplemented;
|
||||
//dw_unwind_parse_fde_x64(raw_eh_frame.str, fde_range, ptr_ctx, &cie, fde_read_offset, &fde);
|
||||
|
||||
// range check instruction pointer
|
||||
if (contains_1u64(fde.pc_range, ip_voff)) {
|
||||
result.valid = 1;
|
||||
result.cie = cie;
|
||||
result.fde = fde;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
internal String8
|
||||
eh_string_from_ptr_enc_type(EH_PtrEnc type)
|
||||
{
|
||||
switch (type) {
|
||||
case EH_PtrEnc_Ptr: return str8_lit("Ptr");
|
||||
case EH_PtrEnc_ULEB128: return str8_lit("ULEB128");
|
||||
case EH_PtrEnc_UData2: return str8_lit("UData2");
|
||||
case EH_PtrEnc_UData4: return str8_lit("UData4");
|
||||
case EH_PtrEnc_UData8: return str8_lit("UData8");
|
||||
case EH_PtrEnc_Signed: return str8_lit("Signed");
|
||||
case EH_PtrEnc_SLEB128: return str8_lit("SLEB128");
|
||||
case EH_PtrEnc_SData2: return str8_lit("SData2");
|
||||
case EH_PtrEnc_SData4: return str8_lit("SData4");
|
||||
case EH_PtrEnc_SData8: return str8_lit("SData8");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier)
|
||||
{
|
||||
switch (modifier) {
|
||||
case EH_PtrEnc_PcRel: return str8_lit("PcRel");
|
||||
case EH_PtrEnc_TextRel: return str8_lit("TextRel");
|
||||
case EH_PtrEnc_DataRel: return str8_lit("DataRel");
|
||||
case EH_PtrEnc_FuncRel: return str8_lit("FuncRel");
|
||||
case EH_PtrEnc_Aligned: return str8_lit("Aligned");
|
||||
}
|
||||
return str8_zero();
|
||||
}
|
||||
|
||||
internal String8
|
||||
eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc)
|
||||
{
|
||||
String8 type_str = eh_string_from_ptr_enc_type(enc & EH_PtrEnc_TypeMask);
|
||||
String8 modifer_str = eh_string_from_ptr_enc_modifier(enc & EH_PtrEnc_ModifierMask);
|
||||
String8 indir_str = enc & EH_PtrEnc_Indirect ? str8_lit("Indirect") : str8_zero();
|
||||
String8 result = str8f(arena, "Type: %S, Modifier %S (%S)", type_str, modifer_str, indir_str);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#ifndef EH_FRAME_H
|
||||
#define EH_FRAME_H
|
||||
|
||||
typedef U8 EH_PtrEnc;
|
||||
enum
|
||||
{
|
||||
EH_PtrEnc_Ptr = 0x00, // Pointer sized unsigned value
|
||||
EH_PtrEnc_ULEB128 = 0x01, // Unsigned LE base-128 value
|
||||
EH_PtrEnc_UData2 = 0x02, // Unsigned 16-bit value
|
||||
EH_PtrEnc_UData4 = 0x03, // Unsigned 32-bit value
|
||||
EH_PtrEnc_UData8 = 0x04, // Unsigned 64-bit value
|
||||
EH_PtrEnc_Signed = 0x08, // Signed pointer
|
||||
EH_PtrEnc_SLEB128 = 0x09, // Signed LE base-128 value
|
||||
EH_PtrEnc_SData2 = 0x0A, // Signed 16-bit value
|
||||
EH_PtrEnc_SData4 = 0x0B, // Signed 32-bit value
|
||||
EH_PtrEnc_SData8 = 0x0C, // Signed 64-bit value
|
||||
|
||||
EH_PtrEnc_TypeMask = 0x0F,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EH_PtrEnc_PcRel = 0x10, // Value is relative to the current program counter.
|
||||
EH_PtrEnc_TextRel = 0x20, // Value is relative to the .text section.
|
||||
EH_PtrEnc_DataRel = 0x30, // Value is relative to the .got or .eh_frame_hdr section.
|
||||
EH_PtrEnc_FuncRel = 0x40, // Value is relative to the function.
|
||||
EH_PtrEnc_Aligned = 0x50, // Value is aligned to an address unit sized boundary.
|
||||
|
||||
EH_PtrEnc_ModifierMask = 0x70,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
EH_PtrEnc_Indirect = 0x80, // Value is stored in virtual memory.
|
||||
EH_PtrEnc_Omit = 0xFF,
|
||||
};
|
||||
|
||||
typedef struct EH_PtrCtx
|
||||
{
|
||||
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
|
||||
U64 ptr_align;
|
||||
} EH_PtrCtx;
|
||||
|
||||
typedef U8 EH_AugFlags;
|
||||
enum
|
||||
{
|
||||
EH_AugFlag_HasLSDA = (1 << 0),
|
||||
EH_AugFlag_HasHandler = (1 << 1),
|
||||
EH_AugFlag_HasAddrEnc = (1 << 2),
|
||||
};
|
||||
|
||||
typedef struct EH_Augmentation
|
||||
{
|
||||
EH_AugFlags flags;
|
||||
U64 handler_ip;
|
||||
EH_PtrEnc handler_encoding;
|
||||
EH_PtrEnc lsda_encoding;
|
||||
EH_PtrEnc addr_encoding;
|
||||
} EH_Augmentation;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
internal U64 eh_read_ptr(String8 frame_base, U64 off, EH_PtrCtx *ptr_ctx, EH_PtrEnc encoding, U64 *ptr_out);
|
||||
internal U64 eh_parse_aug_data(String8 aug_string, String8 aug_data, EH_PtrCtx *ptr_ctx, EH_Augmentation *aug_out);
|
||||
internal U64 eh_size_from_aug_data(String8 aug_string, String8 data, EH_PtrCtx *ptr_ctx);
|
||||
|
||||
////////////////////////////////
|
||||
//~ Enum -> String
|
||||
|
||||
internal String8 eh_string_from_ptr_enc_type(EH_PtrEnc type);
|
||||
internal String8 eh_string_from_ptr_enc_modifier(EH_PtrEnc modifier);
|
||||
internal String8 eh_string_from_ptr_enc(Arena *arena, EH_PtrEnc enc);
|
||||
|
||||
#endif // EH_FRAME_H
|
||||
|
||||
@@ -570,6 +570,7 @@ struct E_ConsTypeSlot
|
||||
typedef struct E_Module E_Module;
|
||||
struct E_Module
|
||||
{
|
||||
DI_Key dbgi_key;
|
||||
RDI_Parsed *rdi;
|
||||
Rng1U64 vaddr_range;
|
||||
Arch arch;
|
||||
@@ -744,8 +745,8 @@ struct E_AutoHookParams
|
||||
////////////////////////////////
|
||||
//~ rjf: Evaluation Context
|
||||
|
||||
typedef U64 E_SpaceGenFunction(void *user_data, E_Space space);
|
||||
typedef B32 E_SpaceRWFunction(void *user_data, E_Space space, void *out, Rng1U64 offset_range);
|
||||
typedef U64 E_SpaceGenFunction(E_Space space);
|
||||
typedef B32 E_SpaceRWFunction(E_Space space, void *out, Rng1U64 offset_range);
|
||||
|
||||
//- rjf: base context
|
||||
|
||||
@@ -763,10 +764,8 @@ struct E_BaseCtx
|
||||
E_Module *modules;
|
||||
U64 modules_count;
|
||||
E_Module *primary_module;
|
||||
DI_MatchStore *dbgi_match_store;
|
||||
|
||||
// rjf: space hooks
|
||||
void *space_rw_user_data;
|
||||
E_SpaceGenFunction *space_gen;
|
||||
E_SpaceRWFunction *space_read;
|
||||
E_SpaceRWFunction *space_write;
|
||||
@@ -1112,7 +1111,7 @@ read_only global E_String2ExprMap e_string2expr_map_nil = {0};
|
||||
read_only global E_Expr e_expr_nil = {&e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil, &e_expr_nil};
|
||||
read_only global E_IRNode e_irnode_nil = {&e_irnode_nil, &e_irnode_nil, &e_irnode_nil};
|
||||
read_only global E_Eval e_eval_nil = {{0}, {0}, {0}, &e_expr_nil, {&e_irnode_nil}};
|
||||
read_only global E_Module e_module_nil = {&rdi_parsed_nil};
|
||||
read_only global E_Module e_module_nil = {{0}, &rdi_parsed_nil};
|
||||
read_only global E_CacheBundle e_cache_bundle_nil = {0, {0}, {0}, {0}, {{0}, 0, &e_expr_nil, &e_expr_nil}, {&e_irnode_nil}};
|
||||
thread_static E_BaseCtx *e_base_ctx = 0;
|
||||
thread_static E_IRCtx *e_ir_ctx = 0;
|
||||
|
||||
+182
-63
@@ -61,7 +61,7 @@ e_space_gen(E_Space space)
|
||||
U64 result = 0;
|
||||
if(e_base_ctx->space_gen != 0)
|
||||
{
|
||||
result = e_base_ctx->space_gen(e_base_ctx->space_rw_user_data, space);
|
||||
result = e_base_ctx->space_gen(space);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -71,9 +71,70 @@ e_space_read(E_Space space, void *out, Rng1U64 range)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
B32 result = 0;
|
||||
if(e_interpret_ctx->space_read != 0)
|
||||
{
|
||||
result = e_interpret_ctx->space_read(e_interpret_ctx->space_rw_user_data, space, out, range);
|
||||
switch(space.kind)
|
||||
{
|
||||
//- rjf: reads from hash store key
|
||||
case E_SpaceKind_HashStoreKey:
|
||||
{
|
||||
C_Root root = {space.u64_0};
|
||||
C_ID id = {space.u128};
|
||||
C_Key key = c_key_make(root, id);
|
||||
U128 hash = c_hash_from_key(key, 0);
|
||||
Access *access = access_open();
|
||||
{
|
||||
String8 data = c_data_from_hash(access, hash);
|
||||
Rng1U64 legal_range = r1u64(0, data.size);
|
||||
Rng1U64 read_range = intersect_1u64(range, legal_range);
|
||||
if(read_range.min < read_range.max)
|
||||
{
|
||||
result = 1;
|
||||
MemoryCopy(out, data.str + read_range.min, dim_1u64(read_range));
|
||||
}
|
||||
}
|
||||
access_close(access);
|
||||
}break;
|
||||
|
||||
//- rjf: file reads
|
||||
case E_SpaceKind_File:
|
||||
{
|
||||
// rjf: unpack space/path
|
||||
U64 file_path_string_id = space.u64_0;
|
||||
String8 file_path = e_string_from_id(file_path_string_id);
|
||||
|
||||
// rjf: find containing chunk range
|
||||
U64 chunk_size = KB(4);
|
||||
Rng1U64 containing_range = range;
|
||||
containing_range.min -= containing_range.min%chunk_size;
|
||||
containing_range.max += chunk_size-1;
|
||||
containing_range.max -= containing_range.max%chunk_size;
|
||||
|
||||
// rjf: map to hash
|
||||
C_Key key = fs_key_from_path_range(file_path, containing_range, 0);
|
||||
U128 hash = c_hash_from_key(key, 0);
|
||||
|
||||
// rjf: look up from hash store
|
||||
Access *access = access_open();
|
||||
{
|
||||
String8 data = c_data_from_hash(access, hash);
|
||||
Rng1U64 legal_range = r1u64(containing_range.min, containing_range.min + data.size);
|
||||
Rng1U64 read_range = intersect_1u64(range, legal_range);
|
||||
if(read_range.min < read_range.max)
|
||||
{
|
||||
result = 1;
|
||||
MemoryCopy(out, data.str + read_range.min - containing_range.min, dim_1u64(read_range));
|
||||
}
|
||||
}
|
||||
access_close(access);
|
||||
}break;
|
||||
|
||||
//- rjf: default -> use hooks
|
||||
default:
|
||||
if(e_base_ctx->space_read != 0)
|
||||
{
|
||||
result = e_base_ctx->space_read(space, out, range);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
return result;
|
||||
@@ -84,9 +145,15 @@ e_space_write(E_Space space, void *in, Rng1U64 range)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
B32 result = 0;
|
||||
if(e_interpret_ctx->space_write != 0)
|
||||
if(e_base_ctx->space_write != 0)
|
||||
{
|
||||
result = e_interpret_ctx->space_write(e_interpret_ctx->space_rw_user_data, space, in, range);
|
||||
switch(space.kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
result = e_base_ctx->space_write(space, in, range);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
ProfEnd();
|
||||
return result;
|
||||
@@ -125,7 +192,7 @@ e_interpret(String8 bytecode)
|
||||
}
|
||||
else switch(op)
|
||||
{
|
||||
case E_IRExtKind_SetSpace: {ctrlbits = RDI_EVAL_CTRLBITS(32, 0, 0);}break;
|
||||
case E_IRExtKind_SetSpace:{ctrlbits = RDI_EVAL_CTRLBITS(32, 0, 0);}break;
|
||||
default:
|
||||
{
|
||||
result.code = E_InterpretationCode_BadOp;
|
||||
@@ -150,6 +217,10 @@ e_interpret(String8 bytecode)
|
||||
ptr = next_ptr;
|
||||
}
|
||||
|
||||
// rjf: unpack imm -> type group & arithmetic width
|
||||
RDI_EvalTypeGroup type_group = (RDI_EvalTypeGroup)imm.u512.u8[0];
|
||||
U64 op_arithmetic_size = (U64)imm.u512.u8[1];
|
||||
|
||||
// rjf: pop
|
||||
E_Value *svals = 0;
|
||||
{
|
||||
@@ -206,10 +277,6 @@ e_interpret(String8 bytecode)
|
||||
result.code = E_InterpretationCode_BadMemRead;
|
||||
goto done;
|
||||
}
|
||||
if(e_space_match(selected_space, e_interpret_ctx->reg_space))
|
||||
{
|
||||
selected_space = e_interpret_ctx->primary_space;
|
||||
}
|
||||
}break;
|
||||
|
||||
case RDI_EvalOp_RegRead:
|
||||
@@ -297,7 +364,7 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Abs:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.f32 = svals[0].f32;
|
||||
if(svals[0].f32 < 0)
|
||||
@@ -305,7 +372,7 @@ e_interpret(String8 bytecode)
|
||||
nval.f32 = -svals[0].f32;
|
||||
}
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.f64 = svals[0].f64;
|
||||
if(svals[0].f64 < 0)
|
||||
@@ -325,11 +392,11 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Neg:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.f32 = -svals[0].f32;
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.f64 = -svals[0].f64;
|
||||
}
|
||||
@@ -341,11 +408,11 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Add:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.f32 = svals[0].f32 + svals[1].f32;
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.f64 = svals[0].f64 + svals[1].f64;
|
||||
}
|
||||
@@ -357,11 +424,11 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Sub:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.f32 = svals[0].f32 - svals[1].f32;
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.f64 = svals[0].f64 - svals[1].f64;
|
||||
}
|
||||
@@ -373,11 +440,11 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Mul:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.f32 = svals[0].f32*svals[1].f32;
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.f64 = svals[0].f64*svals[1].f64;
|
||||
}
|
||||
@@ -389,7 +456,7 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Div:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
if(svals[1].f32 != 0.f)
|
||||
{
|
||||
@@ -401,7 +468,7 @@ e_interpret(String8 bytecode)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
if(svals[1].f64 != 0.)
|
||||
{
|
||||
@@ -413,8 +480,8 @@ e_interpret(String8 bytecode)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
else if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
if(svals[1].u64 != 0)
|
||||
{
|
||||
@@ -435,8 +502,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Mod:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
if(svals[1].u64 != 0)
|
||||
{
|
||||
@@ -452,10 +519,27 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_LShift:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U)
|
||||
{
|
||||
nval.u64 = svals[0].u64 << svals[1].u64;
|
||||
switch(op_arithmetic_size)
|
||||
{
|
||||
default:{}break;
|
||||
case 1:{nval.u8 = svals[0].u8 << svals[1].u8;}break;
|
||||
case 2:{nval.u16 = svals[0].u16 << svals[1].u16;}break;
|
||||
case 4:{nval.u32 = svals[0].u32 << svals[1].u32;}break;
|
||||
case 8:{nval.u64 = svals[0].u64 << svals[1].u64;}break;
|
||||
}
|
||||
}
|
||||
else if(type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
switch(op_arithmetic_size)
|
||||
{
|
||||
default:{}break;
|
||||
case 1:{nval.s8 = svals[0].s8 << svals[1].s8;}break;
|
||||
case 2:{nval.s16 = svals[0].s16 << svals[1].s16;}break;
|
||||
case 4:{nval.s32 = svals[0].s32 << svals[1].s32;}break;
|
||||
case 8:{nval.s64 = svals[0].s64 << svals[1].s64;}break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -466,13 +550,27 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_RShift:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U)
|
||||
if(type_group == RDI_EvalTypeGroup_U)
|
||||
{
|
||||
nval.u64 = svals[0].u64 >> svals[1].u64;
|
||||
switch(op_arithmetic_size)
|
||||
{
|
||||
default:{}break;
|
||||
case 1:{nval.u8 = svals[0].u8 >> svals[1].u8;}break;
|
||||
case 2:{nval.u16 = svals[0].u16 >> svals[1].u16;}break;
|
||||
case 4:{nval.u32 = svals[0].u32 >> svals[1].u32;}break;
|
||||
case 8:{nval.u64 = svals[0].u64 >> svals[1].u64;}break;
|
||||
}
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_S)
|
||||
else if(type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = svals[0].s64 >> svals[1].u64;
|
||||
switch(op_arithmetic_size)
|
||||
{
|
||||
default:{}break;
|
||||
case 1:{nval.s8 = svals[0].s8 >> svals[1].s8;}break;
|
||||
case 2:{nval.s16 = svals[0].s16 >> svals[1].s16;}break;
|
||||
case 4:{nval.s32 = svals[0].s32 >> svals[1].s32;}break;
|
||||
case 8:{nval.s64 = svals[0].s64 >> svals[1].s64;}break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -483,8 +581,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_BitAnd:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = svals[0].u64&svals[1].u64;
|
||||
}
|
||||
@@ -497,8 +595,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_BitOr:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = svals[0].u64|svals[1].u64;
|
||||
}
|
||||
@@ -511,8 +609,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_BitXor:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = svals[0].u64^svals[1].u64;
|
||||
}
|
||||
@@ -525,8 +623,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_BitNot:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = ~svals[0].u64;
|
||||
}
|
||||
@@ -539,8 +637,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_LogAnd:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = (svals[0].u64 && svals[1].u64);
|
||||
}
|
||||
@@ -553,8 +651,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_LogOr:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = (svals[0].u64 || svals[1].u64);
|
||||
}
|
||||
@@ -567,8 +665,8 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_LogNot:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_U ||
|
||||
imm.u64 == RDI_EvalTypeGroup_S)
|
||||
if(type_group == RDI_EvalTypeGroup_U ||
|
||||
type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = (!svals[0].u64);
|
||||
}
|
||||
@@ -593,19 +691,19 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_LsEq:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.u64 = (svals[0].f32 <= svals[1].f32);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.u64 = (svals[0].f64 <= svals[1].f64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_U)
|
||||
else if(type_group == RDI_EvalTypeGroup_U)
|
||||
{
|
||||
nval.u64 = (svals[0].u64 <= svals[1].u64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_S)
|
||||
else if(type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = (svals[0].s64 <= svals[1].s64);
|
||||
}
|
||||
@@ -618,19 +716,19 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_GrEq:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.u64 = (svals[0].f32 >= svals[1].f32);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.u64 = (svals[0].f64 >= svals[1].f64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_U)
|
||||
else if(type_group == RDI_EvalTypeGroup_U)
|
||||
{
|
||||
nval.u64 = (svals[0].u64 >= svals[1].u64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_S)
|
||||
else if(type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = (svals[0].s64 >= svals[1].s64);
|
||||
}
|
||||
@@ -643,19 +741,19 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Less:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.u64 = (svals[0].f32 < svals[1].f32);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.u64 = (svals[0].f64 < svals[1].f64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_U)
|
||||
else if(type_group == RDI_EvalTypeGroup_U)
|
||||
{
|
||||
nval.u64 = (svals[0].u64 < svals[1].u64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_S)
|
||||
else if(type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = (svals[0].s64 < svals[1].s64);
|
||||
}
|
||||
@@ -668,19 +766,19 @@ e_interpret(String8 bytecode)
|
||||
|
||||
case RDI_EvalOp_Grtr:
|
||||
{
|
||||
if(imm.u64 == RDI_EvalTypeGroup_F32)
|
||||
if(type_group == RDI_EvalTypeGroup_F32)
|
||||
{
|
||||
nval.u64 = (svals[0].f32 > svals[1].f32);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_F64)
|
||||
else if(type_group == RDI_EvalTypeGroup_F64)
|
||||
{
|
||||
nval.u64 = (svals[0].f64 > svals[1].f64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_U)
|
||||
else if(type_group == RDI_EvalTypeGroup_U)
|
||||
{
|
||||
nval.u64 = (svals[0].u64 > svals[1].u64);
|
||||
}
|
||||
else if(imm.u64 == RDI_EvalTypeGroup_S)
|
||||
else if(type_group == RDI_EvalTypeGroup_S)
|
||||
{
|
||||
nval.u64 = (svals[0].s64 > svals[1].s64);
|
||||
}
|
||||
@@ -841,6 +939,27 @@ e_interpret(String8 bytecode)
|
||||
case 8:{nval.u64 = bswap_u64(svals[0].u64);}break;
|
||||
}
|
||||
}break;
|
||||
|
||||
case RDI_EvalOp_CallSiteValue:
|
||||
{
|
||||
NotImplemented;
|
||||
}break;
|
||||
|
||||
case RDI_EvalOp_PartialValue:
|
||||
{
|
||||
NotImplemented;
|
||||
}break;
|
||||
|
||||
case RDI_EvalOp_PartialValueBit:
|
||||
{
|
||||
NotImplemented;
|
||||
}break;
|
||||
|
||||
case RDI_EvalOp_Swap:
|
||||
{
|
||||
// TODO: add support for pushing multiple values onto the stack
|
||||
NotImplemented;
|
||||
}break;
|
||||
}
|
||||
|
||||
// rjf: push
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
typedef struct E_InterpretCtx E_InterpretCtx;
|
||||
struct E_InterpretCtx
|
||||
{
|
||||
void *space_rw_user_data;
|
||||
E_SpaceRWFunction *space_read;
|
||||
E_SpaceRWFunction *space_write;
|
||||
E_Space primary_space;
|
||||
Arch reg_arch;
|
||||
E_Space reg_space;
|
||||
|
||||
+92
-40
@@ -163,19 +163,20 @@ e_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode
|
||||
}
|
||||
|
||||
internal E_IRNode *
|
||||
e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *l, E_IRNode *r)
|
||||
e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, U64 operand_size, E_IRNode *l, E_IRNode *r)
|
||||
{
|
||||
E_IRNode *n = e_push_irnode(arena, op);
|
||||
n->value.u64 = group;
|
||||
n->value.u512.u8[0] = (U8)group;
|
||||
n->value.u512.u8[1] = (U8)operand_size;
|
||||
e_irnode_push_child(n, l);
|
||||
e_irnode_push_child(n, r);
|
||||
return n;
|
||||
}
|
||||
|
||||
internal E_IRNode *
|
||||
e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, E_IRNode *l, E_IRNode *r)
|
||||
e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, U64 operand_size, E_IRNode *l, E_IRNode *r)
|
||||
{
|
||||
E_IRNode *n = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, l, r);
|
||||
E_IRNode *n = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_U, operand_size, l, r);
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -314,8 +315,8 @@ e_irtree_resolve_to_value(Arena *arena, E_Mode from_mode, E_IRNode *tree, E_Type
|
||||
{
|
||||
valid_bits_mask |= (1ull<<idx);
|
||||
}
|
||||
result = e_irtree_binary_op_u(arena, RDI_EvalOp_RShift, result, e_irtree_const_u(arena, type->off));
|
||||
result = e_irtree_binary_op_u(arena, RDI_EvalOp_BitAnd, result, e_irtree_const_u(arena, valid_bits_mask));
|
||||
result = e_irtree_binary_op_u(arena, RDI_EvalOp_RShift, type->byte_size, result, e_irtree_const_u(arena, type->off));
|
||||
result = e_irtree_binary_op_u(arena, RDI_EvalOp_BitAnd, type->byte_size, result, e_irtree_const_u(arena, valid_bits_mask));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -475,7 +476,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default)
|
||||
if(r_value != 0 && !r_is_constant_value)
|
||||
{
|
||||
E_IRNode *const_tree = e_irtree_const_u(arena, r_value);
|
||||
new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, new_tree, const_tree);
|
||||
new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, e_type_byte_size_from_key(new_tree_type), new_tree, const_tree);
|
||||
}
|
||||
else if(r_is_constant_value)
|
||||
{
|
||||
@@ -544,7 +545,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default)
|
||||
if(direct_type_size > 1)
|
||||
{
|
||||
E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size);
|
||||
offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree);
|
||||
offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, 8, offset_tree, const_tree);
|
||||
}
|
||||
|
||||
// rjf: ops to push stack value, push offset, + read from stack value
|
||||
@@ -562,7 +563,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default)
|
||||
if(direct_type_size > 1)
|
||||
{
|
||||
E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size);
|
||||
offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, offset_tree, const_tree);
|
||||
offset_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, 8, offset_tree, const_tree);
|
||||
}
|
||||
|
||||
// rjf: ops to compute the base offset (resolve to value if addr-of-pointer)
|
||||
@@ -573,7 +574,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(default)
|
||||
}
|
||||
|
||||
// rjf: ops to compute the final address
|
||||
new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, offset_tree, base_tree);
|
||||
new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, 8, offset_tree, base_tree);
|
||||
if(mode != E_Mode_Null)
|
||||
{
|
||||
mode = E_Mode_Offset;
|
||||
@@ -1136,6 +1137,9 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
E_TypeKey r_type = e_type_key_unwrap(r_tree.type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKind l_type_kind = e_type_kind_from_key(l_type);
|
||||
E_TypeKind r_type_kind = e_type_kind_from_key(r_type);
|
||||
U64 l_type_size = e_type_byte_size_from_key(l_type);
|
||||
U64 r_type_size = e_type_byte_size_from_key(r_type);
|
||||
U64 op_operand_size = Max(l_type_size, r_type_size);
|
||||
|
||||
// rjf: resolve complex types to simple arithmetic tyeps
|
||||
if(l_type_kind == E_TypeKind_Bitfield)
|
||||
@@ -1254,7 +1258,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
E_IRNode *r_value_tree = e_irtree_resolve_to_value(arena, r_tree.mode, r_tree.root, r_type);
|
||||
l_value_tree = e_irtree_convert_hi(arena, l_value_tree, l_type, l_type);
|
||||
r_value_tree = e_irtree_convert_hi(arena, r_value_tree, l_type, r_type);
|
||||
E_IRNode *new_tree = e_irtree_binary_op(arena, op, l_type_group, l_value_tree, r_value_tree);
|
||||
E_IRNode *new_tree = e_irtree_binary_op(arena, op, l_type_group, op_operand_size, l_value_tree, r_value_tree);
|
||||
result.root = new_tree;
|
||||
result.type_key = final_type_key;
|
||||
result.mode = E_Mode_Value;
|
||||
@@ -1267,10 +1271,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
// rjf: map l/r to ptr/int
|
||||
E_IRTreeAndType *ptr_tree = &l_tree;
|
||||
E_IRTreeAndType *int_tree = &r_tree;
|
||||
U64 ptr_size = l_type_size;
|
||||
B32 ptr_is_decay = l_is_decay;
|
||||
if(ptr_arithmetic_mul_rptr)
|
||||
{
|
||||
ptr_tree = &r_tree;
|
||||
ptr_size = r_type_size;
|
||||
int_tree = &l_tree;
|
||||
ptr_is_decay = r_is_decay;
|
||||
}
|
||||
@@ -1291,14 +1297,14 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
if(direct_type_size > 1)
|
||||
{
|
||||
E_IRNode *const_root = e_irtree_const_u(arena, direct_type_size);
|
||||
int_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, int_root, const_root);
|
||||
int_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, ptr_size, int_root, const_root);
|
||||
}
|
||||
E_TypeKey ptr_type = ptr_tree->type_key;
|
||||
if(ptr_is_decay)
|
||||
{
|
||||
ptr_type = e_type_key_cons_ptr(e_base_ctx->primary_module->arch, direct_type, 1, 0);
|
||||
}
|
||||
E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_root, int_root);
|
||||
E_IRNode *new_root = e_irtree_binary_op_u(arena, op, ptr_size, ptr_root, int_root);
|
||||
result.root = new_root;
|
||||
result.type_key = ptr_type;
|
||||
result.mode = E_Mode_Value;
|
||||
@@ -1323,12 +1329,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
r_root = e_irtree_resolve_to_value(arena, r_tree.mode, r_root, r_type);
|
||||
}
|
||||
E_IRNode *op_tree = e_irtree_binary_op_u(arena, op, l_root, r_root);
|
||||
E_IRNode *op_tree = e_irtree_binary_op_u(arena, op, l_type_size, l_root, r_root);
|
||||
E_IRNode *new_tree = op_tree;
|
||||
if(direct_type_size > 1)
|
||||
{
|
||||
E_IRNode *const_tree = e_irtree_const_u(arena, direct_type_size);
|
||||
new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Div, new_tree, const_tree);
|
||||
new_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Div, l_type_size, new_tree, const_tree);
|
||||
}
|
||||
result.root = new_tree;
|
||||
result.type_key = e_type_key_basic(E_TypeKind_U64);
|
||||
@@ -1342,11 +1348,13 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
B32 ptr_is_decay = l_is_decay;
|
||||
E_IRTreeAndType *ptr_tree = &l_tree;
|
||||
E_IRTreeAndType *arr_tree = &r_tree;
|
||||
U64 ptr_size = l_type_size;
|
||||
if(l_type_kind == E_TypeKind_Array && l_tree.mode == E_Mode_Value)
|
||||
{
|
||||
ptr_is_decay = r_is_decay;
|
||||
ptr_tree = &r_tree;
|
||||
arr_tree = &l_tree;
|
||||
ptr_size = r_type_size;
|
||||
}
|
||||
|
||||
// rjf: resolve pointer to value, sized same as array
|
||||
@@ -1361,7 +1369,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
E_IRNode *mem_root = e_irtree_mem_read_type(arena, ptr_root, arr_tree->type_key);
|
||||
|
||||
// rjf: generate
|
||||
result.root = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_Other, mem_root, arr_root);
|
||||
result.root = e_irtree_binary_op(arena, op, RDI_EvalTypeGroup_Other, ptr_size, mem_root, arr_root);
|
||||
result.type_key = e_type_key_basic(E_TypeKind_Bool);
|
||||
result.mode = E_Mode_Value;
|
||||
}break;
|
||||
@@ -1815,6 +1823,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), local->type_idx, module_idx);
|
||||
|
||||
// rjf: extract local's location block
|
||||
B32 got_location_block = 0;
|
||||
U64 ip_voff = e_base_ctx->thread_ip_voff;
|
||||
for(U32 loc_block_idx = local->location_first;
|
||||
loc_block_idx < local->location_opl;
|
||||
@@ -1825,8 +1834,15 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
mapped_location_block_module = module;
|
||||
mapped_location_block = block;
|
||||
got_location_block = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: no location block -> error
|
||||
if(!got_location_block)
|
||||
{
|
||||
e_msgf(arena, &result.msgs, E_MsgKind_MissingInfo, expr->range, "Could not find location info for `%S`.", string__redirected);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -1866,9 +1882,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
//- rjf: debug info matches
|
||||
case E_IdentifierResolutionPath_DebugInfoMatch:
|
||||
{
|
||||
if(!string_mapped && e_base_ctx->dbgi_match_store != 0 && (qualifier.size == 0 || str8_match(qualifier, str8_lit("symbol"), 0)))
|
||||
if(!string_mapped && (qualifier.size == 0 || str8_match(qualifier, str8_lit("symbol"), 0)))
|
||||
{
|
||||
DI_Match match = di_match_from_name(e_base_ctx->dbgi_match_store, string, 0);
|
||||
Access *access = access_open();
|
||||
|
||||
// rjf: find match
|
||||
DI_Match match = di_match_from_string(string, 0, e_base_ctx->primary_module->dbgi_key, 0);
|
||||
if(match.idx == 0)
|
||||
{
|
||||
String8List namespaceified_strings = {0};
|
||||
@@ -1897,18 +1916,38 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
}
|
||||
for(String8Node *n = namespaceified_strings.first; n != 0; n = n->next)
|
||||
{
|
||||
match = di_match_from_name(e_base_ctx->dbgi_match_store, n->string, 0);
|
||||
match = di_match_from_string(n->string, 0, e_base_ctx->primary_module->dbgi_key, 0);
|
||||
if(match.idx != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(match.idx != 0 && match.dbgi_idx < e_base_ctx->modules_count)
|
||||
|
||||
// rjf: match -> RDI
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0);
|
||||
|
||||
// rjf: find module from dbgi key
|
||||
U32 dbgi_idx = 0;
|
||||
E_Module *module = &e_module_nil;
|
||||
for EachIndex(idx, e_base_ctx->modules_count)
|
||||
{
|
||||
E_Module *module = &e_base_ctx->modules[match.dbgi_idx];
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
switch(match.section)
|
||||
if(e_base_ctx->modules[idx].rdi == rdi)
|
||||
{
|
||||
module = &e_base_ctx->modules[idx];
|
||||
dbgi_idx = (U32)idx;
|
||||
if(module == e_base_ctx->primary_module ||
|
||||
e_space_match(module->space, e_base_ctx->primary_module->space))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: form result
|
||||
if(match.idx != 0 && module != &e_module_nil)
|
||||
{
|
||||
switch(match.section_kind)
|
||||
{
|
||||
default:{}break;
|
||||
case RDI_SectionKind_GlobalVariables:
|
||||
@@ -1919,7 +1958,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + global_var->voff));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = module->space;
|
||||
@@ -1932,7 +1971,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_TLSOff, e_value_u64(thread_var->tls_off));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = module->space;
|
||||
@@ -1955,7 +1994,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(value));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
mapped_bytecode_space = module->space;
|
||||
@@ -1973,7 +2012,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff));
|
||||
string_mapped = 1;
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx);
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Value;
|
||||
mapped_bytecode_space = module->space;
|
||||
@@ -1982,11 +2021,12 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
U32 type_idx = match.idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
mapped_type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, dbgi_idx);
|
||||
string_mapped = 1;
|
||||
}break;
|
||||
}
|
||||
}
|
||||
access_close(access);
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -2004,7 +2044,16 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = e_base_ctx->thread_reg_space;
|
||||
mapped_type_key = e_type_key_reg(e_base_ctx->primary_module->arch, reg_num);
|
||||
REGS_UsageKind reg_usage_kind = regs_reg_code_usage_kind_table_from_arch(e_base_ctx->primary_module->arch)[reg_num];
|
||||
if(0){}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 1) {mapped_type_key = e_type_key_basic(E_TypeKind_U8);}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 2) {mapped_type_key = e_type_key_basic(E_TypeKind_U16);}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 4) {mapped_type_key = e_type_key_basic(E_TypeKind_U32);}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && reg_rng.byte_size == 8) {mapped_type_key = e_type_key_basic(E_TypeKind_U64);}
|
||||
else
|
||||
{
|
||||
mapped_type_key = e_type_key_reg(e_base_ctx->primary_module->arch, reg_num);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -2023,7 +2072,16 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
mapped_bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
mapped_bytecode_mode = E_Mode_Offset;
|
||||
mapped_bytecode_space = e_base_ctx->thread_reg_space;
|
||||
mapped_type_key = e_type_key_reg_alias(e_base_ctx->primary_module->arch, alias_num);
|
||||
REGS_UsageKind reg_usage_kind = regs_alias_code_usage_kind_table_from_arch(e_base_ctx->primary_module->arch)[alias_num];
|
||||
if(0){}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 1) {mapped_type_key = e_type_key_basic(E_TypeKind_U8);}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 2) {mapped_type_key = e_type_key_basic(E_TypeKind_U16);}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 4) {mapped_type_key = e_type_key_basic(E_TypeKind_U32);}
|
||||
else if(reg_usage_kind == REGS_UsageKind_Normal && alias_slice.byte_size == 8) {mapped_type_key = e_type_key_basic(E_TypeKind_U64);}
|
||||
else
|
||||
{
|
||||
mapped_type_key = e_type_key_reg_alias(e_base_ctx->primary_module->arch, alias_num);
|
||||
}
|
||||
}
|
||||
}break;
|
||||
|
||||
@@ -2120,7 +2178,6 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
{
|
||||
string_mapped = 1;
|
||||
RDI_LocationReg loc = *(RDI_LocationReg *)(all_location_data + block->location_data_off);
|
||||
|
||||
REGS_RegCode regs_reg_code = regs_reg_code_from_arch_rdi_code(arch, loc.reg_code);
|
||||
REGS_Rng reg_rng = regs_reg_code_rng_table_from_arch(arch)[regs_reg_code];
|
||||
E_OpList oplist = {0};
|
||||
@@ -2365,12 +2422,7 @@ e_push_irtree_and_type_from_expr(Arena *arena, E_IRTreeAndType *root_parent, E_I
|
||||
}
|
||||
if(irext != 0 && result.user_data == 0)
|
||||
{
|
||||
E_IRTreeAndType irtree_stripped = result;
|
||||
if(type->kind == E_TypeKind_Lens)
|
||||
{
|
||||
irtree_stripped.type_key = e_type_key_direct(irtree_stripped.type_key);
|
||||
}
|
||||
E_IRExt ext = irext(arena, expr, &irtree_stripped);
|
||||
E_IRExt ext = irext(arena, expr, &result);
|
||||
result.user_data = ext.user_data;
|
||||
}
|
||||
}
|
||||
@@ -2543,8 +2595,8 @@ e_append_oplist_from_irtree(Arena *arena, E_IRNode *root, E_Space *current_space
|
||||
U32 op = root->op;
|
||||
{
|
||||
E_Space zero_space = zero_struct;
|
||||
if(!MemoryMatchStruct(&root->space, &zero_space) &&
|
||||
!MemoryMatchStruct(&root->space, current_space))
|
||||
if(!e_space_match(root->space, zero_space) &&
|
||||
!e_space_match(root->space, *current_space))
|
||||
{
|
||||
*current_space = root->space;
|
||||
e_oplist_push_set_space(arena, out, root->space);
|
||||
@@ -2669,7 +2721,7 @@ e_bytecode_from_oplist(Arena *arena, E_OpList *oplist)
|
||||
|
||||
// rjf: fill bytecode
|
||||
ptr[0] = opcode;
|
||||
MemoryCopy(ptr + 1, &op->value.u64, extra_byte_count);
|
||||
MemoryCopy(ptr + 1, &op->value.u512.u8[0], extra_byte_count);
|
||||
|
||||
// rjf: advance
|
||||
ptr = next_ptr;
|
||||
|
||||
+2
-2
@@ -138,8 +138,8 @@ internal void e_irnode_push_child(E_IRNode *parent, E_IRNode *child);
|
||||
internal E_IRNode *e_irtree_const_u(Arena *arena, U64 v);
|
||||
internal E_IRNode *e_irtree_leaf_u128(Arena *arena, U128 u128);
|
||||
internal E_IRNode *e_irtree_unary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *c);
|
||||
internal E_IRNode *e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, E_IRNode *l, E_IRNode *r);
|
||||
internal E_IRNode *e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, E_IRNode *l, E_IRNode *r);
|
||||
internal E_IRNode *e_irtree_binary_op(Arena *arena, RDI_EvalOp op, RDI_EvalTypeGroup group, U64 operand_size, E_IRNode *l, E_IRNode *r);
|
||||
internal E_IRNode *e_irtree_binary_op_u(Arena *arena, RDI_EvalOp op, U64 operand_size, E_IRNode *l, E_IRNode *r);
|
||||
internal E_IRNode *e_irtree_conditional(Arena *arena, E_IRNode *c, E_IRNode *l, E_IRNode *r);
|
||||
internal E_IRNode *e_irtree_bytecode_no_copy(Arena *arena, String8 bytecode);
|
||||
internal E_IRNode *e_irtree_string_literal(Arena *arena, String8 string);
|
||||
|
||||
+16
-7
@@ -585,14 +585,23 @@ e_leaf_type_key_from_name(String8 name)
|
||||
E_TypeKey key = e_leaf_builtin_type_key_from_name(name);
|
||||
if(!e_type_key_match(e_type_key_zero(), key))
|
||||
{
|
||||
DI_Match match = di_match_from_name(e_base_ctx->dbgi_match_store, name, 0);
|
||||
if(match.section == RDI_SectionKind_TypeNodes)
|
||||
DI_Match match = di_match_from_string(name, 0, e_base_ctx->primary_module->dbgi_key, 0);
|
||||
if(match.section_kind == RDI_SectionKind_TypeNodes)
|
||||
{
|
||||
E_Module *module = &e_base_ctx->modules[match.dbgi_idx];
|
||||
RDI_Parsed *rdi = module->rdi;
|
||||
U32 type_idx = match.idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)match.dbgi_idx);
|
||||
Access *access = access_open();
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, match.key, 0, 0);
|
||||
for EachIndex(idx, e_base_ctx->modules_count)
|
||||
{
|
||||
E_Module *module = &e_base_ctx->modules[idx];
|
||||
if(module->rdi == rdi)
|
||||
{
|
||||
U32 type_idx = match.idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, type_idx);
|
||||
key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
access_close(access);
|
||||
}
|
||||
}
|
||||
return key;
|
||||
|
||||
+318
-3
@@ -2570,6 +2570,320 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(array)
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: (Built-In Type Hooks) `list` lens
|
||||
|
||||
internal AC_Artifact
|
||||
e_list_gather_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
//- rjf: unpack key
|
||||
// TODO(rjf): this needs to take any `E_Space`, once eval has been upgraded.
|
||||
CTRL_Handle process = {0};
|
||||
U64 base_off = 0;
|
||||
U64 member_element_off = 0;
|
||||
U64 member_size = 0;
|
||||
E_SpaceRWFunction *space_read = 0;
|
||||
{
|
||||
U64 key_read_off = 0;
|
||||
key_read_off += str8_deserial_read_struct(key, key_read_off, &process);
|
||||
key_read_off += str8_deserial_read_struct(key, key_read_off, &base_off);
|
||||
key_read_off += str8_deserial_read_struct(key, key_read_off, &member_element_off);
|
||||
key_read_off += str8_deserial_read_struct(key, key_read_off, &member_size);
|
||||
key_read_off += str8_deserial_read_struct(key, key_read_off, &space_read);
|
||||
}
|
||||
|
||||
//- rjf: gather chain
|
||||
typedef struct HitOffsetNode HitOffsetNode;
|
||||
struct HitOffsetNode
|
||||
{
|
||||
HitOffsetNode *next;
|
||||
U64 off;
|
||||
};
|
||||
typedef struct OffsetChunk OffsetChunk;
|
||||
struct OffsetChunk
|
||||
{
|
||||
OffsetChunk *next;
|
||||
U64 *v;
|
||||
U64 count;
|
||||
U64 cap;
|
||||
};
|
||||
OffsetChunk *first_chunk = 0;
|
||||
OffsetChunk *last_chunk = 0;
|
||||
U64 total_count = 0;
|
||||
B32 retry = 0;
|
||||
{
|
||||
U64 hit_slots_count = 4096;
|
||||
HitOffsetNode **hit_slots = push_array(scratch.arena, HitOffsetNode *, hit_slots_count);
|
||||
for(U64 off = base_off, next_off = 0;; off = next_off)
|
||||
{
|
||||
//- rjf: see if we've cycled
|
||||
B32 hit_cycle = 0;
|
||||
{
|
||||
U64 hash = u64_hash_from_str8(str8_struct(&off));
|
||||
U64 slot_idx = hash%hit_slots_count;
|
||||
for(HitOffsetNode *n = hit_slots[slot_idx]; n != 0; n = n->next)
|
||||
{
|
||||
if(n->off == off)
|
||||
{
|
||||
hit_cycle = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: terminate loop
|
||||
B32 terminated = (hit_cycle || off == 0);
|
||||
if(terminated)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
//- rjf: another node -> push offset to chunk list
|
||||
OffsetChunk *chunk = last_chunk;
|
||||
if(chunk == 0 || chunk->count >= chunk->cap)
|
||||
{
|
||||
chunk = push_array(scratch.arena, OffsetChunk, 1);
|
||||
SLLQueuePush(first_chunk, last_chunk, chunk);
|
||||
chunk->cap = 1024;
|
||||
chunk->v = push_array_no_zero(scratch.arena, U64, chunk->cap);
|
||||
}
|
||||
chunk->v[chunk->count] = off;
|
||||
chunk->count += 1;
|
||||
total_count += 1;
|
||||
|
||||
//- rjf: read next offset, advance
|
||||
B32 read_stale = 0;
|
||||
B32 read_good = ctrl_process_memory_read(process, r1u64(off + member_element_off, off + member_size), &read_stale, &next_off, 0);
|
||||
if(read_stale)
|
||||
{
|
||||
retry = 1;
|
||||
}
|
||||
if(!read_good)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: retry
|
||||
if(retry)
|
||||
{
|
||||
retry_out[0] = 1;
|
||||
}
|
||||
|
||||
//- rjf: flatten
|
||||
Arena *arena = 0;
|
||||
U64 node_offs_count = 0;
|
||||
U64 *node_offs = 0;
|
||||
if(!retry && total_count != 0)
|
||||
{
|
||||
arena = arena_alloc();
|
||||
node_offs_count = total_count;
|
||||
node_offs = push_array_no_zero(arena, U64, node_offs_count);
|
||||
{
|
||||
U64 idx = 0;
|
||||
for EachNode(n, OffsetChunk, first_chunk)
|
||||
{
|
||||
MemoryCopy(node_offs + idx, n->v, n->count * sizeof(n->v[0]));
|
||||
idx += n->count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: package
|
||||
AC_Artifact artifact = {0};
|
||||
{
|
||||
artifact.u64[0] = (U64)arena;
|
||||
artifact.u64[1] = (U64)node_offs;
|
||||
artifact.u64[2] = node_offs_count;
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return artifact;
|
||||
}
|
||||
|
||||
internal void
|
||||
e_list_gather_artifact_destroy(AC_Artifact artifact)
|
||||
{
|
||||
Arena *arena = (Arena *)artifact.u64[0];
|
||||
if(arena != 0)
|
||||
{
|
||||
arena_release(arena);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct E_ListIRExt E_ListIRExt;
|
||||
struct E_ListIRExt
|
||||
{
|
||||
U64 *offs;
|
||||
U64 offs_count;
|
||||
};
|
||||
|
||||
E_TYPE_IREXT_FUNCTION_DEF(list)
|
||||
{
|
||||
E_IRExt result = {0};
|
||||
E_Type *type = e_type_from_key(irtree->type_key);
|
||||
|
||||
//- rjf: get member encoding the link to the next node
|
||||
E_Member next_link_member = {0};
|
||||
{
|
||||
E_TypeKey node_type_key = e_type_key_unwrap(irtree->type_key, E_TypeUnwrapFlag_All);
|
||||
|
||||
// rjf: try explicitly-passed name
|
||||
if(next_link_member.kind == E_MemberKind_Null && type->args != 0 && type->count > 0 && type->args[0]->kind == E_ExprKind_LeafIdentifier)
|
||||
{
|
||||
String8 name = type->args[0]->string;
|
||||
next_link_member = e_type_member_from_key_name__cached(node_type_key, name);
|
||||
}
|
||||
|
||||
// rjf: try `next`
|
||||
if(next_link_member.kind == E_MemberKind_Null)
|
||||
{
|
||||
next_link_member = e_type_member_from_key_name__cached(node_type_key, str8_lit("next"));
|
||||
}
|
||||
|
||||
// rjf: try `prev`
|
||||
if(next_link_member.kind == E_MemberKind_Null)
|
||||
{
|
||||
next_link_member = e_type_member_from_key_name__cached(node_type_key, str8_lit("prev"));
|
||||
}
|
||||
|
||||
// rjf: try any pointer to the same type
|
||||
if(next_link_member.kind == E_MemberKind_Null)
|
||||
{
|
||||
E_Type *node_type = e_type_from_key(node_type_key);
|
||||
if(node_type->members != 0)
|
||||
{
|
||||
for EachIndex(idx, node_type->count)
|
||||
{
|
||||
if(node_type->members[idx].kind != E_MemberKind_DataField)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
E_TypeKey member_type_key = node_type->members[idx].type_key;
|
||||
E_TypeKey member_type_key_undecorated = e_type_key_unwrap(member_type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
E_TypeKey member_ptee_type_key = e_type_key_unwrap(member_type_key_undecorated, E_TypeUnwrapFlag_All);
|
||||
if(e_type_kind_from_key(member_type_key_undecorated) == E_TypeKind_Ptr &&
|
||||
e_type_key_match(member_ptee_type_key, node_type_key))
|
||||
{
|
||||
next_link_member = node_type->members[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//- rjf: generate expansion info
|
||||
E_TypeExpandInfo info = {0, 0};
|
||||
if(next_link_member.kind != E_MemberKind_DataField)
|
||||
{
|
||||
// TODO(rjf): error reporting
|
||||
}
|
||||
else
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
Access *access = access_open();
|
||||
|
||||
// rjf: evaluate first offset
|
||||
E_OpList oplist = e_oplist_from_irtree(scratch.arena, irtree->root);
|
||||
String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist);
|
||||
E_Interpretation base_off_interpret = e_interpret(bytecode);
|
||||
|
||||
// rjf: get artifact
|
||||
#pragma pack(push, 1)
|
||||
struct
|
||||
{
|
||||
CTRL_Handle process;
|
||||
U64 base_off;
|
||||
U64 member_element_off;
|
||||
U64 member_size;
|
||||
E_SpaceRWFunction *space_read;
|
||||
}
|
||||
key_data =
|
||||
{
|
||||
// TODO(rjf): we cannot use `rd_` here - only doing this because the base eval layer does not
|
||||
// support what we need yet...
|
||||
rd_ctrl_entity_from_eval_space(base_off_interpret.space)->handle,
|
||||
base_off_interpret.value.u64,
|
||||
next_link_member.off,
|
||||
e_type_byte_size_from_key(next_link_member.type_key),
|
||||
e_base_ctx->space_read,
|
||||
};
|
||||
#pragma pack(pop)
|
||||
AC_Artifact gather_artifact = ac_artifact_from_key(access, str8_struct(&key_data), e_list_gather_artifact_create, e_list_gather_artifact_destroy, 0, .gen = e_space_gen(base_off_interpret.space));
|
||||
U64 *offs = (U64 *)gather_artifact.u64[1];
|
||||
U64 offs_count = gather_artifact.u64[2];
|
||||
|
||||
// rjf: fill info from artifact
|
||||
E_ListIRExt *ext = push_array(arena, E_ListIRExt, 1);
|
||||
ext->offs = offs;
|
||||
ext->offs_count = offs_count;
|
||||
result.user_data = ext;
|
||||
|
||||
access_close(access);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
E_TYPE_EXPAND_INFO_FUNCTION_DEF(list)
|
||||
{
|
||||
E_ListIRExt *ext = (E_ListIRExt *)eval.irtree.user_data;
|
||||
U64 count = 0;
|
||||
if(ext != 0)
|
||||
{
|
||||
count = ext->offs_count;
|
||||
}
|
||||
E_TypeExpandInfo info = {0, count};
|
||||
return info;
|
||||
}
|
||||
|
||||
E_TYPE_ACCESS_FUNCTION_DEF(list)
|
||||
{
|
||||
E_IRTreeAndType result = {&e_irnode_nil};
|
||||
E_ListIRExt *ext = (E_ListIRExt *)lhs_irtree->user_data;
|
||||
if(ext != 0 && expr->kind == E_ExprKind_ArrayIndex)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
|
||||
// rjf: compute index
|
||||
E_Expr *rhs_expr = expr->last;
|
||||
E_IRTreeAndType rhs_irtree = e_push_irtree_and_type_from_expr(scratch.arena, overridden, &e_default_identifier_resolution_rule, 0, 0, rhs_expr);
|
||||
E_OpList rhs_oplist = e_oplist_from_irtree(scratch.arena, rhs_irtree.root);
|
||||
String8 rhs_bytecode = e_bytecode_from_oplist(scratch.arena, &rhs_oplist);
|
||||
E_Interpretation rhs_interpret = e_interpret(rhs_bytecode);
|
||||
U64 idx = rhs_interpret.value.u64;
|
||||
|
||||
// rjf: get offset
|
||||
U64 off = 0;
|
||||
if(idx < ext->offs_count)
|
||||
{
|
||||
off = ext->offs[idx];
|
||||
}
|
||||
|
||||
// rjf: generate IR tree to compute this offset w/ the node type
|
||||
result.root = e_irtree_const_u(arena, off);
|
||||
result.type_key = e_type_key_unwrap(lhs_irtree->type_key, E_TypeUnwrapFlag_AllDecorative);
|
||||
result.mode = E_Mode_Offset;
|
||||
|
||||
scratch_end(scratch);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
E_TYPE_EXPAND_RANGE_FUNCTION_DEF(list)
|
||||
{
|
||||
U64 read_range_count = dim_1u64(idx_range);
|
||||
for(U64 idx = 0; idx < read_range_count; idx += 1)
|
||||
{
|
||||
evals_out[idx] = e_eval_wrapf(eval, "$[%I64u]", idx_range.min + idx);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: (Built-In Type Hooks) `slice` lens
|
||||
|
||||
@@ -2661,6 +2975,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(slice)
|
||||
if(ext->base_ptr_member != 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
U64 addr_size = e_type_byte_size_from_key(ext->base_ptr_member->type_key);
|
||||
|
||||
// rjf: compute ir tree for struct base
|
||||
E_IRNode *struct_base_tree = &e_irnode_nil;
|
||||
@@ -2681,7 +2996,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(slice)
|
||||
base_ptr_tree = struct_base_tree;
|
||||
if(ext->base_ptr_member->off != 0)
|
||||
{
|
||||
base_ptr_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, struct_base_tree, e_irtree_const_u(arena, ext->base_ptr_member->off));
|
||||
base_ptr_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, addr_size, struct_base_tree, e_irtree_const_u(arena, ext->base_ptr_member->off));
|
||||
}
|
||||
base_ptr_tree = e_irtree_mem_read_type(arena, base_ptr_tree, ext->base_ptr_member->type_key);
|
||||
}
|
||||
@@ -2692,8 +3007,8 @@ E_TYPE_ACCESS_FUNCTION_DEF(slice)
|
||||
{
|
||||
E_IRTreeAndType idx_irtree = e_push_irtree_and_type_from_expr(arena, 0, &e_default_identifier_resolution_rule, 0, 1, expr->first->next);
|
||||
E_IRNode *idx_root = e_irtree_resolve_to_value(arena, idx_irtree.mode, idx_irtree.root, idx_irtree.type_key);
|
||||
E_IRNode *off_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, idx_root, e_irtree_const_u(arena, e_type_byte_size_from_key(e_type_key_unwrap(ext->base_ptr_member->type_key, E_TypeUnwrapFlag_All))));
|
||||
idxed_base_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, base_ptr_tree, off_root);
|
||||
E_IRNode *off_root = e_irtree_binary_op_u(arena, RDI_EvalOp_Mul, addr_size, idx_root, e_irtree_const_u(arena, e_type_byte_size_from_key(e_type_key_unwrap(ext->base_ptr_member->type_key, E_TypeUnwrapFlag_All))));
|
||||
idxed_base_tree = e_irtree_binary_op_u(arena, RDI_EvalOp_Add, addr_size, base_ptr_tree, off_root);
|
||||
}
|
||||
|
||||
// rjf: form final result
|
||||
|
||||
@@ -1769,6 +1769,18 @@ ev_string_iter_next(Arena *arena, EV_StringIter *it, String8 *out_string)
|
||||
new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key);
|
||||
}break;
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: bitfields
|
||||
//
|
||||
case E_TypeKind_Bitfield:
|
||||
{
|
||||
need_pop = 1;
|
||||
need_new_task = 1;
|
||||
new_task.params = *params;
|
||||
new_task.eval = e_value_eval_from_eval(eval);
|
||||
new_task.eval.irtree.type_key = e_type_key_direct(eval.irtree.type_key);
|
||||
}break;
|
||||
|
||||
//////////////////////////
|
||||
//- rjf: pointers
|
||||
//
|
||||
|
||||
@@ -32,7 +32,7 @@ fs_change_gen(void)
|
||||
//~ rjf: Cache Interaction
|
||||
|
||||
internal AC_Artifact
|
||||
fs_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out)
|
||||
fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
@@ -55,7 +55,7 @@ internal U64 fs_change_gen(void);
|
||||
////////////////////////////////
|
||||
//~ rjf: Artifact Cache Hooks / Accessing API
|
||||
|
||||
internal AC_Artifact fs_artifact_create(String8 key, U64 gen, U64 *requested_gen, B32 *retry_out);
|
||||
internal AC_Artifact fs_artifact_create(String8 key, B32 *cancel_signal, B32 *retry_out, U64 *gen_out);
|
||||
internal void fs_artifact_destroy(AC_Artifact artifact);
|
||||
|
||||
internal C_Key fs_key_from_path_range(String8 path, Rng1U64 range, U64 endt_us);
|
||||
|
||||
+26
-4
@@ -10,7 +10,7 @@
|
||||
#ifndef RDI_C
|
||||
#define RDI_C
|
||||
|
||||
RDI_U16 rdi_section_element_size_table[40] =
|
||||
RDI_U16 rdi_section_element_size_table[44] =
|
||||
{
|
||||
sizeof(RDI_U8),
|
||||
sizeof(RDI_TopLevelInfo),
|
||||
@@ -48,13 +48,17 @@ sizeof(RDI_LocationBlock),
|
||||
sizeof(RDI_U8),
|
||||
sizeof(RDI_U8),
|
||||
sizeof(RDI_U32),
|
||||
sizeof(RDI_MD5),
|
||||
sizeof(RDI_SHA1),
|
||||
sizeof(RDI_SHA256),
|
||||
sizeof(RDI_U64),
|
||||
sizeof(RDI_NameMap),
|
||||
sizeof(RDI_NameMapBucket),
|
||||
sizeof(RDI_NameMapNode),
|
||||
sizeof(RDI_U8),
|
||||
};
|
||||
|
||||
RDI_U16 rdi_eval_op_ctrlbits_table[52] =
|
||||
RDI_U16 rdi_eval_op_ctrlbits_table[53] =
|
||||
{
|
||||
RDI_EVAL_CTRLBITS(0, 0, 0),
|
||||
RDI_EVAL_CTRLBITS(0, 0, 0),
|
||||
@@ -81,8 +85,8 @@ RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(2, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(2, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
RDI_EVAL_CTRLBITS(1, 2, 1),
|
||||
@@ -107,6 +111,7 @@ RDI_EVAL_CTRLBITS(1, 1, 1),
|
||||
RDI_EVAL_CTRLBITS(4, 0, 0),
|
||||
RDI_EVAL_CTRLBITS(4, 0, 0),
|
||||
RDI_EVAL_CTRLBITS(8, 0, 0),
|
||||
RDI_EVAL_CTRLBITS(0, 2, 2),
|
||||
RDI_EVAL_CTRLBITS(0, 0, 0),
|
||||
};
|
||||
|
||||
@@ -317,4 +322,21 @@ rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RD
|
||||
return rdi_eval_conversion_kind_message_string_table[kind].str;
|
||||
}
|
||||
|
||||
RDI_PROC RDI_SectionKind
|
||||
rdi_section_kind_from_checksum_kind(RDI_ChecksumKind kind)
|
||||
{
|
||||
RDI_SectionKind result = 0;
|
||||
switch(kind)
|
||||
{
|
||||
default:{}break;
|
||||
case RDI_ChecksumKind_NULL:{result = RDI_SectionKind_NULL;}break;
|
||||
case RDI_ChecksumKind_MD5:{result = RDI_SectionKind_MD5Checksums;}break;
|
||||
case RDI_ChecksumKind_SHA1:{result = RDI_SectionKind_SHA1Checksums;}break;
|
||||
case RDI_ChecksumKind_SHA256:{result = RDI_SectionKind_SHA256Checksums;}break;
|
||||
case RDI_ChecksumKind_Timestamp:{result = RDI_SectionKind_Timestamps;}break;
|
||||
case RDI_ChecksumKind_COUNT:{result = RDI_SectionKind_NULL;}break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // RDI_C
|
||||
|
||||
+65
-8
@@ -40,6 +40,18 @@ typedef int32_t RDI_S32;
|
||||
typedef int64_t RDI_S64;
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Checksum Types
|
||||
|
||||
typedef union RDI_MD5 RDI_MD5;
|
||||
union RDI_MD5 {RDI_U8 u8[16]; RDI_U64 u64[2];};
|
||||
|
||||
typedef union RDI_SHA1 RDI_SHA1;
|
||||
union RDI_SHA1 {RDI_U8 u8[20];};
|
||||
|
||||
typedef union RDI_SHA256 RDI_SHA256;
|
||||
union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Overridable Enabling/Disabling Of Table Index Typechecking
|
||||
|
||||
@@ -52,7 +64,7 @@ typedef int64_t RDI_S64;
|
||||
|
||||
// "raddbg\0\0"
|
||||
#define RDI_MAGIC_CONSTANT 0x0000676264646172
|
||||
#define RDI_ENCODING_VERSION 13
|
||||
#define RDI_ENCODING_VERSION 16
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//~ Format Types & Functions
|
||||
@@ -96,10 +108,14 @@ RDI_SectionKind_LocationBlocks = 0x0020,
|
||||
RDI_SectionKind_LocationData = 0x0021,
|
||||
RDI_SectionKind_ConstantValueData = 0x0022,
|
||||
RDI_SectionKind_ConstantValueTable = 0x0023,
|
||||
RDI_SectionKind_NameMaps = 0x0024,
|
||||
RDI_SectionKind_NameMapBuckets = 0x0025,
|
||||
RDI_SectionKind_NameMapNodes = 0x0026,
|
||||
RDI_SectionKind_COUNT = 0x0027,
|
||||
RDI_SectionKind_MD5Checksums = 0x0024,
|
||||
RDI_SectionKind_SHA1Checksums = 0x0025,
|
||||
RDI_SectionKind_SHA256Checksums = 0x0026,
|
||||
RDI_SectionKind_Timestamps = 0x0027,
|
||||
RDI_SectionKind_NameMaps = 0x0028,
|
||||
RDI_SectionKind_NameMapBuckets = 0x0029,
|
||||
RDI_SectionKind_NameMapNodes = 0x002A,
|
||||
RDI_SectionKind_COUNT = 0x002B,
|
||||
} RDI_SectionKindEnum;
|
||||
|
||||
typedef RDI_U32 RDI_SectionEncoding;
|
||||
@@ -305,6 +321,17 @@ RDI_BinarySectionFlag_Write = 1<<1,
|
||||
RDI_BinarySectionFlag_Execute = 1<<2,
|
||||
} RDI_BinarySectionFlagsEnum;
|
||||
|
||||
typedef RDI_U32 RDI_ChecksumKind;
|
||||
typedef enum RDI_ChecksumKindEnum
|
||||
{
|
||||
RDI_ChecksumKind_NULL = 0,
|
||||
RDI_ChecksumKind_MD5 = 1,
|
||||
RDI_ChecksumKind_SHA1 = 2,
|
||||
RDI_ChecksumKind_SHA256 = 3,
|
||||
RDI_ChecksumKind_Timestamp = 4,
|
||||
RDI_ChecksumKind_COUNT = 5,
|
||||
} RDI_ChecksumKindEnum;
|
||||
|
||||
typedef RDI_U32 RDI_Language;
|
||||
typedef enum RDI_LanguageEnum
|
||||
{
|
||||
@@ -496,7 +523,8 @@ RDI_EvalOp_ByteSwap = 47,
|
||||
RDI_EvalOp_CallSiteValue = 48,
|
||||
RDI_EvalOp_PartialValue = 49,
|
||||
RDI_EvalOp_PartialValueBit = 50,
|
||||
RDI_EvalOp_COUNT = 51,
|
||||
RDI_EvalOp_Swap = 51,
|
||||
RDI_EvalOp_COUNT = 52,
|
||||
} RDI_EvalOpEnum;
|
||||
|
||||
typedef RDI_U8 RDI_EvalTypeGroup;
|
||||
@@ -578,6 +606,10 @@ X(LocationBlocks, location_blocks, RDI_LocationBlock)\
|
||||
X(LocationData, location_data, RDI_U8)\
|
||||
X(ConstantValueData, constant_value_data, RDI_U8)\
|
||||
X(ConstantValueTable, constant_value_table, RDI_U32)\
|
||||
X(MD5Checksums, md5_checksums, RDI_MD5)\
|
||||
X(SHA1Checksums, sha1_checksums, RDI_SHA1)\
|
||||
X(SHA256Checksums, sha256_checksums, RDI_SHA256)\
|
||||
X(Timestamps, timestamps, RDI_U64)\
|
||||
X(NameMaps, name_maps, RDI_NameMap)\
|
||||
X(NameMapBuckets, name_map_buckets, RDI_NameMapBucket)\
|
||||
X(NameMapNodes, name_map_nodes, RDI_NameMapNode)\
|
||||
@@ -790,6 +822,14 @@ X(RDI_U64, voff_opl)\
|
||||
X(RDI_U64, foff_first)\
|
||||
X(RDI_U64, foff_opl)\
|
||||
|
||||
#define RDI_ChecksumKind_XList \
|
||||
X(NULL, NULL)\
|
||||
X(MD5, MD5Checksums)\
|
||||
X(SHA1, SHA1Checksums)\
|
||||
X(SHA256, SHA256Checksums)\
|
||||
X(Timestamp, Timestamps)\
|
||||
X(COUNT, NULL)\
|
||||
|
||||
#define RDI_FilePathNode_XList \
|
||||
X(RDI_U32, name_string_idx)\
|
||||
X(RDI_U32, parent_path_node)\
|
||||
@@ -801,6 +841,8 @@ X(RDI_U32, source_file_idx)\
|
||||
X(RDI_U32, file_path_node_idx)\
|
||||
X(RDI_U32, normal_full_path_string_idx)\
|
||||
X(RDI_U32, source_line_map_idx)\
|
||||
X(RDI_ChecksumKind, checksum_kind)\
|
||||
X(RDI_U32, checksum_idx)\
|
||||
|
||||
#define RDI_Unit_XList \
|
||||
X(RDI_U32, unit_name_string_idx)\
|
||||
@@ -1081,6 +1123,7 @@ X(ByteSwap)\
|
||||
X(CallSiteValue)\
|
||||
X(PartialValue)\
|
||||
X(PartialValueBit)\
|
||||
X(Swap)\
|
||||
|
||||
#define RDI_EvalTypeGroup_XList \
|
||||
X(Other)\
|
||||
@@ -1152,6 +1195,10 @@ typedef struct RDI_U32_LocationBlocks { RDI_U32 v; } RDI_U32_Locati
|
||||
typedef struct RDI_U32_LocationData { RDI_U32 v; } RDI_U32_LocationData;
|
||||
typedef struct RDI_U32_ConstantValueData { RDI_U32 v; } RDI_U32_ConstantValueData;
|
||||
typedef struct RDI_U32_ConstantValueTable { RDI_U32 v; } RDI_U32_ConstantValueTable;
|
||||
typedef struct RDI_U32_MD5Checksums { RDI_U32 v; } RDI_U32_MD5Checksums;
|
||||
typedef struct RDI_U32_SHA1Checksums { RDI_U32 v; } RDI_U32_SHA1Checksums;
|
||||
typedef struct RDI_U32_SHA256Checksums { RDI_U32 v; } RDI_U32_SHA256Checksums;
|
||||
typedef struct RDI_U32_Timestamps { RDI_U32 v; } RDI_U32_Timestamps;
|
||||
typedef struct RDI_U32_NameMaps { RDI_U32 v; } RDI_U32_NameMaps;
|
||||
typedef struct RDI_U32_NameMapBuckets { RDI_U32 v; } RDI_U32_NameMapBuckets;
|
||||
typedef struct RDI_U32_NameMapNodes { RDI_U32 v; } RDI_U32_NameMapNodes;
|
||||
@@ -1188,6 +1235,10 @@ typedef RDI_U32_Table RDI_U32_LocationBlocks;
|
||||
typedef RDI_U32_Table RDI_U32_LocationData;
|
||||
typedef RDI_U32_Table RDI_U32_ConstantValueData;
|
||||
typedef RDI_U32_Table RDI_U32_ConstantValueTable;
|
||||
typedef RDI_U32_Table RDI_U32_MD5Checksums;
|
||||
typedef RDI_U32_Table RDI_U32_SHA1Checksums;
|
||||
typedef RDI_U32_Table RDI_U32_SHA256Checksums;
|
||||
typedef RDI_U32_Table RDI_U32_Timestamps;
|
||||
typedef RDI_U32_Table RDI_U32_NameMaps;
|
||||
typedef RDI_U32_Table RDI_U32_NameMapBuckets;
|
||||
typedef RDI_U32_Table RDI_U32_NameMapNodes;
|
||||
@@ -1262,6 +1313,8 @@ struct RDI_SourceFile
|
||||
RDI_U32 file_path_node_idx;
|
||||
RDI_U32 normal_full_path_string_idx;
|
||||
RDI_U32 source_line_map_idx;
|
||||
RDI_ChecksumKind checksum_kind;
|
||||
RDI_U32 checksum_idx;
|
||||
};
|
||||
|
||||
typedef struct RDI_Unit RDI_Unit;
|
||||
@@ -1555,6 +1608,10 @@ typedef RDI_LocationBlock RDI_SectionElementType_LocationBlocks;
|
||||
typedef RDI_U8 RDI_SectionElementType_LocationData;
|
||||
typedef RDI_U8 RDI_SectionElementType_ConstantValueData;
|
||||
typedef RDI_U32 RDI_SectionElementType_ConstantValueTable;
|
||||
typedef RDI_MD5 RDI_SectionElementType_MD5Checksums;
|
||||
typedef RDI_SHA1 RDI_SectionElementType_SHA1Checksums;
|
||||
typedef RDI_SHA256 RDI_SectionElementType_SHA256Checksums;
|
||||
typedef RDI_U64 RDI_SectionElementType_Timestamps;
|
||||
typedef RDI_NameMap RDI_SectionElementType_NameMaps;
|
||||
typedef RDI_NameMapBucket RDI_SectionElementType_NameMapBuckets;
|
||||
typedef RDI_NameMapNode RDI_SectionElementType_NameMapNodes;
|
||||
@@ -1567,7 +1624,7 @@ RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_kind_from_typegroups(RDI_Eva
|
||||
RDI_PROC RDI_S32 rdi_eval_op_typegroup_are_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group);
|
||||
RDI_PROC RDI_U8 *rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RDI_U64 *size_out);
|
||||
|
||||
extern RDI_U16 rdi_section_element_size_table[40];
|
||||
extern RDI_U16 rdi_eval_op_ctrlbits_table[52];
|
||||
extern RDI_U16 rdi_section_element_size_table[44];
|
||||
extern RDI_U16 rdi_eval_op_ctrlbits_table[53];
|
||||
|
||||
#endif // RDI_H
|
||||
|
||||
+113
-8
@@ -941,7 +941,7 @@ rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkList *dst, RDIM_
|
||||
|
||||
//- rjf: bytecode
|
||||
|
||||
RDI_PROC void
|
||||
RDI_PROC RDIM_EvalBytecodeOp *
|
||||
rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p)
|
||||
{
|
||||
RDI_U16 ctrlbits = rdi_eval_op_ctrlbits_table[op];
|
||||
@@ -955,6 +955,8 @@ rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp
|
||||
RDIM_SLLQueuePush(bytecode->first_op, bytecode->last_op, node);
|
||||
bytecode->op_count += 1;
|
||||
bytecode->encoded_size += 1 + p_size;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
RDI_PROC void
|
||||
@@ -1002,6 +1004,12 @@ rdim_bytecode_push_sconst(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_S6
|
||||
}
|
||||
}
|
||||
|
||||
RDI_PROC void
|
||||
rdim_bytecode_push_convert(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalTypeGroup in, RDI_EvalTypeGroup out)
|
||||
{
|
||||
rdim_bytecode_push_op(arena, bytecode, RDI_EvalOp_Convert, (U16)(in) | ((U16)(out) << 8));
|
||||
}
|
||||
|
||||
RDI_PROC void
|
||||
rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed)
|
||||
{
|
||||
@@ -1022,6 +1030,21 @@ rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *ri
|
||||
}
|
||||
}
|
||||
|
||||
RDI_PROC B32
|
||||
rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bytecode)
|
||||
{
|
||||
B32 result = 0;
|
||||
for(RDIM_EvalBytecodeOp *n = bytecode.first_op; n != 0; n = n->next)
|
||||
{
|
||||
if(n->op == RDI_EvalOp_TLSOff)
|
||||
{
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//- rjf: locations
|
||||
|
||||
RDI_PROC RDI_U64
|
||||
@@ -1148,6 +1171,90 @@ rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RD
|
||||
return rdim_push_location_case(arena, scopes, &local->location_cases, location, voff_range);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: [Building] Bake Parameter Joining
|
||||
|
||||
RDI_PROC void
|
||||
rdim_bake_params_concat_in_place(RDIM_BakeParams *dst, RDIM_BakeParams *src)
|
||||
{
|
||||
// rjf: join top-level info (deduplicate - throw away conflicts)
|
||||
{
|
||||
dst->subset_flags |= src->subset_flags;
|
||||
if(dst->top_level_info.arch == RDI_Arch_NULL)
|
||||
{
|
||||
dst->top_level_info.arch = src->top_level_info.arch;
|
||||
}
|
||||
if(dst->top_level_info.exe_name.size == 0)
|
||||
{
|
||||
dst->top_level_info.exe_name = src->top_level_info.exe_name;
|
||||
}
|
||||
if(dst->top_level_info.exe_hash == 0)
|
||||
{
|
||||
dst->top_level_info.exe_hash = src->top_level_info.exe_hash;
|
||||
}
|
||||
if(dst->top_level_info.voff_max == 0)
|
||||
{
|
||||
dst->top_level_info.voff_max = src->top_level_info.voff_max;
|
||||
}
|
||||
if(dst->top_level_info.producer_name.size == 0)
|
||||
{
|
||||
dst->top_level_info.producer_name = src->top_level_info.producer_name;
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: join binary sections (deduplicate)
|
||||
{
|
||||
RDIM_Temp scratch = rdim_scratch_begin(0, 0);
|
||||
RDI_U64 slots_count = 256;
|
||||
RDIM_BinarySectionNode **slots = rdim_push_array(scratch.arena, RDIM_BinarySectionNode *, slots_count);
|
||||
for(RDIM_BinarySectionNode *n = dst->binary_sections.first; n != 0; n = n->next)
|
||||
{
|
||||
RDIM_BinarySectionNode *hash_node = rdim_push_array(scratch.arena, RDIM_BinarySectionNode, 1);
|
||||
RDI_U64 hash = rdi_hash(n->v.name.str, n->v.name.size);
|
||||
RDI_U64 slot_idx = hash%slots_count;
|
||||
RDIM_SLLStackPush(slots[slot_idx], hash_node);
|
||||
hash_node->v = n->v;
|
||||
}
|
||||
for(RDIM_BinarySectionNode *n = src->binary_sections.first, *next = 0; n != 0; n = next)
|
||||
{
|
||||
next = n->next;
|
||||
RDI_U64 hash = rdi_hash(n->v.name.str, n->v.name.size);
|
||||
RDI_U64 slot_idx = hash%slots_count;
|
||||
RDI_S32 is_duplicate = 0;
|
||||
for(RDIM_BinarySectionNode *hash_n = slots[slot_idx]; hash_n != 0; hash_n = hash_n->next)
|
||||
{
|
||||
if(rdim_str8_match(hash_n->v.name, n->v.name, 0))
|
||||
{
|
||||
is_duplicate = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!is_duplicate)
|
||||
{
|
||||
RDIM_SLLQueuePush(dst->binary_sections.first, dst->binary_sections.last, n);
|
||||
dst->binary_sections.count += 1;
|
||||
}
|
||||
}
|
||||
rdim_scratch_end(scratch);
|
||||
}
|
||||
|
||||
// rjf: join non-top-level chunk lists
|
||||
{
|
||||
rdim_unit_chunk_list_concat_in_place(&dst->units, &src->units);
|
||||
rdim_type_chunk_list_concat_in_place(&dst->types, &src->types);
|
||||
rdim_udt_chunk_list_concat_in_place(&dst->udts, &src->udts);
|
||||
rdim_src_file_chunk_list_concat_in_place(&dst->src_files, &src->src_files);
|
||||
rdim_line_table_chunk_list_concat_in_place(&dst->line_tables, &src->line_tables);
|
||||
rdim_location_chunk_list_concat_in_place(&dst->locations, &src->locations);
|
||||
rdim_symbol_chunk_list_concat_in_place(&dst->global_variables, &src->global_variables);
|
||||
rdim_symbol_chunk_list_concat_in_place(&dst->thread_variables, &src->thread_variables);
|
||||
rdim_symbol_chunk_list_concat_in_place(&dst->constants, &src->constants);
|
||||
rdim_symbol_chunk_list_concat_in_place(&dst->procedures, &src->procedures);
|
||||
rdim_scope_chunk_list_concat_in_place(&dst->scopes, &src->scopes);
|
||||
rdim_inline_site_chunk_list_concat_in_place(&dst->inline_sites, &src->inline_sites);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: [Baking Helpers] Deduplicated String Baking Map
|
||||
|
||||
@@ -2022,15 +2129,13 @@ rdim_serialized_section_bundle_from_bake_results(RDIM_BakeResults *results)
|
||||
bundle.sections[RDI_SectionKind_ScopeVMap] = rdim_serialized_section_make_unpacked_array(results->scope_vmap.vmap.vmap, results->scope_vmap.vmap.count);
|
||||
bundle.sections[RDI_SectionKind_InlineSites] = rdim_serialized_section_make_unpacked_array(results->inline_sites.inline_sites, results->inline_sites.inline_sites_count);
|
||||
bundle.sections[RDI_SectionKind_Locals] = rdim_serialized_section_make_unpacked_array(results->scopes.locals, results->scopes.locals_count);
|
||||
bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks.str, results->location_blocks.size);
|
||||
bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->location_data.str, results->location_data.size);
|
||||
if(results->location_blocks.size == 0)
|
||||
{
|
||||
bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks2.location_blocks, results->location_blocks2.location_blocks_count);
|
||||
bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->locations.location_data, results->locations.location_data_size);
|
||||
}
|
||||
bundle.sections[RDI_SectionKind_LocationBlocks] = rdim_serialized_section_make_unpacked_array(results->location_blocks.location_blocks, results->location_blocks.location_blocks_count);
|
||||
bundle.sections[RDI_SectionKind_LocationData] = rdim_serialized_section_make_unpacked_array(results->locations.location_data, results->locations.location_data_size);
|
||||
bundle.sections[RDI_SectionKind_ConstantValueData] = rdim_serialized_section_make_unpacked_array(results->constants.constant_value_data, results->constants.constant_value_data_size);
|
||||
bundle.sections[RDI_SectionKind_ConstantValueTable] = rdim_serialized_section_make_unpacked_array(results->constants.constant_values, results->constants.constant_values_count);
|
||||
bundle.sections[RDI_SectionKind_MD5Checksums] = rdim_serialized_section_make_unpacked_array(results->checksums.md5s, results->checksums.md5s_count);
|
||||
bundle.sections[RDI_SectionKind_SHA1Checksums] = rdim_serialized_section_make_unpacked_array(results->checksums.sha1s, results->checksums.sha1s_count);
|
||||
bundle.sections[RDI_SectionKind_SHA256Checksums] = rdim_serialized_section_make_unpacked_array(results->checksums.sha256s, results->checksums.sha256s_count);
|
||||
bundle.sections[RDI_SectionKind_NameMaps] = rdim_serialized_section_make_unpacked_array(results->top_level_name_maps.name_maps, results->top_level_name_maps.name_maps_count);
|
||||
bundle.sections[RDI_SectionKind_NameMapBuckets] = rdim_serialized_section_make_unpacked_array(results->name_maps.buckets, results->name_maps.buckets_count);
|
||||
bundle.sections[RDI_SectionKind_NameMapNodes] = rdim_serialized_section_make_unpacked_array(results->name_maps.nodes, results->name_maps.nodes_count);
|
||||
|
||||
+42
-11
@@ -325,19 +325,21 @@ X(Types, types)\
|
||||
X(UDTs, udts)\
|
||||
X(LineInfo, line_info)\
|
||||
X(InlineLineInfo, inline_line_info)\
|
||||
X(GlobalVariableNameMap, global_variable_name_map)\
|
||||
X(ThreadVariableNameMap, thread_variable_name_map)\
|
||||
X(ProcedureNameMap, procedure_name_map)\
|
||||
X(ConstantNameMap, constant_name_map)\
|
||||
X(TypeNameMap, type_name_map)\
|
||||
X(LinkNameProcedureNameMap, link_name_procedure_name_map)\
|
||||
X(NormalSourcePathNameMap, normal_source_path_name_map)\
|
||||
Y(GlobalVariableNameMap, global_variable_name_map)\
|
||||
Y(ThreadVariableNameMap, thread_variable_name_map)\
|
||||
Y(ProcedureNameMap, procedure_name_map)\
|
||||
Y(ConstantNameMap, constant_name_map)\
|
||||
Y(TypeNameMap, type_name_map)\
|
||||
Y(LinkNameProcedureNameMap, link_name_procedure_name_map)\
|
||||
Y(NormalSourcePathNameMap, normal_source_path_name_map)\
|
||||
|
||||
typedef enum RDIM_Subset
|
||||
{
|
||||
#define X(name, name_lower) RDIM_Subset_##name,
|
||||
#define Y(name, name_lower) RDIM_Subset_##name,
|
||||
RDIM_Subset_XList
|
||||
#undef X
|
||||
#undef Y
|
||||
}
|
||||
RDIM_Subset;
|
||||
|
||||
@@ -345,8 +347,15 @@ typedef U32 RDIM_SubsetFlags;
|
||||
enum
|
||||
{
|
||||
#define X(name, name_lower) RDIM_SubsetFlag_##name = (1<<RDIM_Subset_##name),
|
||||
#define Y(name, name_lower) RDIM_SubsetFlag_##name = (1<<RDIM_Subset_##name),
|
||||
RDIM_Subset_XList
|
||||
#undef X
|
||||
#undef Y
|
||||
#define X(name, name_lower)
|
||||
#define Y(name, name_lower) |RDIM_SubsetFlag_##name
|
||||
RDIM_SubsetFlag_NameMaps = 0 RDIM_Subset_XList,
|
||||
#undef X
|
||||
#undef Y
|
||||
RDIM_SubsetFlag_All = 0xffffffffu,
|
||||
};
|
||||
|
||||
@@ -540,6 +549,8 @@ struct RDIM_SrcFile
|
||||
RDIM_SrcFileLineMapFragment *first_line_map_fragment;
|
||||
RDIM_SrcFileLineMapFragment *last_line_map_fragment;
|
||||
RDI_U64 total_line_count;
|
||||
RDI_ChecksumKind checksum_kind;
|
||||
RDIM_String8 checksum;
|
||||
};
|
||||
|
||||
typedef struct RDIM_SrcFileChunkNode RDIM_SrcFileChunkNode;
|
||||
@@ -994,6 +1005,7 @@ struct RDIM_ScopeChunkList
|
||||
typedef struct RDIM_BakeParams RDIM_BakeParams;
|
||||
struct RDIM_BakeParams
|
||||
{
|
||||
RDIM_SubsetFlags subset_flags;
|
||||
RDIM_TopLevelInfo top_level_info;
|
||||
RDIM_BinarySectionList binary_sections;
|
||||
RDIM_UnitChunkList units;
|
||||
@@ -1310,6 +1322,19 @@ struct RDIM_SrcFileBakeResult
|
||||
RDI_U64 source_line_map_voffs_count;
|
||||
};
|
||||
|
||||
typedef struct RDIM_ChecksumBakeResult RDIM_ChecksumBakeResult;
|
||||
struct RDIM_ChecksumBakeResult
|
||||
{
|
||||
RDI_MD5 *md5s;
|
||||
RDI_U64 md5s_count;
|
||||
RDI_SHA1 *sha1s;
|
||||
RDI_U64 sha1s_count;
|
||||
RDI_SHA256 *sha256s;
|
||||
RDI_U64 sha256s_count;
|
||||
RDI_U64 *timestamps;
|
||||
RDI_U64 timestamps_count;
|
||||
};
|
||||
|
||||
typedef struct RDIM_LineTableBakeResult RDIM_LineTableBakeResult;
|
||||
struct RDIM_LineTableBakeResult
|
||||
{
|
||||
@@ -1464,6 +1489,7 @@ struct RDIM_BakeResults
|
||||
RDIM_UnitBakeResult units;
|
||||
RDIM_UnitVMapBakeResult unit_vmap;
|
||||
RDIM_SrcFileBakeResult src_files;
|
||||
RDIM_ChecksumBakeResult checksums;
|
||||
RDIM_LineTableBakeResult line_tables;
|
||||
RDIM_TypeNodeBakeResult type_nodes;
|
||||
RDIM_UDTBakeResult udts;
|
||||
@@ -1481,9 +1507,7 @@ struct RDIM_BakeResults
|
||||
RDIM_StringBakeResult strings;
|
||||
RDIM_IndexRunBakeResult idx_runs;
|
||||
RDIM_LocationBakeResult locations;
|
||||
RDIM_LocationBlockBakeResult location_blocks2;
|
||||
RDIM_String8 location_blocks;
|
||||
RDIM_String8 location_data;
|
||||
RDIM_LocationBlockBakeResult location_blocks;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
@@ -1634,10 +1658,12 @@ RDI_PROC void rdim_inline_site_chunk_list_concat_in_place(RDIM_InlineSiteChunkLi
|
||||
//~ rjf: [Building] Location Info Building
|
||||
|
||||
//- rjf: bytecode
|
||||
RDI_PROC void rdim_bytecode_push_op(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalOp op, RDI_U64 p);
|
||||
RDI_PROC RDIM_EvalBytecodeOp * 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_push_convert(RDIM_Arena *arena, RDIM_EvalBytecode *bytecode, RDI_EvalTypeGroup in, RDI_EvalTypeGroup out);
|
||||
RDI_PROC void rdim_bytecode_concat_in_place(RDIM_EvalBytecode *left_dst, RDIM_EvalBytecode *right_destroyed);
|
||||
RDI_PROC B32 rdim_is_bytecode_tls_dependent(RDIM_EvalBytecode bytecode);
|
||||
|
||||
//- rjf: locations
|
||||
RDI_PROC RDI_U64 rdim_encoded_size_from_location_info(RDIM_LocationInfo *info);
|
||||
@@ -1655,6 +1681,11 @@ RDI_PROC void rdim_scope_push_voff_range(RDIM_Arena *arena, RDIM_ScopeChunkList
|
||||
RDI_PROC RDIM_Local *rdim_scope_push_local(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *scope);
|
||||
RDI_PROC RDIM_LocationCase *rdim_local_push_location_case(RDIM_Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Local *local, RDIM_Location *location, RDIM_Rng1U64 voff_range);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: [Building] Bake Parameter Joining
|
||||
|
||||
RDI_PROC void rdim_bake_params_concat_in_place(RDIM_BakeParams *dst, RDIM_BakeParams *src);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: [Baking Helpers] Deduplicated String Baking Map
|
||||
|
||||
|
||||
@@ -7,5 +7,4 @@
|
||||
#include "base_arrays.c"
|
||||
#include "base_bit_array.c"
|
||||
#include "base_crc32.c"
|
||||
#include "base_md5.c"
|
||||
|
||||
|
||||
@@ -10,5 +10,4 @@
|
||||
#include "base_blake3.h"
|
||||
#include "base_bit_array.h"
|
||||
#include "base_crc32.h"
|
||||
#include "base_md5.h"
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal MD5Hash
|
||||
md5_hash_from_string(String8 data)
|
||||
{
|
||||
MD5_CTX ctx; MD5_Init(&ctx);
|
||||
MD5_Update(&ctx, (void*)data.str, safe_cast_u32(data.size));
|
||||
MD5Hash hash; MD5_Final((unsigned char*)&hash, &ctx);
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct MD5Hash
|
||||
{
|
||||
U8 value[16];
|
||||
} MD5Hash;
|
||||
|
||||
internal MD5Hash md5_hash_from_string(String8 data);
|
||||
|
||||
+4
-7
@@ -14,9 +14,6 @@
|
||||
|
||||
#include "base_ext/base_blake3.h"
|
||||
#include "base_ext/base_blake3.c"
|
||||
#define MD5_API static
|
||||
#include "third_party/md5/md5.c"
|
||||
#include "third_party/md5/md5.h"
|
||||
#define XXH_INLINE_ALL
|
||||
#define XXH_IMPLEMENTATION
|
||||
#define XXH_STATIC_LINKING_ONLY
|
||||
@@ -667,7 +664,7 @@ lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer,
|
||||
String8 exe_path,
|
||||
CV_Arch arch,
|
||||
String8List res_file_list,
|
||||
MD5Hash *res_hash_array)
|
||||
MD5 *res_hash_array)
|
||||
{
|
||||
ProfBeginFunction();
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
@@ -686,7 +683,7 @@ lnk_add_resource_debug_s(COFF_ObjWriter *obj_writer,
|
||||
for (String8Node *n = res_file_list.first; n != NULL; n = n->next, ++node_idx) {
|
||||
CV_C13Checksum checksum = {0};
|
||||
checksum.name_off = string_srl.total_size;
|
||||
checksum.len = sizeof(MD5Hash);
|
||||
checksum.len = sizeof(MD5);
|
||||
checksum.kind = CV_C13ChecksumKind_MD5;
|
||||
str8_serial_push_struct(scratch.arena, &file_srl, &checksum);
|
||||
str8_serial_push_struct(scratch.arena, &file_srl, &res_hash_array[node_idx]);
|
||||
@@ -779,10 +776,10 @@ lnk_make_res_obj(Arena *arena,
|
||||
|
||||
// load res files
|
||||
PE_ResourceDir *root_dir = push_array(scratch.arena, PE_ResourceDir, 1);
|
||||
MD5Hash *res_hash_array = push_array(scratch.arena, MD5Hash, res_data_list.node_count);
|
||||
MD5 *res_hash_array = push_array(scratch.arena, MD5, res_data_list.node_count);
|
||||
U64 node_idx = 0;
|
||||
for (String8Node *node = res_data_list.first; node != 0; node = node->next, node_idx += 1) {
|
||||
res_hash_array[node_idx] = md5_hash_from_string(node->string);
|
||||
res_hash_array[node_idx] = md5_from_data(node->string);
|
||||
pe_resource_dir_push_res_file(scratch.arena, root_dir, node->string);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,15 +14,6 @@ StaticAssert(sizeof(RDI_Header) == AlignPow2(sizeof(RDI_Header), 8), g_rdi_heade
|
||||
#define RDI_IsBuiltinType(x) (RDI_TypeKind_FirstBuiltIn <= (x) && (x) <= RDI_TypeKind_LastBuiltIn)
|
||||
#define RDI_IsPtrType(x) ((x) == RDI_TypeKind_Ptr || (x) == RDI_TypeKind_LRef || (x) == RDI_TypeKind_RRef)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RDI_Checksum_Null,
|
||||
RDI_Checksum_MD5,
|
||||
RDI_Checksum_SHA1,
|
||||
RDI_Checksum_SHA256,
|
||||
RDI_Checksum_TimeStamp
|
||||
} RDI_ChecksumKind;
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -234,11 +234,10 @@ internal RDI_ChecksumKind
|
||||
rdi_checksum_from_cv_c13(CV_C13ChecksumKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case CV_C13ChecksumKind_Null: return RDI_Checksum_Null;
|
||||
case CV_C13ChecksumKind_MD5: return RDI_Checksum_MD5;
|
||||
case CV_C13ChecksumKind_SHA1: return RDI_Checksum_SHA1;
|
||||
case CV_C13ChecksumKind_SHA256: return RDI_Checksum_SHA256;
|
||||
case CV_C13ChecksumKind_Null: return RDI_ChecksumKind_NULL;
|
||||
case CV_C13ChecksumKind_MD5: return RDI_ChecksumKind_MD5;
|
||||
case CV_C13ChecksumKind_SHA1: return RDI_ChecksumKind_SHA1;
|
||||
case CV_C13ChecksumKind_SHA256: return RDI_ChecksumKind_SHA256;
|
||||
}
|
||||
InvalidPath;
|
||||
return RDI_Checksum_Null;
|
||||
return RDI_ChecksumKind_NULL;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#if !_WIN32
|
||||
# define RADDBG_MARKUP_STUBS
|
||||
@@ -523,6 +524,20 @@ type_coverage_eval_tests(void)
|
||||
|
||||
Has_Enums has_enums = {(Kind)4, (Flag)7};
|
||||
|
||||
struct EnumBitfields
|
||||
{
|
||||
Kind k1 : 4;
|
||||
Kind k2 : 3;
|
||||
Kind k3 : 1;
|
||||
Kind k4 : 16;
|
||||
};
|
||||
|
||||
EnumBitfields enum_bitfields = {};
|
||||
enum_bitfields.k1 = Kind_First;
|
||||
enum_bitfields.k2 = Kind_Second;
|
||||
enum_bitfields.k3 = Kind_None;
|
||||
enum_bitfields.k4 = Kind_Fourth;
|
||||
|
||||
Crazy_Union crazy_union = {};
|
||||
|
||||
crazy_union.kind = Kind_First;
|
||||
@@ -555,6 +570,20 @@ type_coverage_eval_tests(void)
|
||||
|
||||
Linked_List list = {&list, &list, 0};
|
||||
|
||||
struct SLLNode
|
||||
{
|
||||
SLLNode *next;
|
||||
SLLNode *the_real_next_ptr;
|
||||
int x;
|
||||
};
|
||||
SLLNode node6 = {0, 0, 6};
|
||||
SLLNode node5 = {0, &node6, 5};
|
||||
SLLNode node4 = {0, &node5, 4};
|
||||
SLLNode node3 = {0, &node4, 3};
|
||||
SLLNode node2 = {0, &node3, 2};
|
||||
SLLNode node1 = {0, &node2, 1};
|
||||
raddbg_pin(list(node1, the_real_next_ptr));
|
||||
|
||||
Alias1 a1 = has_enums.kind;
|
||||
Alias2 a2 = has_enums.flags;
|
||||
Alias3 a3 = has_enums;
|
||||
@@ -635,6 +664,13 @@ type_coverage_eval_tests(void)
|
||||
int_vector.push_back(6);
|
||||
int_vector.push_back(7);
|
||||
|
||||
std::unordered_map<std::string, int> people =
|
||||
{
|
||||
{"Peter", 1},
|
||||
{"Oliver", 2},
|
||||
{"Jack", 3},
|
||||
};
|
||||
|
||||
std::vector<int> *pint_vector = &int_vector;
|
||||
std::vector<int> &rint_vector = int_vector;
|
||||
|
||||
|
||||
@@ -800,8 +800,8 @@ os_process_kill(OS_Handle handle)
|
||||
////////////////////////////////
|
||||
//~ rjf: @os_hooks Threads (Implemented Per-OS)
|
||||
|
||||
internal OS_Handle
|
||||
os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params)
|
||||
internal Thread
|
||||
os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr)
|
||||
{
|
||||
OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Thread);
|
||||
entity->thread.func = func;
|
||||
@@ -814,14 +814,14 @@ os_thread_launch(ThreadEntryPointFunctionType *func, void *ptr, void *params)
|
||||
entity = 0;
|
||||
}
|
||||
}
|
||||
OS_Handle handle = {(U64)entity};
|
||||
Thread handle = {(U64)entity};
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_thread_join(OS_Handle handle, U64 endt_us)
|
||||
os_thread_join(Thread handle, U64 endt_us)
|
||||
{
|
||||
if(os_handle_match(handle, os_handle_zero())) { return 0; }
|
||||
if(MemoryIsZeroStruct(&handle)) { return 0; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)handle.u64[0];
|
||||
int join_result = pthread_join(entity->thread.handle, 0);
|
||||
B32 result = (join_result == 0);
|
||||
@@ -830,9 +830,9 @@ os_thread_join(OS_Handle handle, U64 endt_us)
|
||||
}
|
||||
|
||||
internal void
|
||||
os_thread_detach(OS_Handle handle)
|
||||
os_thread_detach(Thread handle)
|
||||
{
|
||||
if(os_handle_match(handle, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&handle)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)handle.u64[0];
|
||||
os_lnx_entity_release(entity);
|
||||
}
|
||||
@@ -842,7 +842,7 @@ os_thread_detach(OS_Handle handle)
|
||||
|
||||
//- rjf: mutexes
|
||||
|
||||
internal OS_Handle
|
||||
internal Mutex
|
||||
os_mutex_alloc(void)
|
||||
{
|
||||
OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Mutex);
|
||||
@@ -856,38 +856,38 @@ os_mutex_alloc(void)
|
||||
os_lnx_entity_release(entity);
|
||||
entity = 0;
|
||||
}
|
||||
OS_Handle handle = {(U64)entity};
|
||||
Mutex handle = {(U64)entity};
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal void
|
||||
os_mutex_release(OS_Handle mutex)
|
||||
os_mutex_release(Mutex mutex)
|
||||
{
|
||||
if(os_handle_match(mutex, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&mutex)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0];
|
||||
pthread_mutex_destroy(&entity->mutex_handle);
|
||||
os_lnx_entity_release(entity);
|
||||
}
|
||||
|
||||
internal void
|
||||
os_mutex_take(OS_Handle mutex)
|
||||
os_mutex_take(Mutex mutex)
|
||||
{
|
||||
if(os_handle_match(mutex, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&mutex)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0];
|
||||
pthread_mutex_lock(&entity->mutex_handle);
|
||||
}
|
||||
|
||||
internal void
|
||||
os_mutex_drop(OS_Handle mutex)
|
||||
os_mutex_drop(Mutex mutex)
|
||||
{
|
||||
if(os_handle_match(mutex, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&mutex)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)mutex.u64[0];
|
||||
pthread_mutex_unlock(&entity->mutex_handle);
|
||||
}
|
||||
|
||||
//- rjf: reader/writer mutexes
|
||||
|
||||
internal OS_Handle
|
||||
internal RWMutex
|
||||
os_rw_mutex_alloc(void)
|
||||
{
|
||||
OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_RWMutex);
|
||||
@@ -897,23 +897,23 @@ os_rw_mutex_alloc(void)
|
||||
os_lnx_entity_release(entity);
|
||||
entity = 0;
|
||||
}
|
||||
OS_Handle handle = {(U64)entity};
|
||||
RWMutex handle = {(U64)entity};
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal void
|
||||
os_rw_mutex_release(OS_Handle rw_mutex)
|
||||
os_rw_mutex_release(RWMutex rw_mutex)
|
||||
{
|
||||
if(os_handle_match(rw_mutex, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&rw_mutex)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0];
|
||||
pthread_rwlock_destroy(&entity->rwmutex_handle);
|
||||
os_lnx_entity_release(entity);
|
||||
}
|
||||
|
||||
internal void
|
||||
os_rw_mutex_take(OS_Handle rw_mutex, B32 write_mode)
|
||||
os_rw_mutex_take(RWMutex rw_mutex, B32 write_mode)
|
||||
{
|
||||
if(os_handle_match(rw_mutex, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&rw_mutex)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0];
|
||||
if(write_mode)
|
||||
{
|
||||
@@ -926,16 +926,16 @@ os_rw_mutex_take(OS_Handle rw_mutex, B32 write_mode)
|
||||
}
|
||||
|
||||
internal void
|
||||
os_rw_mutex_drop(OS_Handle rw_mutex, B32 write_mode)
|
||||
os_rw_mutex_drop(RWMutex rw_mutex, B32 write_mode)
|
||||
{
|
||||
if(os_handle_match(rw_mutex, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&rw_mutex)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)rw_mutex.u64[0];
|
||||
pthread_rwlock_unlock(&entity->rwmutex_handle);
|
||||
}
|
||||
|
||||
//- rjf: condition variables
|
||||
|
||||
internal OS_Handle
|
||||
internal CondVar
|
||||
os_cond_var_alloc(void)
|
||||
{
|
||||
OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_ConditionVariable);
|
||||
@@ -956,14 +956,14 @@ os_cond_var_alloc(void)
|
||||
os_lnx_entity_release(entity);
|
||||
entity = 0;
|
||||
}
|
||||
OS_Handle handle = {(U64)entity};
|
||||
CondVar handle = {(U64)entity};
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal void
|
||||
os_cond_var_release(OS_Handle cv)
|
||||
os_cond_var_release(CondVar cv)
|
||||
{
|
||||
if(os_handle_match(cv, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&cv)) { return; }
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity *)cv.u64[0];
|
||||
pthread_cond_destroy(&entity->cv.cond_handle);
|
||||
pthread_mutex_destroy(&entity->cv.rwlock_mutex_handle);
|
||||
@@ -971,10 +971,10 @@ os_cond_var_release(OS_Handle cv)
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_cond_var_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us)
|
||||
os_cond_var_wait(CondVar cv, Mutex mutex, U64 endt_us)
|
||||
{
|
||||
if(os_handle_match(cv, os_handle_zero())) { return 0; }
|
||||
if(os_handle_match(mutex, os_handle_zero())) { return 0; }
|
||||
if(MemoryIsZeroStruct(&cv)) { return 0; }
|
||||
if(MemoryIsZeroStruct(&mutex)) { return 0; }
|
||||
OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0];
|
||||
OS_LNX_Entity *mutex_entity = (OS_LNX_Entity *)mutex.u64[0];
|
||||
struct timespec endt_timespec;
|
||||
@@ -986,14 +986,14 @@ os_cond_var_wait(OS_Handle cv, OS_Handle mutex, U64 endt_us)
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_cond_var_wait_rw(OS_Handle cv, OS_Handle mutex_rw, B32 write_mode, U64 endt_us)
|
||||
os_cond_var_wait_rw(CondVar cv, RWMutex mutex_rw, B32 write_mode, U64 endt_us)
|
||||
{
|
||||
// TODO(rjf): because pthread does not supply cv/rw natively, I had to hack
|
||||
// this together, but this would probably just be a lot better if we just
|
||||
// implemented the primitives ourselves with e.g. futexes
|
||||
//
|
||||
if(os_handle_match(cv, os_handle_zero())) { return 0; }
|
||||
if(os_handle_match(mutex_rw, os_handle_zero())) { return 0; }
|
||||
if(MemoryIsZeroStruct(&cv)) { return 0; }
|
||||
if(MemoryIsZeroStruct(&mutex_rw)) { return 0; }
|
||||
OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0];
|
||||
OS_LNX_Entity *rw_mutex_entity = (OS_LNX_Entity *)mutex_rw.u64[0];
|
||||
struct timespec endt_timespec;
|
||||
@@ -1036,27 +1036,27 @@ os_cond_var_wait_rw(OS_Handle cv, OS_Handle mutex_rw, B32 write_mode, U64 endt_u
|
||||
}
|
||||
|
||||
internal void
|
||||
os_cond_var_signal(OS_Handle cv)
|
||||
os_cond_var_signal(CondVar cv)
|
||||
{
|
||||
if(os_handle_match(cv, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&cv)) { return; }
|
||||
OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0];
|
||||
pthread_cond_signal(&cv_entity->cv.cond_handle);
|
||||
}
|
||||
|
||||
internal void
|
||||
os_cond_var_broadcast(OS_Handle cv)
|
||||
os_cond_var_broadcast(CondVar cv)
|
||||
{
|
||||
if(os_handle_match(cv, os_handle_zero())) { return; }
|
||||
if(MemoryIsZeroStruct(&cv)) { return; }
|
||||
OS_LNX_Entity *cv_entity = (OS_LNX_Entity *)cv.u64[0];
|
||||
pthread_cond_broadcast(&cv_entity->cv.cond_handle);
|
||||
}
|
||||
|
||||
//- rjf: cross-process semaphores
|
||||
|
||||
internal OS_Handle
|
||||
internal Semaphore
|
||||
os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name)
|
||||
{
|
||||
OS_Handle result = {0};
|
||||
Semaphore result = {0};
|
||||
if (name.size > 0)
|
||||
{
|
||||
// TODO: we need to allocate shared memory to store sem_t
|
||||
@@ -1076,26 +1076,26 @@ os_semaphore_alloc(U32 initial_count, U32 max_count, String8 name)
|
||||
}
|
||||
|
||||
internal void
|
||||
os_semaphore_release(OS_Handle semaphore)
|
||||
os_semaphore_release(Semaphore semaphore)
|
||||
{
|
||||
int err = munmap((void*)semaphore.u64[0], sizeof(sem_t));
|
||||
AssertAlways(err == 0);
|
||||
}
|
||||
|
||||
internal OS_Handle
|
||||
internal Semaphore
|
||||
os_semaphore_open(String8 name)
|
||||
{
|
||||
NotImplemented;
|
||||
}
|
||||
|
||||
internal void
|
||||
os_semaphore_close(OS_Handle semaphore)
|
||||
os_semaphore_close(Semaphore semaphore)
|
||||
{
|
||||
NotImplemented;
|
||||
}
|
||||
|
||||
internal B32
|
||||
os_semaphore_take(OS_Handle semaphore, U64 endt_us)
|
||||
os_semaphore_take(Semaphore semaphore, U64 endt_us)
|
||||
{
|
||||
// TODO(rjf): we need to use `sem_timedwait` here.
|
||||
AssertAlways(endt_us == max_U64);
|
||||
@@ -1116,7 +1116,7 @@ os_semaphore_take(OS_Handle semaphore, U64 endt_us)
|
||||
}
|
||||
|
||||
internal void
|
||||
os_semaphore_drop(OS_Handle semaphore)
|
||||
os_semaphore_drop(Semaphore semaphore)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
@@ -1138,28 +1138,37 @@ os_semaphore_drop(OS_Handle semaphore)
|
||||
|
||||
//- rjf: barriers
|
||||
|
||||
internal OS_Handle
|
||||
internal Barrier
|
||||
os_barrier_alloc(U64 count)
|
||||
{
|
||||
OS_LNX_Entity *entity = os_lnx_entity_alloc(OS_LNX_EntityKind_Barrier);
|
||||
pthread_barrier_init(&entity->barrier, 0, count);
|
||||
OS_Handle result = {IntFromPtr(entity)};
|
||||
if(entity != 0)
|
||||
{
|
||||
pthread_barrier_init(&entity->barrier, 0, count);
|
||||
}
|
||||
Barrier result = {IntFromPtr(entity)};
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
os_barrier_release(OS_Handle barrier)
|
||||
os_barrier_release(Barrier barrier)
|
||||
{
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
pthread_barrier_destroy(&entity->barrier);
|
||||
os_lnx_entity_release(entity);
|
||||
if(entity != 0)
|
||||
{
|
||||
pthread_barrier_destroy(&entity->barrier);
|
||||
os_lnx_entity_release(entity);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
os_barrier_wait(OS_Handle barrier)
|
||||
os_barrier_wait(Barrier barrier)
|
||||
{
|
||||
OS_LNX_Entity *entity = (OS_LNX_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
pthread_barrier_wait(&entity->barrier);
|
||||
if(entity != 0)
|
||||
{
|
||||
pthread_barrier_wait(&entity->barrier);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
@@ -1288,9 +1297,10 @@ main(int argc, char **argv)
|
||||
for(S64 cap = 4096, r = 0; r < 4; cap *= 2, r += 1)
|
||||
{
|
||||
scratch_end(scratch);
|
||||
buffer = push_array_no_zero(scratch.arena, U8, cap);
|
||||
size = gethostname((char*)buffer, cap);
|
||||
if(size < cap)
|
||||
buffer = push_array(scratch.arena, U8, cap);
|
||||
int gethostname_result = gethostname((char*)buffer, cap);
|
||||
size = cstring8_length(buffer);
|
||||
if(gethostname_result == 0 && size < cap)
|
||||
{
|
||||
got_final_result = 1;
|
||||
break;
|
||||
|
||||
@@ -336,6 +336,11 @@ os_file_open(OS_AccessFlags flags, String8 path)
|
||||
{
|
||||
result.u64[0] = (U64)file;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
(void)err;
|
||||
}
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
@@ -1151,6 +1156,7 @@ internal void
|
||||
os_mutex_release(Mutex mutex)
|
||||
{
|
||||
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(mutex.u64[0]);
|
||||
DeleteCriticalSection(&entity->mutex);
|
||||
os_w32_entity_release(entity);
|
||||
}
|
||||
|
||||
@@ -1336,7 +1342,11 @@ internal Barrier
|
||||
os_barrier_alloc(U64 count)
|
||||
{
|
||||
OS_W32_Entity *entity = os_w32_entity_alloc(OS_W32_EntityKind_Barrier);
|
||||
BOOL init_good = InitializeSynchronizationBarrier(&entity->sb, count, -1);
|
||||
if(entity != 0)
|
||||
{
|
||||
BOOL init_good = InitializeSynchronizationBarrier(&entity->sb, count, -1);
|
||||
(void)init_good;
|
||||
}
|
||||
Barrier result = {IntFromPtr(entity)};
|
||||
return result;
|
||||
}
|
||||
@@ -1345,15 +1355,21 @@ internal void
|
||||
os_barrier_release(Barrier barrier)
|
||||
{
|
||||
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
DeleteSynchronizationBarrier(&entity->sb);
|
||||
os_w32_entity_release(entity);
|
||||
if(entity != 0)
|
||||
{
|
||||
DeleteSynchronizationBarrier(&entity->sb);
|
||||
os_w32_entity_release(entity);
|
||||
}
|
||||
}
|
||||
|
||||
internal void
|
||||
os_barrier_wait(Barrier barrier)
|
||||
{
|
||||
OS_W32_Entity *entity = (OS_W32_Entity*)PtrFromInt(barrier.u64[0]);
|
||||
EnterSynchronizationBarrier(&entity->sb, 0);
|
||||
if(entity != 0)
|
||||
{
|
||||
EnterSynchronizationBarrier(&entity->sb, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
|
||||
@@ -369,6 +369,7 @@ os_w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
BeginPaint(hwnd, &ps);
|
||||
update();
|
||||
EndPaint(hwnd, &ps);
|
||||
DwmFlush();
|
||||
}break;
|
||||
|
||||
case WM_CLOSE:
|
||||
@@ -1056,7 +1057,7 @@ os_window_open(Rng2F32 rect, OS_WindowFlags flags, String8 title)
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
String16 title16 = str16_from_8(scratch.arena, title);
|
||||
os_w32_new_window_custom_border = custom_border;
|
||||
hwnd = CreateWindowExW(WS_EX_APPWINDOW,
|
||||
hwnd = CreateWindowExW(WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP,
|
||||
L"graphical-window",
|
||||
(WCHAR*)title16.str,
|
||||
WS_OVERLAPPEDWINDOW | WS_SIZEBOX,
|
||||
|
||||
+89
-51
@@ -291,6 +291,7 @@ rb_thread_entry_point(void *p)
|
||||
if(file_format == RB_FileFormat_PE) ProfScope("PE file => generate task for PDB")
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 file_path = n->string;
|
||||
PE_BinInfo pe_bin_info = pe_bin_info_from_data(scratch.arena, file_data);
|
||||
String8 raw_debug_dir = str8_substr(file_data, pe_bin_info.data_dir_franges[PE_DataDirectoryIndex_DEBUG]);
|
||||
PE_DebugInfoList debug_dir = pe_debug_info_list_from_raw_debug_dir(scratch.arena, file_data, raw_debug_dir);
|
||||
@@ -298,6 +299,7 @@ rb_thread_entry_point(void *p)
|
||||
{
|
||||
if(n->v.path.size != 0)
|
||||
{
|
||||
log_infof("Found reference to separate debug info file in %S (%S) at %S\n", file_path, rb_file_format_display_name_table[file_format], n->v.path);
|
||||
str8_list_push(arena, &input_file_path_tasks, n->v.path);
|
||||
}
|
||||
}
|
||||
@@ -315,6 +317,7 @@ rb_thread_entry_point(void *p)
|
||||
ELF_GnuDebugLink debug_link = elf_gnu_debug_link_from_bin(file_data, &bin);
|
||||
if(debug_link.path.size != 0)
|
||||
{
|
||||
log_infof("Found reference to separate debug info file in %S (%S) at %S\n", n->string, rb_file_format_display_name_table[file_format], debug_link.path);
|
||||
str8_list_push(arena, &input_file_path_tasks, debug_link.path);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
@@ -331,8 +334,9 @@ rb_thread_entry_point(void *p)
|
||||
String8 string_table = str8_substr(file_data, pe_bin_info.string_table_range);
|
||||
U64 section_count = raw_section_table.size / sizeof(COFF_SectionHeader);
|
||||
COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str;
|
||||
if(dw_is_dwarf_present_coff_section_table(file_data, string_table, section_count, section_table))
|
||||
if(dw_is_dwarf_present_coff_section_table(string_table, section_count, section_table))
|
||||
{
|
||||
log_infof("DWARF data detected in %S (%S)\n", n->string, rb_file_format_display_name_table[file_format]);
|
||||
file_format_flags |= RB_FileFormatFlag_HasDWARF;
|
||||
}
|
||||
scratch_end(scratch);
|
||||
@@ -348,6 +352,7 @@ rb_thread_entry_point(void *p)
|
||||
ELF_Bin elf_bin = elf_bin_from_data(scratch.arena, file_data);
|
||||
if(dw_is_dwarf_present_from_elf_bin(file_data, &elf_bin))
|
||||
{
|
||||
log_infof("DWARF data detected in %S (%S)\n", n->string, rb_file_format_display_name_table[file_format]);
|
||||
file_format_flags |= RB_FileFormatFlag_HasDWARF;
|
||||
}
|
||||
scratch_end(scratch);
|
||||
@@ -558,8 +563,10 @@ rb_thread_entry_point(void *p)
|
||||
|
||||
fprintf(stderr, "RAD DEBUG INFO SUBSET NAMES\n\n");
|
||||
#define X(name, name_lower) fprintf(stderr, " - " #name_lower "\n");
|
||||
#define Y(name, name_lower) X(name, name_lower)
|
||||
RDIM_Subset_XList
|
||||
#undef X
|
||||
#undef Y
|
||||
}break;
|
||||
case OutputKind_Breakpad:
|
||||
{
|
||||
@@ -584,16 +591,20 @@ rb_thread_entry_point(void *p)
|
||||
{
|
||||
if(0){}
|
||||
#define X(name, name_lower) else if(str8_match(n->string, str8_lit(#name_lower), 0)) { subset_flags |= RDIM_SubsetFlag_##name; }
|
||||
#define Y(name, name_lower) X(name, name_lower)
|
||||
RDIM_Subset_XList
|
||||
#undef X
|
||||
#undef Y
|
||||
}
|
||||
String8List omit_names = cmd_line_strings(cmdline, str8_lit("omit"));
|
||||
for(String8Node *n = omit_names.first; n != 0; n = n->next)
|
||||
{
|
||||
if(0){}
|
||||
#define X(name, name_lower) else if(str8_match(n->string, str8_lit(#name_lower), 0)) { subset_flags &= ~RDIM_SubsetFlag_##name; }
|
||||
#define Y(name, name_lower) X(name, name_lower)
|
||||
RDIM_Subset_XList
|
||||
#undef X
|
||||
#undef Y
|
||||
}
|
||||
}break;
|
||||
case OutputKind_Breakpad:
|
||||
@@ -604,17 +615,20 @@ rb_thread_entry_point(void *p)
|
||||
|
||||
//- rjf: convert inputs to RDI info
|
||||
B32 convert_done = 0;
|
||||
RDIM_BakeParams bake_params = {0};
|
||||
RDIM_BakeParams pdb_bake_params = {0};
|
||||
RDIM_BakeParams dwarf_bake_params = {0};
|
||||
{
|
||||
//- rjf: PE inputs w/ DWARF, or ELF inputs => DWARF -> RDI conversion
|
||||
if(!convert_done &&
|
||||
((input_files_from_format_table[RB_FileFormat_PE].count != 0 &&
|
||||
input_files_from_format_table[RB_FileFormat_PE].first->v->format_flags & RB_FileFormatFlag_HasDWARF) ||
|
||||
(input_files_from_format_table[RB_FileFormat_ELF32].count != 0 ||
|
||||
input_files_from_format_table[RB_FileFormat_ELF64].count != 0)))
|
||||
B32 pe_w_dwarf = (input_files_from_format_table[RB_FileFormat_PE].count != 0 &&
|
||||
input_files_from_format_table[RB_FileFormat_PE].first->v->format_flags & RB_FileFormatFlag_HasDWARF);
|
||||
B32 elf_w_dwarf = (input_files_from_format_table[RB_FileFormat_ELF32].count != 0 ||
|
||||
input_files_from_format_table[RB_FileFormat_ELF64].count != 0);
|
||||
if(pe_w_dwarf || elf_w_dwarf)
|
||||
{
|
||||
convert_done = 1;
|
||||
log_infof("PEs w/ DWARF, or ELFs specified; producing RDI by converting DWARF data\n");
|
||||
if(0){}
|
||||
else if(pe_w_dwarf) { log_infof("PEs w/ DWARF specified; converting DWARF data to RDI\n"); }
|
||||
else if(elf_w_dwarf) { log_infof("ELFs specified; converting DWARF data to RDI\n"); }
|
||||
|
||||
// rjf: convert
|
||||
D2R_ConvertParams convert_params = {0};
|
||||
@@ -695,21 +709,14 @@ rb_thread_entry_point(void *p)
|
||||
convert_params.subset_flags = subset_flags;
|
||||
convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic"));
|
||||
}
|
||||
ProfScope("convert") bake_params = d2r_convert(arena, &convert_params);
|
||||
|
||||
// rjf: no output path? -> pick one based on debug
|
||||
if(output_path.size == 0)
|
||||
{
|
||||
output_path = push_str8f(arena, "%S.rdi", str8_chop_last_dot(convert_params.dbg_name));
|
||||
}
|
||||
ProfScope("convert") dwarf_bake_params = d2r_convert(arena, &convert_params);
|
||||
}
|
||||
|
||||
//- rjf: PDB inputs => PDB -> RDI conversion
|
||||
if(!convert_done &&
|
||||
input_files_from_format_table[RB_FileFormat_PDB].count != 0)
|
||||
if(input_files_from_format_table[RB_FileFormat_PDB].count != 0)
|
||||
{
|
||||
convert_done = 1;
|
||||
log_infof("PDBs specified; producing RDI by converting PDB data\n");
|
||||
log_infof("PDBs specified; converting PDB data to RDI\n");
|
||||
|
||||
// rjf: get EXE/PDB file data
|
||||
RB_File *exe_file = rb_file_list_first(&input_files_from_format_table[RB_FileFormat_PE]);
|
||||
@@ -729,21 +736,40 @@ rb_thread_entry_point(void *p)
|
||||
convert_params.subset_flags = subset_flags;
|
||||
convert_params.deterministic = cmd_line_has_flag(cmdline, str8_lit("deterministic"));
|
||||
}
|
||||
ProfScope("convert") bake_params = p2r_convert(arena, &convert_params);
|
||||
|
||||
// rjf: no output path? -> pick one based on PDB
|
||||
if(output_path.size == 0) switch(output_kind)
|
||||
ProfScope("convert") pdb_bake_params = p2r_convert(arena, &convert_params);
|
||||
}
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
//- rjf: join conversion artifacts
|
||||
RDIM_BakeParams *bake_params = 0;
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
bake_params = push_array(arena, RDIM_BakeParams, 1);
|
||||
rdim_bake_params_concat_in_place(bake_params, &pdb_bake_params);
|
||||
rdim_bake_params_concat_in_place(bake_params, &dwarf_bake_params);
|
||||
}
|
||||
lane_sync_u64(&bake_params, 0);
|
||||
|
||||
//- rjf: no output path? -> pick one based on input files
|
||||
if(output_path.size == 0)
|
||||
{
|
||||
String8 output_path__noext = {0};
|
||||
if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_PDB])->path); }
|
||||
if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_PE])->path); }
|
||||
if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_ELF64])->path); }
|
||||
if(output_path__noext.size == 0) { output_path__noext = str8_chop_last_dot(rb_file_list_first(&input_files_from_format_table[RB_FileFormat_ELF32])->path); }
|
||||
switch(output_kind)
|
||||
{
|
||||
default:{}break;
|
||||
case OutputKind_RDI:
|
||||
{
|
||||
default:{}break;
|
||||
case OutputKind_RDI:
|
||||
{
|
||||
output_path = push_str8f(arena, "%S.rdi", str8_chop_last_dot(convert_params.input_pdb_name));
|
||||
}break;
|
||||
case OutputKind_Breakpad:
|
||||
{
|
||||
output_path = push_str8f(arena, "%S.psym", str8_chop_last_dot(convert_params.input_pdb_name));
|
||||
}break;
|
||||
}
|
||||
output_path = push_str8f(arena, "%S.rdi", output_path__noext);
|
||||
}break;
|
||||
case OutputKind_Breakpad:
|
||||
{
|
||||
output_path = push_str8f(arena, "%S.psym", output_path__noext);
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,9 +781,9 @@ rb_thread_entry_point(void *p)
|
||||
|
||||
//- rjf: bake
|
||||
RDIM_BakeResults bake_results = {0};
|
||||
if(convert_done) ProfScope("bake")
|
||||
ProfScope("bake")
|
||||
{
|
||||
bake_results = rdim_bake(arena, &bake_params);
|
||||
bake_results = rdim_bake(arena, bake_params);
|
||||
}
|
||||
|
||||
//- rjf: convert done => generate output
|
||||
@@ -769,14 +795,19 @@ rb_thread_entry_point(void *p)
|
||||
case OutputKind_RDI:
|
||||
{
|
||||
// rjf: serialize
|
||||
RDIM_SerializedSectionBundle serialized_section_bundle = {0};
|
||||
ProfScope("serialize") serialized_section_bundle = rdim_serialized_section_bundle_from_bake_results(&bake_results);
|
||||
RDIM_SerializedSectionBundle *serialized_section_bundle = 0;
|
||||
ProfScope("serialize") if(lane_idx() == 0)
|
||||
{
|
||||
serialized_section_bundle = push_array(arena, RDIM_SerializedSectionBundle, 1);
|
||||
serialized_section_bundle[0] = rdim_serialized_section_bundle_from_bake_results(&bake_results);
|
||||
}
|
||||
lane_sync_u64(&serialized_section_bundle, 0);
|
||||
|
||||
// rjf: compress
|
||||
RDIM_SerializedSectionBundle serialized_section_bundle__compressed = serialized_section_bundle;
|
||||
RDIM_SerializedSectionBundle serialized_section_bundle__compressed = serialized_section_bundle[0];
|
||||
if(cmd_line_has_flag(cmdline, str8_lit("compress"))) ProfScope("compress")
|
||||
{
|
||||
serialized_section_bundle__compressed = rdim_compress(arena, &serialized_section_bundle);
|
||||
serialized_section_bundle__compressed = rdim_compress(arena, serialized_section_bundle);
|
||||
}
|
||||
|
||||
// rjf: serialize
|
||||
@@ -799,8 +830,8 @@ rb_thread_entry_point(void *p)
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
p2b_shared = push_array(arena, P2B_Shared, 1);
|
||||
p2b_shared->lane_chunk_file_dumps = push_array(arena, String8List, lane_count()*bake_params.src_files.chunk_count);
|
||||
p2b_shared->lane_chunk_func_dumps = push_array(arena, String8List, lane_count()*bake_params.procedures.chunk_count);
|
||||
p2b_shared->lane_chunk_file_dumps = push_array(arena, String8List, lane_count()*bake_params->src_files.chunk_count);
|
||||
p2b_shared->lane_chunk_func_dumps = push_array(arena, String8List, lane_count()*bake_params->procedures.chunk_count);
|
||||
}
|
||||
lane_sync();
|
||||
|
||||
@@ -808,7 +839,7 @@ rb_thread_entry_point(void *p)
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
// rjf: pick name to identify module
|
||||
String8 module_name_string = bake_params.top_level_info.exe_name;
|
||||
String8 module_name_string = bake_params->top_level_info.exe_name;
|
||||
if(module_name_string.size == 0 && input_files.first != 0)
|
||||
{
|
||||
module_name_string = input_files.first->v->path;
|
||||
@@ -816,9 +847,9 @@ rb_thread_entry_point(void *p)
|
||||
|
||||
// rjf: pick string for unique code
|
||||
String8 unique_identifier_string = {0};
|
||||
if(unique_identifier_string.size == 0 && bake_params.top_level_info.exe_hash != 0)
|
||||
if(unique_identifier_string.size == 0 && bake_params->top_level_info.exe_hash != 0)
|
||||
{
|
||||
unique_identifier_string = str8f(arena, "%I64x", bake_params.top_level_info.exe_hash);
|
||||
unique_identifier_string = str8f(arena, "%I64x", bake_params->top_level_info.exe_hash);
|
||||
}
|
||||
if(unique_identifier_string.size == 0 && input_files.first != 0 && input_files.first->v->format == RB_FileFormat_PDB)
|
||||
{
|
||||
@@ -856,14 +887,14 @@ rb_thread_entry_point(void *p)
|
||||
ProfScope("dump FILE records")
|
||||
{
|
||||
U64 chunk_idx = 0;
|
||||
for EachNode(n, RDIM_SrcFileChunkNode, bake_params.src_files.first)
|
||||
for EachNode(n, RDIM_SrcFileChunkNode, bake_params->src_files.first)
|
||||
{
|
||||
Rng1U64 range = lane_range(n->count);
|
||||
for EachInRange(idx, range)
|
||||
{
|
||||
U64 file_idx = rdim_idx_from_src_file(&n->v[idx]);
|
||||
String8 src_path = n->v[idx].path;
|
||||
str8_list_pushf(arena, &p2b_shared->lane_chunk_file_dumps[lane_idx()*bake_params.src_files.chunk_count + chunk_idx], "FILE %I64u %S\n", file_idx, src_path);
|
||||
str8_list_pushf(arena, &p2b_shared->lane_chunk_file_dumps[lane_idx()*bake_params->src_files.chunk_count + chunk_idx], "FILE %I64u %S\n", file_idx, src_path);
|
||||
}
|
||||
chunk_idx += 1;
|
||||
}
|
||||
@@ -873,9 +904,9 @@ rb_thread_entry_point(void *p)
|
||||
ProfScope("dump FUNC records")
|
||||
{
|
||||
U64 chunk_idx = 0;
|
||||
for EachNode(n, RDIM_SymbolChunkNode, bake_params.procedures.first)
|
||||
for EachNode(n, RDIM_SymbolChunkNode, bake_params->procedures.first)
|
||||
{
|
||||
String8List *out = &p2b_shared->lane_chunk_func_dumps[lane_idx()*bake_params.procedures.chunk_count + chunk_idx];
|
||||
String8List *out = &p2b_shared->lane_chunk_func_dumps[lane_idx()*bake_params->procedures.chunk_count + chunk_idx];
|
||||
Rng1U64 range = lane_range(n->count);
|
||||
for EachInRange(idx, range)
|
||||
{
|
||||
@@ -942,18 +973,18 @@ rb_thread_entry_point(void *p)
|
||||
lane_sync();
|
||||
if(lane_idx() == 0)
|
||||
{
|
||||
for EachIndex(chunk_idx, bake_params.src_files.chunk_count)
|
||||
for EachIndex(chunk_idx, bake_params->src_files.chunk_count)
|
||||
{
|
||||
for EachIndex(ln_idx, lane_count())
|
||||
{
|
||||
str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_file_dumps[ln_idx*bake_params.src_files.chunk_count + chunk_idx]);
|
||||
str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_file_dumps[ln_idx*bake_params->src_files.chunk_count + chunk_idx]);
|
||||
}
|
||||
}
|
||||
for EachIndex(chunk_idx, bake_params.procedures.chunk_count)
|
||||
for EachIndex(chunk_idx, bake_params->procedures.chunk_count)
|
||||
{
|
||||
for EachIndex(ln_idx, lane_count())
|
||||
{
|
||||
str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_func_dumps[ln_idx*bake_params.procedures.chunk_count + chunk_idx]);
|
||||
str8_list_concat_in_place(&p2b_shared->dump, &p2b_shared->lane_chunk_func_dumps[ln_idx*bake_params->procedures.chunk_count + chunk_idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1132,6 +1163,13 @@ rb_thread_entry_point(void *p)
|
||||
{
|
||||
RDI_Parsed rdi = {0};
|
||||
RDI_ParseStatus rdi_status = rdi_parse(f->data.str, f->data.size, &rdi);
|
||||
U64 decompressed_size = rdi_decompressed_size_from_parsed(&rdi);
|
||||
if(decompressed_size > rdi.raw_data_size)
|
||||
{
|
||||
U8 *decompressed_data = push_array_no_zero(arena, U8, decompressed_size);
|
||||
rdi_decompress_parsed(decompressed_data, decompressed_size, &rdi);
|
||||
rdi_status = rdi_parse(decompressed_data, decompressed_size, &rdi);
|
||||
}
|
||||
switch(rdi_status)
|
||||
{
|
||||
default:{}break;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "base/base_inc.h"
|
||||
#include "linker/hash_table.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "async/async.h"
|
||||
#include "rdi/rdi_local.h"
|
||||
#include "rdi_make/rdi_make_local.h"
|
||||
#include "coff/coff_inc.h"
|
||||
@@ -23,6 +22,7 @@
|
||||
#include "elf/elf_parse.h"
|
||||
#include "codeview/codeview.h"
|
||||
#include "codeview/codeview_parse.h"
|
||||
#include "eh/eh_frame.h"
|
||||
#include "dwarf/dwarf_inc.h"
|
||||
#include "msf/msf.h"
|
||||
#include "msf/msf_parse.h"
|
||||
@@ -39,7 +39,6 @@
|
||||
#include "base/base_inc.c"
|
||||
#include "linker/hash_table.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "async/async.c"
|
||||
#include "rdi/rdi_local.c"
|
||||
#include "rdi_make/rdi_make_local.c"
|
||||
#include "coff/coff_inc.c"
|
||||
@@ -48,6 +47,7 @@
|
||||
#include "elf/elf_parse.c"
|
||||
#include "codeview/codeview.c"
|
||||
#include "codeview/codeview_parse.c"
|
||||
#include "eh/eh_frame.c"
|
||||
#include "dwarf/dwarf_inc.c"
|
||||
#include "msf/msf.c"
|
||||
#include "msf/msf_parse.c"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -449,14 +449,14 @@ CTRL_Handle module;
|
||||
CTRL_Handle process;
|
||||
CTRL_Handle thread;
|
||||
CTRL_Handle ctrl_entity;
|
||||
RD_CfgID window;
|
||||
RD_CfgID panel;
|
||||
RD_CfgID tab;
|
||||
RD_CfgID view;
|
||||
RD_CfgID prev_tab;
|
||||
RD_CfgID dst_panel;
|
||||
RD_CfgID cfg;
|
||||
RD_CfgIDList cfg_list;
|
||||
CFG_ID window;
|
||||
CFG_ID panel;
|
||||
CFG_ID tab;
|
||||
CFG_ID view;
|
||||
CFG_ID prev_tab;
|
||||
CFG_ID dst_panel;
|
||||
CFG_ID cfg;
|
||||
CFG_IDList cfg_list;
|
||||
E_Space eval_space;
|
||||
U64 unwind_count;
|
||||
U64 inline_depth;
|
||||
@@ -592,7 +592,7 @@ C_LINKAGE_BEGIN
|
||||
extern String8 rd_tab_fast_path_view_name_table[24];
|
||||
extern String8 rd_tab_fast_path_query_name_table[24];
|
||||
extern RD_VocabInfo rd_vocab_info_table[352];
|
||||
extern RD_NameSchemaInfo rd_name_schema_info_table[24];
|
||||
extern RD_NameSchemaInfo rd_name_schema_info_table[25];
|
||||
extern String8 rd_reg_slot_code_name_table[47];
|
||||
extern Rng1U64 rd_reg_slot_range_table[47];
|
||||
extern String8 rd_binding_version_remap_old_name_table[8];
|
||||
|
||||
+23
-12
@@ -470,6 +470,18 @@ RD_VocabTable:
|
||||
}
|
||||
```
|
||||
}
|
||||
{
|
||||
list,
|
||||
```
|
||||
x:
|
||||
{
|
||||
@description("An expression describing the first node in the list.")
|
||||
'expression': expr_string,
|
||||
@order(0) @description("The name of the member which encodes the link to the next node.")
|
||||
'member_name': code_string,
|
||||
}
|
||||
```
|
||||
}
|
||||
{
|
||||
text,
|
||||
```
|
||||
@@ -713,14 +725,14 @@ RD_RegTable:
|
||||
{CTRL_Handle ctrl_entity CtrlEntity }
|
||||
|
||||
// rjf: cfgs
|
||||
{RD_CfgID window Window }
|
||||
{RD_CfgID panel Panel }
|
||||
{RD_CfgID tab Tab }
|
||||
{RD_CfgID view View }
|
||||
{RD_CfgID prev_tab PrevTab }
|
||||
{RD_CfgID dst_panel DstPanel }
|
||||
{RD_CfgID cfg Cfg }
|
||||
{RD_CfgIDList cfg_list CfgList }
|
||||
{CFG_ID window Window }
|
||||
{CFG_ID panel Panel }
|
||||
{CFG_ID tab Tab }
|
||||
{CFG_ID view View }
|
||||
{CFG_ID prev_tab PrevTab }
|
||||
{CFG_ID dst_panel DstPanel }
|
||||
{CFG_ID cfg Cfg }
|
||||
{CFG_IDList cfg_list CfgList }
|
||||
|
||||
// rjf: evaluation space
|
||||
{E_Space eval_space EvalSpace }
|
||||
@@ -733,10 +745,10 @@ RD_RegTable:
|
||||
{String8 file_path FilePath }
|
||||
{TxtPt cursor Cursor }
|
||||
{TxtPt mark Mark }
|
||||
{C_Key text_key TextKey }
|
||||
{C_Key text_key TextKey }
|
||||
{TXT_LangKind lang_kind LangKind }
|
||||
{D_LineList lines Lines }
|
||||
{DI_Key dbgi_key DbgiKey }
|
||||
{DI_Key dbgi_key DbgiKey }
|
||||
{U64 vaddr Vaddr }
|
||||
{U64 voff Voff }
|
||||
{Rng1U64 vaddr_range VaddrRange }
|
||||
@@ -1301,7 +1313,7 @@ RD_DefaultBindingTable:
|
||||
{ "toggle_dev_menu" D ctrl shift alt }
|
||||
}
|
||||
|
||||
@data(`struct {String8 string; RD_Binding binding;}`) @c_file rd_default_binding_table:
|
||||
@data(`struct {String8 string; CFG_Binding binding;}`) @c_file rd_default_binding_table:
|
||||
{
|
||||
@expand(RD_DefaultBindingTable a) ```{str8_lit_comp("$(a.name)"), {OS_Key_$(a.key), 0 $(a.ctrl != 0 -> `|OS_Modifier_Ctrl`) $(a.shift != 0 -> `|OS_Modifier_Shift`) $(a.alt != 0 -> `|OS_Modifier_Alt`)}}```;
|
||||
}
|
||||
@@ -1320,7 +1332,6 @@ RD_BindingVersionRemapTable:
|
||||
{"address_breakpoint" "add_address_breakpoint"}
|
||||
{"function_breakpoint" "add_function_breakpoint"}
|
||||
{"toggle_breakpoint_cursor" "toggle_breakpoint"}
|
||||
|
||||
}
|
||||
|
||||
@data(String8) rd_binding_version_remap_old_name_table:
|
||||
|
||||
+1480
-2601
File diff suppressed because it is too large
Load Diff
+35
-310
@@ -4,85 +4,13 @@
|
||||
#ifndef RADDBG_CORE_H
|
||||
#define RADDBG_CORE_H
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config IDs
|
||||
|
||||
typedef U64 RD_CfgID;
|
||||
|
||||
typedef struct RD_CfgIDNode RD_CfgIDNode;
|
||||
struct RD_CfgIDNode
|
||||
{
|
||||
RD_CfgIDNode *next;
|
||||
RD_CfgID v;
|
||||
};
|
||||
|
||||
typedef struct RD_CfgIDList RD_CfgIDList;
|
||||
struct RD_CfgIDList
|
||||
{
|
||||
RD_CfgIDNode *first;
|
||||
RD_CfgIDNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Key Bindings
|
||||
|
||||
typedef struct RD_Binding RD_Binding;
|
||||
struct RD_Binding
|
||||
{
|
||||
OS_Key key;
|
||||
OS_Modifiers modifiers;
|
||||
};
|
||||
|
||||
typedef struct RD_KeyMapNode RD_KeyMapNode;
|
||||
struct RD_KeyMapNode
|
||||
{
|
||||
RD_KeyMapNode *name_hash_next;
|
||||
RD_KeyMapNode *binding_hash_next;
|
||||
RD_CfgID cfg_id;
|
||||
String8 name;
|
||||
RD_Binding binding;
|
||||
};
|
||||
|
||||
typedef struct RD_KeyMapNodePtr RD_KeyMapNodePtr;
|
||||
struct RD_KeyMapNodePtr
|
||||
{
|
||||
RD_KeyMapNodePtr *next;
|
||||
RD_KeyMapNode *v;
|
||||
};
|
||||
|
||||
typedef struct RD_KeyMapNodePtrList RD_KeyMapNodePtrList;
|
||||
struct RD_KeyMapNodePtrList
|
||||
{
|
||||
RD_KeyMapNodePtr *first;
|
||||
RD_KeyMapNodePtr *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct RD_KeyMapSlot RD_KeyMapSlot;
|
||||
struct RD_KeyMapSlot
|
||||
{
|
||||
RD_KeyMapNode *first;
|
||||
RD_KeyMapNode *last;
|
||||
};
|
||||
|
||||
typedef struct RD_KeyMap RD_KeyMap;
|
||||
struct RD_KeyMap
|
||||
{
|
||||
U64 name_slots_count;
|
||||
RD_KeyMapSlot *name_slots;
|
||||
U64 binding_slots_count;
|
||||
RD_KeyMapSlot *binding_slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Evaluation Spaces
|
||||
|
||||
typedef U64 RD_EvalSpaceKind;
|
||||
enum
|
||||
{
|
||||
RD_EvalSpaceKind_CtrlEntity = E_SpaceKind_FirstUserDefined,
|
||||
RD_EvalSpaceKind_MetaQuery,
|
||||
RD_EvalSpaceKind_MetaQuery = CTRL_EvalSpaceKind_FirstUserDefined,
|
||||
RD_EvalSpaceKind_MetaCfg,
|
||||
RD_EvalSpaceKind_MetaCmd,
|
||||
RD_EvalSpaceKind_MetaTheme,
|
||||
@@ -198,7 +126,7 @@ struct RD_ViewState
|
||||
// rjf: hash links & key
|
||||
RD_ViewState *hash_next;
|
||||
RD_ViewState *hash_prev;
|
||||
RD_CfgID cfg_id;
|
||||
CFG_ID cfg_id;
|
||||
|
||||
// rjf: touch info
|
||||
U64 last_frame_index_touched;
|
||||
@@ -268,59 +196,6 @@ struct RD_VocabInfoMap
|
||||
RD_VocabInfoMapSlot *plural_slots;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Tree
|
||||
|
||||
typedef struct RD_Cfg RD_Cfg;
|
||||
struct RD_Cfg
|
||||
{
|
||||
RD_Cfg *first;
|
||||
RD_Cfg *last;
|
||||
RD_Cfg *next;
|
||||
RD_Cfg *prev;
|
||||
RD_Cfg *parent;
|
||||
RD_CfgID id;
|
||||
String8 string;
|
||||
};
|
||||
|
||||
typedef struct RD_CfgNode RD_CfgNode;
|
||||
struct RD_CfgNode
|
||||
{
|
||||
RD_CfgNode *next;
|
||||
RD_CfgNode *prev;
|
||||
RD_Cfg *v;
|
||||
};
|
||||
|
||||
typedef struct RD_CfgSlot RD_CfgSlot;
|
||||
struct RD_CfgSlot
|
||||
{
|
||||
RD_CfgNode *first;
|
||||
RD_CfgNode *last;
|
||||
};
|
||||
|
||||
typedef struct RD_CfgList RD_CfgList;
|
||||
struct RD_CfgList
|
||||
{
|
||||
RD_CfgNode *first;
|
||||
RD_CfgNode *last;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct RD_CfgArray RD_CfgArray;
|
||||
struct RD_CfgArray
|
||||
{
|
||||
RD_Cfg **v;
|
||||
U64 count;
|
||||
};
|
||||
|
||||
typedef struct RD_CfgRec RD_CfgRec;
|
||||
struct RD_CfgRec
|
||||
{
|
||||
RD_Cfg *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Structured Locations, Parsed From Config Trees
|
||||
|
||||
@@ -332,48 +207,6 @@ struct RD_Location
|
||||
String8 expr;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Structured Panel Trees, Parsed From Config Trees
|
||||
|
||||
typedef struct RD_PanelNode RD_PanelNode;
|
||||
struct RD_PanelNode
|
||||
{
|
||||
// rjf: links data
|
||||
RD_PanelNode *first;
|
||||
RD_PanelNode *last;
|
||||
RD_PanelNode *next;
|
||||
RD_PanelNode *prev;
|
||||
RD_PanelNode *parent;
|
||||
U64 child_count;
|
||||
RD_Cfg *cfg;
|
||||
|
||||
// rjf: split data
|
||||
Axis2 split_axis;
|
||||
F32 pct_of_parent;
|
||||
|
||||
// rjf: tab params
|
||||
Side tab_side;
|
||||
|
||||
// rjf: which tabs are attached
|
||||
RD_CfgList tabs;
|
||||
RD_Cfg *selected_tab;
|
||||
};
|
||||
|
||||
typedef struct RD_PanelTree RD_PanelTree;
|
||||
struct RD_PanelTree
|
||||
{
|
||||
RD_PanelNode *root;
|
||||
RD_PanelNode *focused;
|
||||
};
|
||||
|
||||
typedef struct RD_PanelNodeRec RD_PanelNodeRec;
|
||||
struct RD_PanelNodeRec
|
||||
{
|
||||
RD_PanelNode *next;
|
||||
S32 push_count;
|
||||
S32 pop_count;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Command Types
|
||||
|
||||
@@ -433,7 +266,7 @@ struct RD_WindowState
|
||||
RD_WindowState *order_prev;
|
||||
RD_WindowState *hash_next;
|
||||
RD_WindowState *hash_prev;
|
||||
RD_CfgID cfg_id;
|
||||
CFG_ID cfg_id;
|
||||
U64 frames_alive;
|
||||
U64 last_frame_index_touched;
|
||||
|
||||
@@ -471,8 +304,8 @@ struct RD_WindowState
|
||||
B32 query_is_active;
|
||||
Arena *query_arena;
|
||||
RD_Regs *query_regs;
|
||||
RD_CfgID query_view_id;
|
||||
RD_CfgID query_last_view_id;
|
||||
CFG_ID query_view_id;
|
||||
CFG_ID query_last_view_id;
|
||||
|
||||
// rjf: hover eval state
|
||||
B32 hover_eval_focused;
|
||||
@@ -510,25 +343,6 @@ struct RD_WindowStateSlot
|
||||
////////////////////////////////
|
||||
//~ rjf: Main Per-Process Graphical State
|
||||
|
||||
read_only global U64 rd_name_bucket_chunk_sizes[] =
|
||||
{
|
||||
16,
|
||||
64,
|
||||
256,
|
||||
1024,
|
||||
4096,
|
||||
16384,
|
||||
65536,
|
||||
0xffffffffffffffffull,
|
||||
};
|
||||
|
||||
typedef struct RD_NameChunkNode RD_NameChunkNode;
|
||||
struct RD_NameChunkNode
|
||||
{
|
||||
RD_NameChunkNode *next;
|
||||
U64 size;
|
||||
};
|
||||
|
||||
typedef struct RD_AmbiguousPathNode RD_AmbiguousPathNode;
|
||||
struct RD_AmbiguousPathNode
|
||||
{
|
||||
@@ -576,9 +390,6 @@ struct RD_State
|
||||
C_Key cmdln_cfg_string_key;
|
||||
C_Key transient_cfg_string_key;
|
||||
|
||||
// rjf: schema table
|
||||
MD_NodePtrList *schemas;
|
||||
|
||||
// rjf: default theme table
|
||||
MD_Node *theme_preset_trees[RD_ThemePreset_COUNT];
|
||||
|
||||
@@ -600,12 +411,6 @@ struct RD_State
|
||||
// rjf: frame parameters
|
||||
F32 frame_dt;
|
||||
Access *frame_access;
|
||||
DI_Scope *frame_di_scope;
|
||||
CTRL_CallStackTree frame_call_stack_tree;
|
||||
B32 got_frame_call_stack_tree;
|
||||
|
||||
// rjf: dbgi match store
|
||||
DI_MatchStore *match_store;
|
||||
|
||||
// rjf: evaluation cache
|
||||
E_Cache *eval_cache;
|
||||
@@ -615,7 +420,7 @@ struct RD_State
|
||||
RD_AmbiguousPathNode **ambiguous_path_slots;
|
||||
|
||||
// rjf: key map (constructed from-scratch each frame)
|
||||
RD_KeyMap *key_map;
|
||||
CFG_KeyMap *key_map;
|
||||
|
||||
// rjf: slot -> font tag map (constructed from-scratch each frame)
|
||||
FNT_Tag font_slot_table[RD_FontSlot_COUNT];
|
||||
@@ -672,38 +477,30 @@ struct RD_State
|
||||
RD_DragDropState drag_drop_state;
|
||||
|
||||
// rjf: cfg state
|
||||
RD_NameChunkNode *free_name_chunks[ArrayCount(rd_name_bucket_chunk_sizes)];
|
||||
RD_Cfg *free_cfg;
|
||||
RD_Cfg *root_cfg;
|
||||
U64 cfg_id_slots_count;
|
||||
RD_CfgSlot *cfg_id_slots;
|
||||
RD_CfgNode *free_cfg_id_node;
|
||||
U64 cfg_id_gen;
|
||||
RD_CfgID cfg_last_accessed_id;
|
||||
RD_Cfg *cfg_last_accessed;
|
||||
U64 cfg_change_gen;
|
||||
CFG_State *cfg;
|
||||
CFG_SchemaTable *cfg_schema_table;
|
||||
|
||||
// rjf: window state cache
|
||||
U64 window_state_slots_count;
|
||||
RD_WindowStateSlot *window_state_slots;
|
||||
RD_WindowState *free_window_state;
|
||||
RD_CfgID last_focused_window;
|
||||
CFG_ID last_focused_window;
|
||||
RD_WindowState *first_window_state;
|
||||
RD_WindowState *last_window_state;
|
||||
RD_CfgID window_state_last_accessed_id;
|
||||
CFG_ID window_state_last_accessed_id;
|
||||
RD_WindowState *window_state_last_accessed;
|
||||
|
||||
// rjf: view state cache
|
||||
U64 view_state_slots_count;
|
||||
RD_ViewStateSlot *view_state_slots;
|
||||
RD_ViewState *free_view_state;
|
||||
RD_CfgID view_state_last_accessed_id;
|
||||
CFG_ID view_state_last_accessed_id;
|
||||
RD_ViewState *view_state_last_accessed;
|
||||
|
||||
// rjf: bind change
|
||||
Arena *bind_change_arena;
|
||||
B32 bind_change_active;
|
||||
RD_CfgID bind_change_binding_id;
|
||||
CFG_ID bind_change_binding_id;
|
||||
String8 bind_change_cmd_name;
|
||||
|
||||
// rjf: pre-stop focused window
|
||||
@@ -715,27 +512,6 @@ struct RD_State
|
||||
|
||||
read_only global RD_VocabInfo rd_nil_vocab_info = {0};
|
||||
|
||||
read_only global RD_Cfg rd_nil_cfg =
|
||||
{
|
||||
&rd_nil_cfg,
|
||||
&rd_nil_cfg,
|
||||
&rd_nil_cfg,
|
||||
&rd_nil_cfg,
|
||||
&rd_nil_cfg,
|
||||
};
|
||||
|
||||
read_only global RD_PanelNode rd_nil_panel_node =
|
||||
{
|
||||
&rd_nil_panel_node,
|
||||
&rd_nil_panel_node,
|
||||
&rd_nil_panel_node,
|
||||
&rd_nil_panel_node,
|
||||
&rd_nil_panel_node,
|
||||
0,
|
||||
&rd_nil_cfg,
|
||||
.selected_tab = &rd_nil_cfg,
|
||||
};
|
||||
|
||||
read_only global RD_CmdKindInfo rd_nil_cmd_kind_info = {0};
|
||||
|
||||
RD_VIEW_UI_FUNCTION_DEF(null);
|
||||
@@ -760,14 +536,8 @@ read_only global RD_WindowState rd_nil_window_state =
|
||||
};
|
||||
|
||||
global RD_State *rd_state = 0;
|
||||
global RD_CfgID rd_last_drag_drop_panel = 0;
|
||||
global RD_CfgID rd_last_drag_drop_prev_tab = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config ID Type Functions
|
||||
|
||||
internal void rd_cfg_id_list_push(Arena *arena, RD_CfgIDList *list, RD_CfgID id);
|
||||
internal RD_CfgIDList rd_cfg_id_list_copy(Arena *arena, RD_CfgIDList *src);
|
||||
global CFG_ID rd_last_drag_drop_panel = 0;
|
||||
global CFG_ID rd_last_drag_drop_prev_tab = 0;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Registers Type Functions
|
||||
@@ -800,65 +570,20 @@ internal void rd_set_hover_regs(RD_RegSlot slot);
|
||||
internal RD_Regs *rd_get_hover_regs(void);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Name Allocation
|
||||
//~ rjf: Config Functions
|
||||
|
||||
internal U64 rd_name_bucket_num_from_string_size(U64 size);
|
||||
internal String8 rd_name_alloc(String8 string);
|
||||
internal void rd_name_release(String8 string);
|
||||
internal B32 rd_cfg_is_project_filtered(CFG_Node *cfg);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Config Tree Functions
|
||||
internal Vec4F32 rd_hsva_from_cfg(CFG_Node *cfg);
|
||||
internal Vec4F32 rd_color_from_cfg(CFG_Node *cfg);
|
||||
|
||||
internal RD_Cfg *rd_cfg_alloc(void);
|
||||
internal void rd_cfg_release(RD_Cfg *cfg);
|
||||
internal void rd_cfg_release_all_children(RD_Cfg *cfg);
|
||||
internal RD_Cfg *rd_cfg_from_id(RD_CfgID id);
|
||||
internal RD_Cfg *rd_cfg_new(RD_Cfg *parent, String8 string);
|
||||
internal RD_Cfg *rd_cfg_newf(RD_Cfg *parent, char *fmt, ...);
|
||||
internal RD_Cfg *rd_cfg_new_replace(RD_Cfg *parent, String8 string);
|
||||
internal RD_Cfg *rd_cfg_new_replacef(RD_Cfg *parent, char *fmt, ...);
|
||||
internal RD_Cfg *rd_cfg_deep_copy(RD_Cfg *src_root);
|
||||
internal void rd_cfg_equip_string(RD_Cfg *cfg, String8 string);
|
||||
internal void rd_cfg_equip_stringf(RD_Cfg *cfg, char *fmt, ...);
|
||||
internal void rd_cfg_insert_child(RD_Cfg *parent, RD_Cfg *prev_child, RD_Cfg *new_child);
|
||||
internal void rd_cfg_unhook(RD_Cfg *parent, RD_Cfg *child);
|
||||
internal RD_Cfg *rd_cfg_child_from_string(RD_Cfg *parent, String8 string);
|
||||
internal RD_Cfg *rd_cfg_child_from_string_or_alloc(RD_Cfg *parent, String8 string);
|
||||
internal RD_Cfg *rd_cfg_child_from_string_or_parent(RD_Cfg *parent, String8 string);
|
||||
internal RD_CfgList rd_cfg_child_list_from_string(Arena *arena, RD_Cfg *parent, String8 string);
|
||||
internal RD_CfgList rd_cfg_top_level_list_from_string(Arena *arena, String8 string);
|
||||
internal RD_CfgArray rd_cfg_array_from_list(Arena *arena, RD_CfgList *list);
|
||||
internal RD_CfgList rd_cfg_tree_list_from_string(Arena *arena, String8 root_path, String8 string);
|
||||
internal String8 rd_string_from_cfg_tree(Arena *arena, String8 root_path, RD_Cfg *cfg);
|
||||
internal RD_CfgRec rd_cfg_rec__depth_first(RD_Cfg *root, RD_Cfg *cfg);
|
||||
internal void rd_cfg_list_push(Arena *arena, RD_CfgList *list, RD_Cfg *cfg);
|
||||
internal void rd_cfg_list_push_front(Arena *arena, RD_CfgList *list, RD_Cfg *cfg);
|
||||
#define rd_cfg_list_first(list) ((list)->count ? (list)->first->v : &rd_nil_cfg)
|
||||
#define rd_cfg_list_last(list) ((list)->count ? (list)->last->v : &rd_nil_cfg)
|
||||
internal B32 rd_disabled_from_cfg(CFG_Node *cfg);
|
||||
internal RD_Location rd_location_from_cfg(CFG_Node *cfg);
|
||||
internal String8 rd_label_from_cfg(CFG_Node *cfg);
|
||||
internal String8 rd_expr_from_cfg(CFG_Node *cfg);
|
||||
internal String8 rd_path_from_cfg(CFG_Node *cfg);
|
||||
internal D_Target rd_target_from_cfg(Arena *arena, CFG_Node *cfg);
|
||||
|
||||
internal RD_PanelTree rd_panel_tree_from_cfg(Arena *arena, RD_Cfg *cfg);
|
||||
internal RD_PanelNodeRec rd_panel_node_rec__depth_first(RD_PanelNode *root, RD_PanelNode *panel, U64 sib_off, U64 child_off);
|
||||
#define rd_panel_node_rec__depth_first_pre(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, next), OffsetOf(RD_PanelNode, first))
|
||||
#define rd_panel_node_rec__depth_first_pre_rev(root, p) rd_panel_node_rec__depth_first((root), (p), OffsetOf(RD_PanelNode, prev), OffsetOf(RD_PanelNode, last))
|
||||
internal RD_PanelNode *rd_panel_node_from_tree_cfg(RD_PanelNode *root, RD_Cfg *cfg);
|
||||
internal Rng2F32 rd_target_rect_from_panel_node_child(Rng2F32 parent_rect, RD_PanelNode *parent, RD_PanelNode *panel);
|
||||
internal Rng2F32 rd_target_rect_from_panel_node(Rng2F32 root_rect, RD_PanelNode *root, RD_PanelNode *panel);
|
||||
|
||||
internal B32 rd_cfg_is_project_filtered(RD_Cfg *cfg);
|
||||
internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_name(Arena *arena, String8 string);
|
||||
internal RD_KeyMapNodePtrList rd_key_map_node_ptr_list_from_binding(Arena *arena, RD_Binding binding);
|
||||
|
||||
internal Vec4F32 rd_hsva_from_cfg(RD_Cfg *cfg);
|
||||
internal Vec4F32 rd_color_from_cfg(RD_Cfg *cfg);
|
||||
|
||||
internal B32 rd_disabled_from_cfg(RD_Cfg *cfg);
|
||||
internal RD_Location rd_location_from_cfg(RD_Cfg *cfg);
|
||||
internal String8 rd_label_from_cfg(RD_Cfg *cfg);
|
||||
internal String8 rd_expr_from_cfg(RD_Cfg *cfg);
|
||||
internal String8 rd_path_from_cfg(RD_Cfg *cfg);
|
||||
internal D_Target rd_target_from_cfg(Arena *arena, RD_Cfg *cfg);
|
||||
|
||||
internal MD_NodePtrList rd_schemas_from_name(String8 name);
|
||||
internal String8 rd_default_setting_from_names(String8 schema_name, String8 setting_name);
|
||||
|
||||
internal String8 rd_setting_from_name(String8 name);
|
||||
@@ -866,8 +591,8 @@ internal B32 rd_setting_b32_from_name(String8 name);
|
||||
internal U64 rd_setting_u64_from_name(String8 name);
|
||||
internal F32 rd_setting_f32_from_name(String8 name);
|
||||
|
||||
internal RD_Cfg *rd_immediate_cfg_from_key(String8 string);
|
||||
internal RD_Cfg *rd_immediate_cfg_from_keyf(char *fmt, ...);
|
||||
internal CFG_Node *rd_immediate_cfg_from_key(String8 string);
|
||||
internal CFG_Node *rd_immediate_cfg_from_keyf(char *fmt, ...);
|
||||
|
||||
internal String8 rd_mapped_from_file_path(Arena *arena, String8 file_path);
|
||||
internal String8List rd_possible_overrides_from_file_path(Arena *arena, String8 file_path);
|
||||
@@ -882,8 +607,8 @@ internal String8 rd_name_from_ctrl_entity(Arena *arena, CTRL_Entity *entity);
|
||||
//~ rjf: Evaluation Spaces
|
||||
|
||||
//- rjf: cfg <-> eval space
|
||||
internal RD_Cfg *rd_cfg_from_eval_space(E_Space space);
|
||||
internal E_Space rd_eval_space_from_cfg(RD_Cfg *cfg);
|
||||
internal CFG_Node *rd_cfg_from_eval_space(E_Space space);
|
||||
internal E_Space rd_eval_space_from_cfg(CFG_Node *cfg);
|
||||
|
||||
//- rjf: ctrl entity <-> eval space
|
||||
internal CTRL_Entity *rd_ctrl_entity_from_eval_space(E_Space space);
|
||||
@@ -893,9 +618,9 @@ internal E_Space rd_eval_space_from_ctrl_entity(CTRL_Entity *entity, E_SpaceKind
|
||||
internal String8 rd_cmd_name_from_eval(E_Eval eval);
|
||||
|
||||
//- rjf: eval space reads/writes
|
||||
internal U64 rd_eval_space_gen(void *u, E_Space space);
|
||||
internal B32 rd_eval_space_read(void *u, E_Space space, void *out, Rng1U64 range);
|
||||
internal B32 rd_eval_space_write(void *u, E_Space space, void *in, Rng1U64 range);
|
||||
internal U64 rd_eval_space_gen(E_Space space);
|
||||
internal B32 rd_eval_space_read(E_Space space, void *out, Rng1U64 range);
|
||||
internal B32 rd_eval_space_write(E_Space space, void *in, Rng1U64 range);
|
||||
|
||||
//- rjf: asynchronous streamed reads -> hashes from spaces
|
||||
internal C_Key rd_key_from_eval_space_range(E_Space space, Rng1U64 range, B32 zero_terminated);
|
||||
@@ -920,8 +645,8 @@ internal String8 rd_query_from_eval_string(Arena *arena, String8 string);
|
||||
////////////////////////////////
|
||||
//~ rjf: View Functions
|
||||
|
||||
internal RD_Cfg *rd_view_from_eval(RD_Cfg *parent, E_Eval eval);
|
||||
internal RD_ViewState *rd_view_state_from_cfg(RD_Cfg *cfg);
|
||||
internal CFG_Node *rd_view_from_eval(CFG_Node *parent, E_Eval eval);
|
||||
internal RD_ViewState *rd_view_state_from_cfg(CFG_Node *cfg);
|
||||
internal void rd_view_ui(Rng2F32 rect);
|
||||
|
||||
////////////////////////////////
|
||||
@@ -963,8 +688,8 @@ internal void rd_store_view_paramf(String8 key, char *fmt, ...);
|
||||
//~ rjf: Window Functions
|
||||
|
||||
internal String8 rd_push_window_title(Arena *arena);
|
||||
internal RD_Cfg *rd_window_from_cfg(RD_Cfg *cfg);
|
||||
internal RD_WindowState *rd_window_state_from_cfg(RD_Cfg *cfg);
|
||||
internal CFG_Node *rd_window_from_cfg(CFG_Node *cfg);
|
||||
internal RD_WindowState *rd_window_state_from_cfg(CFG_Node *cfg);
|
||||
internal RD_WindowState *rd_window_state_from_os_handle(OS_Handle os);
|
||||
internal void rd_window_frame(void);
|
||||
|
||||
|
||||
+107
-126
@@ -43,8 +43,8 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(commands)
|
||||
FuzzyMatchRangeList name_matches = fuzzy_match_find(scratch.arena, filter, display_name);
|
||||
FuzzyMatchRangeList tags_matches = fuzzy_match_find(scratch.arena, filter, search_tags);
|
||||
B32 binding_matches_good = 0;
|
||||
RD_KeyMapNodePtrList bindings = rd_key_map_node_ptr_list_from_name(scratch.arena, code_name);
|
||||
for(RD_KeyMapNodePtr *n = bindings.first; n != 0; n = n->next)
|
||||
CFG_KeyMapNodePtrList bindings = cfg_key_map_node_ptr_list_from_name(scratch.arena, rd_state->key_map, code_name);
|
||||
for(CFG_KeyMapNodePtr *n = bindings.first; n != 0; n = n->next)
|
||||
{
|
||||
String8 binding_text = os_string_from_modifiers_key(scratch.arena, n->v->binding.modifiers, n->v->binding.key);
|
||||
FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, binding_text);
|
||||
@@ -208,9 +208,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(registers)
|
||||
CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, rd_regs()->thread);
|
||||
Arch arch = thread->arch;
|
||||
U64 reg_count = regs_reg_code_count_from_arch(arch);
|
||||
U64 alias_count = regs_alias_code_count_from_arch(arch);
|
||||
String8 *reg_strings = regs_reg_code_string_table_from_arch(arch);
|
||||
String8 *alias_strings = regs_alias_code_string_table_from_arch(arch);
|
||||
String8List exprs_list = {0};
|
||||
for(U64 idx = 1; idx < reg_count; idx += 1)
|
||||
{
|
||||
@@ -220,14 +218,6 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(registers)
|
||||
str8_list_push(scratch.arena, &exprs_list, reg_strings[idx]);
|
||||
}
|
||||
}
|
||||
for(U64 idx = 1; idx < alias_count; idx += 1)
|
||||
{
|
||||
FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, alias_strings[idx]);
|
||||
if(matches.count == matches.needle_part_count)
|
||||
{
|
||||
str8_list_push(scratch.arena, &exprs_list, alias_strings[idx]);
|
||||
}
|
||||
}
|
||||
String8Array *accel = push_array(arena, String8Array, 1);
|
||||
*accel = str8_array_from_list(arena, &exprs_list);
|
||||
E_TypeExpandInfo info = {accel, accel->count};
|
||||
@@ -255,7 +245,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(registers)
|
||||
typedef struct RD_SchemaIRExt RD_SchemaIRExt;
|
||||
struct RD_SchemaIRExt
|
||||
{
|
||||
RD_Cfg *cfg;
|
||||
CFG_Node *cfg;
|
||||
CTRL_Entity *entity;
|
||||
MD_NodePtrList schemas;
|
||||
};
|
||||
@@ -272,7 +262,7 @@ E_TYPE_IREXT_FUNCTION_DEF(schema)
|
||||
E_Type *type = e_type_from_key(type_key);
|
||||
ext->cfg = rd_cfg_from_eval_space(interpret.space);
|
||||
ext->entity = rd_ctrl_entity_from_eval_space(interpret.space);
|
||||
ext->schemas = rd_schemas_from_name(type->name);
|
||||
ext->schemas = cfg_schemas_from_name(arena, rd_state->cfg_schema_table, type->name);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
E_IRExt result = {ext};
|
||||
@@ -299,9 +289,9 @@ E_TYPE_ACCESS_FUNCTION_DEF(schema)
|
||||
}
|
||||
if(child_schema != &md_nil_node)
|
||||
{
|
||||
RD_Cfg *cfg = ext->cfg;
|
||||
CFG_Node *cfg = ext->cfg;
|
||||
CTRL_Entity *entity = ext->entity;
|
||||
RD_Cfg *child = rd_cfg_child_from_string(cfg, child_schema->string);
|
||||
CFG_Node *child = cfg_node_child_from_string(cfg, child_schema->string);
|
||||
E_TypeKey child_type_key = zero_struct;
|
||||
B32 wrap_child_w_meta_expr = 0;
|
||||
if(0){}
|
||||
@@ -465,7 +455,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(schema)
|
||||
|
||||
//- rjf: evaluate
|
||||
E_Space child_eval_space = zero_struct;
|
||||
if(cfg != &rd_nil_cfg)
|
||||
if(cfg != &cfg_nil_node)
|
||||
{
|
||||
child_eval_space = e_space_make(RD_EvalSpaceKind_MetaCfg);
|
||||
child_eval_space.u64s[0] = cfg->id;
|
||||
@@ -646,8 +636,8 @@ E_TYPE_ACCESS_FUNCTION_DEF(cfgs)
|
||||
str8_match(str8_prefix(rhs->string, 1), str8_lit("$"), 0))
|
||||
{
|
||||
String8 numeric_part = str8_skip(rhs->string, 1);
|
||||
RD_CfgID id = u64_from_str8(numeric_part, 16);
|
||||
RD_Cfg *cfg = rd_cfg_from_id(id);
|
||||
CFG_ID id = u64_from_str8(numeric_part, 16);
|
||||
CFG_Node *cfg = cfg_node_from_id(id);
|
||||
E_Space space = rd_eval_space_from_cfg(cfg);
|
||||
result.root = e_irtree_set_space(arena, space, e_irtree_const_u(arena, 0));
|
||||
result.type_key = e_string2typekey_map_lookup(rd_state->meta_name2type_map, cfg->string);
|
||||
@@ -684,7 +674,7 @@ struct RD_CfgsIRExt
|
||||
{
|
||||
String8 cfg_name;
|
||||
String8Array cmds;
|
||||
RD_CfgArray cfgs;
|
||||
CFG_NodePtrArray cfgs;
|
||||
Rng1U64 cmds_idx_range;
|
||||
Rng1U64 cfgs_idx_range;
|
||||
};
|
||||
@@ -701,12 +691,12 @@ E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice)
|
||||
String8 cfg_name = rd_singular_from_code_name_plural(type->name);
|
||||
|
||||
//- rjf: gather cfgs
|
||||
RD_CfgList cfgs_list = rd_cfg_top_level_list_from_string(scratch.arena, cfg_name);
|
||||
CFG_NodePtrList cfgs_list = cfg_node_top_level_list_from_string(scratch.arena, cfg_name);
|
||||
|
||||
//- rjf: gather commands
|
||||
String8List cmds_list = {0};
|
||||
{
|
||||
MD_NodePtrList schemas = rd_schemas_from_name(cfg_name);
|
||||
MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, cfg_name);
|
||||
for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *schema = n->v;
|
||||
@@ -720,7 +710,7 @@ E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice)
|
||||
|
||||
//- rjf: package & fill
|
||||
ext->cfg_name = cfg_name;
|
||||
ext->cfgs = rd_cfg_array_from_list(arena, &cfgs_list);
|
||||
ext->cfgs = cfg_node_ptr_array_from_list(arena, &cfgs_list);
|
||||
ext->cmds = str8_array_from_list(arena, &cmds_list);
|
||||
|
||||
scratch_end(scratch);
|
||||
@@ -732,7 +722,7 @@ E_TYPE_IREXT_FUNCTION_DEF(cfgs_slice)
|
||||
E_TYPE_ACCESS_FUNCTION_DEF(cfgs_slice)
|
||||
{
|
||||
E_IRTreeAndType result = {&e_irnode_nil};
|
||||
RD_Cfg *cfg = &rd_nil_cfg;
|
||||
CFG_Node *cfg = &cfg_nil_node;
|
||||
RD_CfgsIRExt *ext = (RD_CfgsIRExt *)lhs_irtree->user_data;
|
||||
switch(expr->kind)
|
||||
{
|
||||
@@ -749,15 +739,15 @@ E_TYPE_ACCESS_FUNCTION_DEF(cfgs_slice)
|
||||
case E_ExprKind_MemberAccess:
|
||||
{
|
||||
String8 rhs_name = expr->first->next->string;
|
||||
RD_CfgID id = 0;
|
||||
CFG_ID id = 0;
|
||||
if(str8_match(str8_prefix(rhs_name, 1), str8_lit("$"), 0))
|
||||
{
|
||||
id = u64_from_str8(str8_skip(rhs_name, 1), 16);
|
||||
cfg = rd_cfg_from_id(id);
|
||||
cfg = cfg_node_from_id(id);
|
||||
}
|
||||
}break;
|
||||
}
|
||||
if(cfg != &rd_nil_cfg)
|
||||
if(cfg != &cfg_nil_node)
|
||||
{
|
||||
result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0));
|
||||
result.mode = E_Mode_Offset;
|
||||
@@ -770,7 +760,7 @@ typedef struct RD_CfgsExpandAccel RD_CfgsExpandAccel;
|
||||
struct RD_CfgsExpandAccel
|
||||
{
|
||||
String8Array cmds;
|
||||
RD_CfgArray cfgs;
|
||||
CFG_NodePtrArray cfgs;
|
||||
Rng1U64 cmds_idx_range;
|
||||
Rng1U64 cfgs_idx_range;
|
||||
};
|
||||
@@ -785,27 +775,27 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_slice)
|
||||
RD_CfgsIRExt *ext = (RD_CfgsIRExt *)eval.irtree.user_data;
|
||||
|
||||
//- rjf: filter cfgs
|
||||
RD_CfgArray cfgs__filtered = ext->cfgs;
|
||||
CFG_NodePtrArray cfgs__filtered = ext->cfgs;
|
||||
if(filter.size != 0)
|
||||
{
|
||||
RD_CfgList cfgs_list__filtered = {0};
|
||||
CFG_NodePtrList cfgs_list__filtered = {0};
|
||||
for EachIndex(idx, ext->cfgs.count)
|
||||
{
|
||||
RD_Cfg *cfg = ext->cfgs.v[idx];
|
||||
CFG_Node *cfg = ext->cfgs.v[idx];
|
||||
DR_FStrList fstrs = rd_title_fstrs_from_cfg(scratch.arena, cfg, 1);
|
||||
String8 string = dr_string_from_fstrs(scratch.arena, &fstrs);
|
||||
FuzzyMatchRangeList fuzzy_matches = fuzzy_match_find(scratch.arena, filter, string);
|
||||
if(fuzzy_matches.count == fuzzy_matches.needle_part_count)
|
||||
{
|
||||
rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, cfg);
|
||||
cfg_node_ptr_list_push(scratch.arena, &cfgs_list__filtered, cfg);
|
||||
}
|
||||
}
|
||||
cfgs__filtered = rd_cfg_array_from_list(arena, &cfgs_list__filtered);
|
||||
cfgs__filtered = cfg_node_ptr_array_from_list(arena, &cfgs_list__filtered);
|
||||
}
|
||||
|
||||
//- rjf: fill
|
||||
// TODO(rjf): @cleanup don't smuggle this through like this...
|
||||
if(rd_cfg_child_from_string(rd_cfg_from_id(rd_regs()->view), str8_lit("lister")) == &rd_nil_cfg)
|
||||
if(cfg_node_child_from_string(cfg_node_from_id(rd_regs()->view), str8_lit("lister")) == &cfg_nil_node)
|
||||
{
|
||||
accel->cmds = ext->cmds;
|
||||
accel->cmds_idx_range = r1u64(0, accel->cmds.count);
|
||||
@@ -823,7 +813,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query)
|
||||
RD_CfgsExpandAccel *accel = push_array(arena, RD_CfgsExpandAccel, 1);
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
RD_Cfg *root_cfg = rd_cfg_from_eval_space(eval.space);
|
||||
CFG_Node *root_cfg = rd_cfg_from_eval_space(eval.space);
|
||||
String8 child_key = e_string_from_id(eval.space.u64s[1]);
|
||||
String8 child_key_singular = rd_singular_from_code_name_plural(child_key);
|
||||
if(child_key_singular.size != 0)
|
||||
@@ -831,7 +821,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query)
|
||||
child_key = child_key_singular;
|
||||
}
|
||||
String8List cmds = {0};
|
||||
MD_NodePtrList schemas = rd_schemas_from_name(child_key);
|
||||
MD_NodePtrList schemas = cfg_schemas_from_name(scratch.arena, rd_state->cfg_schema_table, child_key);
|
||||
for(MD_NodePtrNode *n = schemas.first; n != 0; n = n->next)
|
||||
{
|
||||
MD_Node *schema = n->v;
|
||||
@@ -841,25 +831,25 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(cfgs_query)
|
||||
str8_list_push(scratch.arena, &cmds, cmd->string);
|
||||
}
|
||||
}
|
||||
RD_CfgList children = rd_cfg_child_list_from_string(scratch.arena, root_cfg, child_key);
|
||||
RD_CfgList children__filtered = children;
|
||||
CFG_NodePtrList children = cfg_node_child_list_from_string(scratch.arena, root_cfg, child_key);
|
||||
CFG_NodePtrList children__filtered = children;
|
||||
if(filter.size != 0)
|
||||
{
|
||||
MemoryZeroStruct(&children__filtered);
|
||||
for(RD_CfgNode *n = children.first; n != 0; n = n->next)
|
||||
for(CFG_NodePtrNode *n = children.first; n != 0; n = n->next)
|
||||
{
|
||||
DR_FStrList cfg_fstrs = rd_title_fstrs_from_cfg(scratch.arena, n->v, 1);
|
||||
String8 cfg_string = dr_string_from_fstrs(scratch.arena, &cfg_fstrs);
|
||||
FuzzyMatchRangeList ranges = fuzzy_match_find(scratch.arena, filter, cfg_string);
|
||||
if(ranges.count == ranges.needle_part_count)
|
||||
{
|
||||
rd_cfg_list_push(scratch.arena, &children__filtered, n->v);
|
||||
cfg_node_ptr_list_push(scratch.arena, &children__filtered, n->v);
|
||||
}
|
||||
}
|
||||
}
|
||||
accel->cmds = str8_array_from_list(arena, &cmds);
|
||||
accel->cmds_idx_range = r1u64(0, accel->cmds.count);
|
||||
accel->cfgs = rd_cfg_array_from_list(arena, &children__filtered);
|
||||
accel->cfgs = cfg_node_ptr_array_from_list(arena, &children__filtered);
|
||||
accel->cfgs_idx_range = r1u64(accel->cmds.count + 0, accel->cmds.count + accel->cfgs.count);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
@@ -893,7 +883,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(cfgs_slice)
|
||||
U64 read_count = dim_1u64(read_range);
|
||||
for(U64 idx = 0; idx < read_count; idx += 1, dst_idx += 1)
|
||||
{
|
||||
RD_Cfg *cfg = accel->cfgs.v[idx + read_range.min - cfgs_idx_range.min];
|
||||
CFG_Node *cfg = accel->cfgs.v[idx + read_range.min - cfgs_idx_range.min];
|
||||
evals_out[dst_idx] = e_eval_from_stringf("query:config.$%I64x", cfg->id);
|
||||
}
|
||||
}
|
||||
@@ -908,7 +898,7 @@ E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(cfgs_slice)
|
||||
U64 idx = num-1;
|
||||
if(contains_1u64(accel->cfgs_idx_range, idx))
|
||||
{
|
||||
RD_Cfg *cfg = accel->cfgs.v[idx - accel->cfgs_idx_range.min];
|
||||
CFG_Node *cfg = accel->cfgs.v[idx - accel->cfgs_idx_range.min];
|
||||
id = cfg->id;
|
||||
}
|
||||
else if(contains_1u64(accel->cmds_idx_range, idx))
|
||||
@@ -988,7 +978,7 @@ E_TYPE_ACCESS_FUNCTION_DEF(call_stack)
|
||||
{
|
||||
CTRL_Entity *process = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, accel->process);
|
||||
CTRL_CallStackFrame *f = &call_stack->frames[rhs_value.u64];
|
||||
result.root = e_irtree_set_space(arena, rd_eval_space_from_ctrl_entity(process, RD_EvalSpaceKind_CtrlEntity), e_irtree_const_u(arena, regs_rip_from_arch_block(accel->arch, f->regs)));
|
||||
result.root = e_irtree_set_space(arena, rd_eval_space_from_ctrl_entity(process, CTRL_EvalSpaceKind_Entity), e_irtree_const_u(arena, regs_rip_from_arch_block(accel->arch, f->regs)));
|
||||
result.type_key = e_type_key_cons(.arch = process->arch, .kind = E_TypeKind_Ptr, .direct_key = e_type_key_basic(E_TypeKind_Function), .count = 1, .depth = f->inline_depth);
|
||||
result.mode = E_Mode_Value;
|
||||
}
|
||||
@@ -1011,7 +1001,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack)
|
||||
typedef struct RD_EnvironmentAccel RD_EnvironmentAccel;
|
||||
struct RD_EnvironmentAccel
|
||||
{
|
||||
RD_CfgArray cfgs;
|
||||
CFG_NodePtrArray cfgs;
|
||||
};
|
||||
|
||||
E_TYPE_IREXT_FUNCTION_DEF(environment)
|
||||
@@ -1023,16 +1013,16 @@ E_TYPE_IREXT_FUNCTION_DEF(environment)
|
||||
String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist);
|
||||
E_Interpretation interpret = e_interpret(bytecode);
|
||||
E_Space space = interpret.space;
|
||||
RD_Cfg *target = rd_cfg_from_eval_space(space);
|
||||
RD_CfgList env_strings = {0};
|
||||
for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next)
|
||||
CFG_Node *target = rd_cfg_from_eval_space(space);
|
||||
CFG_NodePtrList env_strings = {0};
|
||||
for(CFG_Node *child = target->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(str8_match(child->string, str8_lit("environment"), 0))
|
||||
{
|
||||
rd_cfg_list_push(scratch.arena, &env_strings, child);
|
||||
cfg_node_ptr_list_push(scratch.arena, &env_strings, child);
|
||||
}
|
||||
}
|
||||
accel->cfgs = rd_cfg_array_from_list(arena, &env_strings);
|
||||
accel->cfgs = cfg_node_ptr_array_from_list(arena, &env_strings);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
E_IRExt result = {accel};
|
||||
@@ -1045,11 +1035,11 @@ E_TYPE_ACCESS_FUNCTION_DEF(environment)
|
||||
if(expr->kind == E_ExprKind_ArrayIndex)
|
||||
{
|
||||
RD_EnvironmentAccel *accel = (RD_EnvironmentAccel *)lhs_irtree->user_data;
|
||||
RD_CfgArray *cfgs = &accel->cfgs;
|
||||
CFG_NodePtrArray *cfgs = &accel->cfgs;
|
||||
E_Value rhs_value = e_value_from_expr(expr->first->next);
|
||||
if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count)
|
||||
{
|
||||
RD_Cfg *cfg = cfgs->v[rhs_value.u64];
|
||||
CFG_Node *cfg = cfgs->v[rhs_value.u64];
|
||||
result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0));
|
||||
result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText);
|
||||
result.mode = E_Mode_Offset;
|
||||
@@ -1125,7 +1115,7 @@ E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(environment)
|
||||
typedef struct RD_WatchesAccel RD_WatchesAccel;
|
||||
struct RD_WatchesAccel
|
||||
{
|
||||
RD_CfgArray cfgs;
|
||||
CFG_NodePtrArray cfgs;
|
||||
};
|
||||
|
||||
E_TYPE_IREXT_FUNCTION_DEF(watches)
|
||||
@@ -1137,16 +1127,16 @@ E_TYPE_IREXT_FUNCTION_DEF(watches)
|
||||
String8 bytecode = e_bytecode_from_oplist(scratch.arena, &oplist);
|
||||
E_Interpretation interpret = e_interpret(bytecode);
|
||||
E_Space space = interpret.space;
|
||||
RD_Cfg *target = rd_cfg_from_eval_space(space);
|
||||
RD_CfgList env_strings = {0};
|
||||
for(RD_Cfg *child = target->first; child != &rd_nil_cfg; child = child->next)
|
||||
CFG_Node *target = rd_cfg_from_eval_space(space);
|
||||
CFG_NodePtrList env_strings = {0};
|
||||
for(CFG_Node *child = target->first; child != &cfg_nil_node; child = child->next)
|
||||
{
|
||||
if(str8_match(child->string, str8_lit("watch"), 0))
|
||||
{
|
||||
rd_cfg_list_push(scratch.arena, &env_strings, child);
|
||||
cfg_node_ptr_list_push(scratch.arena, &env_strings, child);
|
||||
}
|
||||
}
|
||||
accel->cfgs = rd_cfg_array_from_list(arena, &env_strings);
|
||||
accel->cfgs = cfg_node_ptr_array_from_list(arena, &env_strings);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
E_IRExt result = {accel};
|
||||
@@ -1159,11 +1149,11 @@ E_TYPE_ACCESS_FUNCTION_DEF(watches)
|
||||
if(expr->kind == E_ExprKind_ArrayIndex)
|
||||
{
|
||||
RD_WatchesAccel *accel = (RD_WatchesAccel *)lhs_irtree->user_data;
|
||||
RD_CfgArray *cfgs = &accel->cfgs;
|
||||
CFG_NodePtrArray *cfgs = &accel->cfgs;
|
||||
E_Value rhs_value = e_value_from_expr(expr->first->next);
|
||||
if(0 <= rhs_value.u64 && rhs_value.u64 < cfgs->count)
|
||||
{
|
||||
RD_Cfg *cfg = cfgs->v[rhs_value.u64];
|
||||
CFG_Node *cfg = cfgs->v[rhs_value.u64];
|
||||
result.root = e_irtree_set_space(arena, rd_eval_space_from_cfg(cfg), e_irtree_const_u(arena, 0));
|
||||
result.type_key = e_type_key_cons_array(e_type_key_basic(E_TypeKind_U8), cfg->first->string.size, E_TypeFlag_IsCodeText);
|
||||
result.mode = E_Mode_Offset;
|
||||
@@ -1177,22 +1167,22 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(watches)
|
||||
RD_WatchesAccel *ext = (RD_WatchesAccel *)eval.irtree.user_data;
|
||||
RD_WatchesAccel *accel = push_array(arena, RD_WatchesAccel, 1);
|
||||
{
|
||||
RD_CfgArray cfgs__filtered = ext->cfgs;
|
||||
CFG_NodePtrArray cfgs__filtered = ext->cfgs;
|
||||
if(filter.size != 0)
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
RD_CfgList cfgs_list__filtered = {0};
|
||||
CFG_NodePtrList cfgs_list__filtered = {0};
|
||||
for EachIndex(idx, ext->cfgs.count)
|
||||
{
|
||||
RD_Cfg *watch = ext->cfgs.v[idx];
|
||||
CFG_Node *watch = ext->cfgs.v[idx];
|
||||
String8 string = watch->first->string;
|
||||
FuzzyMatchRangeList matches = fuzzy_match_find(scratch.arena, filter, string);
|
||||
if(matches.count == matches.needle_part_count)
|
||||
{
|
||||
rd_cfg_list_push(scratch.arena, &cfgs_list__filtered, watch);
|
||||
cfg_node_ptr_list_push(scratch.arena, &cfgs_list__filtered, watch);
|
||||
}
|
||||
}
|
||||
cfgs__filtered = rd_cfg_array_from_list(arena, &cfgs_list__filtered);
|
||||
cfgs__filtered = cfg_node_ptr_array_from_list(arena, &cfgs_list__filtered);
|
||||
scratch_end(scratch);
|
||||
}
|
||||
accel->cfgs = cfgs__filtered;
|
||||
@@ -1212,7 +1202,7 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(watches)
|
||||
U64 cfg_idx = read_range.min + idx;
|
||||
if(cfg_idx < accel->cfgs.count)
|
||||
{
|
||||
RD_Cfg *cfg = accel->cfgs.v[cfg_idx];
|
||||
CFG_Node *cfg = accel->cfgs.v[cfg_idx];
|
||||
evals_out[idx] = e_eval_from_string(cfg->first->string);
|
||||
}
|
||||
}
|
||||
@@ -1568,17 +1558,15 @@ struct RD_CallStackTreeExpandAccel
|
||||
|
||||
E_TYPE_EXPAND_INFO_FUNCTION_DEF(call_stack_tree)
|
||||
{
|
||||
if(!rd_state->got_frame_call_stack_tree)
|
||||
{
|
||||
rd_state->got_frame_call_stack_tree = 1;
|
||||
rd_state->frame_call_stack_tree = ctrl_call_stack_tree(rd_state->frame_access, 0);
|
||||
}
|
||||
Access *access = access_open();
|
||||
CTRL_CallStackTree call_stack_tree = ctrl_call_stack_tree(access, 0);
|
||||
access_close(access);
|
||||
RD_CallStackTreeExpandAccel *accel = push_array(arena, RD_CallStackTreeExpandAccel, 1);
|
||||
accel->node = &ctrl_call_stack_tree_node_nil;
|
||||
U64 id = e_value_eval_from_eval(eval).value.u64;
|
||||
if(rd_state->frame_call_stack_tree.slots_count != 0)
|
||||
if(call_stack_tree.slots_count != 0)
|
||||
{
|
||||
for(CTRL_CallStackTreeNode *n = rd_state->frame_call_stack_tree.slots[id%rd_state->frame_call_stack_tree.slots_count];
|
||||
for(CTRL_CallStackTreeNode *n = call_stack_tree.slots[id%call_stack_tree.slots_count];
|
||||
n != 0;
|
||||
n = n->hash_next)
|
||||
{
|
||||
@@ -1634,8 +1622,6 @@ typedef struct RD_DebugInfoTableLookupAccel RD_DebugInfoTableLookupAccel;
|
||||
struct RD_DebugInfoTableLookupAccel
|
||||
{
|
||||
RDI_SectionKind section;
|
||||
U64 rdis_count;
|
||||
RDI_Parsed **rdis;
|
||||
DI_SearchItemArray items;
|
||||
};
|
||||
|
||||
@@ -1662,30 +1648,22 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(debug_info_table)
|
||||
if(section != RDI_SectionKind_NULL)
|
||||
{
|
||||
U64 endt_us = rd_state->frame_eval_memread_endt_us;
|
||||
|
||||
//- rjf: unpack context
|
||||
DI_KeyList dbgi_keys_list = d_push_active_dbgi_key_list(scratch.arena);
|
||||
DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list);
|
||||
U64 rdis_count = dbgi_keys.count;
|
||||
RDI_Parsed **rdis = push_array(arena, RDI_Parsed *, rdis_count);
|
||||
for(U64 idx = 0; idx < rdis_count; idx += 1)
|
||||
{
|
||||
rdis[idx] = di_rdi_from_key(rd_state->frame_di_scope, &dbgi_keys.v[idx], 1, endt_us);
|
||||
}
|
||||
|
||||
//- rjf: query all filtered items from dbgi searching system
|
||||
U128 fuzzy_search_key = {d_hash_from_string(str8_struct(&rd_regs()->view)), (U64)section};
|
||||
B32 items_stale = 0;
|
||||
DI_SearchParams params = {section, dbgi_keys};
|
||||
B32 stale = 0;
|
||||
accel->section = section;
|
||||
accel->rdis_count = rdis_count;
|
||||
accel->rdis = rdis;
|
||||
accel->items = di_search_items_from_key_params_query(rd_state->frame_di_scope, fuzzy_search_key, ¶ms, filter, endt_us, &items_stale);
|
||||
if(items_stale)
|
||||
accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, filter, endt_us, &stale);
|
||||
CFG_Node *last_successful_query_cfg = rd_immediate_cfg_from_keyf("last_successful_query_%I64x_%I64u", rd_regs()->view, (U64)section);
|
||||
if(stale)
|
||||
{
|
||||
String8 last_query = last_successful_query_cfg->first->string;
|
||||
accel->items = di_search_item_array_from_target_query(rd_state->frame_access, section, last_query, endt_us, 0);
|
||||
rd_request_frame();
|
||||
}
|
||||
else
|
||||
{
|
||||
cfg_node_new_replace(rd_state->cfg, last_successful_query_cfg, filter);
|
||||
}
|
||||
}
|
||||
|
||||
E_TypeExpandInfo info = {accel, accel->items.count};
|
||||
scratch_end(scratch);
|
||||
return info;
|
||||
@@ -1698,18 +1676,11 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table)
|
||||
U64 needed_row_count = dim_1u64(idx_range);
|
||||
for EachIndex(idx, needed_row_count)
|
||||
{
|
||||
Access *access = access_open();
|
||||
|
||||
// rjf: unpack row
|
||||
DI_SearchItem *item = &accel->items.v[idx_range.min + idx];
|
||||
|
||||
// rjf: skip bad elements
|
||||
if(item->dbgi_idx >= accel->rdis_count)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// rjf: unpack row info
|
||||
RDI_Parsed *rdi = accel->rdis[item->dbgi_idx];
|
||||
E_Module *module = &e_base_ctx->modules[item->dbgi_idx];
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, item->key, 0, 0);
|
||||
|
||||
// rjf: get item's string
|
||||
String8 item_string = {0};
|
||||
@@ -1721,51 +1692,43 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table)
|
||||
default:{}break;
|
||||
case RDI_SectionKind_Procedures:
|
||||
{
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(module->rdi, Procedures, element_idx);
|
||||
RDI_Scope *scope = rdi_element_from_name_idx(module->rdi, Scopes, procedure->root_scope_idx);
|
||||
U64 voff = *rdi_element_from_name_idx(module->rdi, ScopeVOffData, scope->voff_range_first);
|
||||
E_OpList oplist = {0};
|
||||
e_oplist_push_op(arena, &oplist, RDI_EvalOp_ConstU64, e_value_u64(module->vaddr_range.min + voff));
|
||||
String8 bytecode = e_bytecode_from_oplist(arena, &oplist);
|
||||
U32 type_idx = procedure->type_idx;
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, type_idx);
|
||||
E_TypeKey type_key = e_type_key_ext(e_type_kind_from_rdi(type_node->kind), type_idx, (U32)(module - e_base_ctx->modules));
|
||||
RDI_Procedure *procedure = rdi_element_from_name_idx(rdi, Procedures, element_idx);
|
||||
String8 symbol_name = {0};
|
||||
symbol_name.str = rdi_string_from_idx(module->rdi, procedure->name_string_idx, &symbol_name.size);
|
||||
symbol_name.str = rdi_string_from_idx(rdi, procedure->name_string_idx, &symbol_name.size);
|
||||
item_string = symbol_name;
|
||||
}break;
|
||||
case RDI_SectionKind_GlobalVariables:
|
||||
{
|
||||
RDI_GlobalVariable *gvar = rdi_element_from_name_idx(module->rdi, GlobalVariables, element_idx);
|
||||
RDI_GlobalVariable *gvar = rdi_element_from_name_idx(rdi, GlobalVariables, element_idx);
|
||||
String8 symbol_name = {0};
|
||||
symbol_name.str = rdi_string_from_idx(module->rdi, gvar->name_string_idx, &symbol_name.size);
|
||||
symbol_name.str = rdi_string_from_idx(rdi, gvar->name_string_idx, &symbol_name.size);
|
||||
item_string = symbol_name;
|
||||
}break;
|
||||
case RDI_SectionKind_ThreadVariables:
|
||||
{
|
||||
RDI_ThreadVariable *tvar = rdi_element_from_name_idx(module->rdi, ThreadVariables, element_idx);
|
||||
RDI_ThreadVariable *tvar = rdi_element_from_name_idx(rdi, ThreadVariables, element_idx);
|
||||
String8 symbol_name = {0};
|
||||
symbol_name.str = rdi_string_from_idx(module->rdi, tvar->name_string_idx, &symbol_name.size);
|
||||
symbol_name.str = rdi_string_from_idx(rdi, tvar->name_string_idx, &symbol_name.size);
|
||||
item_string = symbol_name;
|
||||
}break;
|
||||
case RDI_SectionKind_Constants:
|
||||
{
|
||||
RDI_Constant *cnst = rdi_element_from_name_idx(module->rdi, Constants, element_idx);
|
||||
RDI_Constant *cnst = rdi_element_from_name_idx(rdi, Constants, element_idx);
|
||||
String8 symbol_name = {0};
|
||||
symbol_name.str = rdi_string_from_idx(module->rdi, cnst->name_string_idx, &symbol_name.size);
|
||||
symbol_name.str = rdi_string_from_idx(rdi, cnst->name_string_idx, &symbol_name.size);
|
||||
item_string = symbol_name;
|
||||
}break;
|
||||
case RDI_SectionKind_UDTs:
|
||||
{
|
||||
RDI_UDT *udt = rdi_element_from_name_idx(module->rdi, UDTs, element_idx);
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(module->rdi, TypeNodes, udt->self_type_idx);
|
||||
RDI_UDT *udt = rdi_element_from_name_idx(rdi, UDTs, element_idx);
|
||||
RDI_TypeNode *type_node = rdi_element_from_name_idx(rdi, TypeNodes, udt->self_type_idx);
|
||||
String8 name = {0};
|
||||
name.str = rdi_string_from_idx(module->rdi, type_node->user_defined.name_string_idx, &name.size);
|
||||
name.str = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name.size);
|
||||
item_string = name;
|
||||
}break;
|
||||
case RDI_SectionKind_SourceFiles:
|
||||
{
|
||||
RDI_SourceFile *sf = rdi_element_from_name_idx(module->rdi, SourceFiles, element_idx);
|
||||
RDI_SourceFile *sf = rdi_element_from_name_idx(rdi, SourceFiles, element_idx);
|
||||
String8List path_parts = {0};
|
||||
for(RDI_FilePathNode *fpn = rdi_element_from_name_idx(rdi, FilePathNodes, sf->file_path_node_idx);
|
||||
fpn != rdi_element_from_name_idx(rdi, FilePathNodes, 0);
|
||||
@@ -1815,6 +1778,8 @@ E_TYPE_EXPAND_RANGE_FUNCTION_DEF(debug_info_table)
|
||||
// rjf: fill
|
||||
evals_out[idx] = item_eval;
|
||||
temp_end(scratch);
|
||||
|
||||
access_close(access);
|
||||
}
|
||||
scratch_end(scratch);
|
||||
}
|
||||
@@ -1825,7 +1790,11 @@ E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(debug_info_table)
|
||||
U64 id = 0;
|
||||
if(0 < num && num <= accel->items.count)
|
||||
{
|
||||
id = accel->items.v[num-1].idx+1;
|
||||
U64 hash = 5381;
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].key.u64[0]));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].key.u64[1]));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[num-1].idx));
|
||||
id = hash;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
@@ -1833,6 +1802,18 @@ E_TYPE_EXPAND_ID_FROM_NUM_FUNCTION_DEF(debug_info_table)
|
||||
E_TYPE_EXPAND_NUM_FROM_ID_FUNCTION_DEF(debug_info_table)
|
||||
{
|
||||
RD_DebugInfoTableLookupAccel *accel = (RD_DebugInfoTableLookupAccel *)user_data;
|
||||
U64 num = di_search_item_num_from_array_element_idx__linear_search(&accel->items, id-1);
|
||||
U64 num = 0;
|
||||
for EachIndex(idx, accel->items.count)
|
||||
{
|
||||
U64 hash = 5381;
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[idx].key.u64[0]));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[idx].key.u64[1]));
|
||||
hash = u64_hash_from_seed_str8(hash, str8_struct(&accel->items.v[idx].idx));
|
||||
if(hash == id)
|
||||
{
|
||||
num = idx+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright (c) Epic Games Tools
|
||||
// Licensed under the MIT license (https://opensource.org/license/mit/)
|
||||
|
||||
internal RD_CfgList
|
||||
internal CFG_NodePtrList
|
||||
rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data)
|
||||
{
|
||||
RD_CfgList result = {0};
|
||||
CFG_NodePtrList result = {0};
|
||||
{
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
String8 folder_path = str8_skip_last_slash(file_path);
|
||||
@@ -24,20 +24,20 @@ rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String
|
||||
String8 stderr_path = md_child_from_string(tln, str8_lit("stderr_path"), 0)->first->string;
|
||||
String8 stdin_path = md_child_from_string(tln, str8_lit("stdin_path"), 0)->first->string;
|
||||
String8 debug_subprocesses= md_child_from_string(tln, str8_lit("debug_subprocesses"), 0)->first->string;
|
||||
RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, str8_lit("target"));
|
||||
rd_cfg_list_push(arena, &result, dst_root);
|
||||
CFG_Node *dst_root = cfg_node_new(rd_state->cfg, &cfg_nil_node, str8_lit("target"));
|
||||
cfg_node_ptr_list_push(arena, &result, dst_root);
|
||||
{
|
||||
if(executable.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("executable")), path_absolute_dst_from_relative_dst_src(scratch.arena, executable, folder_path)); }
|
||||
if(arguments.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("arguments")), raw_from_escaped_str8(scratch.arena, arguments)); }
|
||||
if(working_directory.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("working_directory")), path_absolute_dst_from_relative_dst_src(scratch.arena, working_directory, folder_path)); }
|
||||
if(entry_point.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("entry_point")), raw_from_escaped_str8(scratch.arena, entry_point)); }
|
||||
if(stdout_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stdout_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdout_path, folder_path)); }
|
||||
if(stderr_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stderr_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stderr_path, folder_path)); }
|
||||
if(stdin_path.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("stdin_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdin_path, folder_path)); }
|
||||
if(debug_subprocesses.size != 0) { rd_cfg_new(rd_cfg_new(dst_root, str8_lit("debug_subprocesses")), raw_from_escaped_str8(scratch.arena, debug_subprocesses)); }
|
||||
if(executable.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("executable")), path_absolute_dst_from_relative_dst_src(scratch.arena, executable, folder_path)); }
|
||||
if(arguments.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("arguments")), raw_from_escaped_str8(scratch.arena, arguments)); }
|
||||
if(working_directory.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("working_directory")), path_absolute_dst_from_relative_dst_src(scratch.arena, working_directory, folder_path)); }
|
||||
if(entry_point.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("entry_point")), raw_from_escaped_str8(scratch.arena, entry_point)); }
|
||||
if(stdout_path.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("stdout_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdout_path, folder_path)); }
|
||||
if(stderr_path.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("stderr_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stderr_path, folder_path)); }
|
||||
if(stdin_path.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("stdin_path")), path_absolute_dst_from_relative_dst_src(scratch.arena, stdin_path, folder_path)); }
|
||||
if(debug_subprocesses.size != 0) { cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("debug_subprocesses")), raw_from_escaped_str8(scratch.arena, debug_subprocesses)); }
|
||||
if(!str8_match(disabled_string, str8_lit("1"), 0))
|
||||
{
|
||||
rd_cfg_new(rd_cfg_new(dst_root, str8_lit("enabled")), str8_lit("1"));
|
||||
cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("enabled")), str8_lit("1"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,9 +46,9 @@ rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String
|
||||
if(str8_match(tln->string, str8_lit("recent_file"), 0) ||
|
||||
str8_match(tln->string, str8_lit("recent_project"), 0))
|
||||
{
|
||||
RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, tln->string);
|
||||
rd_cfg_list_push(arena, &result, dst_root);
|
||||
rd_cfg_new(rd_cfg_new(dst_root, str8_lit("path")), path_absolute_dst_from_relative_dst_src(scratch.arena, tln->first->string, folder_path));
|
||||
CFG_Node *dst_root = cfg_node_new(rd_state->cfg, &cfg_nil_node, tln->string);
|
||||
cfg_node_ptr_list_push(arena, &result, dst_root);
|
||||
cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("path")), path_absolute_dst_from_relative_dst_src(scratch.arena, tln->first->string, folder_path));
|
||||
}
|
||||
|
||||
//- rjf: file path maps
|
||||
@@ -56,10 +56,10 @@ rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String
|
||||
{
|
||||
String8 source = md_child_from_string(tln, str8_lit("source"), 0)->first->string;
|
||||
String8 dest = md_child_from_string(tln, str8_lit("dest"), 0)->first->string;
|
||||
RD_Cfg *dst_root = rd_cfg_new(&rd_nil_cfg, tln->string);
|
||||
rd_cfg_list_push(arena, &result, dst_root);
|
||||
rd_cfg_new(rd_cfg_new(dst_root, str8_lit("source")), path_absolute_dst_from_relative_dst_src(scratch.arena, source, folder_path));
|
||||
rd_cfg_new(rd_cfg_new(dst_root, str8_lit("dest")), path_absolute_dst_from_relative_dst_src(scratch.arena, dest, folder_path));
|
||||
CFG_Node *dst_root = cfg_node_new(rd_state->cfg, &cfg_nil_node, tln->string);
|
||||
cfg_node_ptr_list_push(arena, &result, dst_root);
|
||||
cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("source")), path_absolute_dst_from_relative_dst_src(scratch.arena, source, folder_path));
|
||||
cfg_node_new(rd_state->cfg, cfg_node_new(rd_state->cfg, dst_root, str8_lit("dest")), path_absolute_dst_from_relative_dst_src(scratch.arena, dest, folder_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
#ifndef RADDBG_LEGACY_CONFIG_H
|
||||
#define RADDBG_LEGACY_CONFIG_H
|
||||
|
||||
internal RD_CfgList rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data);
|
||||
internal CFG_NodePtrList rd_cfg_tree_list_from_string__pre_0_9_16(Arena *arena, String8 file_path, String8 data);
|
||||
|
||||
#endif // RADDBG_LEGACY_CONFIG_H
|
||||
|
||||
+12
-12
@@ -24,7 +24,7 @@
|
||||
// [ ] fix type intepretations of cursor in bottom pane
|
||||
//
|
||||
//- bug fixes
|
||||
// [ ] disassembly sometimes has a problem where source line annotations are
|
||||
// [x] disassembly sometimes has a problem where source line annotations are
|
||||
// periodically removed/inserted... maybe updating on fs change when we
|
||||
// shouldn't, non-deterministic line annotation path?
|
||||
//
|
||||
@@ -110,10 +110,10 @@
|
||||
//
|
||||
//- visualizer improvements
|
||||
// [ ] disasm starting address - need to use debug info for more correct results...
|
||||
// [ ] linked list view
|
||||
// [ ] multidimensional `array`
|
||||
// [ ] 2-vector, 3-vector, quaternion
|
||||
// [ ] audio waveform views
|
||||
// [x] linked list view
|
||||
//
|
||||
//- eval improvements
|
||||
// [ ] maybe add extra caching layer to process memory querying? we pay a pretty
|
||||
@@ -148,13 +148,13 @@
|
||||
// [ ] step-out-of-loop
|
||||
//
|
||||
//- late-conversion performance improvements
|
||||
// [ ] investigate wide-conversion performance
|
||||
// [ ] oversubscribing cores?
|
||||
// [ ] conversion crashes?
|
||||
// [ ] live++ investigations - ctrl+alt+f11 in UE?
|
||||
// [x] investigate wide-conversion performance
|
||||
// [x] oversubscribing cores?
|
||||
// [x] conversion crashes?
|
||||
//
|
||||
//- memory usage improvements
|
||||
// [ ] "root" concept in hash store, which buckets keys & allows usage code to
|
||||
// [x] "root" concept in hash store, which buckets keys & allows usage code to
|
||||
// jettison a collection of keys in retained mode fashion
|
||||
//
|
||||
//- short-to-medium term future features
|
||||
@@ -219,11 +219,11 @@
|
||||
#include "base/base_inc.h"
|
||||
#include "linker/hash_table.h"
|
||||
#include "os/os_inc.h"
|
||||
#include "async/async.h"
|
||||
#include "artifact_cache/artifact_cache.h"
|
||||
#include "rdi/rdi_local.h"
|
||||
#include "rdi_make/rdi_make_local.h"
|
||||
#include "mdesk/mdesk.h"
|
||||
#include "config/config_inc.h"
|
||||
#include "content/content.h"
|
||||
#include "file_stream/file_stream.h"
|
||||
#include "text/text.h"
|
||||
@@ -240,6 +240,7 @@
|
||||
#include "pdb/pdb.h"
|
||||
#include "pdb/pdb_parse.h"
|
||||
#include "pdb/pdb_stringize.h"
|
||||
#include "eh/eh_frame.h"
|
||||
#include "dwarf/dwarf_inc.h"
|
||||
#include "rdi_from_coff/rdi_from_coff.h"
|
||||
#include "rdi_from_elf/rdi_from_elf.h"
|
||||
@@ -249,7 +250,6 @@
|
||||
#include "regs/regs.h"
|
||||
#include "regs/rdi/regs_rdi.h"
|
||||
#include "dbg_info/dbg_info.h"
|
||||
#include "dbg_info/dbg_info2.h"
|
||||
#include "disasm/disasm.h"
|
||||
#include "demon/demon_inc.h"
|
||||
#include "eval/eval_inc.h"
|
||||
@@ -267,11 +267,11 @@
|
||||
#include "base/base_inc.c"
|
||||
#include "linker/hash_table.c"
|
||||
#include "os/os_inc.c"
|
||||
#include "async/async.c"
|
||||
#include "artifact_cache/artifact_cache.c"
|
||||
#include "rdi/rdi_local.c"
|
||||
#include "rdi_make/rdi_make_local.c"
|
||||
#include "mdesk/mdesk.c"
|
||||
#include "config/config_inc.c"
|
||||
#include "content/content.c"
|
||||
#include "file_stream/file_stream.c"
|
||||
#include "text/text.c"
|
||||
@@ -288,6 +288,7 @@
|
||||
#include "pdb/pdb.c"
|
||||
#include "pdb/pdb_parse.c"
|
||||
#include "pdb/pdb_stringize.c"
|
||||
#include "eh/eh_frame.c"
|
||||
#include "dwarf/dwarf_inc.c"
|
||||
#include "rdi_from_coff/rdi_from_coff.c"
|
||||
#include "rdi_from_elf/rdi_from_elf.c"
|
||||
@@ -297,7 +298,6 @@
|
||||
#include "regs/regs.c"
|
||||
#include "regs/rdi/regs_rdi.c"
|
||||
#include "dbg_info/dbg_info.c"
|
||||
#include "dbg_info/dbg_info2.c"
|
||||
#include "disasm/disasm.c"
|
||||
#include "demon/demon_inc.c"
|
||||
#include "eval/eval_inc.c"
|
||||
@@ -582,7 +582,7 @@ entry_point(CmdLine *cmd_line)
|
||||
if(dst_ws->cfg_id != rd_regs()->window)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
RD_PanelTree panel_tree = rd_panel_tree_from_cfg(scratch.arena, rd_cfg_from_id(dst_ws->cfg_id));
|
||||
CFG_PanelTree panel_tree = cfg_panel_tree_from_cfg(scratch.arena, cfg_node_from_id(dst_ws->cfg_id));
|
||||
rd_regs()->window = dst_ws->cfg_id;
|
||||
rd_regs()->panel = panel_tree.focused->cfg->id;
|
||||
rd_regs()->tab = panel_tree.focused->selected_tab->id;
|
||||
@@ -751,7 +751,7 @@ entry_point(CmdLine *cmd_line)
|
||||
case ExecMode_BinaryUtility:
|
||||
{
|
||||
rb_entry_point(cmd_line);
|
||||
di2_signal_completion();
|
||||
di_signal_completion();
|
||||
}break;
|
||||
|
||||
//- rjf: help message box
|
||||
|
||||
+384
-221
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,7 @@ struct RD_WatchCellList
|
||||
RD_WatchCell *first;
|
||||
RD_WatchCell *last;
|
||||
U64 count;
|
||||
F32 pct_sum;
|
||||
};
|
||||
|
||||
typedef struct RD_WatchRowInfo RD_WatchRowInfo;
|
||||
@@ -123,8 +124,8 @@ struct RD_WatchRowInfo
|
||||
B32 can_expand;
|
||||
B32 expr_is_editable;
|
||||
String8 group_cfg_name;
|
||||
RD_Cfg *group_cfg_parent;
|
||||
RD_Cfg *group_cfg_child;
|
||||
CFG_Node *group_cfg_parent;
|
||||
CFG_Node *group_cfg_child;
|
||||
CTRL_Entity *group_entity;
|
||||
CTRL_Entity *callstack_thread;
|
||||
U64 callstack_unwind_index;
|
||||
@@ -139,7 +140,7 @@ typedef struct RD_WatchRowCellInfo RD_WatchRowCellInfo;
|
||||
struct RD_WatchRowCellInfo
|
||||
{
|
||||
RD_WatchCellFlags flags;
|
||||
RD_Cfg *cfg;
|
||||
CFG_Node *cfg;
|
||||
CTRL_Entity *entity;
|
||||
String8 cmd_name;
|
||||
String8 file_path;
|
||||
@@ -206,7 +207,6 @@ internal RD_CodeViewBuildResult rd_code_view_build(Arena *arena, RD_CodeViewStat
|
||||
|
||||
//- rjf: cell list building
|
||||
internal U64 rd_id_from_watch_cell(RD_WatchCell *cell);
|
||||
internal RD_WatchCell *rd_watch_cell_list_push(Arena *arena, RD_WatchCellList *list);
|
||||
internal RD_WatchCell *rd_watch_cell_list_push_new_(Arena *arena, RD_WatchCellList *list, RD_WatchCell *params);
|
||||
#define rd_watch_cell_list_push_new(arena, list, kind_, eval_, ...) rd_watch_cell_list_push_new_((arena), (list), &(RD_WatchCell){.kind = (kind_), .eval = (eval_), __VA_ARGS__})
|
||||
|
||||
|
||||
+69
-67
@@ -5,7 +5,7 @@
|
||||
//~ rjf: UI Widgets: Fancy Title Strings
|
||||
|
||||
internal DR_FStrList
|
||||
rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
rd_title_fstrs_from_cfg(Arena *arena, CFG_Node *cfg, B32 include_extras)
|
||||
{
|
||||
DR_FStrList result = {0};
|
||||
{
|
||||
@@ -32,8 +32,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
RD_IconKind icon_kind = rd_icon_kind_from_code_name(cfg->string);
|
||||
B32 is_from_command_line = 0;
|
||||
{
|
||||
RD_Cfg *cmd_line_root = rd_cfg_child_from_string(rd_state->root_cfg, str8_lit("command_line"));
|
||||
for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent)
|
||||
CFG_Node *cmd_line_root = cfg_node_child_from_string(cfg_node_root(), str8_lit("command_line"));
|
||||
for(CFG_Node *p = cfg->parent; p != &cfg_nil_node; p = p->parent)
|
||||
{
|
||||
if(p == cmd_line_root)
|
||||
{
|
||||
@@ -44,7 +44,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
}
|
||||
B32 is_within_window = 0;
|
||||
{
|
||||
for(RD_Cfg *p = cfg->parent; p != &rd_nil_cfg; p = p->parent)
|
||||
for(CFG_Node *p = cfg->parent; p != &cfg_nil_node; p = p->parent)
|
||||
{
|
||||
if(str8_match(p->string, str8_lit("window"), 0))
|
||||
{
|
||||
@@ -105,7 +105,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
CTRL_Event stop_event = d_ctrl_last_stop_event();
|
||||
if(stop_event.cause == CTRL_EventCause_UserBreakpoint)
|
||||
{
|
||||
RD_Cfg *bp = rd_cfg_from_id(stop_event.u64_code);
|
||||
CFG_Node *bp = cfg_node_from_id(stop_event.u64_code);
|
||||
if(bp == cfg)
|
||||
{
|
||||
CTRL_Entity *thread = ctrl_entity_from_handle(&d_state->ctrl_entity_store->ctx, stop_event.entity);
|
||||
@@ -147,7 +147,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
}
|
||||
|
||||
//- rjf: push bucket name
|
||||
if(cfg->parent == rd_state->root_cfg)
|
||||
if(cfg->parent == cfg_node_root())
|
||||
{
|
||||
if(str8_match(cfg->string, str8_lit("user"), 0))
|
||||
{
|
||||
@@ -328,7 +328,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
|
||||
//- rjf: push conditions
|
||||
{
|
||||
String8 condition = rd_cfg_child_from_string(cfg, str8_lit("condition"))->first->string;
|
||||
String8 condition = cfg_node_child_from_string(cfg, str8_lit("condition"))->first->string;
|
||||
if(condition.size != 0)
|
||||
{
|
||||
dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("if "), .font = rd_font_from_slot(RD_FontSlot_Code), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Code));
|
||||
@@ -350,7 +350,7 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
|
||||
//- rjf: push hit count
|
||||
{
|
||||
String8 hit_count_value_string = rd_cfg_child_from_string(cfg, str8_lit("hit_count"))->first->string;
|
||||
String8 hit_count_value_string = cfg_node_child_from_string(cfg, str8_lit("hit_count"))->first->string;
|
||||
U64 hit_count = 0;
|
||||
if(try_u64_from_str8_c_rules(hit_count_value_string, &hit_count) && hit_count != 0)
|
||||
{
|
||||
@@ -362,8 +362,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
//- rjf: special case: type views
|
||||
if(str8_match(cfg->string, str8_lit("type_view"), 0))
|
||||
{
|
||||
String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("type"))->first->string;
|
||||
String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("expr"))->first->string;
|
||||
String8 src_string = cfg_node_child_from_string(cfg, str8_lit("type"))->first->string;
|
||||
String8 dst_string = cfg_node_child_from_string(cfg, str8_lit("expr"))->first->string;
|
||||
Vec4F32 src_color = rgba;
|
||||
Vec4F32 dst_color = rgba;
|
||||
DR_FStrList src_fstrs = {0};
|
||||
@@ -398,8 +398,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
//- rjf: special case: file path maps
|
||||
if(str8_match(cfg->string, str8_lit("file_path_map"), 0))
|
||||
{
|
||||
String8 src_string = rd_cfg_child_from_string(cfg, str8_lit("source"))->first->string;
|
||||
String8 dst_string = rd_cfg_child_from_string(cfg, str8_lit("dest"))->first->string;
|
||||
String8 src_string = cfg_node_child_from_string(cfg, str8_lit("source"))->first->string;
|
||||
String8 dst_string = cfg_node_child_from_string(cfg, str8_lit("dest"))->first->string;
|
||||
Vec4F32 src_color = rgba;
|
||||
Vec4F32 dst_color = rgba;
|
||||
if(src_string.size == 0)
|
||||
@@ -422,8 +422,8 @@ rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras)
|
||||
//- rjf: special case: colors
|
||||
if(str8_match(cfg->string, str8_lit("theme_color"), 0))
|
||||
{
|
||||
String8 tags = rd_cfg_child_from_string(cfg, str8_lit("tags"))->first->string;
|
||||
String8 color_string = rd_cfg_child_from_string(cfg, str8_lit("value"))->first->string;
|
||||
String8 tags = cfg_node_child_from_string(cfg, str8_lit("tags"))->first->string;
|
||||
String8 color_string = cfg_node_child_from_string(cfg, str8_lit("value"))->first->string;
|
||||
U32 color_u32 = e_value_from_stringf("(uint32)(%S)", color_string).u32;
|
||||
Vec4F32 color = linear_from_srgba(rgba_from_u32(color_u32));
|
||||
if(tags.size != 0)
|
||||
@@ -548,7 +548,6 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e
|
||||
Vec4F32 symbol_color = ui_color_from_name(str8_lit("code_symbol"));
|
||||
dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" "));
|
||||
Access *access = access_open();
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
CTRL_Entity *process = ctrl_entity_ancestor_from_kind(entity, CTRL_EntityKind_Process);
|
||||
Arch arch = entity->arch;
|
||||
B32 call_stack_high_priority = ctrl_handle_match(entity->handle, rd_base_regs()->thread);
|
||||
@@ -565,7 +564,7 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e
|
||||
String8 name = {0};
|
||||
{
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(module);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
|
||||
if(rdi != &rdi_parsed_nil)
|
||||
{
|
||||
RDI_Procedure *procedure = rdi_procedure_from_voff(rdi, rip_voff);
|
||||
@@ -591,22 +590,21 @@ rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_e
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(di_scope);
|
||||
access_close(access);
|
||||
}
|
||||
|
||||
//- rjf: modules get debug info status extras
|
||||
if(entity->kind == CTRL_EntityKind_Module && include_extras)
|
||||
{
|
||||
DI_Scope *di_scope = di_scope_open();
|
||||
Access *access = access_open();
|
||||
DI_Key dbgi_key = ctrl_dbgi_key_from_module(entity);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, 1, 0);
|
||||
RDI_Parsed *rdi = di_rdi_from_key(access, dbgi_key, 0, 0);
|
||||
if(rdi->raw_data_size == 0)
|
||||
{
|
||||
dr_fstrs_push_new(arena, &result, ¶ms, str8_lit(" "));
|
||||
dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Symbols not found)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color);
|
||||
dr_fstrs_push_new(arena, &result, ¶ms, str8_lit("(Debug information not loaded)"), .font = rd_font_from_slot(RD_FontSlot_Main), .raster_flags = rd_raster_flags_from_slot(RD_FontSlot_Main), .size = extras_size, .color = secondary_color);
|
||||
}
|
||||
di_scope_close(di_scope);
|
||||
access_close(access);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -756,22 +754,22 @@ internal void
|
||||
rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
RD_KeyMapNodePtrList key_map_nodes = rd_key_map_node_ptr_list_from_name(scratch.arena, name);
|
||||
CFG_KeyMapNodePtrList key_map_nodes = cfg_key_map_node_ptr_list_from_name(scratch.arena, rd_state->key_map, name);
|
||||
|
||||
//- rjf: build buttons for each binding
|
||||
UI_CornerRadius(ui_top_font_size()*0.5f) for(RD_KeyMapNodePtr *n = key_map_nodes.first; n != 0; n = n->next)
|
||||
UI_CornerRadius(ui_top_font_size()*0.5f) for(CFG_KeyMapNodePtr *n = key_map_nodes.first; n != 0; n = n->next)
|
||||
{
|
||||
ui_spacer(ui_em(1.f, 1.f));
|
||||
RD_Binding binding = n->v->binding;
|
||||
CFG_Binding binding = n->v->binding;
|
||||
B32 rebinding_active_for_this_binding = (rd_state->bind_change_active &&
|
||||
str8_match(rd_state->bind_change_cmd_name, name, 0) &&
|
||||
n->v->cfg_id == rd_state->bind_change_binding_id);
|
||||
|
||||
//- rjf: grab all conflicts
|
||||
B32 has_conflicts = 0;
|
||||
RD_KeyMapNodePtrList nodes_with_this_binding = rd_key_map_node_ptr_list_from_binding(scratch.arena, binding);
|
||||
CFG_KeyMapNodePtrList nodes_with_this_binding = cfg_key_map_node_ptr_list_from_binding(scratch.arena, rd_state->key_map, binding);
|
||||
{
|
||||
for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
|
||||
for(CFG_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
|
||||
{
|
||||
if(!str8_match(n->v->name, n2->v->name, 0))
|
||||
{
|
||||
@@ -842,7 +840,7 @@ rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new)
|
||||
if(ui_hovering(sig) && has_conflicts) UI_Tooltip
|
||||
{
|
||||
UI_PrefWidth(ui_children_sum(1)) rd_error_label(str8_lit("This binding conflicts with those for:"));
|
||||
for(RD_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
|
||||
for(CFG_KeyMapNodePtr *n2 = nodes_with_this_binding.first; n2 != 0; n2 = n2->next)
|
||||
{
|
||||
if(!str8_match(n2->v->name, n->v->name, 0))
|
||||
{
|
||||
@@ -862,7 +860,7 @@ rd_cmd_binding_buttons(String8 name, String8 filter, B32 add_new)
|
||||
UI_Signal sig = rd_icon_button(RD_IconKind_X, 0, str8_lit("###delete_binding"));
|
||||
if(ui_clicked(sig))
|
||||
{
|
||||
rd_cfg_release(rd_cfg_from_id(rd_state->bind_change_binding_id));
|
||||
cfg_node_release(rd_state->cfg, cfg_node_from_id(rd_state->bind_change_binding_id));
|
||||
rd_state->bind_change_active = 0;
|
||||
}
|
||||
}
|
||||
@@ -974,7 +972,7 @@ rd_cmd_list_menu_buttons(U64 count, String8 *cmd_names, U32 *fastpath_codepoints
|
||||
{
|
||||
rd_cmd(RD_CmdKind_RunCommand, .cmd_name = cmd_names[idx]);
|
||||
ui_ctx_menu_close();
|
||||
RD_Cfg *window = rd_cfg_from_id(rd_regs()->window);
|
||||
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
|
||||
RD_WindowState *ws = rd_window_state_from_cfg(window);
|
||||
ws->menu_bar_focused = 0;
|
||||
}
|
||||
@@ -1310,14 +1308,14 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
//- rjf: dragging cfgs/entities/expressions? -> drop site
|
||||
//
|
||||
B32 drop_can_hit_lines = 0;
|
||||
RD_Cfg *drop_cfg = &rd_nil_cfg;
|
||||
CFG_Node *drop_cfg = &cfg_nil_node;
|
||||
CTRL_Entity *drop_thread = &ctrl_entity_nil;
|
||||
String8 drop_expr = {0};
|
||||
Vec4F32 drop_color = pop_color;
|
||||
UI_Key drop_site_key = ui_key_from_stringf(top_container_box->key, "drop_site");
|
||||
if(rd_drag_is_active())
|
||||
{
|
||||
RD_Cfg *cfg = rd_cfg_from_id(rd_state->drag_drop_regs->cfg);
|
||||
CFG_Node *cfg = cfg_node_from_id(rd_state->drag_drop_regs->cfg);
|
||||
if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg &&
|
||||
(str8_match(cfg->string, str8_lit("breakpoint"), 0) ||
|
||||
str8_match(cfg->string, str8_lit("watch_pin"), 0)))
|
||||
@@ -1490,7 +1488,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
D_Line *line = 0;
|
||||
for(D_LineNode *n = lines->first; n != 0; n = n->next)
|
||||
{
|
||||
if(di_key_match(&n->v.dbgi_key, &dbgi_key))
|
||||
if(di_key_match(n->v.dbgi_key, dbgi_key))
|
||||
{
|
||||
line = &n->v;
|
||||
break;
|
||||
@@ -1555,8 +1553,8 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
line_num += 1, line_idx += 1)
|
||||
{
|
||||
CTRL_EntityList line_ips = params->line_ips[line_idx];
|
||||
RD_CfgList line_bps = params->line_bps[line_idx];
|
||||
RD_CfgList line_pins = params->line_pins[line_idx];
|
||||
CFG_NodePtrList line_bps = params->line_bps[line_idx];
|
||||
CFG_NodePtrList line_pins = params->line_pins[line_idx];
|
||||
ui_set_next_hover_cursor(OS_Cursor_HandPoint);
|
||||
ui_set_next_background_color(v4f32(0, 0, 0, 0));
|
||||
UI_Box *line_margin_box = ui_build_box_from_stringf(UI_BoxFlag_Clickable*!!(params->flags & RD_CodeSliceFlag_Clickable)|UI_BoxFlag_DrawBackground|UI_BoxFlag_DrawActiveEffects, "line_margin_%I64x", line_num);
|
||||
@@ -1644,7 +1642,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
D_Line *line = 0;
|
||||
for(D_LineNode *n = lines->first; n != 0; n = n->next)
|
||||
{
|
||||
if(di_key_match(&n->v.dbgi_key, &dbgi_key))
|
||||
if(di_key_match(n->v.dbgi_key, dbgi_key))
|
||||
{
|
||||
line = &n->v;
|
||||
break;
|
||||
@@ -1685,9 +1683,9 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
}
|
||||
|
||||
//- rjf: build margin breakpoint ui
|
||||
for(RD_CfgNode *n = line_bps.first; n != 0; n = n->next)
|
||||
for(CFG_NodePtrNode *n = line_bps.first; n != 0; n = n->next)
|
||||
{
|
||||
RD_Cfg *bp = n->v;
|
||||
CFG_Node *bp = n->v;
|
||||
Vec4F32 bp_rgba = rd_color_from_cfg(bp);
|
||||
if(bp_rgba.w == 0)
|
||||
{
|
||||
@@ -1703,14 +1701,14 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
RD_BreakpointBoxDrawExtData *bp_draw = push_array(ui_build_arena(), RD_BreakpointBoxDrawExtData, 1);
|
||||
{
|
||||
RD_Regs *hover_regs = rd_get_hover_regs();
|
||||
B32 is_hovering = (rd_cfg_from_id(hover_regs->cfg) == bp && rd_state->hover_regs_slot == RD_RegSlot_Cfg);
|
||||
B32 is_hovering = (cfg_node_from_id(hover_regs->cfg) == bp && rd_state->hover_regs_slot == RD_RegSlot_Cfg);
|
||||
bp_draw->color = bp_rgba;
|
||||
bp_draw->alive_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "cfg_alive_t_%p", bp), 1.f, .rate = entity_alive_t_rate);
|
||||
bp_draw->hover_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "cfg_hover_t_%p", bp), (F32)!!is_hovering, .rate = entity_hover_t_rate);
|
||||
bp_draw->do_lines = do_bp_lines;
|
||||
bp_draw->do_glow = do_bp_glow;
|
||||
bp_draw->is_disabled = bp_is_disabled;
|
||||
bp_draw->is_conditioned = (rd_cfg_child_from_string(bp, str8_lit("condition"))->first->string.size != 0);
|
||||
bp_draw->is_conditioned = (cfg_node_child_from_string(bp, str8_lit("condition"))->first->string.size != 0);
|
||||
if(params->line_vaddrs[line_idx] == 0)
|
||||
{
|
||||
D_LineList *lines = ¶ms->line_infos[line_idx];
|
||||
@@ -1775,9 +1773,9 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
}
|
||||
|
||||
//- rjf: build margin watch pin ui
|
||||
for(RD_CfgNode *n = line_pins.first; n != 0; n = n->next)
|
||||
for(CFG_NodePtrNode *n = line_pins.first; n != 0; n = n->next)
|
||||
{
|
||||
RD_Cfg *pin = n->v;
|
||||
CFG_Node *pin = n->v;
|
||||
Vec4F32 color = rd_color_from_cfg(pin);
|
||||
if(color.w == 0)
|
||||
{
|
||||
@@ -1867,19 +1865,14 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
// rjf: line info on this line -> adjust bg color to visualize
|
||||
B32 has_line_info = 0;
|
||||
{
|
||||
U64 best_stamp = 0;
|
||||
S64 line_info_line_num = 0;
|
||||
F32 line_info_t = 0;
|
||||
D_LineList *lines = ¶ms->line_infos[line_idx];
|
||||
for(D_LineNode *n = lines->first; n != 0; n = n->next)
|
||||
{
|
||||
if(n->v.dbgi_key.min_timestamp >= best_stamp)
|
||||
{
|
||||
has_line_info = (n->v.pt.line == line_num || params->line_vaddrs[line_idx] != 0);
|
||||
line_info_line_num = n->v.pt.line;
|
||||
best_stamp = n->v.dbgi_key.min_timestamp;
|
||||
line_info_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "dbgi_alive_t_%S", n->v.dbgi_key.path), 1.f);
|
||||
}
|
||||
has_line_info = (has_line_info || n->v.pt.line == line_num || params->line_vaddrs[line_idx] != 0);
|
||||
line_info_line_num = n->v.pt.line;
|
||||
line_info_t = ui_anim(ui_key_from_stringf(ui_key_zero(), "dbgi_alive_t_%I64x_%I64x", n->v.dbgi_key.u64[0], n->v.dbgi_key.u64[1]), 1.f);
|
||||
}
|
||||
if(has_line_info)
|
||||
{
|
||||
@@ -2019,13 +2012,12 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
//
|
||||
UI_Focus(UI_FocusKind_Off)
|
||||
{
|
||||
DI_Scope *scope = di_scope_open();
|
||||
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)
|
||||
{
|
||||
RD_CfgList immediate_pins = {0};
|
||||
CFG_NodePtrList immediate_pins = {0};
|
||||
String8 line_text = params->line_text[line_idx];
|
||||
for(U64 off = 0, next_off = line_text.size;
|
||||
off < line_text.size;
|
||||
@@ -2094,29 +2086,29 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
// rjf: build immediate pin for this markup
|
||||
if(expr_string.size != 0)
|
||||
{
|
||||
RD_Cfg *immediate_root = rd_immediate_cfg_from_keyf("markup_pin_%I64x_%I64x", line_num, off);
|
||||
RD_Cfg *pin = rd_cfg_child_from_string_or_alloc(immediate_root, str8_lit("watch_pin"));
|
||||
RD_Cfg *expr = rd_cfg_child_from_string_or_alloc(pin, str8_lit("expression"));
|
||||
rd_cfg_new_replace(expr, expr_string);
|
||||
rd_cfg_list_push(scratch.arena, &immediate_pins, pin);
|
||||
CFG_Node *immediate_root = rd_immediate_cfg_from_keyf("markup_pin_%I64x_%I64x", line_num, off);
|
||||
CFG_Node *pin = cfg_node_child_from_string_or_alloc(rd_state->cfg, immediate_root, str8_lit("watch_pin"));
|
||||
CFG_Node *expr = cfg_node_child_from_string_or_alloc(rd_state->cfg, pin, str8_lit("expression"));
|
||||
cfg_node_new_replace(rd_state->cfg, expr, expr_string);
|
||||
cfg_node_ptr_list_push(scratch.arena, &immediate_pins, pin);
|
||||
}
|
||||
}
|
||||
RD_CfgList pin_lists[] =
|
||||
CFG_NodePtrList pin_lists[] =
|
||||
{
|
||||
params->line_pins[line_idx],
|
||||
immediate_pins,
|
||||
};
|
||||
E_ParentKey(e_key_zero()) for EachElement(list_idx, pin_lists)
|
||||
{
|
||||
RD_CfgList pins = pin_lists[list_idx];
|
||||
CFG_NodePtrList pins = pin_lists[list_idx];
|
||||
if(pins.count != 0) UI_Parent(line_extras_boxes[line_idx])
|
||||
RD_Font(RD_FontSlot_Code)
|
||||
UI_FontSize(params->font_size)
|
||||
UI_PrefHeight(ui_px(params->line_height_px, 1.f))
|
||||
{
|
||||
for(RD_CfgNode *n = pins.first; n != 0; n = n->next)
|
||||
for(CFG_NodePtrNode *n = pins.first; n != 0; n = n->next)
|
||||
{
|
||||
RD_Cfg *pin = n->v;
|
||||
CFG_Node *pin = n->v;
|
||||
String8 pin_expr = rd_expr_from_cfg(pin);
|
||||
E_Eval eval = e_eval_from_string(pin_expr);
|
||||
String8 eval_string = {0};
|
||||
@@ -2152,7 +2144,6 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
}
|
||||
}
|
||||
}
|
||||
di_scope_close(scope);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@@ -2252,7 +2243,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
.cursor = line_vaddr == 0 ? txt_pt(line_num, 1) : txt_pt(0, 0),
|
||||
.vaddr = line_vaddr);
|
||||
}
|
||||
if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && drop_cfg != &rd_nil_cfg)
|
||||
if(rd_state->drag_drop_regs_slot == RD_RegSlot_Cfg && drop_cfg != &cfg_nil_node)
|
||||
{
|
||||
S64 line_num = mouse_pt.line;
|
||||
U64 line_idx = line_num - params->line_num_range.min;
|
||||
@@ -2275,7 +2266,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
D_LineList *lines = ¶ms->line_infos[line_idx];
|
||||
for(D_LineNode *n = lines->first; n != 0; n = n->next)
|
||||
{
|
||||
CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, &n->v.dbgi_key);
|
||||
CTRL_EntityList modules = ctrl_modules_from_dbgi_key(scratch.arena, &d_state->ctrl_entity_store->ctx, n->v.dbgi_key);
|
||||
CTRL_Entity *module = ctrl_module_from_thread_candidates(&d_state->ctrl_entity_store->ctx, thread, &modules);
|
||||
if(module != &ctrl_entity_nil)
|
||||
{
|
||||
@@ -2574,7 +2565,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
{
|
||||
E_Eval eval = e_eval_from_string(mouse_expr);
|
||||
B32 eval_implicit_hover = (eval.irtree.mode != E_Mode_Null &&
|
||||
eval.space.kind == RD_EvalSpaceKind_CtrlEntity);
|
||||
eval.space.kind == CTRL_EvalSpaceKind_Entity);
|
||||
if(eval.msgs.max_kind == E_MsgKind_Null && (eval_implicit_hover || mouse_expr_is_explicit))
|
||||
{
|
||||
U64 line_vaddr = 0;
|
||||
@@ -2805,7 +2796,7 @@ rd_code_slice(RD_CodeSliceParams *params, TxtPt *cursor, TxtPt *mark, S64 *prefe
|
||||
for(D_LineNode *n = lines->first; n != 0; n = n->next)
|
||||
{
|
||||
if((n->v.pt.line == line_num || params->line_vaddrs[line_idx] != 0) &&
|
||||
((di_key_match(&n->v.dbgi_key, &hover_regs->dbgi_key) &&
|
||||
((di_key_match(n->v.dbgi_key, hover_regs->dbgi_key) &&
|
||||
n->v.voff_range.min <= hover_voff_range.min && hover_voff_range.min < n->v.voff_range.max) ||
|
||||
(params->line_vaddrs[line_idx] == hover_regs->vaddr_range.min && hover_regs->vaddr_range.min != 0)))
|
||||
{
|
||||
@@ -3381,8 +3372,10 @@ rd_cell(RD_CellParams *params, String8 string)
|
||||
B32 build_bindings = !!(params->flags & RD_CellFlag_Bindings) && !is_focus_active;
|
||||
B32 build_lhs_name_desc = (params->meta_fstrs.node_count != 0 || params->description.size != 0);
|
||||
B32 build_line_edit = (params->pre_edit_value.size != 0 || params->value_fstrs.node_count != 0);
|
||||
B32 build_note = (params->note_fstrs.node_count != 0 && !is_focus_active);
|
||||
DR_FStrList lhs_name_fstrs = params->meta_fstrs;
|
||||
DR_FStrList value_name_fstrs = params->value_fstrs;
|
||||
DR_FStrList note_fstrs = params->note_fstrs;
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: determine autocompletion string
|
||||
@@ -3810,6 +3803,15 @@ rd_cell(RD_CellParams *params, String8 string)
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: build notes
|
||||
//
|
||||
if(build_note) UI_Parent(box) UI_PrefWidth(params->note_width)
|
||||
{
|
||||
UI_Box *note_box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero());
|
||||
ui_box_equip_display_fstrs(note_box, ¬e_fstrs);
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- rjf: do non-textual edits (delete, copy, cut)
|
||||
//
|
||||
@@ -3915,7 +3917,7 @@ rd_cell(RD_CellParams *params, String8 string)
|
||||
// rjf: any valid *additive* op & autocomplete hint? -> perform autocomplete first, then re-compute op
|
||||
if(!(evt->flags & UI_EventFlag_Delete) && autocomplete_hint_string.size != 0)
|
||||
{
|
||||
RD_Cfg *window = rd_cfg_from_id(rd_regs()->window);
|
||||
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
|
||||
RD_WindowState *ws = rd_window_state_from_cfg(window);
|
||||
RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info;
|
||||
String8 new_string = ui_push_string_replace_range(scratch.arena, edit_string, r1s64(autocomp_cursor_info->replaced_range.min+1, autocomp_cursor_info->replaced_range.max+1), autocomplete_hint_string);
|
||||
@@ -4013,7 +4015,7 @@ rd_cell(RD_CellParams *params, String8 string)
|
||||
}
|
||||
if(autocomplete_hint_string.size != 0)
|
||||
{
|
||||
RD_Cfg *window = rd_cfg_from_id(rd_regs()->window);
|
||||
CFG_Node *window = cfg_node_from_id(rd_regs()->window);
|
||||
RD_WindowState *ws = rd_window_state_from_cfg(window);
|
||||
RD_AutocompCursorInfo *autocomp_cursor_info = &ws->autocomp_cursor_info;
|
||||
String8 autocomplete_append_string = str8_skip(autocomplete_hint_string, params->cursor->column-1 - autocomp_cursor_info->replaced_range.min);
|
||||
|
||||
@@ -51,6 +51,8 @@ struct RD_CellParams
|
||||
String8 pre_edit_value;
|
||||
DR_FStrList meta_fstrs;
|
||||
DR_FStrList value_fstrs;
|
||||
DR_FStrList note_fstrs;
|
||||
UI_Size note_width;
|
||||
String8 search_needle;
|
||||
String8 description;
|
||||
|
||||
@@ -99,9 +101,9 @@ struct RD_CodeSliceParams
|
||||
String8 *line_text;
|
||||
Rng1U64 *line_ranges;
|
||||
TXT_TokenArray *line_tokens;
|
||||
RD_CfgList *line_bps;
|
||||
CFG_NodePtrList *line_bps;
|
||||
CTRL_EntityList *line_ips;
|
||||
RD_CfgList *line_pins;
|
||||
CFG_NodePtrList *line_pins;
|
||||
U64 *line_vaddrs;
|
||||
D_LineList *line_infos;
|
||||
DI_KeyList relevant_dbgi_keys;
|
||||
@@ -137,7 +139,7 @@ struct RD_CodeSliceSignal
|
||||
////////////////////////////////
|
||||
//~ rjf: UI Widgets: Fancy Title Strings
|
||||
|
||||
internal DR_FStrList rd_title_fstrs_from_cfg(Arena *arena, RD_Cfg *cfg, B32 include_extras);
|
||||
internal DR_FStrList rd_title_fstrs_from_cfg(Arena *arena, CFG_Node *cfg, B32 include_extras);
|
||||
internal DR_FStrList rd_title_fstrs_from_ctrl_entity(Arena *arena, CTRL_Entity *entity, B32 include_extras);
|
||||
internal DR_FStrList rd_title_fstrs_from_code_name(Arena *arena, String8 code_name);
|
||||
internal DR_FStrList rd_title_fstrs_from_file_path(Arena *arena, String8 file_path);
|
||||
|
||||
+70
-11
@@ -51,6 +51,18 @@
|
||||
"#endif";
|
||||
"";
|
||||
"////////////////////////////////////////////////////////////////";
|
||||
"//~ Checksum Types";
|
||||
"";
|
||||
"typedef union RDI_MD5 RDI_MD5;";
|
||||
"union RDI_MD5 {RDI_U8 u8[16]; RDI_U64 u64[2];};";
|
||||
"";
|
||||
"typedef union RDI_SHA1 RDI_SHA1;";
|
||||
"union RDI_SHA1 {RDI_U8 u8[20];};";
|
||||
"";
|
||||
"typedef union RDI_SHA256 RDI_SHA256;";
|
||||
"union RDI_SHA256 {RDI_U8 u8[32]; RDI_U64 u64[4];};";
|
||||
"";
|
||||
"////////////////////////////////////////////////////////////////";
|
||||
"//~ Overridable Enabling/Disabling Of Table Index Typechecking";
|
||||
"";
|
||||
"#if !defined(RDI_DISABLE_TABLE_INDEX_TYPECHECKING)";
|
||||
@@ -62,7 +74,7 @@
|
||||
"";
|
||||
"// \"raddbg\\0\\0\"";
|
||||
"#define RDI_MAGIC_CONSTANT 0x0000676264646172";
|
||||
"#define RDI_ENCODING_VERSION 13";
|
||||
"#define RDI_ENCODING_VERSION 16";
|
||||
"";
|
||||
"////////////////////////////////////////////////////////////////";
|
||||
"//~ Format Types & Functions";
|
||||
@@ -156,10 +168,14 @@ RDI_SectionTable:
|
||||
{LocationData location_data RDI_U8 0x0021 U32 ""}
|
||||
{ConstantValueData constant_value_data RDI_U8 0x0022 U32 ""}
|
||||
{ConstantValueTable constant_value_table RDI_U32 0x0023 U32 ""}
|
||||
{NameMaps name_maps RDI_NameMap 0x0024 U32 ""}
|
||||
{NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0025 U32 ""}
|
||||
{NameMapNodes name_map_nodes RDI_NameMapNode 0x0026 U32 ""}
|
||||
{COUNT count RDI_U8 0x0027 - ""}
|
||||
{MD5Checksums md5_checksums RDI_MD5 0x0024 U32 ""}
|
||||
{SHA1Checksums sha1_checksums RDI_SHA1 0x0025 U32 ""}
|
||||
{SHA256Checksums sha256_checksums RDI_SHA256 0x0026 U32 ""}
|
||||
{Timestamps timestamps RDI_U64 0x0027 U32 ""}
|
||||
{NameMaps name_maps RDI_NameMap 0x0028 U32 ""}
|
||||
{NameMapBuckets name_map_buckets RDI_NameMapBucket 0x0029 U32 ""}
|
||||
{NameMapNodes name_map_nodes RDI_NameMapNode 0x002A U32 ""}
|
||||
{COUNT count RDI_U8 0x002B - ""}
|
||||
}
|
||||
|
||||
@table(name value)
|
||||
@@ -534,6 +550,30 @@ RDI_BinarySectionMemberTable:
|
||||
@expand(RDI_BinarySectionMemberTable a) `$(a.type) $(a.name)`
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Checksum Type Tables
|
||||
|
||||
@table(name value section)
|
||||
RDI_ChecksumKindTable:
|
||||
{
|
||||
{NULL 0 NULL }
|
||||
{MD5 1 MD5Checksums }
|
||||
{SHA1 2 SHA1Checksums }
|
||||
{SHA256 3 SHA256Checksums}
|
||||
{Timestamp 4 Timestamps }
|
||||
{COUNT 5 NULL }
|
||||
}
|
||||
|
||||
@enum(RDI_U32) RDI_ChecksumKind:
|
||||
{
|
||||
@expand(RDI_ChecksumKindTable a) `$(a.name .. =>10) = $(a.value)`
|
||||
}
|
||||
|
||||
@xlist RDI_ChecksumKind_XList:
|
||||
{
|
||||
@expand(RDI_ChecksumKindTable a) `$(a.name), $(a.section)`;
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: File Path Tree Info Type Tables
|
||||
|
||||
@@ -550,13 +590,15 @@ RDI_FilePathNodeMemberTable:
|
||||
@table(name type desc)
|
||||
RDI_SourceFileMemberTable:
|
||||
{
|
||||
{file_path_node_idx RDI_U32 ""}
|
||||
{normal_full_path_string_idx RDI_U32 ""}
|
||||
{file_path_node_idx RDI_U32 ""}
|
||||
{normal_full_path_string_idx RDI_U32 ""}
|
||||
// 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))
|
||||
{source_line_map_idx RDI_U32 ""}
|
||||
{source_line_map_idx RDI_U32 ""}
|
||||
{checksum_kind RDI_ChecksumKind ""}
|
||||
{checksum_idx RDI_U32 ""}
|
||||
}
|
||||
|
||||
@xlist RDI_FilePathNode_XList:
|
||||
@@ -1281,8 +1323,8 @@ RDI_EvalOpTable:
|
||||
{Mul 22 1 2 1}
|
||||
{Div 23 1 2 1}
|
||||
{Mod 24 1 2 1}
|
||||
{LShift 25 1 2 1}
|
||||
{RShift 26 1 2 1}
|
||||
{LShift 25 2 2 1}
|
||||
{RShift 26 2 2 1}
|
||||
{BitAnd 27 1 2 1}
|
||||
{BitOr 28 1 2 1}
|
||||
{BitXor 29 1 2 1}
|
||||
@@ -1307,7 +1349,8 @@ RDI_EvalOpTable:
|
||||
{CallSiteValue 48 4 0 0}
|
||||
{PartialValue 49 4 0 0}
|
||||
{PartialValueBit 50 8 0 0}
|
||||
{COUNT 51 0 0 0}
|
||||
{Swap 51 0 2 2} // swaps the top two entries on the stack
|
||||
{COUNT 52 0 0 0}
|
||||
}
|
||||
|
||||
// NOTE(rjf): "ck" -> "conversion kind, when converted to type group", used in square matrix form
|
||||
@@ -1608,3 +1651,19 @@ rdi_explanation_string_from_eval_conversion_kind(RDI_EvalConversionKind kind, RD
|
||||
return rdi_eval_conversion_kind_message_string_table[kind].str;
|
||||
}
|
||||
```
|
||||
|
||||
@gen(functions) @c_file
|
||||
{
|
||||
`RDI_PROC RDI_SectionKind`;
|
||||
`rdi_section_kind_from_checksum_kind(RDI_ChecksumKind kind)`;
|
||||
`{`;
|
||||
`RDI_SectionKind result = 0;`;
|
||||
`switch(kind)`;
|
||||
`{`;
|
||||
`default:{}break;`;
|
||||
@expand(RDI_ChecksumKindTable a) `case RDI_ChecksumKind_$(a.name):{result = RDI_SectionKind_$(a.section);}break;`,
|
||||
`}`;
|
||||
`return result;`;
|
||||
`}`;
|
||||
``;
|
||||
}
|
||||
|
||||
+27
-1
@@ -671,13 +671,39 @@ lane_sync(); if(flags & RDI_DumpSubsetFlag_##name) ProfScope(#name)
|
||||
{
|
||||
U64 count = 0;
|
||||
RDI_SourceFile *v = rdi_table_from_name(rdi, SourceFiles, &count);
|
||||
U64 checksums_count[RDI_ChecksumKind_COUNT] = {0};
|
||||
RDI_U8 *checksums_data[RDI_ChecksumKind_COUNT] = {0};
|
||||
RDI_U64 checksums_element_sizes[RDI_ChecksumKind_COUNT] = {0};
|
||||
for EachEnumVal(RDI_ChecksumKind, k)
|
||||
{
|
||||
RDI_SectionKind section_kind = rdi_section_kind_from_checksum_kind(k);
|
||||
checksums_data[k] = rdi_section_raw_table_from_kind(rdi, section_kind, &checksums_count[k]);
|
||||
checksums_element_sizes[k] = rdi_section_element_size_table[section_kind];
|
||||
}
|
||||
Rng1U64 range = lane_range(count);
|
||||
for EachInRange(idx, range)
|
||||
{
|
||||
RDI_SourceFile *source_file = &v[idx];
|
||||
dumpf("\n { file_path_node_idx: %4u, source_line_map: %4u, path: %-192S } // source_file[%I64u]",
|
||||
RDI_ChecksumKind checksum_kind = source_file->checksum_kind;
|
||||
RDI_U32 checksum_idx = source_file->checksum_idx;
|
||||
String8 checksum_kind_name = {0};
|
||||
switch(checksum_kind)
|
||||
{
|
||||
default:{checksum_kind_name = str8_lit("Null");}break;
|
||||
#define X(name, s) case RDI_ChecksumKind_##name:{checksum_kind_name = str8_lit(#name);}break;
|
||||
RDI_ChecksumKind_XList
|
||||
#undef X
|
||||
}
|
||||
String8 checksum_value = str8(checksums_data[checksum_kind] + checksums_element_sizes[checksum_kind]*checksum_idx, checksums_element_sizes[checksum_kind]);
|
||||
String8List checksum_vals = numeric_str8_list_from_data(arena, 16, checksum_value, 1);
|
||||
StringJoin join = {0};
|
||||
join.sep = str8_lit(", ");
|
||||
String8 checksum_val_string = str8_list_join(arena, &checksum_vals, &join);
|
||||
dumpf("\n { file_path_node_idx: %4u, source_line_map: %4u, checksum_kind: %10S, checksum_value: %192S, path: %-192S } // source_file[%I64u]",
|
||||
source_file->file_path_node_idx,
|
||||
source_file->source_line_map_idx,
|
||||
checksum_kind_name,
|
||||
checksum_val_string,
|
||||
push_str8f(arena, "'%S'", str8_from_rdi_string_idx(rdi, source_file->normal_full_path_string_idx)),
|
||||
idx);
|
||||
}
|
||||
|
||||
+1703
-1178
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,48 @@ typedef struct D2R_CompUnitContribMap
|
||||
RDIM_Rng1U64ChunkList *voff_range_arr;
|
||||
} D2R_CompUnitContribMap;
|
||||
|
||||
#define D2R_ValueType_IsSigned(x) ((x) == D2R_ValueType_S8 || (x) == D2R_ValueType_S16 || (x) == D2R_ValueType_S32 || (x) == D2R_ValueType_S64 || (x) == D2R_ValueType_S128 || (x) == D2R_ValueType_S256 || (x) == D2R_ValueType_S512)
|
||||
#define D2R_ValueType_IsUnsigned(x) ((x) == D2R_ValueType_U8 || (x) == D2R_ValueType_U16 || (x) == D2R_ValueType_U32 || (x) == D2R_ValueType_U64 || (x) == D2R_ValueType_U128 || (x) == D2R_ValueType_U256 || (x) == D2R_ValueType_U512)
|
||||
#define D2R_ValueType_IsFloat(x) ((x) == D2R_ValueType_F32 || (x) == D2R_ValueType_F64)
|
||||
#define D2R_ValueType_IsInt(x) (D2R_ValueType_IsSigned(x) || D2R_ValueType_IsUnsigned(x) || (x) == D2R_ValueType_Address)
|
||||
typedef enum D2R_ValueType
|
||||
{
|
||||
D2R_ValueType_Generic,
|
||||
D2R_ValueType_U8,
|
||||
D2R_ValueType_U16,
|
||||
D2R_ValueType_U32,
|
||||
D2R_ValueType_U64,
|
||||
D2R_ValueType_U128,
|
||||
D2R_ValueType_U256,
|
||||
D2R_ValueType_U512,
|
||||
D2R_ValueType_S8,
|
||||
D2R_ValueType_S16,
|
||||
D2R_ValueType_S32,
|
||||
D2R_ValueType_S64,
|
||||
D2R_ValueType_S128,
|
||||
D2R_ValueType_S256,
|
||||
D2R_ValueType_S512,
|
||||
D2R_ValueType_F32,
|
||||
D2R_ValueType_F64,
|
||||
D2R_ValueType_Address,
|
||||
D2R_ValueType_ImplicitValue,
|
||||
D2R_ValueType_Bool = D2R_ValueType_S8,
|
||||
} D2R_ValueType;
|
||||
|
||||
typedef struct D2R_ValueTypeNode
|
||||
{
|
||||
D2R_ValueType type;
|
||||
|
||||
struct D2R_ValueTypeNode *next;
|
||||
} D2R_ValueTypeNode;
|
||||
|
||||
typedef struct D2R_ValueTypeStack
|
||||
{
|
||||
U64 count;
|
||||
D2R_ValueTypeNode *top;
|
||||
D2R_ValueTypeNode *free_list;
|
||||
} D2R_ValueTypeStack;
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Enum Conversion Helpers
|
||||
|
||||
@@ -66,10 +108,31 @@ internal RDI_TypeKind d2r_unsigned_type_kind_from_size(U64 byte_size);
|
||||
internal RDI_TypeKind d2r_signed_type_kind_from_size(U64 byte_size);
|
||||
internal RDI_EvalTypeGroup d2r_type_group_from_type_kind(RDI_TypeKind x);
|
||||
|
||||
////////////////////////////////
|
||||
//~ RDIM Bytecode Helpers
|
||||
|
||||
internal B32 rdim_is_eval_bytecode_static(RDIM_EvalBytecode bc);
|
||||
internal U64 rdim_virt_off_from_eval_bytecode(RDIM_EvalBytecode bc, U64 image_base);
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Bytecode Conversion Helpers
|
||||
|
||||
internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, B32 *is_addr_out);
|
||||
internal D2R_ValueTypeNode * d2r_value_type_stack_push(Arena *arena, D2R_ValueTypeStack *stack, D2R_ValueType type);
|
||||
internal D2R_ValueType d2r_value_type_stack_pop(D2R_ValueTypeStack *stack);
|
||||
internal D2R_ValueType d2r_value_type_stack_peek(D2R_ValueTypeStack *stack);
|
||||
|
||||
internal D2R_ValueType d2r_unsigned_value_type_from_bit_size(U64 bit_size);
|
||||
internal D2R_ValueType d2r_signed_value_type_from_bit_size(U64 bit_size);
|
||||
internal D2R_ValueType d2r_float_type_from_bit_size(U64 bit_size);
|
||||
internal RDI_EvalTypeGroup d2r_value_type_to_rdi(D2R_ValueType v);
|
||||
internal U64 d2r_size_from_value_type(U64 addr_size, D2R_ValueType value_type);
|
||||
internal D2R_ValueType d2r_pick_common_value_type(D2R_ValueType lhs, D2R_ValueType rhs);
|
||||
|
||||
internal D2R_ValueType d2r_apply_usual_arithmetic_conversions(Arena *arena, D2R_ValueType lhs, D2R_ValueType rhs, RDIM_EvalBytecode *bc);
|
||||
internal void d2r_push_arithmetic_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
|
||||
internal void d2r_push_relational_op(Arena *arena, D2R_ValueTypeStack *stack, RDIM_EvalBytecode *bc, RDI_EvalOp op);
|
||||
|
||||
internal RDIM_EvalBytecode d2r_bytecode_from_expression(Arena *arena, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, String8 expr, DW_CompUnit *cu, D2R_ValueType *result_type_out);
|
||||
internal RDIM_Location * d2r_transpile_expression(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, U64 image_base, U64 address_size, Arch arch, DW_ListUnit *addr_lu, DW_CompUnit *cu, String8 expr);
|
||||
internal RDIM_Location * d2r_location_from_attrib(Arena *arena, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
||||
internal RDIM_LocationCaseList d2r_locset_from_attrib(Arena *arena, RDIM_ScopeChunkList *scopes, RDIM_Scope *curr_scope, RDIM_LocationChunkList *locations, DW_Input *input, DW_CompUnit *cu, U64 image_base, Arch arch, DW_Tag tag, DW_AttribKind kind);
|
||||
|
||||
+488
-336
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user