Author SHA1 Message Date
Ryan Fleury d2d72bd7ab ctrl: eliminate possibility of threads getting stuck at spoof address at the event-pump layer - if we report other events first, the step is already cancelled anyways 2024-01-17 20:58:55 -08:00
Ryan Fleury 268ca9ab53 trap net building & stepping algorithm overview 2024-01-17 19:52:36 -08:00
Ryan Fleury dea5e88906 also look for wmainCRTStartup 2024-01-17 17:07:16 -08:00
Ryan Fleury 25c31b0d77 look for mainCRTStartup as one additional possibility of a default entry point 2024-01-17 17:01:25 -08:00
Ryan Fleury ea2066063a do the same for omit/only 2024-01-17 16:34:02 -08:00
Ryan Fleury bdecb6d522 disable hook-based list view rule, since it is currently unimplemented and visualization engine hooks need to mature before it is formally implemented in them 2024-01-17 16:31:26 -08:00
Tony LandRyan Fleury 739d0977b6 Disable hover if view is scrolling
Also set the first frame index to current index so that the hover popup
doesn't instantly appear once the scroll has ended.
2024-01-17 14:49:29 -08:00
Ryan Fleury 717572c202 non-virtual-inheritance case in mule_main 2024-01-17 13:56:54 -08:00
Ryan Fleury d3931fd3e2 base class -> derived class autocast in eval system; completion of first pass 2024-01-17 13:28:03 -08:00
Ryan Fleury a0a6fc0988 raddbg_from_pdb -> dont skip all members of struct simply because we currently do nothing with vfunctab 2024-01-17 10:36:23 -08:00
Ryan Fleury 7d8f0d478e checkpoint #2 of same... 2024-01-17 09:16:33 -08:00
Ryan Fleury d849b83acb checkpoint in implementing dynamic type resolution in the eval system, for taking a base-class-ptr & by-default patching in the appropriate debug-info-determined derived type 2024-01-16 17:33:17 -08:00
Ryan Fleury adbe42c907 add non-pure dynamic inheritance case 2024-01-16 17:12:51 -08:00
Martins MozeikoandRyan Fleury 99b2d9d6d0 minor d3d11 code improvements
1) automatically tries WARP driver if HW creation fails
2) HRESULT checks for swap chain creation or Present call (can fail if GPU driver crashes)
3) checks HRESULT of D3DCompile functions instead of using shader pointer as error condition
4) releases shader blob memory when not needed anymore
2024-01-16 17:09:07 -08:00
Ryan Fleury 5c179adb68 extend binary * voff -> symbol name lookup to include global variable vmap if scope vmap turns up short; extend address visualization rules to more ambitiously visualize what is being pointed at 2024-01-16 15:29:50 -08:00
Ryan Fleury de6c94ce8f set up nil udt in raddbg conversion - used for empty udt info for e.g. pure virtual structs 2024-01-16 15:05:06 -08:00
Ryan Fleury 743984c318 eliminate stray zero byte in output logs 2024-01-16 14:48:29 -08:00
Ryan Fleury a026ae41f1 import example of user-defined type node which does NOT have a udt entry - this is the cause of the virtual interface display bugs 2024-01-16 14:13:34 -08:00
Ryan Fleury 114dd96e50 data member offset sorting -> take into account base offset, when doing inheritance graph search; visualize inheritance chain for inherited members; use contextual base color in code labels, do not assume default code color implicitly 2024-01-16 14:01:37 -08:00
Ryan Fleury e2e1382508 use same type key -> members path in eval compiler as in eval visualization paths 2024-01-16 12:03:24 -08:00
Ryan Fleury 1c40afc067 import notes from email bugs; add non-virtual-but-still-multiple-inheritance example to mule_main; slightly increase loudness of exception/trap-caused stop ctrl events 2024-01-16 11:59:44 -08:00
Ryan Fleury 79677875c4 fix 64-bit address/value visualization in memory view bottom bar 2024-01-16 11:21:19 -08:00
Ryan Fleury c2e90225b9 type graph data member gathering -> follow single-inheritance base class members + sort members by offset 2024-01-16 11:12:08 -08:00
Ryan Fleury 057a6f3e8e eliminate duplicate binary dbgi parsing requests 2024-01-15 21:33:59 -08:00
Ryan Fleury a9ec1a05b1 notes 2024-01-15 20:30:11 -08:00
Ryan Fleury 2454d426ed eliminate dbgi layer evictor thread - exe and debug info eviction needs to be synchronous with control thread, to allow for HMH-style hotloading. this change moves all dbgi layer binary releasing to the caller thread of the refcount -> 0 dbgi_binary_close. 2024-01-15 20:13:49 -08:00
Ryan Fleury cf58137b0f todo notes 2024-01-15 15:38:12 -08:00
Ryan Fleury c40d0b3acc hot reloading mule 2024-01-15 13:04:25 -08:00
Ryan Fleury dd433c89ff fix ordering of local itypes within itype blocks in type name map; latter added itypes need to come *first* 2024-01-15 08:21:50 -08:00
Ryan Fleury d2ec1d6a3a interpret & visualize __fastfail events correctly 2024-01-14 21:36:39 -08:00
Ryan Fleury f736533933 further mule_main coverage 2024-01-14 20:28:15 -08:00
Ryan Fleury 8d82accc26 complete application of hash adjustment table in pdb -> raddbg converter 2024-01-14 18:12:45 -08:00
Ryan Fleury f61688fff5 checkpoint in implementing pdb hash adjustment table parsing & application 2024-01-14 17:20:35 -08:00
Ryan Fleury c88f715ac2 fix horizontal scroll in text containers causing repeated hidden animation 2024-01-14 14:53:45 -08:00
Ryan Fleury cac911fbf5 add info on converter to readme roadmap section 2024-01-14 11:34:18 -08:00
Ryan Fleury 1261aa55b0 include project short-to-medium-term roadmap in readme 2024-01-14 11:28:15 -08:00
Ryan Fleury 5fe3f56d33 line step into -> if call redirects to a function dispatch unconditional jump table, move stopper trap in trap net to unconditional jump destination, and skip the jump table entirely 2024-01-14 07:02:30 -08:00
Ryan Fleury 0c497abba6 only supply config defaults when doing user config application 2024-01-14 06:42:49 -08:00
31 changed files with 1126 additions and 257 deletions
+70
View File
@@ -99,6 +99,76 @@ raddbg.cpp
If everything worked correctly, there will be a `build` folder in the root If everything worked correctly, there will be a `build` folder in the root
level of the codebase, and it will contain a freshly-built `raddbg.exe`. level of the codebase, and it will contain a freshly-built `raddbg.exe`.
## Short-To-Medium-Term Roadmap
### The Initial Alpha Battle-Testing Phase
The first priority for the project is to ensure that the most crucial debugger
components are functioning extremely reliably for local, x64, Windows
debugging. This would include parts like debug info conversion, debug info
loading, process control, stepping, evaluation (correct usage of both location
info and type info), and a robust frontend which ensures the lower level parts
are usable.
We feel that the debugger has already come a long way in all of these respects,
but given the massive set of possible combinations of languages, build
settings, toolchains, used language features, and patterns of generated code,
there are still cases where the debugger has not been tested, and so there are
still issues. So, we feel that the top priority is eliminating these issues,
such that the debugging experience is rock solid.
Additionally, the debug info conversion process is not fast (nor wide) enough
to support extremely large projects. This is for two reasons: (a) the
PDB-to-RADDBG converter is an unoptimized reference implementation, and (b) the
debugger learns of new modules (and thus which PDBs to load) in a
serially-dependent way (this is necessarily the case for correct debugging
results). We expect that the conversion process' performance can be massively
improved, and also that some heuristics can be used to begin converting PDBs
to RADDBGs before the debugger knows those PDBs are needed, thus ensuring the
associated RADDBG files are ready instantaneously when the associated modules
are finally loaded by the debugger. Improving this situation is a major part of
this phase, as it will make the debugger much more usable for large projects.
### Local x64 Linux Debugging Phase
The next priority for the project is to take the rock solid x64 Windows
debugging experience, and port all of the relevant pieces to support local x64
Linux debugging also.
The debugger has been written to abstract over the parts that need to differ on
either Linux or Windows, and this is mainly going to be a task in building out
different backends for those abstraction layers.
The major parts of this phase are:
- Porting the `src/demon` layer to implement the Demon local process control
abstraction API.
- Porting the `src/unwind` layer to support x64 ELF unwinding (currently, there
is only an x64 PE unwinding implementation).
- Creating a DWARF-to-RADDBG converter (in the same way that we've built a PDB-
to-RADDBG converter). A partial implementation of this is in
`src/raddbg_convert/dwarf`.
- Porting the `src/render` layer to implement all of the rendering features the
frontend needs on a Linux-compatible API (the backend used on Windows is D3D11).
- Porting the `src/font_provider` layer to a Linux-compatible font
rasterization backend, like FreeType (the backend used on Windows is
DirectWrite).
- Porting the `src/os` layers to Linux. This includes core operating system
abstraction (virtual memory allocation, threading and synchronization
primitives, and so on), and graphical operating system abstraction (windows,
input events, and so on).
Once the above list is complete, and once every part is rock solid, the Windows
debugging experience we'll have worked diligently to create will also be
available natively on Linux machines.
### And Beyond!
There are several directions we might take after these two major phases,
like remote debugging, porting to different architectures, further improving
the debugger's features (like improving the visualization engine), and so on.
But for now, we're mostly focused on those first two phases.
## Top-Level Directory Descriptions ## Top-Level Directory Descriptions
- `data`: Small binary files which are used when building, either to embed - `data`: Small binary files which are used when building, either to embed
+6 -4
View File
@@ -43,11 +43,11 @@ if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=add
:: --- Compile/Link Line Definitions ------------------------------------------ :: --- Compile/Link Line Definitions ------------------------------------------
set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /MP set cl_common= /I..\src\ /I..\local\ /nologo /FC /Z7 /MP
set clang_common= -I..\src\ -I..\local\ -maes -mssse3 -msse4 -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf set clang_common= -I..\src\ -I..\local\ -maes -mssse3 -msse4 -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf
set cl_debug= call cl /Od /D_DEBUG %cl_common% set cl_debug= call cl /Od %cl_common%
set cl_release= call cl /O2 /DNDEBUG %cl_common% set cl_release= call cl /O2 /DNDEBUG %cl_common%
set clang_debug= call clang -g -O0 -D_DEBUG %clang_common% set clang_debug= call clang -g -O0 %clang_common%
set clang_release= call clang -g -O3 -DNDEBUG %clang_common% set clang_release= call clang -g -O3 -DNDEBUG %clang_common%
set cl_link= /link /natvis:"%~dp0\src\natvis\base.natvis" set cl_link= /link /INCREMENTAL:NO /natvis:"%~dp0\src\natvis\base.natvis"
set clang_link= -Xlinker /natvis:"%~dp0\src\natvis\base.natvis" set clang_link= -Xlinker /natvis:"%~dp0\src\natvis\base.natvis"
set cl_out= /out: set cl_out= /out:
set clang_out= -o set clang_out= -o
@@ -90,9 +90,11 @@ if "%raddbg_from_pdb%"=="1" %compile% ..\src\raddbg_convert\pdb\r
if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe if "%raddbg_from_dwarf%"=="1" %compile% ..\src\raddbg_convert\dwarf\raddbg_from_dwarf.c %compile_link% %out%raddbg_from_dwarf.exe
if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe if "%raddbg_dump%"=="1" %compile% ..\src\raddbg_dump\raddbg_dump.c %compile_link% %out%raddbg_dump.exe
if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe
if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe
if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe
if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %cl_release% /c ..\src\mule\mule_inline.cpp && %cl_release% /c ..\src\mule\mule_o2.cpp && %cl_debug% /EHsc ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %cl_release% /MT /c ..\src\mule\mule_inline.cpp && %cl_release% /MT /c ..\src\mule\mule_o2.cpp && %cl_debug% /MT /EHsc ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj
if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll
if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll
popd popd
:: --- Unset ------------------------------------------------------------------ :: --- Unset ------------------------------------------------------------------
+19
View File
@@ -54,6 +54,15 @@ commands =
.save_dirty_files = true, .save_dirty_files = true,
.cursor_at_end = false, .cursor_at_end = false,
}, },
.rjf_f2 =
{
.win = "build raddbg_from_pdb",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.rjf_f3 = .rjf_f3 =
{ {
.win = "pushd build && raddbg.exe && popd", .win = "pushd build && raddbg.exe && popd",
@@ -81,6 +90,15 @@ commands =
.save_dirty_files = true, .save_dirty_files = true,
.cursor_at_end = false, .cursor_at_end = false,
}, },
.build_raddbg_dump =
{
.win = "build raddbg_dump",
.linux = "",
.out = "*compilation*",
.footer_panel = true,
.save_dirty_files = true,
.cursor_at_end = false,
},
.build_mule_main = .build_mule_main =
{ {
.win = "build mule_main", .win = "build mule_main",
@@ -112,6 +130,7 @@ fkey_command_override =
.rjf = .rjf =
{ {
.F1 = "rjf_f1", .F1 = "rjf_f1",
.F2 = "rjf_f2",
.F3 = "rjf_f3", .F3 = "rjf_f3",
}, },
}; };
+1 -1
View File
@@ -22,7 +22,7 @@ arena_alloc__sized(U64 init_res, U64 init_cmt)
#if OS_WINDOWS #if OS_WINDOWS
cmt = res; cmt = res;
#else #else
cmt AlignPow2(init_cmt, page_size); cmt = AlignPow2(init_cmt, page_size);
#endif #endif
memory = os_reserve_large(res); memory = os_reserve_large(res);
+52 -42
View File
@@ -1366,6 +1366,7 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
//- rjf: loop -> try to get event, run, repeat //- rjf: loop -> try to get event, run, repeat
U64 spoof_old_ip_value = 0;
ProfScope("loop -> try to get event, run, repeat") for(B32 got_event = 0; got_event == 0;) ProfScope("loop -> try to get event, run, repeat") for(B32 got_event = 0; got_event == 0;)
{ {
//- rjf: get next event //- rjf: get next event
@@ -1437,7 +1438,6 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c
{ {
// rjf: prep spoof // rjf: prep spoof
B32 do_spoof = (spoof != 0 && run_ctrls->single_step_thread == 0); B32 do_spoof = (spoof != 0 && run_ctrls->single_step_thread == 0);
U64 spoof_old_ip_value = 0;
U64 size_of_spoof = 0; U64 size_of_spoof = 0;
if(do_spoof) ProfScope("prep spoof") if(do_spoof) ProfScope("prep spoof")
{ {
@@ -1487,6 +1487,18 @@ ctrl_thread__next_demon_event(Arena *arena, CTRL_Msg *msg, DEMON_RunCtrls *run_c
} }
} }
//- rjf: irrespective of what event came back, we should ALWAYS check the
// spoof's thread and see if it hit the spoof address, because we may have
// simply been sent other debug events first
if(spoof != 0)
{
U64 spoof_thread_rip = demon_read_ip(ctrl_demon_handle_from_ctrl(spoof->thread));
if(spoof_thread_rip == spoof->new_ip_value)
{
demon_write_ip(ctrl_demon_handle_from_ctrl(spoof->thread), spoof_old_ip_value);
}
}
//- rjf: push ctrl events associated with this demon event //- rjf: push ctrl events associated with this demon event
CTRL_EventList evts = {0}; CTRL_EventList evts = {0};
ProfScope("push ctrl events associated with this demon event") switch(event->kind) ProfScope("push ctrl events associated with this demon event") switch(event->kind)
@@ -1821,6 +1833,8 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
str8_lit("wmain"), str8_lit("wmain"),
str8_lit("WinMainCRTStartup"), str8_lit("WinMainCRTStartup"),
str8_lit("wWinMainCRTStartup"), str8_lit("wWinMainCRTStartup"),
str8_lit("mainCRTStartup"),
str8_lit("wmainCRTStartup"),
}; };
// rjf: find voff for one of the custom entry points attached to this msg // rjf: find voff for one of the custom entry points attached to this msg
@@ -2122,10 +2136,14 @@ ctrl_thread__run(CTRL_Msg *msg)
DEMON_Handle target_process = ctrl_demon_handle_from_ctrl(msg->parent); DEMON_Handle target_process = ctrl_demon_handle_from_ctrl(msg->parent);
U64 spoof_ip_vaddr = 911; U64 spoof_ip_vaddr = 911;
//////////////////////////////
//- rjf: gather processes //- rjf: gather processes
//
DEMON_HandleArray processes = demon_all_processes(scratch.arena); DEMON_HandleArray processes = demon_all_processes(scratch.arena);
//////////////////////////////
//- rjf: gather all initial breakpoints //- rjf: gather all initial breakpoints
//
DEMON_TrapChunkList user_traps = {0}; DEMON_TrapChunkList user_traps = {0};
{ {
// rjf: resolve module-dependent user bps // rjf: resolve module-dependent user bps
@@ -2147,6 +2165,7 @@ ctrl_thread__run(CTRL_Msg *msg)
} }
} }
//////////////////////////////
//- rjf: single step "stuck threads" //- rjf: single step "stuck threads"
// //
// "Stuck threads" are threads that are already on a User BP and would hit // "Stuck threads" are threads that are already on a User BP and would hit
@@ -2251,7 +2270,9 @@ ctrl_thread__run(CTRL_Msg *msg)
} }
} }
//////////////////////////////
//- rjf: resolve trap net //- rjf: resolve trap net
//
DEMON_TrapChunkList trap_net_traps = {0}; DEMON_TrapChunkList trap_net_traps = {0};
for(CTRL_TrapNode *node = msg->traps.first; for(CTRL_TrapNode *node = msg->traps.first;
node != 0; node != 0;
@@ -2261,14 +2282,18 @@ ctrl_thread__run(CTRL_Msg *msg)
demon_trap_chunk_list_push(scratch.arena, &trap_net_traps, 256, &trap); demon_trap_chunk_list_push(scratch.arena, &trap_net_traps, 256, &trap);
} }
//////////////////////////////
//- rjf: join user breakpoints and trap net traps //- rjf: join user breakpoints and trap net traps
//
DEMON_TrapChunkList joined_traps = {0}; DEMON_TrapChunkList joined_traps = {0};
{ {
demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &user_traps); demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &user_traps);
demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &trap_net_traps); demon_trap_chunk_list_concat_shallow_copy(scratch.arena, &joined_traps, &trap_net_traps);
} }
//////////////////////////////
//- rjf: record start //- rjf: record start
//
if(stop_event == 0) if(stop_event == 0)
{ {
CTRL_EventList evts = {0}; CTRL_EventList evts = {0};
@@ -2277,31 +2302,37 @@ ctrl_thread__run(CTRL_Msg *msg)
ctrl_c2u_push_events(&evts); ctrl_c2u_push_events(&evts);
} }
//////////////////////////////
//- rjf: run loop //- rjf: run loop
//
if(stop_event == 0) if(stop_event == 0)
{ {
U64 sp_check_value = demon_read_sp(target_thread); U64 sp_check_value = demon_read_sp(target_thread);
B32 spoof_mode = 0; B32 spoof_mode = 0;
CTRL_Spoof spoof = {0}; CTRL_Spoof spoof = {0};
U64 spoof_1_return_ip = 0;
for(;;) for(;;)
{ {
//////////////////////////
//- rjf: choose low level traps //- rjf: choose low level traps
//
DEMON_TrapChunkList *trap_list = &joined_traps; DEMON_TrapChunkList *trap_list = &joined_traps;
if(spoof_mode) if(spoof_mode)
{ {
trap_list = &user_traps; trap_list = &user_traps;
} }
//////////////////////////
//- rjf: choose spoof //- rjf: choose spoof
//
CTRL_Spoof *run_spoof = 0; CTRL_Spoof *run_spoof = 0;
if(spoof_mode) if(spoof_mode)
{ {
run_spoof = &spoof; run_spoof = &spoof;
} }
//////////////////////////
//- rjf: setup run controls //- rjf: setup run controls
//
DEMON_RunCtrls run_ctrls = {0}; DEMON_RunCtrls run_ctrls = {0};
run_ctrls.ignore_previous_exception = 1; run_ctrls.ignore_previous_exception = 1;
run_ctrls.run_entity_count = msg->freeze_state_threads.count; run_ctrls.run_entity_count = msg->freeze_state_threads.count;
@@ -2315,12 +2346,16 @@ ctrl_thread__run(CTRL_Msg *msg)
idx += 1; idx += 1;
} }
} }
run_ctrls.traps = *trap_list; run_ctrls.traps = *trap_list;
//- rjf: get an event //////////////////////////
//- rjf: get next event
//
DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, run_spoof); DEMON_Event *event = ctrl_thread__next_demon_event(scratch.arena, msg, &run_ctrls, run_spoof);
//////////////////////////
//- rjf: determine event handling //- rjf: determine event handling
//
B32 hard_stop = 0; B32 hard_stop = 0;
CTRL_EventCause hard_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind); CTRL_EventCause hard_stop_cause = ctrl_event_cause_from_demon_event_kind(event->kind);
B32 use_stepping_logic = 0; B32 use_stepping_logic = 0;
@@ -2354,7 +2389,9 @@ ctrl_thread__run(CTRL_Msg *msg)
}break; }break;
} }
//////////////////////////
//- rjf: unpack info about thread attached to event //- rjf: unpack info about thread attached to event
//
Architecture arch = demon_arch_from_object(event->thread); Architecture arch = demon_arch_from_object(event->thread);
U64 reg_size = regs_block_size_from_architecture(arch); U64 reg_size = regs_block_size_from_architecture(arch);
void *thread_regs_block = demon_read_regs(event->thread); void *thread_regs_block = demon_read_regs(event->thread);
@@ -2380,11 +2417,14 @@ ctrl_thread__run(CTRL_Msg *msg)
temp_end(temp); temp_end(temp);
} }
//////////////////////////////// //////////////////////////
//- rjf: stepping logic -// //- rjf: stepping logic
//
//{ //{
//////////////////////////
//- rjf: handle if hitting a spoof or baked in trap //- rjf: handle if hitting a spoof or baked in trap
//
B32 hit_spoof = 0; B32 hit_spoof = 0;
B32 exception_stop = 0; B32 exception_stop = 0;
if(use_stepping_logic) if(use_stepping_logic)
@@ -2409,28 +2449,9 @@ ctrl_thread__run(CTRL_Msg *msg)
} }
} }
//- TODO(rjf): Jeff is hitting a bug where a spoof IP (911) has been
// hit by a thread, !!!BUT!!! we seemingly don't catch that until a
// subsequent run of this loop, probably because there are other
// events in the queue that we report first, losing all state about
// spoof mode.
//
// I'm throwing in some detection for this case, so that we can diagnose
// it further from there.
//
if(event->kind == DEMON_EventKind_Exception &&
event->instruction_pointer == 911 &&
(hit_spoof == 0 || spoof_mode == 0))
{
os_graphical_message(1, str8_lit("RADDBG INTERNAL DEVELOPMENT MESSAGE"), str8_lit("a bad, rare bug that Jeff found has been detected to occur - attach with debugger now"));
}
//- rjf: handle spoof hit //- rjf: handle spoof hit
if(hit_spoof) if(hit_spoof)
{ {
// rjf: restore 1 ip
demon_write_ip(target_thread, spoof_1_return_ip);
// rjf: clear spoof mode // rjf: clear spoof mode
spoof_mode = 0; spoof_mode = 0;
MemoryZeroStruct(&spoof); MemoryZeroStruct(&spoof);
@@ -2673,15 +2694,12 @@ ctrl_thread__run(CTRL_Msg *msg)
{ {
// rjf: setup spoof mode // rjf: setup spoof mode
begin_spoof_mode = 1; begin_spoof_mode = 1;
U64 spoof_sp = demon_read_sp(target_thread); U64 spoof_sp = demon_read_sp(target_thread);
spoof_mode = 1; spoof_mode = 1;
spoof.process = ctrl_handle_from_demon(target_process); spoof.process = ctrl_handle_from_demon(target_process);
spoof.thread = ctrl_handle_from_demon(target_thread);
spoof.vaddr = spoof_sp; spoof.vaddr = spoof_sp;
spoof.new_ip_value = spoof_ip_vaddr; spoof.new_ip_value = spoof_ip_vaddr;
// rjf: remember 1 return ip
demon_read_memory(target_process, &spoof_1_return_ip, spoof_sp, sizeof(spoof_1_return_ip));
} }
} }
@@ -2715,7 +2733,8 @@ ctrl_thread__run(CTRL_Msg *msg)
} }
//} //}
//- rjf: stepping logic -// //
//- rjf: stepping logic
//////////////////////////////// ////////////////////////////////
//- rjf: handle step past trap net //- rjf: handle step past trap net
@@ -2786,20 +2805,11 @@ ctrl_thread__run(CTRL_Msg *msg)
break; break;
} }
} }
//- rjf: unstick silently-hit spoofs
if(stop_event != 0 && stop_event->thread != target_thread && spoof_mode != 0)
{
U64 target_thread_rip = demon_read_ip(target_thread);
if(target_thread_rip == spoof.new_ip_value)
{
// rjf: restore 1 ip
demon_write_ip(target_thread, spoof_1_return_ip);
}
}
} }
//////////////////////////////
//- rjf: record stop //- rjf: record stop
//
if(stop_event != 0) if(stop_event != 0)
{ {
CTRL_EventList evts = {0}; CTRL_EventList evts = {0};
+1
View File
@@ -85,6 +85,7 @@ typedef struct CTRL_Spoof CTRL_Spoof;
struct CTRL_Spoof struct CTRL_Spoof
{ {
CTRL_Handle process; CTRL_Handle process;
CTRL_Handle thread;
U64 vaddr; U64 vaddr;
U64 new_ip_value; U64 new_ip_value;
}; };
+38 -66
View File
@@ -44,7 +44,6 @@ dbgi_init(void)
{ {
dbgi_shared->parse_threads[idx] = os_launch_thread(dbgi_parse_thread_entry_point, (void *)idx, 0); dbgi_shared->parse_threads[idx] = os_launch_thread(dbgi_parse_thread_entry_point, (void *)idx, 0);
} }
dbgi_shared->evictor_thread = os_launch_thread(dbgi_evictor_thread_entry_point, 0, 0);
} }
//////////////////////////////// ////////////////////////////////
@@ -253,9 +252,34 @@ dbgi_binary_close(String8 exe_path)
break; break;
} }
} }
B32 need_deletion = 0;
if(binary != 0 && binary->refcount>0) if(binary != 0 && binary->refcount>0)
{ {
binary->refcount -= 1; binary->refcount -= 1;
need_deletion = (binary->refcount == 0);
}
if(need_deletion) for(;;)
{
os_rw_mutex_drop_w(stripe->rw_mutex);
for(U64 start_t = os_now_microseconds();
os_now_microseconds() <= start_t + 250;);
os_rw_mutex_take_w(stripe->rw_mutex);
if(binary->refcount == 0 && ins_atomic_u64_eval(&binary->scope_touch_count) == 0)
{
if(binary->parse.arena != 0) { arena_release(binary->parse.arena); }
if(binary->parse.exe_base != 0) { os_file_map_view_close(binary->exe_file_map, binary->parse.exe_base); }
if(!os_handle_match(os_handle_zero(), binary->exe_file_map)) { os_file_map_close(binary->exe_file_map); }
if(!os_handle_match(os_handle_zero(), binary->exe_file)) { os_file_close(binary->exe_file); }
if(binary->parse.dbg_base != 0) { os_file_map_view_close(binary->dbg_file_map, binary->parse.dbg_base); }
if(!os_handle_match(os_handle_zero(), binary->dbg_file_map)) { os_file_map_close(binary->dbg_file_map); }
if(!os_handle_match(os_handle_zero(), binary->dbg_file)) { os_file_close(binary->dbg_file); }
binary->exe_file_map = binary->exe_file = os_handle_zero();
binary->dbg_file_map = binary->dbg_file = os_handle_zero();
MemoryZeroStruct(&binary->parse);
binary->last_time_enqueued_for_parse_us = 0;
binary->gen = 1;
break;
}
} }
} }
scratch_end(scratch); scratch_end(scratch);
@@ -294,7 +318,7 @@ dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us)
break; break;
} }
else if(!sent && else if(!sent &&
os_now_microseconds() >= ins_atomic_u64_eval(&binary->last_time_enqueued_for_parse_us)+1000000 && ins_atomic_u64_eval(&binary->last_time_enqueued_for_parse_us) == 0 &&
dbgi_u2p_enqueue_exe_path(exe_path, endt_us)) dbgi_u2p_enqueue_exe_path(exe_path, endt_us))
{ {
sent = 1; sent = 1;
@@ -451,7 +475,7 @@ dbgi_parse_thread_entry_point(void *p)
break; break;
} }
} }
if(binary == 0 || binary->flags&DBGI_BinaryFlag_ParseInFlight) if(binary == 0 || binary->flags&DBGI_BinaryFlag_ParseInFlight || binary->refcount == 0)
{ {
task_is_taken_by_other_thread = 1; task_is_taken_by_other_thread = 1;
} }
@@ -708,8 +732,10 @@ dbgi_parse_thread_entry_point(void *p)
} }
} }
//- rjf: cache write, step 1: check if either EXE or raddbg file is new. if //- rjf: cache write, step 1: check if refcount is still nonzero, &
// so, clear all old results & store new top-level info // either EXE or raddbg file is new. if so, clear all old results &
// store new top-level info
B32 binary_refcount_is_zero = 0;
B32 raddbg_or_exe_file_is_updated = 0; B32 raddbg_or_exe_file_is_updated = 0;
if(do_task) ProfScope("cache write, step 1: check if raddbg is new & clear") if(do_task) ProfScope("cache write, step 1: check if raddbg is new & clear")
{ {
@@ -717,6 +743,11 @@ dbgi_parse_thread_entry_point(void *p)
{ {
if(str8_match(bin->exe_path, exe_path, 0)) if(str8_match(bin->exe_path, exe_path, 0))
{ {
if(bin->refcount == 0)
{
binary_refcount_is_zero = 1;
break;
}
if(bin->parse.dbg_props.modified != raddbg_file_props.modified || if(bin->parse.dbg_props.modified != raddbg_file_props.modified ||
bin->parse.exe_props.modified != exe_file_props.modified) bin->parse.exe_props.modified != exe_file_props.modified)
{ {
@@ -751,7 +782,7 @@ dbgi_parse_thread_entry_point(void *p)
//- rjf: raddbg file or exe is not new? cache can stay unmodified, close //- rjf: raddbg file or exe is not new? cache can stay unmodified, close
// handles & skip to end. // handles & skip to end.
if(do_task) if(!raddbg_or_exe_file_is_updated) if(raddbg_file_is_up_to_date) if(do_task) if((!raddbg_or_exe_file_is_updated && raddbg_file_is_up_to_date) || binary_refcount_is_zero)
{ {
os_file_map_view_close(raddbg_file_map, raddbg_file_base); os_file_map_view_close(raddbg_file_map, raddbg_file_base);
os_file_map_close(raddbg_file_map); os_file_map_close(raddbg_file_map);
@@ -759,6 +790,7 @@ dbgi_parse_thread_entry_point(void *p)
os_file_map_view_close(exe_file_map, exe_file_base); os_file_map_view_close(exe_file_map, exe_file_base);
os_file_map_close(exe_file_map); os_file_map_close(exe_file_map);
os_file_close(exe_file); os_file_close(exe_file);
arena_release(parse_arena);
do_task = 0; do_task = 0;
} }
@@ -826,63 +858,3 @@ dbgi_parse_thread_entry_point(void *p)
scratch_end(scratch); scratch_end(scratch);
} }
} }
////////////////////////////////
//~ rjf: Evictor Thread
internal void
dbgi_evictor_thread_entry_point(void *p)
{
TCTX tctx_;
tctx_init_and_equip(&tctx_);
ProfThreadName("[dbgi] evictor");
for(;;)
{
ProfBegin("eviction scan");
U64 slots_per_stripe = dbgi_shared->binary_slots_count/dbgi_shared->binary_stripes_count;
for(U64 stripe_idx = 0; stripe_idx < dbgi_shared->binary_stripes_count; stripe_idx += 1)
{
DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx];
for(U64 slot_in_stripe_idx = 0; slot_in_stripe_idx < slots_per_stripe; slot_in_stripe_idx += 1)
{
U64 slot_idx = slots_per_stripe*stripe_idx + slot_in_stripe_idx;
DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx];
B32 slot_needs_work = 0;
OS_MutexScopeR(stripe->rw_mutex)
{
for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next)
{
if(bin->refcount == 0 && bin->scope_touch_count == 0 && bin->flags == 0 && bin->gen > 1)
{
slot_needs_work = 1;
break;
}
}
}
if(slot_needs_work) ProfScope("eviction task (slot %I64u)", slot_idx) OS_MutexScopeW(stripe->rw_mutex)
{
for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next)
{
if(bin->refcount == 0 && bin->scope_touch_count == 0 && bin->flags == 0)
{
if(bin->parse.arena != 0) { arena_release(bin->parse.arena); }
if(bin->parse.exe_base != 0) { os_file_map_view_close(bin->exe_file_map, bin->parse.exe_base); }
if(!os_handle_match(os_handle_zero(), bin->exe_file_map)) { os_file_map_close(bin->exe_file_map); }
if(!os_handle_match(os_handle_zero(), bin->exe_file)) { os_file_close(bin->exe_file); }
if(bin->parse.dbg_base != 0) { os_file_map_view_close(bin->dbg_file_map, bin->parse.dbg_base); }
if(!os_handle_match(os_handle_zero(), bin->dbg_file_map)) { os_file_map_close(bin->dbg_file_map); }
if(!os_handle_match(os_handle_zero(), bin->dbg_file)) { os_file_close(bin->dbg_file); }
bin->exe_file_map = bin->exe_file = os_handle_zero();
bin->dbg_file_map = bin->dbg_file = os_handle_zero();
MemoryZeroStruct(&bin->parse);
bin->last_time_enqueued_for_parse_us = 0;
bin->gen = 1;
}
}
}
}
}
ProfEnd();
os_sleep_milliseconds(250);
}
}
-6
View File
@@ -198,7 +198,6 @@ struct DBGI_Shared
// rjf: threads // rjf: threads
U64 parse_thread_count; U64 parse_thread_count;
OS_Handle *parse_threads; OS_Handle *parse_threads;
OS_Handle evictor_thread;
}; };
//////////////////////////////// ////////////////////////////////
@@ -254,9 +253,4 @@ internal DBGI_EventList dbgi_p2u_pop_events(Arena *arena, U64 endt_us);
internal void dbgi_parse_thread_entry_point(void *p); internal void dbgi_parse_thread_entry_point(void *p);
////////////////////////////////
//~ rjf: Evictor Thread
internal void dbgi_evictor_thread_entry_point(void *p);
#endif //DBGI_H #endif //DBGI_H
+10 -2
View File
@@ -957,7 +957,9 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *ctrls){
} }
// rjf: check if trap // rjf: check if trap
B32 is_trap = (!first_bp && exception->ExceptionCode == DEMON_W32_EXCEPTION_BREAKPOINT); B32 is_trap = (!first_bp &&
(exception->ExceptionCode == DEMON_W32_EXCEPTION_BREAKPOINT ||
exception->ExceptionCode == DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN));
// rjf: check if this trap is currently registered // rjf: check if this trap is currently registered
B32 hit_user_trap = 0; B32 hit_user_trap = 0;
@@ -979,7 +981,8 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *ctrls){
// TODO(rjf): x86/x64 specific check // TODO(rjf): x86/x64 specific check
// TODO(rjf): do we need to check to make sure the instruction // TODO(rjf): do we need to check to make sure the instruction
// pointer has not changed? // pointer has not changed?
hit_explicit_trap = (instruction_byte == 0xCC); hit_explicit_trap = (instruction_byte == 0xCC ||
instruction_byte == 0xCD);
} }
} }
@@ -1038,6 +1041,11 @@ demon_os_run(Arena *arena, DEMON_OS_RunCtrls *ctrls){
e->kind = report_event_kind; e->kind = report_event_kind;
}break; }break;
case DEMON_W32_EXCEPTION_STACK_BUFFER_OVERRUN:
{
e->kind = DEMON_EventKind_Trap;
}break;
case DEMON_W32_EXCEPTION_SINGLE_STEP: case DEMON_W32_EXCEPTION_SINGLE_STEP:
{ {
e->kind = DEMON_EventKind_SingleStep; e->kind = DEMON_EventKind_SingleStep;
+211 -14
View File
@@ -2642,6 +2642,98 @@ df_debug_info_path_from_module(Arena *arena, DF_Entity *module)
//////////////////////////////// ////////////////////////////////
//~ rjf: Stepping "Trap Net" Builders //~ rjf: Stepping "Trap Net" Builders
// NOTE(rjf): Stepping Algorithm Overview (2024/01/17)
//
// The basic idea behind all stepping algorithms in the debugger are setting up
// a "trap net". A "trap net" is just a collection of high-level traps that are
// meant to "catch" a thread after letting it run. This trap net is submitted
// when the debugger frontend sends a "run" command (it is just empty if doing
// an actual 'run' or 'continue'). The debugger control thread then uses this
// trap net to program a state machine, to appropriately respond to a variety
// of debug events which it is passed from the OS.
//
// These are "high-level traps" because they can have specific behavioral info
// attached to them. These are encoded via the `CTRL_TrapFlags` type, which
// allow expression of the following behaviors:
//
// - end-stepping: when this trap is hit, it will end the stepping operation,
// and the target will not continue.
// - ignore-stack-pointer-check: when a trap in the trap net is hit, it will
// by-default be ignored if the thread's stack pointer has changed. this
// flag disables that behavior, for when the stack pointer is expected to
// change (e.g. step-out).
// - single-step-after-hit: when a trap with this flag is hit, the debugger
// will immediately single-step the thread which hit it.
// - save-stack-pointer: when a trap with this flag is hit, it will rewrite
// the stack pointer which is used to compare against, when deciding
// whether or not to filter a trap (based on stack pointer changes).
// - begin-spoof-mode: this enables "spoof mode". "spoof mode" is a special
// mode that disables the trap net entirely, and lets the thread run
// freely - but it catches the thread not with a trap, but a false return
// address. the debugger will overwrite a specific return address on the
// stack. this address will be overwritten with an address which does NOT
// point to a valid page, such that when the thread returns out of a
// particular call frame, the debugger will receive a debug event, at
// which point it can move the thread back to the correct return address,
// and resume with the trap net enabled. this is used in "step over"
// operations, because it avoids target <-> debugger "roundtrips" (e.g.
// target being stopped, debugger being called with debug events, then
// target resumes when debugger's control thread is done running) for
// recursions. (it doesn't make a difference with non-recursive calls,
// but the debugger can't detect the difference).
//
// Each stepping command prepares its trap net differently.
//
// --- Instruction Step Into --------------------------------------------------
// In this case, no trap net is prepared, and only a low-level single-step is
// performed.
//
// --- Instruction Step Over --------------------------------------------------
// To build a trap net for an instruction-level step-over, the next instruction
// at the thread's current instruction pointer is decoded. If it is a call
// instruction, or if it is a repeating instruction, then a trap with the
// 'end-stepping' behavior is placed at the instruction immediately following
// the 'call' instruction.
//
// --- Line Step Into ---------------------------------------------------------
// For a source-line step-into, the thread's instruction pointer is first used
// to look up into the debug info's line info, to find the machine code in the
// thread's current source line. Every instruction in this range is decoded.
// Traps are then built in the following way:
//
// - 'call' instruction -> if can decode call destination address, place
// "end-stepping | ignore-stack-pointer-check" trap at destination. if
// can't, "end-stepping | single-step-after | ignore-stack-pointer-check"
// trap at call.
// - 'jmp' (both unconditional & conditional) -> if can decode jump destination
// address, AND if jump leaves the line, place "end-stepping | ignore-
// stack-pointer-check" trap at destination. if can't, "end-stepping |
// single-step-after | ignore-stack-pointer-check" trap at jmp. if jump
// stays within the line, do nothing.
// - 'return' -> place "end-stepping | single-step-after" trap at return inst.
// - "end-stepping" trap is placed at the first address after the line, to
// catch all steps which simply proceed linearly through the instruction
// stream.
//
// --- Line Step Over ---------------------------------------------------------
// For a source-line step-over, the thread's instruction pointer is first used
// to look up into the debug info's line info, to find the machine code in the
// thread's current source line. Every instruction in this range is decoded.
// Traps are then built in the following way:
//
// - 'call' instruction -> place "single-step-after | begin-spoof-mode" trap at
// call instruction.
// - 'jmp' (both unconditional & conditional) -> if can decode jump destination
// address, AND if jump leaves the line, place "end-stepping" trap at
// destination. if can't, "end-stepping | single-step-after" trap at jmp.
// if jump stays within the line, do nothing.
// - 'return' -> place "end-stepping | single-step-after" trap at return inst.
// - "end-stepping" trap is placed at the first address after the line, to
// catch all steps which simply proceed linearly through the instruction
// stream.
// - 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 CTRL_TrapList
df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread) df_trap_net_from_thread__step_over_inst(Arena *arena, DF_Entity *thread)
{ {
@@ -2998,7 +3090,7 @@ df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff)
String8 path = df_full_path_from_entity(scratch.arena, binary); String8 path = df_full_path_from_entity(scratch.arena, binary);
DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0);
RADDBG_Parsed *rdbg = &dbgi->rdbg; RADDBG_Parsed *rdbg = &dbgi->rdbg;
if(rdbg->scope_vmap != 0) if(result.size == 0 && rdbg->scope_vmap != 0)
{ {
U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff); U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, voff);
RADDBG_Scope *scope = &rdbg->scopes[scope_idx]; RADDBG_Scope *scope = &rdbg->scopes[scope_idx];
@@ -3008,6 +3100,14 @@ df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff)
U8 *name_ptr = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size); U8 *name_ptr = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size);
result = push_str8_copy(arena, str8(name_ptr, name_size)); result = push_str8_copy(arena, str8(name_ptr, name_size));
} }
if(result.size == 0 && rdbg->global_vmap != 0)
{
U64 global_idx = raddbg_vmap_idx_from_voff(rdbg->global_vmap, rdbg->global_vmap_count, voff);
RADDBG_GlobalVariable *global_var = &rdbg->global_variables[global_idx];
U64 name_size = 0;
U8 *name_ptr = raddbg_string_from_idx(rdbg, global_var->name_string_idx, &name_size);
result = push_str8_copy(arena, str8(name_ptr, name_size));
}
dbgi_scope_close(scope); dbgi_scope_close(scope);
scratch_end(scratch); scratch_end(scratch);
} }
@@ -4047,6 +4147,19 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_
} }
} }
//- rjf: unpack module info & produce eval machine
DF_Entity *module = df_module_from_process_vaddr(process, thread_unwind_ip_vaddr);
U64 module_base = df_base_vaddr_from_module(module);
U64 tls_base = df_tls_base_vaddr_from_thread(thread);
EVAL_Machine machine = {0};
machine.u = (void *)thread->parent;
machine.arch = arch;
machine.memory_read = df_eval_memory_read;
machine.reg_data = thread_unwind_regs_block;
machine.reg_size = reg_size;
machine.module_base = &module_base;
machine.tls_base = &tls_base;
//- rjf: lex & parse //- rjf: lex & parse
EVAL_TokenArray tokens = eval_token_array_from_text(arena, string); EVAL_TokenArray tokens = eval_token_array_from_text(arena, string);
EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(arena, parse_ctx, string, &tokens); EVAL_ParseResult parse = eval_parse_expr_from_text_tokens(arena, parse_ctx, string, &tokens);
@@ -4075,23 +4188,10 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_
bytecode = eval_bytecode_from_oplist(arena, &op_list); bytecode = eval_bytecode_from_oplist(arena, &op_list);
} }
//- rjf: grab thread/module
DF_Entity *module = df_module_from_process_vaddr(process, thread_unwind_ip_vaddr);
//- rjf: evaluate //- rjf: evaluate
EVAL_Result eval = {0}; EVAL_Result eval = {0};
if(bytecode.size != 0) if(bytecode.size != 0)
{ {
U64 module_base = df_base_vaddr_from_module(module);
U64 tls_base = df_tls_base_vaddr_from_thread(thread);
EVAL_Machine machine = {0};
machine.u = (void *)thread->parent;
machine.arch = arch;
machine.memory_read = df_eval_memory_read;
machine.reg_data = thread_unwind_regs_block;
machine.reg_size = reg_size;
machine.module_base = &module_base;
machine.tls_base = &tls_base;
eval = eval_interpret(&machine, bytecode); eval = eval_interpret(&machine, bytecode);
} }
@@ -4122,6 +4222,12 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_
result.errors = errors; result.errors = errors;
} }
//- rjf: apply dynamic type overrides
if(parse.expr != 0 && parse.expr->kind != EVAL_ExprKind_Cast)
{
result = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, result);
}
scratch_end(scratch); scratch_end(scratch);
ProfEnd(); ProfEnd();
return result; return result;
@@ -4196,10 +4302,83 @@ df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *c
return eval; return eval;
} }
internal DF_Eval
df_dynamically_typed_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval)
{
Temp scratch = scratch_begin(0, 0);
DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread);
Architecture arch = df_architecture_from_entity(thread);
DF_Entity *process = thread->parent;
U64 unwind_count = ctrl_ctx->unwind_count;
U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count);
DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr);
TG_Key type_key = eval.type_key;
TG_Kind type_kind = tg_kind_from_key(type_key);
if(type_kind == TG_Kind_Ptr)
{
TG_Key ptee_type_key = tg_direct_from_graph_raddbg_key(graph, rdbg, type_key);
TG_Kind ptee_type_kind = tg_kind_from_key(ptee_type_key);
if(ptee_type_kind == TG_Kind_Struct || ptee_type_kind == TG_Kind_Class)
{
TG_Type *ptee_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, ptee_type_key);
B32 has_vtable = 0;
for(U64 idx = 0; idx < ptee_type->count; idx += 1)
{
if(ptee_type->members[idx].kind == TG_MemberKind_VirtualMethod)
{
has_vtable = 1;
break;
}
}
if(has_vtable)
{
U64 ptr_vaddr = eval.offset;
U64 addr_size = bit_size_from_arch(arch)/8;
String8 ptr_value_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle,
r1u64(ptr_vaddr, ptr_vaddr+addr_size));
if(ptr_value_memory.size >= addr_size)
{
U64 class_base_vaddr = 0;
MemoryCopy(&class_base_vaddr, ptr_value_memory.str, addr_size);
String8 vtable_base_ptr_memory = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle,
r1u64(class_base_vaddr, class_base_vaddr+addr_size));
if(vtable_base_ptr_memory.size >= addr_size)
{
U64 vtable_vaddr = 0;
MemoryCopy(&vtable_vaddr, vtable_base_ptr_memory.str, addr_size);
U64 vtable_voff = df_voff_from_vaddr(module, vtable_vaddr);
U64 global_idx = raddbg_vmap_idx_from_voff(rdbg->global_vmap, rdbg->global_vmap_count, vtable_voff);
if(0 < global_idx && global_idx < rdbg->global_variable_count)
{
RADDBG_GlobalVariable *global_var = &rdbg->global_variables[global_idx];
if(global_var->link_flags & RADDBG_LinkFlag_TypeScoped &&
0 < global_var->container_idx && global_var->container_idx < rdbg->udt_count)
{
RADDBG_UDT *udt = &rdbg->udts[global_var->container_idx];
if(0 < udt->self_type_idx && udt->self_type_idx < rdbg->type_node_count)
{
RADDBG_TypeNode *type = &rdbg->type_nodes[udt->self_type_idx];
TG_Key derived_type_key = tg_key_ext(tg_kind_from_raddbg_type_kind(type->kind), (U64)udt->self_type_idx);
TG_Key ptr_to_derived_type_key = tg_cons_type_make(graph, TG_Kind_Ptr, derived_type_key, 0);
eval.type_key = ptr_to_derived_type_key;
}
}
}
}
}
}
}
}
scratch_end(scratch);
return eval;
}
internal DF_Eval internal DF_Eval
df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, DF_CfgTable *cfg) df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, DF_CfgTable *cfg)
{ {
ProfBeginFunction(); ProfBeginFunction();
//- rjf: apply view rules
for(DF_CfgVal *val = cfg->first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) for(DF_CfgVal *val = cfg->first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next)
{ {
DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string); DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string);
@@ -4877,6 +5056,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie
////////////////////////////// //////////////////////////////
//- rjf: apply view rules & resolve eval //- rjf: apply view rules & resolve eval
// //
eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, eval);
eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, eval, cfg_table); eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, eval, cfg_table);
////////////////////////////// //////////////////////////////
@@ -4976,6 +5156,15 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie
for(DF_CfgVal *val = cfg_table->first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next) for(DF_CfgVal *val = cfg_table->first_val; val != 0 && val != &df_g_nil_cfg_val; val = val->linear_next)
{ {
DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string); DF_CoreViewRuleSpec *spec = df_core_view_rule_spec_from_string(val->string);
if(str8_match(spec->info.string, str8_lit("list"), 0) ||
str8_match(spec->info.string, str8_lit("omit"), 0) ||
str8_match(spec->info.string, str8_lit("only"), 0))
{
// TODO(rjf): "list" view rule needs to be formally moved into the visualization
// engine hooks when the system is mature enough to support it
// also "omit", "only"
continue;
}
if(spec->info.flags & DF_CoreViewRuleSpecInfoFlag_VizBlockProd) if(spec->info.flags & DF_CoreViewRuleSpecInfoFlag_VizBlockProd)
{ {
expand_rule = DF_EvalVizExpandRule_ViewRule; expand_rule = DF_EvalVizExpandRule_ViewRule;
@@ -6227,6 +6416,14 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt)
} }
} }
} }
// rjf: exception or unexpected trap -> push error
if(event->cause == CTRL_EventCause_InterruptedByException ||
event->cause == CTRL_EventCause_InterruptedByTrap)
{
DF_CmdParams params = df_cmd_params_zero();
df_cmd_list_push(arena, cmds, &params, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error));
}
}break; }break;
//- rjf: entity creation/deletion //- rjf: entity creation/deletion
+2
View File
@@ -818,6 +818,7 @@ struct DF_EvalVizRow
String8 expr; String8 expr;
String8 display_value; String8 display_value;
String8 edit_value; String8 edit_value;
TG_KeyList inherited_type_key_chain;
// rjf: variable-size & hook info // rjf: variable-size & hook info
U64 size_in_rows; U64 size_in_rows;
@@ -1562,6 +1563,7 @@ internal EVAL_ParseCtx df_eval_parse_ctx_from_module_voff(DBGI_Scope *scope, DF_
internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt); internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt);
internal DF_Eval df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, String8 string); internal DF_Eval df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, String8 string);
internal DF_Eval df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); internal DF_Eval df_value_mode_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval);
internal DF_Eval df_dynamically_typed_eval_from_eval(TG_Graph *graph, RADDBG_Parsed *rdbg, DF_CtrlCtx *ctrl_ctx, DF_Eval eval);
internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, DF_CfgTable *cfg); internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_Eval eval, DF_CfgTable *cfg);
//////////////////////////////// ////////////////////////////////
+94 -30
View File
@@ -4082,6 +4082,32 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
//- rjf: build hover eval //- rjf: build hover eval
ProfScope("build hover eval") ProfScope("build hover eval")
{ {
// find panel/view pair that the mouse is on and disable hover if that view is scrolling
if(hover_eval_is_open)
{
for(DF_Panel *panel = ws->root_panel; !df_panel_is_nil(panel); panel = df_panel_rec_df_pre(panel).next)
{
if(!df_panel_is_nil(panel->first))
{
continue;
}
DF_View *view = df_selected_view_from_panel(panel);
if (!df_view_is_nil(view))
{
Rng2F32 panel_rect = df_rect_from_panel(content_rect, ws->root_panel, panel);
if(contains_2f32(panel_rect, ws->ui->mouse))
{
if(abs_f32(view->scroll_pos.x.off) > 0.01f ||
abs_f32(view->scroll_pos.y.off) > 0.01f)
{
hover_eval_is_open = 0;
ws->hover_eval_first_frame_idx = df_frame_index();
}
}
}
}
}
if(ws->hover_eval_string.size == 0) if(ws->hover_eval_string.size == 0)
{ {
ws->hover_eval_num_visible_rows_t = 0; ws->hover_eval_num_visible_rows_t = 0;
@@ -4172,7 +4198,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
} }
UI_PrefWidth(ui_em(30.f, 1.f)) UI_PrefWidth(ui_em(30.f, 1.f))
{ {
UI_PrefWidth(ui_text_dim(10, 1.f)) df_code_label(1.f, 1, row->expr); UI_PrefWidth(ui_text_dim(10, 1.f)) df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), row->expr);
ui_spacer(ui_em(1.5f, 1.f)); ui_spacer(ui_em(1.5f, 1.f));
if(row->flags & DF_EvalVizRowFlag_CanEditValue) if(row->flags & DF_EvalVizRowFlag_CanEditValue)
{ {
@@ -4197,7 +4223,7 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
} }
else else
{ {
df_code_label(1.f, 1, row->display_value); df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), row->display_value);
} }
} }
ui_spacer(ui_em(0.75f, 1.f)); ui_spacer(ui_em(0.75f, 1.f));
@@ -4990,7 +5016,8 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
}break; }break;
case CTRL_EventCause_InterruptedByTrap: case CTRL_EventCause_InterruptedByTrap:
{ {
icon = DF_IconKind_WarningBig;
explanation = push_str8f(scratch.arena, "%S interrupted by trap - 0x%x", thread_display_string, stop_event.exception_code);
}break; }break;
case CTRL_EventCause_InterruptedByHalt: case CTRL_EventCause_InterruptedByHalt:
{ {
@@ -5050,18 +5077,21 @@ df_window_update_and_render(Arena *arena, OS_EventList *events, DF_Window *ws, D
Vec4F32 tx_color = df_rgba_from_theme_color(DF_ThemeColor_FailureText); Vec4F32 tx_color = df_rgba_from_theme_color(DF_ThemeColor_FailureText);
F32 alpha_factor = Max(ws->error_t, 0.2f); F32 alpha_factor = Max(ws->error_t, 0.2f);
tx_color.w *= alpha_factor; tx_color.w *= alpha_factor;
ui_set_next_text_color(tx_color); String8 error_string = str8(ws->error_buffer, ws->error_string_size);
ui_set_next_pref_width(ui_children_sum(1)); if(error_string.size != 0)
UI_CornerRadius(4)
UI_Row
UI_PrefWidth(ui_text_dim(10, 1))
UI_TextAlignment(UI_TextAlign_Center)
{ {
String8 error_string = str8(ws->error_buffer, ws->error_string_size); ui_set_next_text_color(tx_color);
UI_Font(df_font_from_slot(DF_FontSlot_Icons)) ui_set_next_pref_width(ui_children_sum(1));
UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons)) UI_CornerRadius(4)
ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); UI_Row
ui_label(error_string); UI_PrefWidth(ui_text_dim(10, 1))
UI_TextAlignment(UI_TextAlign_Center)
{
UI_Font(df_font_from_slot(DF_FontSlot_Icons))
UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Icons))
ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]);
ui_label(error_string);
}
} }
} }
} }
@@ -6811,7 +6841,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags
} }
// rjf: arrow // rjf: arrow
if(did_ptr_value && direct_type_has_content && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules)) if(did_ptr_value && (direct_type_has_content || symbol_name.size != 0) && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules))
{ {
String8 arrow = str8_lit(" -> "); String8 arrow = str8_lit(" -> ");
str8_list_push(arena, &list, arrow); str8_list_push(arena, &list, arrow);
@@ -6831,7 +6861,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags
} }
// rjf: special-case: symbols // rjf: special-case: symbols
else if(direct_type_has_content && (flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules) && symbol_name.size != 0) else if((flags & DF_EvalVizStringFlag_ReadOnlyDisplayRules) && symbol_name.size != 0)
{ {
str8_list_push(arena, &list, symbol_name); str8_list_push(arena, &list, symbol_name);
space_taken += f_dim_from_tag_size_string(font, font_size, symbol_name).x; space_taken += f_dim_from_tag_size_string(font, font_size, symbol_name).x;
@@ -7191,6 +7221,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop
// rjf: apply view rules to eval // rjf: apply view rules to eval
{ {
member_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, member_eval);
member_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, member_eval, &view_rule_table); member_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, member_eval, &view_rule_table);
} }
@@ -7203,6 +7234,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop
row->expr = push_str8_copy(arena, member->name); row->expr = push_str8_copy(arena, member->name);
row->display_value = str8_list_join(arena, &display_strings, 0); row->display_value = str8_list_join(arena, &display_strings, 0);
row->edit_value = str8_list_join(arena, &edit_strings, 0); row->edit_value = str8_list_join(arena, &edit_strings, 0);
row->inherited_type_key_chain = tg_key_list_copy(arena, &member->inheritance_key_chain);
row->value_ui_rule_node = value_ui_rule_node; row->value_ui_rule_node = value_ui_rule_node;
row->value_ui_rule_spec = value_ui_rule_spec; row->value_ui_rule_spec = value_ui_rule_spec;
row->expand_ui_rule_node = expand_ui_rule_node; row->expand_ui_rule_node = expand_ui_rule_node;
@@ -7270,6 +7302,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop
// rjf: apply view rules to eval // rjf: apply view rules to eval
{ {
elem_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, elem_eval);
elem_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, elem_eval, &view_rule_table); elem_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, elem_eval, &view_rule_table);
} }
@@ -7349,6 +7382,7 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop
df_cfg_table_push_unparsed_string(scratch.arena, &view_rule_table, view_rule_string, DF_CfgSrc_User); df_cfg_table_push_unparsed_string(scratch.arena, &view_rule_table, view_rule_string, DF_CfgSrc_User);
// rjf: apply view rules to eval // rjf: apply view rules to eval
link_eval = df_dynamically_typed_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdbg, ctrl_ctx, link_eval);
link_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, link_eval, &view_rule_table); link_eval = df_eval_from_eval_cfg_table(arena, scope, ctrl_ctx, parse_ctx, link_eval, &view_rule_table);
TG_Kind link_type_kind = tg_kind_from_key(link_eval.type_key); TG_Kind link_type_kind = tg_kind_from_key(link_eval.type_key);
@@ -8642,14 +8676,14 @@ df_entity_tooltips(DF_Entity *entity)
stop_condition = str8_lit("true"); stop_condition = str8_lit("true");
} }
UI_PrefWidth(ui_em(12.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("Stop Condition: "); UI_PrefWidth(ui_em(12.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("Stop Condition: ");
UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, stop_condition); UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), stop_condition);
} }
UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_children_sum(1)) UI_Row
{ {
U64 hit_count = entity->u64; U64 hit_count = entity->u64;
String8 hit_count_text = str8_from_u64(scratch.arena, hit_count, 10, 0, 0); String8 hit_count_text = str8_from_u64(scratch.arena, hit_count, 10, 0, 0);
UI_PrefWidth(ui_em(12.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("Hit Count: "); UI_PrefWidth(ui_em(12.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("Hit Count: ");
UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, hit_count_text); UI_PrefWidth(ui_text_dim(10, 1)) UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), hit_count_text);
} }
}break; }break;
case DF_EntityKind_WatchPin: UI_Font(df_font_from_slot(DF_FontSlot_Code)) case DF_EntityKind_WatchPin: UI_Font(df_font_from_slot(DF_FontSlot_Code))
@@ -8660,7 +8694,7 @@ df_entity_tooltips(DF_Entity *entity)
ui_set_next_text_color(color); ui_set_next_text_color(color);
} }
String8 display_string = df_display_string_from_entity(scratch.arena, entity); String8 display_string = df_display_string_from_entity(scratch.arena, entity);
UI_PrefWidth(ui_text_dim(10, 1)) df_code_label(1.f, 1, display_string); UI_PrefWidth(ui_text_dim(10, 1)) df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), display_string);
}break; }break;
} }
scratch_end(scratch); scratch_end(scratch);
@@ -9550,8 +9584,8 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_
ws->entity_ctx_menu_entity = df_handle_from_entity(pin); ws->entity_ctx_menu_entity = df_handle_from_entity(pin);
} }
} }
df_code_label(0.8f, 1, pin_expr); df_code_label(0.8f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), pin_expr);
df_code_label(0.6f, 1, eval_string); df_code_label(0.6f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), eval_string);
} }
UI_Signal pin_sig = ui_signal_from_box(pin_box); UI_Signal pin_sig = ui_signal_from_box(pin_box);
if(ui_key_match(pin_box_key, ui_hot_key())) if(ui_key_match(pin_box_key, ui_hot_key()))
@@ -10462,7 +10496,7 @@ df_help_label(String8 string)
} }
internal D_FancyStringList internal D_FancyStringList
df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, String8 string) df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string)
{ {
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
D_FancyStringList fancy_strings = {0}; D_FancyStringList fancy_strings = {0};
@@ -10491,6 +10525,17 @@ df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s
}; };
d_fancy_string_list_push(arena, &fancy_strings, &fancy_string); d_fancy_string_list_push(arena, &fancy_strings, &fancy_string);
}break; }break;
case TXTI_TokenKind_Identifier:
{
D_FancyString fancy_string =
{
ui_top_font(),
token_string,
base_color,
ui_top_font_size() * (1.f - !!indirection_size_change*(indirection_counter/10.f)),
};
d_fancy_string_list_push(arena, &fancy_strings, &fancy_string);
}break;
case TXTI_TokenKind_Numeric: case TXTI_TokenKind_Numeric:
{ {
Vec4F32 token_color_rgba_alt = token_color_rgba; Vec4F32 token_color_rgba_alt = token_color_rgba;
@@ -10602,10 +10647,10 @@ df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_s
} }
internal void internal void
df_code_label(F32 alpha, B32 indirection_size_change, String8 string) df_code_label(F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string)
{ {
Temp scratch = scratch_begin(0, 0); Temp scratch = scratch_begin(0, 0);
D_FancyStringList fancy_strings = df_fancy_string_list_from_code_string(scratch.arena, alpha, indirection_size_change, string); D_FancyStringList fancy_strings = df_fancy_string_list_from_code_string(scratch.arena, alpha, indirection_size_change, base_color, string);
UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero()); UI_Box *box = ui_build_box_from_key(UI_BoxFlag_DrawText, ui_key_zero());
ui_box_equip_display_fancy_strings(box, &fancy_strings); ui_box_equip_display_fancy_strings(box, &fancy_strings);
scratch_end(scratch); scratch_end(scratch);
@@ -10811,11 +10856,11 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, TxtPt *cursor, TxtPt *mark, U8 *
if(!(flags & DF_LineEditFlag_PreferDisplayString) && pre_edit_value.size != 0) if(!(flags & DF_LineEditFlag_PreferDisplayString) && pre_edit_value.size != 0)
{ {
display_string = pre_edit_value; display_string = pre_edit_value;
df_code_label(1.f, 1, display_string); df_code_label(1.f, 1, ui_top_text_color(), display_string);
} }
else if(flags & DF_LineEditFlag_DisplayStringIsCode) else if(flags & DF_LineEditFlag_DisplayStringIsCode)
{ {
df_code_label(1.f, 1, display_string); df_code_label(1.f, 1, ui_top_text_color(), display_string);
} }
else else
{ {
@@ -10844,7 +10889,7 @@ df_line_edit(DF_LineEditFlags flags, S32 depth, TxtPt *cursor, TxtPt *mark, U8 *
F32 total_editstr_width = total_text_width - !!(flags & (DF_LineEditFlag_Expander|DF_LineEditFlag_ExpanderSpace|DF_LineEditFlag_ExpanderPlaceholder)) * expander_size_px; F32 total_editstr_width = total_text_width - !!(flags & (DF_LineEditFlag_Expander|DF_LineEditFlag_ExpanderSpace|DF_LineEditFlag_ExpanderPlaceholder)) * expander_size_px;
ui_set_next_pref_width(ui_px(total_editstr_width+ui_top_font_size()*2, 0.f)); ui_set_next_pref_width(ui_px(total_editstr_width+ui_top_font_size()*2, 0.f));
UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr"); UI_Box *editstr_box = ui_build_box_from_stringf(UI_BoxFlag_DrawText|UI_BoxFlag_DisableTextTrunc, "###editstr");
D_FancyStringList code_fancy_strings = df_fancy_string_list_from_code_string(scratch.arena, 1.f, 0, edit_string); D_FancyStringList code_fancy_strings = df_fancy_string_list_from_code_string(scratch.arena, 1.f, 0, ui_top_text_color(), edit_string);
ui_box_equip_display_fancy_strings(editstr_box, &code_fancy_strings); ui_box_equip_display_fancy_strings(editstr_box, &code_fancy_strings);
UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1); UI_LineEditDrawData *draw_data = push_array(ui_build_arena(), UI_LineEditDrawData, 1);
draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string); draw_data->edited_string = push_str8_copy(ui_build_arena(), edit_string);
@@ -11053,6 +11098,22 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds)
} }
}break; }break;
//- rjf: errors
case DF_CoreCmdKind_Error:
{
DF_Window *window = df_window_from_handle(params.window);
if(window == 0)
{
for(DF_Window *w = df_gfx_state->first_window; w != 0; w = w->next)
{
DF_CmdParams p = df_cmd_params_from_window(w);
p.string = push_str8_copy(arena, params.string);
df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String);
df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error));
}
}
}break;
//- rjf: windows //- rjf: windows
case DF_CoreCmdKind_OpenWindow: case DF_CoreCmdKind_OpenWindow:
{ {
@@ -11534,7 +11595,10 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds)
} }
//- rjf: apply keybindings //- rjf: apply keybindings
df_clear_bindings(); if(src == DF_CfgSrc_User)
{
df_clear_bindings();
}
DF_CfgVal *keybindings = df_cfg_val_from_string(table, str8_lit("keybindings")); DF_CfgVal *keybindings = df_cfg_val_from_string(table, str8_lit("keybindings"));
for(DF_CfgNode *keybinding_set = keybindings->first; for(DF_CfgNode *keybinding_set = keybindings->first;
keybinding_set != &df_g_nil_cfg_node; keybinding_set != &df_g_nil_cfg_node;
@@ -11649,7 +11713,7 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds)
} }
//- rjf: if config opened 0 windows, we need to do some sensible default //- rjf: if config opened 0 windows, we need to do some sensible default
if(windows->first == &df_g_nil_cfg_node) if(src == DF_CfgSrc_User && windows->first == &df_g_nil_cfg_node)
{ {
OS_Handle preferred_monitor = os_primary_monitor(); OS_Handle preferred_monitor = os_primary_monitor();
Vec2F32 monitor_dim = os_dim_from_monitor(preferred_monitor); Vec2F32 monitor_dim = os_dim_from_monitor(preferred_monitor);
@@ -11660,7 +11724,7 @@ df_gfx_begin_frame(Arena *arena, DF_CmdList *cmds)
} }
//- rjf: if config bound 0 keys, we need to do some sensible default //- rjf: if config bound 0 keys, we need to do some sensible default
if(df_gfx_state->key_map_total_count == 0) if(src == DF_CfgSrc_User && df_gfx_state->key_map_total_count == 0)
{ {
for(U64 idx = 0; idx < ArrayCount(df_g_default_binding_table); idx += 1) for(U64 idx = 0; idx < ArrayCount(df_g_default_binding_table); idx += 1)
{ {
+2 -2
View File
@@ -1031,8 +1031,8 @@ internal B32 df_do_dasm_controls(DASM_Handle handle, U64 line_count_per_page, Tx
internal UI_Signal df_error_label(String8 string); internal UI_Signal df_error_label(String8 string);
internal B32 df_help_label(String8 string); internal B32 df_help_label(String8 string);
internal D_FancyStringList df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, String8 string); internal D_FancyStringList df_fancy_string_list_from_code_string(Arena *arena, F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string);
internal void df_code_label(F32 alpha, B32 indirection_size_change, String8 string); internal void df_code_label(F32 alpha, B32 indirection_size_change, Vec4F32 base_color, String8 string);
//////////////////////////////// ////////////////////////////////
//~ rjf: UI Widgets: Line Edit //~ rjf: UI Widgets: Line Edit
+50 -23
View File
@@ -1051,22 +1051,49 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW
// rjf: build // rjf: build
UI_Signal sig = {0}; UI_Signal sig = {0};
B32 next_expanded = row_expanded; B32 next_expanded = row_expanded;
UI_TableCell UI_Font(code_font) UI_TableCell UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing)
UI_TextColor(row->depth > 0 ? df_rgba_from_theme_color(DF_ThemeColor_WeakText) : ui_top_text_color())
UI_FocusHot(cell_selected) UI_FocusActive(cell_selected && ewv->input_editing)
{ {
B32 expr_editing_active = ui_is_focus_active(); B32 expr_editing_active = ui_is_focus_active();
sig = df_line_editf((DF_LineEditFlag_CodeContents| B32 is_inherited = (row->inherited_type_key_chain.count != 0);
DF_LineEditFlag_NoBackground| UI_Font(code_font) UI_TextColor(row->depth > 0 ? df_rgba_from_theme_color(DF_ThemeColor_WeakText) : ui_top_text_color())
DF_LineEditFlag_DisableEdit*(!can_edit_expr)| {
DF_LineEditFlag_Expander*!!(row->flags & DF_EvalVizRowFlag_CanExpand)| if(is_inherited)
DF_LineEditFlag_ExpanderPlaceholder*(row->depth==0)| {
DF_LineEditFlag_ExpanderSpace*(row->depth!=0)), Vec4F32 inherited_bg_color = df_rgba_from_theme_color(DF_ThemeColor_Highlight1);
row->depth, inherited_bg_color.w *= 0.2f;
&ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, &next_expanded, ui_set_next_background_color(inherited_bg_color);
row->expr, }
"###row_%I64x", row_hash); sig = df_line_editf((DF_LineEditFlag_CodeContents|
DF_LineEditFlag_NoBackground*(!is_inherited)|
DF_LineEditFlag_DisableEdit*(!can_edit_expr)|
DF_LineEditFlag_Expander*!!(row->flags & DF_EvalVizRowFlag_CanExpand)|
DF_LineEditFlag_ExpanderPlaceholder*(row->depth==0)|
DF_LineEditFlag_ExpanderSpace*(row->depth!=0)),
row->depth,
&ewv->input_cursor, &ewv->input_mark, ewv->input_buffer, sizeof(ewv->input_buffer), &ewv->input_size, &next_expanded,
row->expr,
"###row_%I64x", row_hash);
}
edit_commit = edit_commit || sig.commit; edit_commit = edit_commit || sig.commit;
if(sig.hovering && is_inherited) UI_Tooltip
{
String8List inheritance_chain_type_names = {0};
for(TG_KeyNode *n = row->inherited_type_key_chain.first; n != 0; n = n->next)
{
String8 inherited_type_name = tg_string_from_key(scratch.arena, parse_ctx.type_graph, parse_ctx.rdbg, n->v);
inherited_type_name = str8_skip_chop_whitespace(inherited_type_name);
str8_list_push(scratch.arena, &inheritance_chain_type_names, inherited_type_name);
}
StringJoin join = {0};
join.sep = str8_lit("::");
String8 inheritance_type = str8_list_join(scratch.arena, &inheritance_chain_type_names, &join);
ui_set_next_pref_width(ui_children_sum(1));
UI_Row
{
ui_labelf("Inherited from ");
UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1.f, df_rgba_from_theme_color(DF_ThemeColor_CodeType), inheritance_type);
}
}
if(sig.hovering && DEV_eval_watch_key_tooltips) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Code)) if(sig.hovering && DEV_eval_watch_key_tooltips) UI_Tooltip UI_Font(df_font_from_slot(DF_FontSlot_Code))
{ {
ui_labelf("Parent Key: %I64x, %I64x, %I64x", row->parent_key.uniquifier, row->parent_key.parent_hash, row->parent_key.child_num); ui_labelf("Parent Key: %I64x, %I64x, %I64x", row->parent_key.uniquifier, row->parent_key.parent_hash, row->parent_key.child_num);
@@ -1217,7 +1244,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###val_%I64x", row_hash); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###val_%I64x", row_hash);
UI_Parent(box) UI_Parent(box)
{ {
df_code_label(1.f, 1, row->display_value); df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), row->display_value);
} }
sig = ui_signal_from_box(box); sig = ui_signal_from_box(box);
} }
@@ -1261,7 +1288,7 @@ df_eval_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_EvalW
UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###type_%I64x", row_hash); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###type_%I64x", row_hash);
if(!tg_key_match(key, tg_key_zero())) UI_Parent(box) if(!tg_key_match(key, tg_key_zero())) UI_Parent(box)
{ {
df_code_label(1.f, 1, string); df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeType), string);
} }
UI_Signal sig = ui_signal_from_box(box); UI_Signal sig = ui_signal_from_box(box);
if(sig.pressed) if(sig.pressed)
@@ -5153,7 +5180,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code)
if(txti_buffer_is_ready) UI_Parent(container_box) if(txti_buffer_is_ready) UI_Parent(container_box)
{ {
//- rjf: build fractional space //- rjf: build fractional space
container_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; container_box->view_off.x = container_box->view_off_target.x = view->scroll_pos.x.idx + view->scroll_pos.x.off;
container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1); container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1);
//- rjf: build code slice //- rjf: build code slice
@@ -6033,7 +6060,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly)
if(has_disasm) UI_Parent(container_box) if(has_disasm) UI_Parent(container_box)
{ {
//- rjf: build fractional space //- rjf: build fractional space
container_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; container_box->view_off.x = container_box->view_off_target.x = view->scroll_pos.x.idx + view->scroll_pos.x.off;
container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1); container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1);
//- rjf: build code slice //- rjf: build code slice
@@ -6967,7 +6994,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output)
if(txti_buffer_is_ready) UI_Parent(container_box) if(txti_buffer_is_ready) UI_Parent(container_box)
{ {
//- rjf: build fractional space //- rjf: build fractional space
container_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; container_box->view_off.x = container_box->view_off_target.x = view->scroll_pos.x.idx + view->scroll_pos.x.off;
container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1); container_box->view_off.y = container_box->view_off_target.y = code_line_height*mod_f32(view->scroll_pos.y.off, 1.f) + code_line_height*(view->scroll_pos.y.off < 0) - code_line_height*(view->scroll_pos.y.off == -1.f && view->scroll_pos.y.idx == 1);
//- rjf: build code slice //- rjf: build code slice
@@ -7723,7 +7750,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory)
UI_BoxFlag_AllowOverflowX| UI_BoxFlag_AllowOverflowX|
UI_BoxFlag_AllowOverflowY, UI_BoxFlag_AllowOverflowY,
"scrollable_box"); "scrollable_box");
scrollable_box->view_off.x = view->scroll_pos.x.idx + view->scroll_pos.x.off; container_box->view_off.x = container_box->view_off_target.x = view->scroll_pos.x.idx + view->scroll_pos.x.off;
scrollable_box->view_off.y = scrollable_box->view_off_target.y = floor_f32(row_height_px*mod_f32(view->scroll_pos.y.off, 1.f) + row_height_px*(view->scroll_pos.y.off < 0)); scrollable_box->view_off.y = scrollable_box->view_off_target.y = floor_f32(row_height_px*mod_f32(view->scroll_pos.y.off, 1.f) + row_height_px*(view->scroll_pos.y.off < 0));
} }
@@ -7928,7 +7955,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory)
} }
if(a->type_string.size != 0) if(a->type_string.size != 0)
{ {
df_code_label(1.f, 1, a->type_string); df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeType), a->type_string);
} }
UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(str8_from_memory_size(scratch.arena, dim_1u64(a->vaddr_range))); UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_label(str8_from_memory_size(scratch.arena, dim_1u64(a->vaddr_range)));
if(a->next != 0) if(a->next != 0)
@@ -8017,7 +8044,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory)
UI_PrefHeight(ui_px(row_height_px, 0.f)) UI_PrefHeight(ui_px(row_height_px, 0.f))
{ {
B32 cursor_in_range = (viz_range_bytes.min <= mv->cursor && mv->cursor+8 <= viz_range_bytes.max); B32 cursor_in_range = (viz_range_bytes.min <= mv->cursor && mv->cursor+8 <= viz_range_bytes.max);
ui_labelf("%016X", mv->cursor); ui_labelf("%016I64X", mv->cursor);
if(cursor_in_range) if(cursor_in_range)
{ {
U64 as_u8 = 0; U64 as_u8 = 0;
@@ -8032,7 +8059,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory)
ui_labelf("%02X (%I64u)", as_u8, as_u8); ui_labelf("%02X (%I64u)", as_u8, as_u8);
ui_labelf("%04X (%I64u)", as_u16, as_u16); ui_labelf("%04X (%I64u)", as_u16, as_u16);
ui_labelf("%08X (%I64u)", as_u32, as_u32); ui_labelf("%08X (%I64u)", as_u32, as_u32);
ui_labelf("%016X (%I64u)", as_u64, as_u64); ui_labelf("%016I64X (%I64u)", as_u64, as_u64);
} }
} }
} }
@@ -8197,7 +8224,7 @@ DF_VIEW_UI_FUNCTION_DEF(Breakpoints)
UI_Parent(box) UI_Parent(box)
{ {
String8 hit_count_string = str8_from_u64(scratch.arena, entity->u64, 10, 0, 0); String8 hit_count_string = str8_from_u64(scratch.arena, entity->u64, 10, 0, 0);
UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, hit_count_string); UI_Font(df_font_from_slot(DF_FontSlot_Code)) df_code_label(1.f, 1, df_rgba_from_theme_color(DF_ThemeColor_CodeDefault), hit_count_string);
} }
UI_Signal sig = ui_signal_from_box(box); UI_Signal sig = ui_signal_from_box(box);
if(sig.pressed) if(sig.pressed)
+3 -3
View File
@@ -942,14 +942,14 @@ eval_irtree_and_type_from_expr(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdb
if (l_good && r_good){ if (l_good && r_good){
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
TG_Type *check_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, check_type_key); TG_MemberArray check_type_members = tg_data_members_from_graph_raddbg_key(scratch.arena, graph, rdbg, check_type_key);
// lookup member // lookup member
String8 member_name = exprr->name; String8 member_name = exprr->name;
TG_Member *match = 0; TG_Member *match = 0;
for(U64 member_idx = 0; member_idx < check_type->count; member_idx += 1) for(U64 member_idx = 0; member_idx < check_type_members.count; member_idx += 1)
{ {
TG_Member *member = &check_type->members[member_idx]; TG_Member *member = &check_type_members.v[member_idx];
if(str8_match(member->name, member_name, 0)) if(str8_match(member->name, member_name, 0))
{ {
match = member; match = member;
+3 -1
View File
@@ -470,7 +470,7 @@ eval_leaf_type_from_name(RADDBG_Parsed *rdbg, String8 name)
U32 *matches = raddbg_matches_from_map_node(rdbg, node, &match_count); U32 *matches = raddbg_matches_from_map_node(rdbg, node, &match_count);
if(match_count != 0) if(match_count != 0)
{ {
U32 type_node_idx = matches[match_count-1]; U32 type_node_idx = matches[0];
if(type_node_idx < rdbg->type_node_count) if(type_node_idx < rdbg->type_node_count)
{ {
RADDBG_TypeNode *type_node = &rdbg->type_nodes[type_node_idx]; RADDBG_TypeNode *type_node = &rdbg->type_nodes[type_node_idx];
@@ -778,6 +778,7 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8
case EVAL_TokenKind_Identifier: case EVAL_TokenKind_Identifier:
{ {
B32 mapped_identifier = 0; B32 mapped_identifier = 0;
B32 identifier_type_is_possibly_dynamically_overridden = 0;
B32 identifier_looks_like_type_expr = 0; B32 identifier_looks_like_type_expr = 0;
RADDBG_LocationKind loc_kind = RADDBG_LocationKind_NULL; RADDBG_LocationKind loc_kind = RADDBG_LocationKind_NULL;
RADDBG_LocationRegister loc_reg = {0}; RADDBG_LocationRegister loc_reg = {0};
@@ -808,6 +809,7 @@ eval_parse_expr_from_text_tokens__prec(Arena *arena, EVAL_ParseCtx *ctx, String8
ctx->rdbg->type_nodes != 0) ctx->rdbg->type_nodes != 0)
{ {
mapped_identifier = 1; mapped_identifier = 1;
identifier_type_is_possibly_dynamically_overridden = 1;
RADDBG_Local *local_var = &ctx->rdbg->locals[local_num-1]; RADDBG_Local *local_var = &ctx->rdbg->locals[local_num-1];
// rjf: grab location info // rjf: grab location info
+48
View File
@@ -0,0 +1,48 @@
#include <stdint.h>
#include <windows.h>
int main(int argc, char **argv)
{
int lib_loaded = 0;
HANDLE lib = {0};
FILETIME lib_last_filetime = {0};
int (*get_number)(void) = 0;
for(;;)
{
//- rjf: hot-load dll
{
HANDLE file = CreateFileA("mule_hotload_module.dll", GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
FILETIME modified = {0};
if(GetFileTime(file, 0, 0, &modified) &&
CompareFileTime(&lib_last_filetime, &modified) == -1)
{
for(int reloaded = 0; !reloaded;)
{
if(lib_loaded)
{
FreeLibrary(lib);
lib_loaded = 0;
}
BOOL copy_worked = CopyFile("mule_hotload_module.dll", "mule_hotload_module_temp.dll", 0);
lib = LoadLibraryA("mule_hotload_module_temp.dll");
if(lib != INVALID_HANDLE_VALUE)
{
reloaded = 1;
lib_last_filetime = modified;
get_number = (int(*)(void))GetProcAddress(lib, "get_number");
lib_loaded = 1;
}
}
}
CloseHandle(file);
}
int number = get_number();
printf("got a number: %i\n", number);
if(number == 0)
{
break;
}
Sleep(1000);
}
return 0;
}
+13
View File
@@ -0,0 +1,13 @@
__declspec(dllexport) int
get_number(void)
{
int sum = 0;
for(int i = 0; i < 100; i += 1)
{
sum += i;
sum += i;
sum += 1;
}
sum = 1000;
return sum;
}
+187 -1
View File
@@ -914,6 +914,18 @@ struct Template_Example3{
} }
}; };
struct SingleInheritanceBase
{
int x;
int y;
};
struct SingleInheritanceDerived : SingleInheritanceBase
{
int z;
int w;
};
struct Has_Members{ struct Has_Members{
int a; int a;
int b; int b;
@@ -1090,6 +1102,86 @@ struct Vinheritance_Child : Vinheritance_MidLeft, Vinheritance_MidRight{
}; };
}; };
struct Minheritance_Base{
int x;
int y;
};
struct Minheritance_MidLeft : Minheritance_Base{
float left;
};
struct Minheritance_MidRight : Minheritance_Base{
float right;
};
struct Minheritance_Child : Minheritance_MidLeft, Minheritance_MidRight{
char *name;
};
struct Pure
{
virtual ~Pure() = default;
virtual void Foo() = 0;
};
struct PureChild : Pure
{
virtual ~PureChild() = default;
virtual void Foo() {a += 1;}
double a = 0;
};
struct Base
{
int x;
int y;
int z;
virtual ~Base() = default;
virtual void Foo() = 0;
};
struct Derived : Base
{
int r;
int g;
int b;
int a;
virtual ~Derived() = default;
virtual void Foo() {a += 1;}
};
struct DerivedA : Base
{
float a;
float b;
virtual void Foo() {a += 1;}
virtual ~DerivedA() = default;
};
struct DerivedB : Base
{
double c;
double d;
virtual void Foo() {c += 1;}
virtual ~DerivedB() = default;
};
struct NonVirtualBase
{
int x;
int y;
int z;
};
struct NonVirtualDerived : NonVirtualBase
{
int r;
int g;
int b;
int a;
};
struct OverloadedMethods{ struct OverloadedMethods{
int x; int x;
int cool_method(void){ int cool_method(void){
@@ -1245,6 +1337,12 @@ extended_type_coverage_eval_tests(void){
Template_Example3<void *, float> temp3_vi((void *)&temp3_if, 1.f); Template_Example3<void *, float> temp3_vi((void *)&temp3_if, 1.f);
Template_Example3<int, Template_Example2<int, float>> temp3_itif(123, temp_if); Template_Example3<int, Template_Example2<int, float>> temp3_itif(123, temp_if);
SingleInheritanceDerived sid;
sid.x = 123;
sid.y = 456;
sid.z = 789;
sid.w = 999;
Pointer_To_Member pointer_to_member = { Pointer_To_Member pointer_to_member = {
&Has_Members::a, &Has_Members::c, &Has_Members::bas, &Has_Members::a, &Has_Members::c, &Has_Members::bas,
&Has_Members::x, &Has_Members::z, &Has_Members::bas_f, &Has_Members::x, &Has_Members::z, &Has_Members::bas_f,
@@ -1279,6 +1377,46 @@ extended_type_coverage_eval_tests(void){
vinheritance_child.x = -1; vinheritance_child.x = -1;
vinheritance_child.y = -1; vinheritance_child.y = -1;
Minheritance_Child minheritance_child;
minheritance_child.name = "foobar";
minheritance_child.left = 10.5f;
minheritance_child.right = 13.0f;
minheritance_child.Minheritance_MidLeft::x = -1;
minheritance_child.Minheritance_MidLeft::y = -1;
minheritance_child.Minheritance_MidRight::x = +1;
minheritance_child.Minheritance_MidRight::y = +1;
Pure *child = new PureChild();
child->Foo();
child->Foo();
child->Foo();
delete child;
Base *derived = new Derived();
derived->Foo();
derived->Foo();
derived->Foo();
delete derived;
NonVirtualBase *non_virtual_derived = new NonVirtualDerived();
non_virtual_derived->x += 1;
non_virtual_derived->x += 1;
non_virtual_derived->x += 1;
delete non_virtual_derived;
Base *base_array[1024] = {0};
for(int i = 0; i < sizeof(base_array)/sizeof(base_array[0]); i += 1)
{
if(i & 1 == 1)
{
base_array[i] = new DerivedA();
}
else
{
base_array[i] = new DerivedB();
}
}
OverloadedMethods overloaded_methods; OverloadedMethods overloaded_methods;
{ {
overloaded_methods.x = 0; overloaded_methods.x = 0;
@@ -1317,7 +1455,53 @@ extended_type_coverage_eval_tests(void){
} }
//////////////////////////////// ////////////////////////////////
// NOTE(allen): C Type Coverage //~ rjf: Templated Function Eval Tests
typedef struct TemplateArg TemplateArg;
struct TemplateArg
{
int x;
int y;
int z;
float a;
float b;
float c;
char *name;
};
template<typename T> static T
templated_factorial(T t)
{
T result = t;
if(t > 1)
{
result *= templated_factorial<T>(t-1);
}
return result;
}
template<typename T> static T
compute_template_arg_info(T t)
{
int sum = t.x + t.y + t.z;
int size = sizeof(t);
float sum_f = t.a + t.b + t.c;
OutputDebugStringA(t.name);
return t;
}
static void
templated_function_eval_tests(void)
{
int int_factorial = templated_factorial<int>(10);
float float_factorial = templated_factorial<float>(10);
TemplateArg arg = {1, 2, 3, 4.f, 5.f, 6.f, "my template arg"};
compute_template_arg_info(arg);
int x = 0;
}
////////////////////////////////
//~ NOTE(allen): C Type Coverage
extern "C"{ extern "C"{
#include "mule_c.h" #include "mule_c.h"
@@ -2343,6 +2527,8 @@ mule_main(int argc, char** argv){
extended_type_coverage_eval_tests(); extended_type_coverage_eval_tests();
templated_function_eval_tests();
c_type_coverage_eval_tests(); c_type_coverage_eval_tests();
c_type_with_bitfield_usage(); c_type_with_bitfield_usage();
+15 -18
View File
@@ -6,19 +6,6 @@
// //
// [ ] ** Thread/process control bullet-proofing, including solo-step mode // [ ] ** Thread/process control bullet-proofing, including solo-step mode
// [ ] ** ASAN targets // [ ] ** ASAN targets
// [ ] ** while typing, "Alt" Windows menu things should not happen
//
// [ ] ** I can't seem to get the .raddbg files to update consistently, or
// something. I can't seem to reproduce it reliably, but sometimes when I
// rebuild, for example, it seems to keep using the old PDB data
// effectively - like it doesn't think it needs to update the raddbg file,
// or something? But if I manually delete the raddbg file and relaunch,
// then it will have the new debug info. It would be nice if there was
// some kind of way to interrogate this in the debugger so I can send a
// more constructive report, like some way to get a hash of the PDB that
// is thinks it has converted to the RAD format, and then a way I can hash
// the PDB on the drive, or something, so I can figure out if they are
// mismatching for sure?
// //
// [ ] ** In solo-stepping mode, if I step over something like CreateFileA, it // [ ] ** In solo-stepping mode, if I step over something like CreateFileA, it
// pseudo-hangs the debugger. I can't seem to do anything else, including // pseudo-hangs the debugger. I can't seem to do anything else, including
@@ -30,10 +17,12 @@
// progress bar in the disassembly window. I had to close and restart. Is // progress bar in the disassembly window. I had to close and restart. Is
// console app debugging not working yet, perhaps? // console app debugging not working yet, perhaps?
// //
// [ ] Setting the code_font/main_font values to a font name doesn't work. // [ ] register value committing in watch
// Should probably make note that you have to set it to a path to a TTF, //
// since that's not normally how Windows fonts work. // [ ] Setting the code_font/main_font values to a font name doesn't work.
// Should probably make note that you have to set it to a path to a TTF,
// since that's not normally how Windows fonts work.
//
// [ ] ** Converter performance & heuristics for asynchronously doing it early // [ ] ** Converter performance & heuristics for asynchronously doing it early
// //
// [ ] disasm animation & go-to-address // [ ] disasm animation & go-to-address
@@ -44,6 +33,8 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) //~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup)
// //
// [ ] ** while typing, "Alt" Windows menu things should not happen
//
// [ ] I was a little confused about what a profile file was. I understood // [ ] I was a little confused about what a profile file was. I understood
// what the user file was, but the profile file sounded like it should // what the user file was, but the profile file sounded like it should
// perhaps be per-project, yet it sounded like it was meant to be somewhat // perhaps be per-project, yet it sounded like it was meant to be somewhat
@@ -202,6 +193,12 @@
//////////////////////////////// ////////////////////////////////
//~ rjf: Hot, Low Priority Tasks (UI Opinions, Less-Serious Jank, Preferences, Cleanup) //~ rjf: Hot, Low Priority Tasks (UI Opinions, Less-Serious Jank, Preferences, Cleanup)
// //
// [ ] ** Directory picking is kind of busted, as it goes through the same
// path as file picking, and this doesn't give the user a clean path to
// actually pick a folder, just navigate with them
//
// [ ] ** Hover-Eval-Popup-While-Scrolling is very annoying!
//
// [ ] ** In the call stack, I would like to be able to click quickly and move // [ ] ** In the call stack, I would like to be able to click quickly and move
// around the stack. Right now, you can do that with the first and third // around the stack. Right now, you can do that with the first and third
// column, but the second column drops down a context menu. Since right // column, but the second column drops down a context menu. Since right
@@ -422,7 +419,7 @@
#define RADDBG_VERSION_MAJOR 0 #define RADDBG_VERSION_MAJOR 0
#define RADDBG_VERSION_MINOR 9 #define RADDBG_VERSION_MINOR 9
#define RADDBG_VERSION_PATCH 1 #define RADDBG_VERSION_PATCH 4
#define RADDBG_VERSION_STRING_LITERAL Stringify(RADDBG_VERSION_MAJOR) "." Stringify(RADDBG_VERSION_MINOR) "." Stringify(RADDBG_VERSION_PATCH) #define RADDBG_VERSION_STRING_LITERAL Stringify(RADDBG_VERSION_MAJOR) "." Stringify(RADDBG_VERSION_MINOR) "." Stringify(RADDBG_VERSION_PATCH)
#if defined(NDEBUG) #if defined(NDEBUG)
# define RADDBG_TITLE_STRING_LITERAL "The RAD Debugger (" RADDBG_VERSION_STRING_LITERAL " ALPHA) - " __DATE__ "" # define RADDBG_TITLE_STRING_LITERAL "The RAD Debugger (" RADDBG_VERSION_STRING_LITERAL " ALPHA) - " __DATE__ ""
+5
View File
@@ -35,6 +35,11 @@ cons_root_new(CONS_RootParams *params){
result->scope_count += 1; result->scope_count += 1;
} }
// rjf: setup null UDT
{
cons__type_udt_from_any_type(result, result->nil_type);
}
// initialize maps // initialize maps
{ {
#define BKTCOUNT(x) ((x)?(u64_up_to_pow2(x)):(128)) #define BKTCOUNT(x) ((x)?(u64_up_to_pow2(x)):(128))
+10 -3
View File
@@ -763,7 +763,13 @@ pdbconv_type_equip_members(PDBCONV_Ctx *ctx, CONS_Type *owner_type, CV_TypeId fi
// discard cases - we don't currently do anything with these // discard cases - we don't currently do anything with these
case CV_LeafKind_VFUNCTAB: case CV_LeafKind_VFUNCTAB:
{}break; {
// TODO(rjf): error if bad range
if(list_item_off + sizeof(CV_LeafVFuncTab) <= cap)
{
list_item_opl_off = list_item_off + sizeof(CV_LeafVFuncTab);
}
}break;
// unhandled or invalid cases // unhandled or invalid cases
default: default:
@@ -1310,6 +1316,7 @@ pdbconv_type_cons_leaf_record(PDBCONV_Ctx *ctx, CV_TypeId itype){
case CV_LeafKind_STRUCTURE: case CV_LeafKind_STRUCTURE:
{ {
ProfBegin("CV_LeafKind_CLASS/CV_LeafKind_STRUCTURE"); ProfBegin("CV_LeafKind_CLASS/CV_LeafKind_STRUCTURE");
// TODO(allen): error if bad range // TODO(allen): error if bad range
if (sizeof(CV_LeafStruct) <= cap){ if (sizeof(CV_LeafStruct) <= cap){
CV_LeafStruct *lf_struct = (CV_LeafStruct*)first; CV_LeafStruct *lf_struct = (CV_LeafStruct*)first;
@@ -2935,7 +2942,7 @@ str8_list_pushf(arena, &out->errors, fmt, __VA_ARGS__);\
if (tpi != 0) ProfScope("parse tpi hash"){ if (tpi != 0) ProfScope("parse tpi hash"){
String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn); String8 hash_data = msf_data_from_stream(msf, tpi->hash_sn);
String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux); String8 aux_data = msf_data_from_stream(msf, tpi->hash_sn_aux);
tpi_hash = pdb_tpi_hash_from_data(arena, tpi, hash_data, aux_data); tpi_hash = pdb_tpi_hash_from_data(arena, strtbl, tpi, hash_data, aux_data);
PARSE_CHECK_ERROR(tpi_hash, "TPI hash table"); PARSE_CHECK_ERROR(tpi_hash, "TPI hash table");
} }
@@ -2954,7 +2961,7 @@ str8_list_pushf(arena, &out->errors, fmt, __VA_ARGS__);\
if (ipi != 0) ProfScope("parse ipi hash"){ if (ipi != 0) ProfScope("parse ipi hash"){
String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn); String8 hash_data = msf_data_from_stream(msf, ipi->hash_sn);
String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux); String8 aux_data = msf_data_from_stream(msf, ipi->hash_sn_aux);
ipi_hash = pdb_tpi_hash_from_data(arena, ipi, hash_data, aux_data); ipi_hash = pdb_tpi_hash_from_data(arena, strtbl, ipi, hash_data, aux_data);
PARSE_CHECK_ERROR(tpi_hash, "IPI hash table"); PARSE_CHECK_ERROR(tpi_hash, "IPI hash table");
} }
+79 -5
View File
@@ -303,7 +303,7 @@ pdb_tpi_from_data(Arena *arena, String8 data){
} }
static PDB_TpiHashParsed* static PDB_TpiHashParsed*
pdb_tpi_hash_from_data(Arena *arena, PDB_TpiParsed *tpi, String8 data, String8 aux_data){ pdb_tpi_hash_from_data(Arena *arena, PDB_Strtbl *strtbl, PDB_TpiParsed *tpi, String8 data, String8 aux_data){
ProfBegin("pdb_tpi_hash_from_data"); ProfBegin("pdb_tpi_hash_from_data");
PDB_TpiHashParsed *result = 0; PDB_TpiHashParsed *result = 0;
@@ -335,7 +335,11 @@ pdb_tpi_hash_from_data(Arena *arena, PDB_TpiParsed *tpi, String8 data, String8 a
block = push_array(arena, PDB_TpiHashBlock, 1); block = push_array(arena, PDB_TpiHashBlock, 1);
SLLStackPush(buckets[bucket_idx], block); SLLStackPush(buckets[bucket_idx], block);
} }
block->itypes[block->local_count] = itype; if(block->local_count != 0)
{
MemoryCopy(block->itypes+1, block->itypes, sizeof(CV_TypeId)*block->local_count);
}
block->itypes[0] = itype;
block->local_count += 1; block->local_count += 1;
} }
@@ -344,15 +348,85 @@ pdb_tpi_hash_from_data(Arena *arena, PDB_TpiParsed *tpi, String8 data, String8 a
itype += 1; itype += 1;
} }
//- rjf: compute bucket mask
U32 bucket_mask = 0;
if(IsPow2OrZero(bucket_count))
{
bucket_mask = bucket_count-1;
}
//- rjf: apply hash adjustments, to pull correct type IDs to the front of
// the chains
if(tpi->hash_adj_size != 0)
{
// NOTE(rjf): this table is laid out in the following format:
//
// pair_count: U32 -> # of name_index/type_index pairs
// slot_count: U32 -> # of slots in this hash table
// present_bit_array_count: U32 -> count for next array
// present_bit_array: U32[present_bit_array_count] -> 1 bit per slot, "is present"
// deleted_bit_array_count: U32 -> count for next array
// deleted_bit_array: U32[deleted_bit_array_count] -> 1 bit per slot, "is deleted"
// (U32, U32)[pair_count] -> array of name_index/type_index pairs
//
U8 *adjs = data.str + tpi->hash_adj_off;
U8 *adjs_opl = adjs + tpi->hash_adj_size;
U8 *adjs_cursor = adjs;
U32 pair_count = *(U32 *)adjs_cursor;
adjs_cursor += sizeof(U32);
U32 slot_count = *(U32 *)adjs_cursor;
adjs_cursor += sizeof(U32);
U32 present_bit_array_count = *(U32 *)adjs_cursor; // skip present_bit_array
adjs_cursor += sizeof(U32);
adjs_cursor += present_bit_array_count*sizeof(U32);
U32 deleted_bit_array_count = *(U32 *)adjs_cursor; // skip deleted_bit_array
adjs_cursor += sizeof(U32);
adjs_cursor += deleted_bit_array_count*sizeof(U32);
U32 adjs_stride = sizeof(U32)*2;
U32 pair_idx = 0;
for(;adjs_cursor < adjs_opl && pair_idx < pair_count;
adjs_cursor += adjs_stride, pair_idx += 1)
{
U32 name_off = ((U32 *)adjs_cursor)[0];
CV_TypeId type_id = ((CV_TypeId *)adjs_cursor)[1];
String8 string = pdb_strtbl_string_from_off(strtbl, name_off);
U32 hash = pdb_string_hash1(string);
U32 bucket_idx = ((bucket_mask != 0) ? hash&bucket_mask : hash%bucket_count);
PDB_TpiHashBlock *prev_block = 0;
for(PDB_TpiHashBlock *block = buckets[bucket_idx];
block != 0;
prev_block = block, block = block->next)
{
for(U32 local_idx = 0;
local_idx < block->local_count && local_idx < ArrayCount(block->itypes);
local_idx += 1)
{
if(block->itypes[local_idx] == type_id)
{
if(prev_block != 0)
{
prev_block->next = block->next;
block->next = buckets[bucket_idx];
buckets[bucket_idx] = block;
}
if(local_idx != 0)
{
Swap(CV_TypeId, block->itypes[0], block->itypes[local_idx]);
}
break;
}
}
}
}
}
// fill result // fill result
result = push_array(arena, PDB_TpiHashParsed, 1); result = push_array(arena, PDB_TpiHashParsed, 1);
result->data = data; result->data = data;
result->aux_data = aux_data; result->aux_data = aux_data;
result->buckets = buckets; result->buckets = buckets;
result->bucket_count = bucket_count; result->bucket_count = bucket_count;
if (IsPow2OrZero(bucket_count)){ result->bucket_mask = bucket_mask;
result->bucket_mask = bucket_count - 1;
}
} }
ProfEnd(); ProfEnd();
+1
View File
@@ -407,6 +407,7 @@ static PDB_Strtbl* pdb_strtbl_from_data(Arena *arena, String8 strtbl_da
static PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 dbi_data); static PDB_DbiParsed* pdb_dbi_from_data(Arena *arena, String8 dbi_data);
static PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 tpi_data); static PDB_TpiParsed* pdb_tpi_from_data(Arena *arena, String8 tpi_data);
static PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena, static PDB_TpiHashParsed* pdb_tpi_hash_from_data(Arena *arena,
PDB_Strtbl *strtbl,
PDB_TpiParsed *tpi, PDB_TpiParsed *tpi,
String8 tpi_hash_data, String8 tpi_hash_data,
String8 tpi_hash_aux_data); String8 tpi_hash_aux_data);
+35 -5
View File
@@ -161,7 +161,19 @@ r_init(CmdLine *cmdln)
feature_levels, ArrayCount(feature_levels), feature_levels, ArrayCount(feature_levels),
D3D11_SDK_VERSION, D3D11_SDK_VERSION,
&r_d3d11_state->base_device, 0, &r_d3d11_state->base_device_ctx); &r_d3d11_state->base_device, 0, &r_d3d11_state->base_device_ctx);
if(!SUCCEEDED(error)) if(FAILED(error) && driver_type == D3D_DRIVER_TYPE_HARDWARE)
{
// try with WARP driver as backup solution in case HW device is not available
error = D3D11CreateDevice(0,
D3D_DRIVER_TYPE_WARP,
0,
creation_flags,
feature_levels, ArrayCount(feature_levels),
D3D11_SDK_VERSION,
&r_d3d11_state->base_device, 0, &r_d3d11_state->base_device_ctx);
}
if(FAILED(error))
{ {
char buffer[256] = {0}; char buffer[256] = {0};
raddbg_snprintf(buffer, sizeof(buffer), "D3D11 device creation failure (%x). The process is terminating.", error); raddbg_snprintf(buffer, sizeof(buffer), "D3D11 device creation failure (%x). The process is terminating.", error);
@@ -307,7 +319,7 @@ r_init(CmdLine *cmdln)
&vshad_source_blob, &vshad_source_blob,
&vshad_source_errors); &vshad_source_errors);
String8 errors = {0}; String8 errors = {0};
if(vshad_source_errors) if(FAILED(error))
{ {
errors = str8((U8 *)vshad_source_errors->GetBufferPointer(), errors = str8((U8 *)vshad_source_errors->GetBufferPointer(),
(U64)vshad_source_errors->GetBufferSize()); (U64)vshad_source_errors->GetBufferSize());
@@ -328,6 +340,8 @@ r_init(CmdLine *cmdln)
vshad_source_blob->GetBufferSize(), vshad_source_blob->GetBufferSize(),
&ilay); &ilay);
} }
vshad_source_blob->Release();
// rjf: store // rjf: store
r_d3d11_state->vshads[kind] = vshad; r_d3d11_state->vshads[kind] = vshad;
@@ -359,7 +373,7 @@ r_init(CmdLine *cmdln)
&pshad_source_blob, &pshad_source_blob,
&pshad_source_errors); &pshad_source_errors);
String8 errors = {0}; String8 errors = {0};
if(pshad_source_errors) if(FAILED(error))
{ {
errors = str8((U8 *)pshad_source_errors->GetBufferPointer(), errors = str8((U8 *)pshad_source_errors->GetBufferPointer(),
(U64)pshad_source_errors->GetBufferSize()); (U64)pshad_source_errors->GetBufferSize());
@@ -370,6 +384,8 @@ r_init(CmdLine *cmdln)
error = r_d3d11_state->device->CreatePixelShader(pshad_source_blob->GetBufferPointer(), pshad_source_blob->GetBufferSize(), 0, &pshad); error = r_d3d11_state->device->CreatePixelShader(pshad_source_blob->GetBufferPointer(), pshad_source_blob->GetBufferSize(), 0, &pshad);
} }
} }
pshad_source_blob->Release();
// rjf: store // rjf: store
r_d3d11_state->pshads[kind] = pshad; r_d3d11_state->pshads[kind] = pshad;
@@ -463,7 +479,14 @@ r_window_equip(OS_Handle handle)
swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; swapchain_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
swapchain_desc.Flags = 0; swapchain_desc.Flags = 0;
} }
r_d3d11_state->dxgi_factory->CreateSwapChainForHwnd(r_d3d11_state->device, hwnd, &swapchain_desc, 0, 0, &window->swapchain); HRESULT error = r_d3d11_state->dxgi_factory->CreateSwapChainForHwnd(r_d3d11_state->device, hwnd, &swapchain_desc, 0, 0, &window->swapchain);
if(FAILED(error))
{
char buffer[256] = {0};
raddbg_snprintf(buffer, sizeof(buffer), "DXGI swap chain creation failure (%x). The process is terminating.", error);
os_graphical_message(1, str8_lit("Fatal Error"), str8_cstring(buffer));
os_exit_process(1);
}
//- rjf: create framebuffer & view //- rjf: create framebuffer & view
window->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&window->framebuffer)); window->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&window->framebuffer));
@@ -971,7 +994,14 @@ r_window_end_frame(OS_Handle window, R_Handle window_equip)
//////////////////////////// ////////////////////////////
//- rjf: present //- rjf: present
// //
wnd->swapchain->Present(1, 0); HRESULT error = wnd->swapchain->Present(1, 0);
if(FAILED(error))
{
char buffer[256] = {0};
raddbg_snprintf(buffer, sizeof(buffer), "D3D11 present failure (%x). The process is terminating.", error);
os_graphical_message(1, str8_lit("Fatal Error"), str8_cstring(buffer));
os_exit_process(1);
}
d_ctx->ClearState(); d_ctx->ClearState();
} }
ProfEnd(); ProfEnd();
+7
View File
@@ -0,0 +1,7 @@
#include <fstream>
int main()
{
std::fstream temp;
return 0;
}
+39 -4
View File
@@ -1,14 +1,49 @@
// Copyright (c) 2024 Epic Games Tools // Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/) // Licensed under the MIT license (https://opensource.org/license/mit/)
#include <stdlib.h> // build with:
// cl /Zi /nologo look_at_raddbg.c
#include <windows.h>
#include <stdint.h>
#include "raddbg_format/raddbg_format.h"
#include "raddbg_format/raddbg_format_parse.h"
#include "raddbg_format/raddbg_format.c"
#include "raddbg_format/raddbg_format_parse.c"
typedef struct Foo Foo;
struct Foo
{
int x;
int y;
int z;
};
int main(int argument_count, char **arguments) int main(int argument_count, char **arguments)
{ {
int *arr = malloc(sizeof(int)*1000); Foo foo = {123, 456, 789};
for(int i = 0; i < 1001; i += 1) HANDLE file = CreateFileA(arguments[1], GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
DWORD size_hi32 = 0;
DWORD size_lo32 = GetFileSize(file, &size_hi32);
HANDLE map = CreateFileMappingA(file, 0, PAGE_READONLY, 0, 0, 0);
uint64_t data_size = (size_lo32 | ((uint64_t)size_hi32 << 32));
uint8_t *data = (uint8_t *)MapViewOfFile(map, FILE_MAP_READ, 0, 0, data_size);
RADDBG_Parsed rdbg = {0};
RADDBG_ParseStatus parse_status = raddbg_parse(data, data_size, &rdbg);
uint64_t foo_count = 0;
for(uint64_t idx = 0; idx < rdbg.type_node_count; idx += 1)
{ {
arr[i] = i; RADDBG_TypeNode *type_node = &rdbg.type_nodes[idx];
if(RADDBG_TypeKind_FirstUserDefined <= type_node->kind && type_node->kind <= RADDBG_TypeKind_LastUserDefined)
{
uint64_t name_size = 0;
uint8_t *name = raddbg_string_from_idx(&rdbg, type_node->user_defined.name_string_idx, &name_size);
if(name_size == 3 && name[0] == 'f' && name[1] == 'o' && name[2] == 'o')
{
foo_count += 1;
}
}
} }
printf("%s -> %I64u foos\n", arguments[1], foo_count);
return 0; return 0;
} }
+9 -2
View File
@@ -1123,7 +1123,7 @@ txti_mut_thread_entry_point(void *p)
U8 *append_data_buffer = push_array_no_zero(buffer->data_arena, U8, msg->string.size); U8 *append_data_buffer = push_array_no_zero(buffer->data_arena, U8, msg->string.size);
MemoryCopy(append_data_buffer, msg->string.str, msg->string.size); MemoryCopy(append_data_buffer, msg->string.str, msg->string.size);
buffer->data.size += msg->string.size; buffer->data.size += msg->string.size;
if(buffer->data.str == 0) if(buffer->data.str == 0 && msg->string.size != 0)
{ {
buffer->data.str = append_data_buffer; buffer->data.str = append_data_buffer;
} }
@@ -1133,7 +1133,14 @@ txti_mut_thread_entry_point(void *p)
case TXTI_MsgKind_Reload: ProfScope("reload") case TXTI_MsgKind_Reload: ProfScope("reload")
{ {
arena_clear(buffer->data_arena); arena_clear(buffer->data_arena);
buffer->data = push_str8_copy(buffer->data_arena, file_contents); if(file_contents.size != 0)
{
buffer->data = push_str8_copy(buffer->data_arena, file_contents);
}
else
{
MemoryZeroStruct(&buffer->data);
}
}break; }break;
} }
+93 -21
View File
@@ -15,6 +15,41 @@ tg_hash_from_string(U64 seed, String8 string)
return result; return result;
} }
internal int
tg_qsort_compare_members_offset(TG_Member *a, TG_Member *b)
{
int result = 0;
if(a->off < b->off)
{
result = -1;
}
else if(a->off > b->off)
{
result = +1;
}
return result;
}
internal void
tg_key_list_push(Arena *arena, TG_KeyList *list, TG_Key key)
{
TG_KeyNode *n = push_array(arena, TG_KeyNode, 1);
n->v = key;
SLLQueuePush(list->first, list->last, n);
list->count += 1;
}
internal TG_KeyList
tg_key_list_copy(Arena *arena, TG_KeyList *src)
{
TG_KeyList dst = {0};
for(TG_KeyNode *n = src->first; n != 0; n = n->next)
{
tg_key_list_push(arena, &dst, n->v);
}
return dst;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: RADDBG <-> TG Enum Conversions //~ rjf: RADDBG <-> TG Enum Conversions
@@ -742,7 +777,7 @@ tg_type_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg
// rjf: commit members // rjf: commit members
type->count = members.count; type->count = members.count;
type->members = push_array_no_zero(arena, TG_Member, 1); type->members = push_array_no_zero(arena, TG_Member, members.count);
U64 idx = 0; U64 idx = 0;
for(TG_MemberNode *n = members.first; n != 0; n = n->next, idx += 1) for(TG_MemberNode *n = members.first; n != 0; n = n->next, idx += 1)
{ {
@@ -912,36 +947,73 @@ tg_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *r
internal TG_MemberArray internal TG_MemberArray
tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key) tg_data_members_from_graph_raddbg_key(Arena *arena, TG_Graph *graph, RADDBG_Parsed *rdbg, TG_Key key)
{ {
TG_MemberArray result = {0};
Temp scratch = scratch_begin(&arena, 1); Temp scratch = scratch_begin(&arena, 1);
TG_MemberList members_list = {0};
B32 members_need_offset_sort = 0;
{ {
TG_Type *type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key); TG_Type *root_type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, key);
if(type->members != 0) typedef struct Task Task;
struct Task
{ {
U64 data_member_count = 0; Task *next;
for(U64 member_idx = 0; member_idx < type->count; member_idx += 1) U64 base_off;
TG_KeyList inheritance_chain;
TG_Key type_key;
TG_Type *type;
};
Task start_task = {0, 0, {0}, key, root_type};
Task *first_task = &start_task;
Task *last_task = &start_task;
for(Task *task = first_task; task != 0; task = task->next)
{
TG_Type *type = task->type;
if(type->members != 0)
{ {
if(type->members[member_idx].kind == TG_MemberKind_DataField) for(U64 member_idx = 0; member_idx < type->count; member_idx += 1)
{ {
data_member_count += 1; if(type->members[member_idx].kind == TG_MemberKind_DataField)
} {
} TG_MemberNode *n = push_array(scratch.arena, TG_MemberNode, 1);
result.count = data_member_count; MemoryCopyStruct(&n->v, &type->members[member_idx]);
result.v = push_array_no_zero(arena, TG_Member, result.count); n->v.off += task->base_off;
U64 idx = 0; n->v.inheritance_key_chain = task->inheritance_chain;
for(U64 member_idx = 0; member_idx < type->count; member_idx += 1) SLLQueuePush(members_list.first, members_list.last, n);
{ members_list.count += 1;
if(type->members[member_idx].kind == TG_MemberKind_DataField) }
{ else if(type->members[member_idx].kind == TG_MemberKind_Base)
MemoryCopyStruct(&result.v[idx], &type->members[member_idx]); {
result.v[idx].name = push_str8_copy(arena, result.v[idx].name); Task *t = push_array(scratch.arena, Task, 1);
idx += 1; t->base_off = type->members[member_idx].off + task->base_off;
t->inheritance_chain = tg_key_list_copy(scratch.arena, &task->inheritance_chain);
tg_key_list_push(scratch.arena, &t->inheritance_chain, type->members[member_idx].type_key);
t->type_key = type->members[member_idx].type_key;
t->type = tg_type_from_graph_raddbg_key(scratch.arena, graph, rdbg, type->members[member_idx].type_key);
SLLQueuePush(first_task, last_task, t);
members_need_offset_sort = 1;
}
} }
} }
} }
} }
TG_MemberArray members = {0};
{
members.count = members_list.count;
members.v = push_array(arena, TG_Member, members.count);
U64 idx = 0;
for(TG_MemberNode *n = members_list.first; n != 0; n = n->next)
{
MemoryCopyStruct(&members.v[idx], &n->v);
members.v[idx].name = push_str8_copy(arena, members.v[idx].name);
members.v[idx].inheritance_key_chain = tg_key_list_copy(arena, &members.v[idx].inheritance_key_chain);
idx += 1;
}
}
if(members_need_offset_sort)
{
qsort(members.v, members.count, sizeof(TG_Member), (int (*)(const void *, const void *))tg_qsort_compare_members_offset);
}
scratch_end(scratch); scratch_end(scratch);
return result; return members;
} }
internal void internal void
+19
View File
@@ -31,6 +31,21 @@ struct TG_Key
U64 u64[1]; // ext -> unique id; cons -> idx; reg -> code U64 u64[1]; // ext -> unique id; cons -> idx; reg -> code
}; };
typedef struct TG_KeyNode TG_KeyNode;
struct TG_KeyNode
{
TG_KeyNode *next;
TG_Key v;
};
typedef struct TG_KeyList TG_KeyList;
struct TG_KeyList
{
TG_KeyNode *first;
TG_KeyNode *last;
U64 count;
};
//////////////////////////////// ////////////////////////////////
//~ rjf: Graph Types //~ rjf: Graph Types
@@ -102,6 +117,7 @@ struct TG_Member
TG_Key type_key; TG_Key type_key;
String8 name; String8 name;
U64 off; U64 off;
TG_KeyList inheritance_key_chain;
}; };
typedef struct TG_MemberNode TG_MemberNode; typedef struct TG_MemberNode TG_MemberNode;
@@ -179,6 +195,9 @@ thread_static Arena *tg_build_arena = 0;
//~ rjf: Basic Helpers //~ rjf: Basic Helpers
internal U64 tg_hash_from_string(U64 seed, String8 string); internal U64 tg_hash_from_string(U64 seed, String8 string);
internal int tg_qsort_compare_members_offset(TG_Member *a, TG_Member *b);
internal void tg_key_list_push(Arena *arena, TG_KeyList *list, TG_Key key);
internal TG_KeyList tg_key_list_copy(Arena *arena, TG_KeyList *src);
//////////////////////////////// ////////////////////////////////
//~ rjf: RADDBG <-> TG Enum Conversions //~ rjf: RADDBG <-> TG Enum Conversions
+4 -4
View File
@@ -118,7 +118,7 @@ ui_nav_eat_action_node(UI_NavActionList *list, UI_NavActionNode *node)
internal B32 internal B32
ui_nav_char_is_code_symbol(U8 c) ui_nav_char_is_code_symbol(U8 c)
{ {
return (char_is_alpha(c) || char_is_digit(c, 10) || c == '_'); return (char_is_alpha(c) || char_is_digit(c, 10) || c == '_');
} }
internal S64 internal S64
@@ -134,7 +134,7 @@ ui_nav_scanned_column_from_column(String8 string, S64 start_column, Side side)
U8 byte = (col <= string.size) ? string.str[col-1] : 0; U8 byte = (col <= string.size) ? string.str[col-1] : 0;
B32 is_non_space = !char_is_space(byte); B32 is_non_space = !char_is_space(byte);
B32 is_name = ui_nav_char_is_code_symbol(byte); B32 is_name = ui_nav_char_is_code_symbol(byte);
if (((side == Side_Min) && (col == 1)) || if (((side == Side_Min) && (col == 1)) ||
((side == Side_Max) && (col == string.size+1)) || ((side == Side_Max) && (col == string.size+1)) ||
(found_non_space && !is_non_space) || (found_non_space && !is_non_space) ||
@@ -143,9 +143,9 @@ ui_nav_scanned_column_from_column(String8 string, S64 start_column, Side side)
new_column = col + (!side && col != 1); new_column = col + (!side && col != 1);
break; break;
} else if (!found_text && is_name) { } else if (!found_text && is_name) {
found_text = 1; found_text = 1;
} else if (!found_non_space && is_non_space ) { } else if (!found_non_space && is_non_space ) {
found_non_space = 1; found_non_space = 1;
} }
} }
return new_column; return new_column;