Merge tag 'v0.9.23-alpha'

This commit is contained in:
2025-10-17 11:42:36 -04:00
120 changed files with 15076 additions and 13038 deletions
+96 -7
View File
@@ -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.
+24 -30
View File
@@ -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.
+11 -9
View File
@@ -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
View File
@@ -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]
+27 -14
View File
@@ -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);
+8 -2
View File
@@ -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
-286
View File
@@ -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(&params->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(&params_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, &params_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);
}
}
-162
View File
@@ -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
+1 -1
View File
@@ -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)
+6
View File
@@ -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)
{
+32
View File
@@ -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);
////////////////////////////////
+5 -6
View File
@@ -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
}
+50
View File
@@ -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;
}
+48
View File
@@ -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
+1
View File
@@ -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"
+1
View File
@@ -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"
+9 -2
View File
@@ -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
+2 -1
View File
@@ -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);
+2 -2
View File
@@ -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;
}
+24 -12
View File
@@ -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;
+10 -6
View File
@@ -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;
+111
View File
@@ -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;
}
+59
View File
@@ -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
+896
View File
@@ -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;
}
+233
View File
@@ -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
+8
View File
@@ -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
+13
View File
@@ -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
+217
View File
@@ -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;
}
+67
View File
@@ -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
View File
@@ -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)
{
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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, &params_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
+18 -9
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+242 -366
View File
@@ -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
-281
View File
@@ -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
+1 -1
View File
@@ -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
+4 -2
View File
@@ -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
View File
@@ -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, &params);
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, &params.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
View File
@@ -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);
+158
View File
@@ -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
View File
@@ -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
View File
@@ -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 = &section_table[i];
String8 name = coff_name_from_section_header(string_table, header);
for EachIndex(idx, section_count)
{
COFF_SectionHeader *header = &section_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;
}
+1 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+20 -19
View File
@@ -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
View File
@@ -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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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, &reg);
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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+59 -190
View File
@@ -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
+281
View File
@@ -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;
}
+81
View File
@@ -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
+4 -5
View File
@@ -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
View File
@@ -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
-3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
//
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
-1
View File
@@ -7,5 +7,4 @@
#include "base_arrays.c"
#include "base_bit_array.c"
#include "base_crc32.c"
#include "base_md5.c"
-1
View File
@@ -10,5 +10,4 @@
#include "base_blake3.h"
#include "base_bit_array.h"
#include "base_crc32.h"
#include "base_md5.h"
-12
View File
@@ -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;
}
-12
View File
@@ -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
View File
@@ -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);
}
-9
View File
@@ -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
+5 -6
View File
@@ -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;
}
+36
View File
@@ -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;
+65 -55
View File
@@ -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;
+20 -4
View File
@@ -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);
}
}
////////////////////////////////
+2 -1
View File
@@ -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
View File
@@ -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;
+2 -2
View File
@@ -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
+9 -9
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+35 -310
View File
@@ -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
View File
@@ -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, &params, 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;
}
+20 -20
View File
@@ -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));
}
}
}
+1 -1
View File
@@ -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
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -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
View File
@@ -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, &params, 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, &params, 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, &params, str8_lit(" "));
dr_fstrs_push_new(arena, &result, &params, 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, &params, 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 = &params->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 = &params->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 = &params->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, &note_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);
+5 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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);
}
File diff suppressed because it is too large Load Diff
+64 -1
View File
@@ -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);
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