diff --git a/README.md b/README.md index 13d40cec..0dfe8775 100644 --- a/README.md +++ b/README.md @@ -20,26 +20,20 @@ You can download pre-built binaries for the debugger [here](https://github.com/EpicGames/raddebugger/releases). The RAD Debugger project aims to simplify the debugger by simplifying and -unifying the underlying debug info format. In that pursuit we've built -the RADDBGI debug info format, which is what the debugger parses and uses. To -work with existing toolchains, we convert PDB (and eventually PE/ELF files -with embedded DWARF) into the RADDBGI format on-demand. This conversion process -is currently an unoptimized reference version. Nevertheless it's still quite -fast for smaller PDB files (in many cases faster than many other programs -simply deserialize the PDBs). It is much slower for much larger projects at the -moment, but we expect this will vastly improve overtime. +unifying the underlying debug info format. In that pursuit we've built the RAD +Debug Info (RDI) format, which is what the debugger parses and uses. To work +with existing toolchains, we convert PDB (and eventually PE/ELF files with +embedded DWARF) into the RDI format on-demand. -The RADDBGI format is currently specified in code, in the files within the -`src/lib_raddbgi_format` folder. The other relevant folders for working with -the format are: +The RDI format is currently specified in code, in the files within the +`src/lib_rdi_format` folder. The other relevant folders for working with the +format are: -- `lib_raddbgi_make`: The "RAD Debug Info Make" library, for making RADDBGI - debug info. -- `raddbgi_from_pdb`: Our PDB-to-RADDBGI converter. Can be used as a helper - codebase layer, or built as an executable with a command line interface - frontend. -- `raddbgi_from_dwarf`: Our in-progress DWARF-to-RADDBGI converter. -- `raddbgi_dump`: Our RADDBGI textual dumping utility. +- `lib_rdi_make`: The "RAD Debug Info Make" library, for making RDI debug info. +- `rdi_from_pdb`: Our PDB-to-RDI converter. Can be used as a helper codebase + layer, or built as an executable with a command line interface frontend. +- `rdi_from_dwarf`: Our in-progress DWARF-to-RDI converter. +- `rdi_dump`: Our RDI textual dumping utility. ## Development Setup Instructions @@ -126,18 +120,6 @@ 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-RADDBGI converter is an unoptimized reference implementation, and (b) -the debugger learns of new modules (and thus which PDBs to load) in a -serially-dependent way (this is necessarily the case for correct debugging -results). We expect that the conversion process' performance can be massively -improved, and also that some heuristics can be used to begin converting PDBs -to RADDBGIs before the debugger knows those PDBs are needed, thus ensuring the -associated RADDBGI files are ready instantaneously when the associated modules -are finally loaded by the debugger. Improving this situation is a major part of -this phase, as it will make the debugger much more usable for large projects. - ### Local x64 Linux Debugging Phase The next priority for the project is to take the rock solid x64 Windows @@ -152,11 +134,10 @@ 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-RADDBGI converter (in the same way that we've built a -PDB-to-RADDBGI converter). A partial implementation of this is in -`src/raddbgi_from_dwarf`. +- Implementing an x64 ELF Linux unwinder in the `src/ctrl` layer. +- Creating a DWARF-to-RDI converter (in the same way that we've built a +PDB-to-RDI converter). A partial implementation of this is in +`src/rdi_from_dwarf`. - Porting the `src/render` layer to implement all of the rendering features the frontend needs on a Linux-compatible API (the backend used on Windows is D3D11). - Porting the `src/font_provider` layer to a Linux-compatible font @@ -218,7 +199,7 @@ so in other words, layers are arranged into a directed acyclic graph. A few layers are built to be used completely independently from the rest of the codebase, as libraries in other codebases and projects. As such, these layers do not depend on any other layers in the codebase. The folders which contain these -layers are prefixed with `lib_`, like `lib_raddbgi_format`. +layers are prefixed with `lib_`, like `lib_rdi_format`. A list of the layers in the codebase and their associated namespaces is below: - `base` (no namespace): Universal, codebase-wide constructs. Strings, math, @@ -235,11 +216,11 @@ A list of the layers in the codebase and their associated namespaces is below: - `dasm` (`DASM_`): An asynchronous disassembly decoder and cache. Users ask for disassembly for a particular virtual address range in a process, and threads implemented in this layer decode and cache the disassembly for that range. -- `dbgi` (`DBGI_`): An asynchronous debug info loader and cache. Loads debug - info stored in the RADDBGI format. Users ask for debug info for a particular - executable, and on separate threads, this layer loads the associated debug - info file. If necessary, it will launch a separate conversion process to - convert original debug info into the RADDBGI format. +- `dbgi` (`DI_`): An asynchronous debug info loader and cache. Loads debug info + stored in the RDI format. Users ask for debug info for a particular path, and + on separate threads, this layer loads the associated debug info file. If + necessary, it will launch a separate conversion process to convert original + debug info into the RDI format. - `demon` (`DEMON_`): An abstraction layer for local-machine, low-level process control. The abstraction is used to provide a common interface for process control on target platforms. Used to implement part of `ctrl`. @@ -274,13 +255,13 @@ A list of the layers in the codebase and their associated namespaces is below: - `lib_raddbg_markup` (`RADDBG_`): Standalone library for marking up user programs to work with various features in the `raddbg` debugger. Does not depend on `base`, and can be independently relocated to other codebases. -- `lib_raddbgi_make` (`RDIM_`): Standalone library for constructing RADDBGI - debug info data. Does not depend on `base`, and can be independently relocated +- `lib_rdi_make` (`RDIM_`): Standalone library for constructing RDI debug info + data. Does not depend on `base`, and can be independently relocated to other codebases. -- `lib_raddbgi_format` (`RDI_`): Standalone library which defines the core - RADDBGI types and helper functions for reading and writing the RADDBGI debug - info file format. Does not depend on `base`, and can be independently - relocated to other codebases. +- `lib_rdi_format` (`RDI_`): Standalone library which defines the core RDI types + and helper functions for reading and writing the RDI debug info file format. + Does not depend on `base`, and can be independently relocated to other + codebases. - `metagen` (`MG_`): A metaprogram which is used to generate primarily code and data tables. Consumes Metadesk files, stored with the extension `.mdesk`, and generates C code which is then included by hand-written C code. Currently, it @@ -315,11 +296,11 @@ A list of the layers in the codebase and their associated namespaces is below: - `raddbg` (no namespace): The layer which ties everything together for the main graphical debugger. Not much "meat", just drives `df`, implements command line options, and so on. -- `raddbgi_from_pdb` (`P2R_`): Our implementation of PDB-to-RADDBGI conversion. -- `raddbgi_from_dwarf` (`D2R_`): Our in-progress implementation of - DWARF-to-RADDBGI conversion. -- `raddbgi_dump` (`RADDBGIDUMP_`): A dumper utility program for dumping - textualizations of RADDBGI debug info files. +- `rdi_from_pdb` (`P2R_`): Our implementation of PDB-to-RDI conversion. +- `rdi_from_dwarf` (`D2R_`): Our in-progress implementation of DWARF-to-RDI + conversion. +- `rdi_dump` (no namespace): A dumper utility program for dumping + textualizations of RDI debug info files. - `regs` (`REGS_`): Types, helper functions, and metadata for registers on supported architectures. Used in reading/writing registers in `demon`, or in looking up register metadata. @@ -338,11 +319,9 @@ A list of the layers in the codebase and their associated namespaces is below: Used by the debugger to visualize source code files. Users ask for text lines, tokens, and metadata, and it is prepared on background threads. - `type_graph` (`TG_`): Code for analyzing and navigating type structures from - RADDBGI debug info files, with the additional capability of constructing + RDI debug info files, with the additional capability of constructing synthetic types *not* found in debug info. Used in `eval` and for various visualization features. - `ui` (`UI_`): Machinery for building graphical user interfaces. Provides a core immediate mode hierarchical user interface data structure building API, and has helper layers for building some higher-level widgets. -- `unwind` (`UNW_`): Code for generating unwind information from threads, for - supported operating systems and architectures. diff --git a/build.bat b/build.bat index 348d870e..dd11f047 100644 --- a/build.bat +++ b/build.bat @@ -15,7 +15,7 @@ cd /D "%~dp0" :: `build raddbg clang` :: `build raddbg release` :: `build raddbg asan telemetry` -:: `build raddbgi_from_pdb` +:: `build rdi_from_pdb` :: :: For a full list of possible build targets and their build command lines, :: search for @build_targets in this file. @@ -54,12 +54,14 @@ set clang_out= -o :: --- Per-Build Settings ----------------------------------------------------- set link_dll=-DLL -if "%msvc%"=="1" set only_compile=/c -if "%clang%"=="1" set only_compile=-c -if "%msvc%"=="1" set EHsc=/EHsc -if "%clang%"=="1" set EHsc= -if "%msvc%"=="1" set rc=rc.exe -if "%clang%"=="1" set rc=llvm-rc.exe +if "%msvc%"=="1" set only_compile=/c +if "%clang%"=="1" set only_compile=-c +if "%msvc%"=="1" set EHsc=/EHsc +if "%clang%"=="1" set EHsc= +if "%msvc%"=="1" set no_aslr=/DYNAMICBASE:NO +if "%clang%"=="1" set no_aslr= +if "%msvc%"=="1" set rc=rc.exe +if "%clang%"=="1" set rc=llvm-rc.exe :: --- Choose Compile/Link Lines ---------------------------------------------- if "%msvc%"=="1" set compile_debug=%cl_debug% @@ -97,16 +99,23 @@ if not "%no_meta%"=="1" ( :: --- Build Everything (@build_targets) -------------------------------------- pushd build if "%raddbg%"=="1" %compile% %gfx% ..\src\raddbg\raddbg_main.cpp %compile_link% %out%raddbg.exe || exit /b 1 -if "%raddbgi_from_pdb%"=="1" %compile% ..\src\raddbgi_from_pdb\raddbgi_from_pdb_main.c %compile_link% %out%raddbgi_from_pdb.exe || exit /b 1 -if "%raddbgi_from_dwarf%"=="1" %compile% ..\src\raddbgi_from_dwarf\raddbgi_from_dwarf.c %compile_link% %out%raddbgi_from_dwarf.exe || exit /b 1 -if "%raddbgi_dump%"=="1" %compile% ..\src\raddbgi_dump\raddbgi_dump_main.c %compile_link% %out%raddbgi_dump.exe || exit /b 1 -if "%raddbgi_breakpad_from_pdb%"=="1" %compile% ..\src\raddbgi_breakpad_from_pdb\raddbgi_breakpad_from_pdb_main.c %compile_link% %out%raddbgi_breakpad_from_pdb.exe || exit /b 1 +if "%rdi_from_pdb%"=="1" %compile% ..\src\rdi_from_pdb\rdi_from_pdb_main.c %compile_link% %out%rdi_from_pdb.exe || exit /b 1 +if "%rdi_from_dwarf%"=="1" %compile% ..\src\rdi_from_dwarf\rdi_from_dwarf.c %compile_link% %out%rdi_from_dwarf.exe || exit /b 1 +if "%rdi_dump%"=="1" %compile% ..\src\rdi_dump\rdi_dump_main.c %compile_link% %out%rdi_dump.exe || exit /b 1 +if "%rdi_breakpad_from_pdb%"=="1" %compile% ..\src\rdi_breakpad_from_pdb\rdi_breakpad_from_pdb_main.c %compile_link% %out%rdi_breakpad_from_pdb.exe || exit /b 1 if "%ryan_scratch%"=="1" %compile% ..\src\scratch\ryan_scratch.c %compile_link% %out%ryan_scratch.exe || exit /b 1 if "%cpp_tests%"=="1" %compile% ..\src\scratch\i_hate_c_plus_plus.cpp %compile_link% %out%cpp_tests.exe || exit /b 1 if "%look_at_raddbg%"=="1" %compile% ..\src\scratch\look_at_raddbg.c %compile_link% %out%look_at_raddbg.exe || exit /b 1 -if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %out%mule_main.exe || exit /b 1 +if "%mule_main%"=="1" del vc*.pdb mule*.pdb && %compile_release% %only_compile% ..\src\mule\mule_inline.cpp && %compile_release% %only_compile% ..\src\mule\mule_o2.cpp && %compile_debug% %EHsc% ..\src\mule\mule_main.cpp ..\src\mule\mule_c.c mule_inline.obj mule_o2.obj %compile_link% %no_aslr% %out%mule_main.exe || exit /b 1 if "%mule_module%"=="1" %compile% ..\src\mule\mule_module.cpp %compile_link% %link_dll% %out%mule_module.dll || exit /b 1 if "%mule_hotload%"=="1" %compile% ..\src\mule\mule_hotload_main.c %compile_link% %out%mule_hotload.exe & %compile% ..\src\mule\mule_hotload_module_main.c %compile_link% %link_dll% %out%mule_hotload_module.dll || exit /b 1 +if "%mule_peb_trample%"=="1" ( + if exist mule_peb_trample.exe move mule_peb_trample.exe mule_peb_trample_old_%random%.exe + if exist mule_peb_trample_new.pdb move mule_peb_trample_new.pdb mule_peb_trample_old_%random%.pdb + if exist mule_peb_trample_new.rdi move mule_peb_trample_new.rdi mule_peb_trample_old_%random%.rdi + %compile% ..\src\mule\mule_peb_trample.c %compile_link% %out%mule_peb_trample_new.exe || exit /b 1 + move mule_peb_trample_new.exe mule_peb_trample.exe +) popd :: --- Unset ------------------------------------------------------------------ diff --git a/project.4coder b/project.4coder index 0fb436c2..4b6edfe2 100644 --- a/project.4coder +++ b/project.4coder @@ -56,7 +56,7 @@ commands = }, .rjf_f2 = { - .win = "build raddbgi_from_pdb telemetry release", + .win = "build mule_peb_trample", .linux = "", .out = "*compilation*", .footer_panel = true, @@ -74,7 +74,7 @@ commands = }, .rjf_f4 = { - .win = "build raddbgi_from_pdb release telemetry && pushd build && raddbgi_from_pdb.exe --exe:UnrealEditorFortnite.exe --pdb:UnrealEditorFortnite.pdb --out:UnrealEditorFortnite.raddbgi --capture && popd", + .win = "build rdi_from_pdb release telemetry && pushd build && rdi_from_pdb.exe --exe:UnrealEditorFortnite.exe --pdb:UnrealEditorFortnite.pdb --out:UnrealEditorFortnite.rdi --capture && popd", .linux = "", .out = "*compilation*", .footer_panel = true, @@ -83,7 +83,7 @@ commands = }, .rjf_f5 = { - .win = "pushd build && raddbgi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.raddbg --capture && popd", + .win = "pushd build && rdi_from_pdb.exe --exe:raddbg.exe --pdb:raddbg.pdb --out:raddbg.rdi --capture && popd", .linux = "", .out = "*compilation*", .footer_panel = true, @@ -108,18 +108,18 @@ commands = .save_dirty_files = true, .cursor_at_end = false, }, - .build_raddbgi_from_pdb = + .build_rdi_from_pdb = { - .win = "build raddbgi_from_pdb", + .win = "build rdi_from_pdb", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, - .build_raddbgi_dump = + .build_rdi_dump = { - .win = "build raddbgi_dump", + .win = "build rdi_dump", .linux = "", .out = "*compilation*", .footer_panel = true, diff --git a/src/base/base_command_line.c b/src/base/base_command_line.c index 1bf3312d..2c761583 100644 --- a/src/base/base_command_line.c +++ b/src/base/base_command_line.c @@ -92,6 +92,7 @@ cmd_line_from_string_list(Arena *arena, String8List command_line) // NOTE(rjf): Parse command line. B32 after_passthrough_option = 0; + B32 first_passthrough = 1; for(String8Node *node = command_line.first->next, *next = 0; node != 0; node = next) { next = node->next; @@ -175,10 +176,11 @@ cmd_line_from_string_list(Arena *arena, String8List command_line) // NOTE(rjf): Default path, treat as a passthrough config option to be // handled by tool-specific code. - else if(!str8_match(node->string, str8_lit("--"), 0)) + else if(!str8_match(node->string, str8_lit("--"), 0) || !first_passthrough) { str8_list_push(arena, &parsed.inputs, node->string); after_passthrough_option = 1; + first_passthrough = 0; } } diff --git a/src/base/base_entry_point.c b/src/base/base_entry_point.c index 325d1f83..3c4b9926 100644 --- a/src/base/base_entry_point.c +++ b/src/base/base_entry_point.c @@ -18,59 +18,62 @@ main_thread_base_entry_point(void (*entry_point)(CmdLine *cmdline), char **argum { ProfBeginCapture(arguments[0]); } -#if defined(OS_CORE_H) +#if defined(OS_CORE_H) && !defined(OS_INIT_MANUAL) os_init(); #endif -#if defined(TASK_SYSTEM_H) +#if defined(TASK_SYSTEM_H) && !defined(TS_INIT_MANUAL) ts_init(); #endif -#if defined(HASH_STORE_H) +#if defined(HASH_STORE_H) && !defined(HS_INIT_MANUAL) hs_init(); #endif -#if defined(FILE_STREAM_H) +#if defined(FILE_STREAM_H) && !defined(FS_INIT_MANUAL) fs_init(); #endif -#if defined(TEXT_CACHE_H) +#if defined(TEXT_CACHE_H) && !defined(TXT_INIT_MANUAL) txt_init(); #endif -#if defined(DASM_CACHE_H) +#if defined(DASM_CACHE_H) && !defined(DASM_INIT_MANUAL) dasm_init(); #endif -#if defined(DBGI_H) - dbgi_init(); +#if defined(DI_H) && !defined(DI_INIT_MANUAL) + di_init(); #endif -#if defined(TXTI_H) +#if defined(FUZZY_SEARCH_H) && !defined(FZY_INIT_MANUAL) + fzy_init(); +#endif +#if defined(TXTI_H) && !defined(TXTI_INIT_MANUAL) txti_init(); #endif -#if defined(DEMON_CORE_H) +#if defined(DEMON_CORE_H) && !defined(DMN_INIT_MANUAL) dmn_init(); #endif -#if defined(CTRL_CORE_H) +#if defined(CTRL_CORE_H) && !defined(CTRL_INIT_MANUAL) ctrl_init(); #endif -#if defined(OS_GRAPHICAL_H) +#if defined(OS_GRAPHICAL_H) && !defined(OS_GFX_INIT_MANUAL) os_graphical_init(); #endif -#if defined(FONT_PROVIDER_H) +#if defined(FONT_PROVIDER_H) && !defined(FP_INIT_MANUAL) fp_init(); #endif -#if defined(RENDER_CORE_H) +#if defined(RENDER_CORE_H) && !defined(R_INIT_MANUAL) r_init(&cmdline); #endif -#if defined(TEXTURE_CACHE_H) +#if defined(TEXTURE_CACHE_H) && !defined(TEX_INIT_MANUAL) tex_init(); #endif -#if defined(GEO_CACHE_H) +#if defined(GEO_CACHE_H) && !defined(GEO_INIT_MANUAL) geo_init(); #endif -#if defined(FONT_CACHE_H) +#if defined(FONT_CACHE_H) && !defined(F_INIT_MANUAL) f_init(); #endif -#if defined(DF_CORE_H) +#if defined(DF_CORE_H) && !defined(DF_INIT_MANUAL) DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); df_core_init(&cmdline, hist); #endif -#if defined(DF_GFX_H) +#if defined(DF_GFX_H) && !defined(DF_GFX_INIT_MANUAL) df_gfx_init(update_and_render, df_state_delta_history()); #endif entry_point(&cmdline); diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 625b6485..427ac1d0 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -419,6 +419,7 @@ ctrl_serialized_string_from_event(Arena *arena, CTRL_Event *event) str8_serial_push_struct(scratch.arena, &srl, &event->rip_vaddr); str8_serial_push_struct(scratch.arena, &srl, &event->stack_base); str8_serial_push_struct(scratch.arena, &srl, &event->tls_root); + str8_serial_push_struct(scratch.arena, &srl, &event->timestamp); str8_serial_push_struct(scratch.arena, &srl, &event->exception_code); str8_serial_push_struct(scratch.arena, &srl, &event->string.size); str8_serial_push_data(scratch.arena, &srl, event->string.str, event->string.size); @@ -448,6 +449,7 @@ ctrl_event_from_serialized_string(Arena *arena, String8 string) read_off += str8_deserial_read_struct(string, read_off, &event.rip_vaddr); read_off += str8_deserial_read_struct(string, read_off, &event.stack_base); read_off += str8_deserial_read_struct(string, read_off, &event.tls_root); + read_off += str8_deserial_read_struct(string, read_off, &event.timestamp); read_off += str8_deserial_read_struct(string, read_off, &event.exception_code); read_off += str8_deserial_read_struct(string, read_off, &event.string.size); event.string.str = push_array_no_zero(arena, U8, event.string.size); @@ -481,6 +483,8 @@ ctrl_entity_store_release(CTRL_EntityStore *cache) arena_release(cache->arena); } +//- rjf: string allocation/deletion + internal U64 ctrl_name_bucket_idx_from_string_size(U64 size) { @@ -732,6 +736,23 @@ ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machi return entity; } +internal CTRL_Entity * +ctrl_entity_child_from_kind(CTRL_Entity *parent, CTRL_EntityKind kind) +{ + CTRL_Entity *result = &ctrl_entity_nil; + for(CTRL_Entity *child = parent->first; + child != &ctrl_entity_nil; + child = child->next) + { + if(child->kind == kind) + { + result = child; + break; + } + } + return result; +} + //- rjf: applying events to entity caches internal void @@ -787,16 +808,33 @@ ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list) //- rjf: modules case CTRL_EventKind_NewModule: { + Temp scratch = scratch_begin(0, 0); CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->parent); CTRL_Entity *module = ctrl_entity_alloc(store, process, CTRL_EntityKind_Module, event->arch, event->machine_id, event->entity, event->vaddr_rng.min); ctrl_entity_equip_string(store, module, event->string); + module->timestamp = event->timestamp; + CTRL_Entity *debug_info_path = ctrl_entity_alloc(store, module, CTRL_EntityKind_DebugInfoPath, Architecture_Null, 0, dmn_handle_zero(), 0); + String8 initial_debug_info_path = ctrl_initial_debug_info_path_from_module(scratch.arena, event->machine_id, event->entity); + ctrl_entity_equip_string(store, debug_info_path, initial_debug_info_path); module->vaddr_range = event->vaddr_rng; + debug_info_path->timestamp = module->timestamp; + scratch_end(scratch); }break; case CTRL_EventKind_EndModule: { CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); ctrl_entity_release(store, module); }break; + case CTRL_EventKind_ModuleDebugInfoPathChange: + { + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, event->machine_id, event->entity); + CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + if(debug_info_path == &ctrl_entity_nil) + { + debug_info_path = ctrl_entity_alloc(store, module, CTRL_EntityKind_DebugInfoPath, Architecture_Null, 0, dmn_handle_zero(), 0); + } + ctrl_entity_equip_string(store, debug_info_path, event->string); + }break; } } } @@ -845,6 +883,15 @@ ctrl_init(void) ctrl_state->thread_reg_cache.stripes[idx].arena = arena_alloc(); ctrl_state->thread_reg_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); } + ctrl_state->module_image_info_cache.slots_count = 1024; + ctrl_state->module_image_info_cache.slots = push_array(arena, CTRL_ModuleImageInfoCacheSlot, ctrl_state->module_image_info_cache.slots_count); + ctrl_state->module_image_info_cache.stripes_count = os_logical_core_count(); + ctrl_state->module_image_info_cache.stripes = push_array(arena, CTRL_ModuleImageInfoCacheStripe, ctrl_state->module_image_info_cache.stripes_count); + for(U64 idx = 0; idx < ctrl_state->module_image_info_cache.stripes_count; idx += 1) + { + ctrl_state->module_image_info_cache.stripes[idx].arena = arena_alloc(); + ctrl_state->module_image_info_cache.stripes[idx].rw_mutex = os_rw_mutex_alloc(); + } ctrl_state->u2c_ring_size = KB(64); ctrl_state->u2c_ring_base = push_array_no_zero(arena, U8, ctrl_state->u2c_ring_size); ctrl_state->u2c_ring_mutex = os_mutex_alloc(); @@ -920,6 +967,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { U128 result = {0}; U64 size = dim_1u64(range); + U64 pre_mem_gen = dmn_mem_gen(); if(size != 0) for(;;) { CTRL_ProcessMemoryCache *cache = &ctrl_state->process_memory_cache; @@ -932,7 +980,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle //- rjf: try to read from cache B32 is_good = 0; - B32 is_stale = 0; + B32 is_stale = 1; OS_MutexScopeR(process_stripe->rw_mutex) { for(CTRL_ProcessMemoryCacheNode *n = process_slot->first; n != 0; n = n->next) @@ -947,7 +995,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { result = range_n->hash; is_good = 1; - is_stale = (range_n->mem_gen != dmn_mem_gen()); + is_stale = (range_n->mem_gen != pre_mem_gen); goto read_cache__break_all; } } @@ -1036,7 +1084,6 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle { U64 range_slot_idx = range_hash%n->range_hash_slots_count; CTRL_ProcessMemoryRangeHashSlot *range_slot = &n->range_hash_slots[range_slot_idx]; - B32 range_node_exists = 0; for(CTRL_ProcessMemoryRangeHashNode *range_n = range_slot->first; range_n != 0; range_n = range_n->next) { if(MemoryMatchStruct(&range_n->vaddr_range, &range) && range_n->zero_terminated == zero_terminated) @@ -1053,7 +1100,7 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle //- rjf: out of time? -> exit if(os_now_microseconds() >= endt_us) { - if(is_good && is_stale && out_is_stale) + if(is_stale && out_is_stale) { out_is_stale[0] = 1; } @@ -1066,6 +1113,11 @@ ctrl_stored_hash_from_process_vaddr_range(CTRL_MachineID machine_id, DMN_Handle break; } } + U64 post_mem_gen = dmn_mem_gen(); + if(post_mem_gen != pre_mem_gen && out_is_stale) + { + out_is_stale[0] = 1; + } return result; } @@ -1245,6 +1297,25 @@ ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CT return result; } +internal B32 +ctrl_read_cached_process_memory(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us) +{ + Temp scratch = scratch_begin(0, 0); + U64 needed_size = dim_1u64(range); + CTRL_ProcessMemorySlice slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, machine_id, process, range, endt_us); + B32 good = (slice.data.size >= needed_size && !slice.any_byte_bad); + if(good) + { + MemoryCopy(out, slice.data.str, needed_size); + } + if(slice.stale && is_stale_out) + { + *is_stale_out = 1; + } + scratch_end(scratch); + return good; +} + //- rjf: process memory writing internal B32 @@ -1388,9 +1459,23 @@ ctrl_query_cached_reg_block_from_thread(Arena *arena, CTRL_EntityStore *store, C B32 need_stale = 1; if(node->reg_gen != current_reg_gen && dmn_thread_read_reg_block(thread, result)) { - need_stale = 0; - node->reg_gen = current_reg_gen; - MemoryCopy(node->block, result, reg_block_size); + OS_MutexScopeRWPromote(stripe->rw_mutex) + { + for(CTRL_ThreadRegCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->thread, thread)) + { + node = n; + break; + } + } + if(node != 0) + { + need_stale = 0; + node->reg_gen = current_reg_gen; + MemoryCopy(node->block, result, reg_block_size); + } + } } if(need_stale) { @@ -1429,17 +1514,1034 @@ ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void * return good; } +//////////////////////////////// +//~ rjf: Module Image Info Functions + +//- rjf: cache lookups + +internal PE_IntelPdata * +ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle, U64 voff) +{ + PE_IntelPdata *first_pdata = 0; + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + PE_IntelPdata *pdatas = n->pdatas; + U64 pdatas_count = n->pdatas_count; + if(n->pdatas_count != 0 && voff >= n->pdatas[0].voff_first) + { + // NOTE(rjf): + // + // binary search: + // find max index s.t. pdata_array[index].voff_first <= voff + // we assume (i < j) -> (pdata_array[i].voff_first < pdata_array[j].voff_first) + U64 index = pdatas_count; + U64 min = 0; + U64 opl = pdatas_count; + for(;;) + { + U64 mid = (min + opl)/2; + PE_IntelPdata *pdata = pdatas + mid; + if(voff < pdata->voff_first) + { + opl = mid; + } + else if(pdata->voff_first < voff) + { + min = mid; + } + else + { + index = mid; + break; + } + if(min + 1 >= opl) + { + index = min; + break; + } + } + + // rjf: if we are in range fill result + { + PE_IntelPdata *pdata = pdatas + index; + if(pdata->voff_first <= voff && voff < pdata->voff_one_past_last) + { + first_pdata = push_array(arena, PE_IntelPdata, 1); + MemoryCopyStruct(first_pdata, pdata); + } + } + } + break; + } + } + } + return first_pdata; +} + +internal U64 +ctrl_entry_point_voff_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + U64 result = 0; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = n->entry_point_voff; + break; + } + } + return result; +} + +internal Rng1U64 +ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + Rng1U64 result = {0}; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = n->tls_vaddr_range; + break; + } + } + return result; +} + +internal String8 +ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle) +{ + String8 result = {0}; + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module_handle); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module_handle)) + { + result = push_str8_copy(arena, n->initial_debug_info_path); + break; + } + } + return result; +} + //////////////////////////////// //~ rjf: Unwinding Functions +//- rjf: unwind deep copier + +internal CTRL_Unwind +ctrl_unwind_deep_copy(Arena *arena, Architecture arch, CTRL_Unwind *src) +{ + CTRL_Unwind dst = {0}; + { + dst.flags = src->flags; + dst.frames.count = src->frames.count; + dst.frames.v = push_array(arena, CTRL_UnwindFrame, dst.frames.count); + MemoryCopy(dst.frames.v, src->frames.v, sizeof(dst.frames.v[0])*dst.frames.count); + U64 block_size = regs_block_size_from_architecture(arch); + for(U64 idx = 0; idx < dst.frames.count; idx += 1) + { + dst.frames.v[idx].regs = push_array_no_zero(arena, U8, block_size); + MemoryCopy(dst.frames.v[idx].regs, src->frames.v[idx].regs, block_size); + } + } + return dst; +} + +//- rjf: [x64] + +internal REGS_Reg64 * +ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg) +{ + local_persist REGS_Reg64 dummy = {0}; + REGS_Reg64 *result = &dummy; + switch(gpr_reg) + { + case PE_UnwindGprRegX64_RAX:{result = ®s->rax;}break; + case PE_UnwindGprRegX64_RCX:{result = ®s->rcx;}break; + case PE_UnwindGprRegX64_RDX:{result = ®s->rdx;}break; + case PE_UnwindGprRegX64_RBX:{result = ®s->rbx;}break; + case PE_UnwindGprRegX64_RSP:{result = ®s->rsp;}break; + case PE_UnwindGprRegX64_RBP:{result = ®s->rbp;}break; + case PE_UnwindGprRegX64_RSI:{result = ®s->rsi;}break; + case PE_UnwindGprRegX64_RDI:{result = ®s->rdi;}break; + case PE_UnwindGprRegX64_R8 :{result = ®s->r8 ;}break; + case PE_UnwindGprRegX64_R9 :{result = ®s->r9 ;}break; + case PE_UnwindGprRegX64_R10:{result = ®s->r10;}break; + case PE_UnwindGprRegX64_R11:{result = ®s->r11;}break; + case PE_UnwindGprRegX64_R12:{result = ®s->r12;}break; + case PE_UnwindGprRegX64_R13:{result = ®s->r13;}break; + case PE_UnwindGprRegX64_R14:{result = ®s->r14;}break; + case PE_UnwindGprRegX64_R15:{result = ®s->r15;}break; + } + return result; +} + +internal CTRL_UnwindStepResult +ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process_handle, DMN_Handle module_handle, REGS_RegBlockX64 *regs, U64 endt_us) +{ + B32 is_stale = 0; + B32 is_good = 1; + Temp scratch = scratch_begin(0, 0); + + ////////////////////////////// + //- rjf: unpack parameters + // + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(store, machine_id, module_handle); + CTRL_Entity *process = ctrl_entity_from_machine_id_handle(store, machine_id, process_handle); + U64 rip_voff = regs->rip.u64 - module->vaddr_range.min; + + ////////////////////////////// + //- rjf: rip_voff -> first pdata + // + PE_IntelPdata *first_pdata = ctrl_intel_pdata_from_module_voff(scratch.arena, machine_id, module_handle, rip_voff); + + ////////////////////////////// + //- rjf: pdata -> detect if in epilog + // + B32 has_pdata_and_in_epilog = 0; + if(first_pdata) ProfScope("pdata -> detect if in epilog") + { + // NOTE(allen): There are restrictions placed on how an epilog is allowed + // to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160) + // Here we interpret machine code directly according to the rules + // given there to determine if the code we're looking at looks like an epilog. + + //- rjf: set up parsing state + B32 is_epilog = 0; + B32 keep_parsing = 1; + U64 read_vaddr = regs->rip.u64; + U64 read_vaddr_opl = read_vaddr + 256; + + //- rjf: check first instruction + { + B32 inst_good = 0; + U8 inst[4] = {0}; + if(read_vaddr + sizeof(inst) <= read_vaddr_opl) + { + inst_good = ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(read_vaddr, read_vaddr+sizeof(inst)), &is_stale, inst, endt_us); + inst_good = inst_good && !is_stale; + } + if(!inst_good) + { + keep_parsing = 0; + } + else if((inst[0] & 0xF8) == 0x48) + { + switch(inst[1]) + { + // rjf: add $nnnn,%rsp + case 0x81: + { + if(inst[0] == 0x48 && inst[2] == 0xC4) + { + read_vaddr += 7; + } + else + { + keep_parsing = 0; + } + }break; + + // rjf: add $n,%rsp + case 0x83: + { + if(inst[0] == 0x48 && inst[2] == 0xC4) + { + read_vaddr += 4; + } + else + { + keep_parsing = 0; + } + }break; + + // rjf: lea n(reg),%rsp + case 0x8D: + { + if((inst[0] & 0x06) == 0 && + ((inst[2] >> 3) & 0x07) == 0x04 && + (inst[2] & 0x07) != 0x04) + { + U8 imm_size = (inst[2] >> 6); + + // rjf: 1-byte immediate + if(imm_size == 1) + { + read_vaddr += 4; + } + + // rjf: 4-byte immediate + else if(imm_size == 2) + { + read_vaddr += 7; + } + + // rjf: other case + else + { + keep_parsing = 0; + } + } + else + { + keep_parsing = 0; + } + }break; + } + } + } + + //- rjf: continue parsing instructions + for(;keep_parsing;) + { + // rjf: read next instruction byte + B32 inst_byte_good = 0; + U8 inst_byte = 0; + if(read_vaddr + sizeof(inst_byte) <= read_vaddr_opl) + { + inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + } + if(!inst_byte_good || is_stale) + { + keep_parsing = 0; + } + + // rjf: when (... I don't know ...) rely on the next byte + B32 check_inst_byte_good = inst_byte_good; + U64 check_vaddr = read_vaddr; + U8 check_inst_byte = inst_byte; + if(inst_byte_good && (inst_byte & 0xF0) == 0x40) + { + check_vaddr = read_vaddr + 1; + if(read_vaddr + sizeof(check_inst_byte) <= read_vaddr_opl) + { + check_inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &check_inst_byte, endt_us); + } + if(!check_inst_byte_good || is_stale) + { + keep_parsing = 0; + } + } + + // rjf: check instruction byte + if(check_inst_byte_good) + { + switch(check_inst_byte) + { + // rjf: pop + case 0x58:case 0x59:case 0x5A:case 0x5B: + case 0x5C:case 0x5D:case 0x5E:case 0x5F: + { + read_vaddr = check_vaddr + 1; + }break; + + // rjf: ret + case 0xC2: + case 0xC3: + { + is_epilog = 1; + keep_parsing = 0; + }break; + + // rjf: jmp nnnn + case 0xE9: + { + U64 imm_vaddr = check_vaddr + 1; + S32 imm = 0; + B32 imm_good = 0; + if(read_vaddr + sizeof(imm) <= read_vaddr_opl) + { + imm_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us); + } + if(!imm_good || is_stale) + { + keep_parsing = 0; + } + if(imm_good) + { + U64 next_vaddr = (U64)(imm_vaddr + sizeof(imm) + imm); + U64 next_voff = next_vaddr - module->vaddr_range.min; // TODO(rjf): verify that this offset is from module base vaddr, not section + if(!(first_pdata->voff_first <= next_voff && next_voff < first_pdata->voff_one_past_last)) + { + keep_parsing = 0; + } + else + { + read_vaddr = next_vaddr; + } + } + // TODO(allen): why isn't this just the end of the epilog? + }break; + + // rjf: rep; ret (for amd64 prediction bug) + case 0xF3: + { + U8 next_inst_byte = 0; + B32 next_inst_byte_good = 0; + if(read_vaddr + sizeof(next_inst_byte) <= read_vaddr_opl) + { + next_inst_byte_good = ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &next_inst_byte, endt_us); + } + if(next_inst_byte_good) + { + is_epilog = (next_inst_byte == 0xC3); + } + keep_parsing = 0; + }break; + + default:{keep_parsing = 0;}break; + } + } + } + has_pdata_and_in_epilog = is_epilog; + } + + ////////////////////////////// + //- rjf: pdata & in epilog -> epilog unwind + // + if(first_pdata && has_pdata_and_in_epilog) ProfScope("pdata & in epilog -> epilog unwind") + { + U64 read_vaddr = regs->rip.u64; + for(B32 keep_parsing = 1;keep_parsing != 0;) + { + //- rjf: assume no more parsing after this instruction + keep_parsing = 0; + + //- rjf: read next instruction byte + U8 inst_byte = 0; + is_good = is_good && ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + is_good = is_good && !is_stale; + read_vaddr += 1; + + //- rjf: extract rex from instruction byte + U8 rex = 0; + if((inst_byte & 0xF0) == 0x40) + { + rex = inst_byte & 0xF; // rex prefix + is_good = is_good && ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &inst_byte, endt_us); + is_good = is_good && !is_stale; + read_vaddr += 1; + } + + //- rjf: parse remainder of instruction + switch(inst_byte) + { + // rjf: pop + case 0x58: + case 0x59: + case 0x5A: + case 0x5B: + case 0x5C: + case 0x5D: + case 0x5E: + case 0x5F: + { + // rjf: read value at rsp + U64 sp = regs->rsp.u64; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &value, endt_us) || + is_stale) + { + is_good = 0; + break; + } + + // rjf: modify registers + PE_UnwindGprRegX64 gpr_reg = (inst_byte - 0x58) + (rex & 1)*8; + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, gpr_reg); + reg->u64 = value; + regs->rsp.u64 = sp + 8; + + // rjf: not a final instruction, so keep mparsing + keep_parsing = 1; + }break; + + // rjf: add $nnnn,%rsp + case 0x81: + { + // rjf: skip one byte (we already know what it is in this scenario) + read_vaddr += 1; + + // rjf: read the 4-byte immediate + S32 imm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) + { + is_good = 0; + break; + } + read_vaddr += 4; + + // rjf: update stack pointer + regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); + + // rjf: not a final instruction; keep parsing + keep_parsing = 1; + }break; + + // rjf: add $n,%rsp + case 0x83: + { + // rjf: skip one byte (we already know what it is in this scenario) + read_vaddr += 1; + + // rjf: read the 4-byte immediate + S8 imm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) + { + is_good = 0; + break; + } + read_vaddr += 1; + + // rjf: update stack pointer + regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); + + // rjf: not a final instruction; keep parsing + keep_parsing = 1; + }break; + + // rjf: lea imm8/imm32,$rsp + case 0x8D: + { + // rjf: read source register + U8 modrm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &modrm, endt_us) || + is_stale) + { + is_good = 0; + break; + } + read_vaddr += 1; + PE_UnwindGprRegX64 gpr_reg = (modrm & 7) + (rex & 1)*8; + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, gpr_reg); + U64 reg_value = reg->u64; + + // rjf: read immediate + S32 imm = 0; + { + // rjf: read 1-byte immediate + if((modrm >> 6) == 1) + { + S8 imm8 = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm8, endt_us) || + is_stale) + { + is_good = 0; + break; + } + read_vaddr += 1; + imm = (S32)imm8; + } + + // rjf: read 4-byte immediate + else + { + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) + { + is_good = 0; + break; + } + read_vaddr += 4; + } + } + + // rjf: update stack pointer + regs->rsp.u64 = (U64)(reg_value + imm); + + // rjf: not a final instruction; keep parsing + keep_parsing = 1; + }break; + + // rjf: ret $nn + case 0xC2: + { + // rjf: read new ip + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us) || + is_stale) + { + is_good = 0; + break; + } + + // rjf: read 2-byte immediate & advance stack pointer + U16 imm = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, read_vaddr, &is_stale, &imm, endt_us) || + is_stale) + { + is_good = 0; + break; + } + U64 new_sp = sp + 8 + imm; + + // rjf: commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + }break; + + // rjf: ret / rep; ret + case 0xF3: + { + // Assert(!"Hit me!"); + }break; + case 0xC3: + { + // rjf: read new ip + U64 sp = regs->rsp.u64; + U64 new_ip = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp, &is_stale, &new_ip, endt_us) || + is_stale) + { + is_good = 0; + break; + } + + // rjf: advance stack pointer + U64 new_sp = sp + 8; + + // rjf: commit registers + regs->rip.u64 = new_ip; + regs->rsp.u64 = new_sp; + }break; + + // rjf: jmp nnnn + case 0xE9: + { + // Assert(!"Hit Me"); + // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done + // we don't have any cases to exercise this right now. no guess implementation! + }break; + + // rjf: Sjmp n + case 0xEB: + { + // Assert(!"Hit Me"); + // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done + // we don't have any cases to exercise this right now. no guess implementation! + }break; + } + } + } + + ////////////////////////////// + //- rjf: pdata & not in epilog -> xdata unwind + // + B32 xdata_unwind_did_machframe = 0; + if(first_pdata && !has_pdata_and_in_epilog) ProfScope("pdata & not in epilog -> xdata unwind") + { + //- rjf: get frame reg + B32 bad_frame_reg_info = 0; + REGS_Reg64 *frame_reg = 0; + U64 frame_off = 0; + { + U64 unwind_info_off = first_pdata->voff_unwind_info; + PE_UnwindInfo unwind_info = {0}; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us) || + is_stale) + { + is_good = 0; + } + U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info.frame); + U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info.frame); + if(frame_reg_id != 0) + { + frame_reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, frame_reg_id); + bad_frame_reg_info = (frame_reg == 0); // NOTE(rjf): frame_reg should never be 0 at this point, in valid exe + } + frame_off = frame_off_val; + } + + //- rjf: iterate pdatas, apply opcodes + PE_IntelPdata *last_pdata = 0; + PE_IntelPdata *pdata = first_pdata; + if(!bad_frame_reg_info) for(B32 keep_parsing = 1; keep_parsing && pdata != last_pdata;) + { + //- rjf: unpack unwind info & codes + B32 good_unwind_info = 1; + U64 unwind_info_off = pdata->voff_unwind_info; + PE_UnwindInfo unwind_info = {0}; + good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+unwind_info_off, &is_stale, &unwind_info, endt_us); + PE_UnwindCode *unwind_codes = push_array(scratch.arena, PE_UnwindCode, unwind_info.codes_num); + good_unwind_info = good_unwind_info && ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(module->vaddr_range.min+unwind_info_off+sizeof(unwind_info), + module->vaddr_range.min+unwind_info_off+sizeof(unwind_info)+sizeof(PE_UnwindCode)*unwind_info.codes_num), + &is_stale, unwind_codes, endt_us); + good_unwind_info = good_unwind_info && !is_stale; + + //- rjf: bad unwind info -> abort + if(!good_unwind_info) + { + is_good = 0; + break; + } + + //- rjf: unpack frame base + U64 frame_base = regs->rsp.u64; + if(frame_reg != 0) + { + U64 raw_frame_base = frame_reg->u64; + U64 adjusted_frame_base = raw_frame_base - frame_off*16; + if(adjusted_frame_base < raw_frame_base) + { + frame_base = adjusted_frame_base; + } + } + + //- rjf: apply opcodes + PE_UnwindCode *code_ptr = unwind_codes; + PE_UnwindCode *code_opl = unwind_codes + unwind_info.codes_num; + for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) + { + // rjf: unpack opcode info + U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); + U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); + U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); + if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) + { + slot_count += 1; + } + + // rjf: detect bad slot counts + if(slot_count == 0 || code_ptr+slot_count > code_opl) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: set next op code pointer + next_code_ptr = code_ptr + slot_count; + + // rjf: interpret this op code + U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; + if(code_voff <= rip_voff) + { + switch(op_code) + { + case PE_UnwindOpCode_PUSH_NONVOL: + { + // rjf: read value from stack pointer + U64 rsp = regs->rsp.u64; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &value, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: advance stack ptr + U64 new_rsp = rsp + 8; + + // rjf: commit registers + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, op_info); + reg->u64 = value; + regs->rsp.u64 = new_rsp; + }break; + + case PE_UnwindOpCode_ALLOC_LARGE: + { + // rjf: read alloc size + U64 size = 0; + if(op_info == 0) + { + size = code_ptr[1].u16*8; + } + else if(op_info == 1) + { + size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + } + else + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: advance stack pointer + U64 rsp = regs->rsp.u64; + U64 new_rsp = rsp + size; + + // rjf: advance stack pointer + regs->rsp.u64 = new_rsp; + }break; + + case PE_UnwindOpCode_ALLOC_SMALL: + { + // rjf: advance stack pointer + regs->rsp.u64 += op_info*8 + 8; + }break; + + case PE_UnwindOpCode_SET_FPREG: + { + // rjf: put stack pointer back to the frame base + regs->rsp.u64 = frame_base; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL: + { + // rjf: read value from frame base + U64 off = code_ptr[1].u16*8; + U64 addr = frame_base + off; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: commit to register + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_SAVE_NONVOL_FAR: + { + // rjf: read value from frame base + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + U64 value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, addr, &is_stale, &value, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: commit to register + REGS_Reg64 *reg = ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(regs, op_info); + reg->u64 = value; + }break; + + case PE_UnwindOpCode_EPILOG: + { + keep_parsing = 0; + is_good = 0; + }break; + + case PE_UnwindOpCode_SPARE_CODE: + { + // TODO(rjf): ??? + keep_parsing = 0; + is_good = 0; + }break; + + case PE_UnwindOpCode_SAVE_XMM128: + { + // rjf: read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16*16; + U64 addr = frame_base + off; + if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+sizeof(buf)), &is_stale, buf, endt_us)) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_SAVE_XMM128_FAR: + { + // rjf: read new register values + U8 buf[16]; + U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); + U64 addr = frame_base + off; + if(!ctrl_read_cached_process_memory(machine_id, process->handle, r1u64(addr, addr+16), &is_stale, buf, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: commit to register + void *xmm_reg = (®s->ymm0) + op_info; + MemoryCopy(xmm_reg, buf, sizeof(buf)); + }break; + + case PE_UnwindOpCode_PUSH_MACHFRAME: + { + // NOTE(rjf): this was found by stepping through kernel code after an exception was + // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main + if(op_info > 1) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: read values + U64 sp_og = regs->rsp.u64; + U64 sp_adj = sp_og; + if(op_info == 1) + { + sp_adj += 8; + } + U64 ip_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_adj, &is_stale, &ip_value, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + U64 sp_after_ip = sp_adj + 8; + U16 ss_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ip, &is_stale, &ss_value, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + U64 sp_after_ss = sp_after_ip + 8; + U64 rflags_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_ss, &is_stale, &rflags_value, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + U64 sp_after_rflags = sp_after_ss + 8; + U64 sp_value = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, sp_after_rflags, &is_stale, &sp_value, endt_us) || + is_stale) + { + keep_parsing = 0; + is_good = 0; + break; + } + + // rjf: commit registers + regs->rip.u64 = ip_value; + regs->ss.u16 = ss_value; + regs->rflags.u64 = rflags_value; + regs->rsp.u64 = sp_value; + + // rjf: mark machine frame + xdata_unwind_did_machframe = 1; + }break; + } + } + } + + //- rjf: iterate to next pdata + if(keep_parsing) + { + U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info.header); + if(!(flags & PE_UnwindInfoFlag_CHAINED)) + { + break; + } + U64 code_count_rounded = AlignPow2(unwind_info.codes_num, sizeof(PE_UnwindCode)); + U64 code_size = code_count_rounded*sizeof(PE_UnwindCode); + U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; + last_pdata = pdata; + pdata = push_array(scratch.arena, PE_IntelPdata, 1); + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, module->vaddr_range.min+chained_pdata_off, &is_stale, pdata, endt_us) || + is_stale) + { + is_good = 0; + break; + } + } + } + } + + ////////////////////////////// + //- rjf: no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer + // + if(!first_pdata || (!has_pdata_and_in_epilog && !xdata_unwind_did_machframe)) ProfScope("no pdata, or didn't do machframe in xdata unwind -> unwind by reading stack pointer") + { + // rjf: read rip from stack pointer + U64 rsp = regs->rsp.u64; + U64 new_rip = 0; + if(!ctrl_read_cached_process_memory_struct(machine_id, process->handle, rsp, &is_stale, &new_rip, endt_us) || + is_stale) + { + is_good = 0; + } + + // rjf: commit registers + if(is_good) + { + U64 new_rsp = rsp + 8; + regs->rip.u64 = new_rip; + regs->rsp.u64 = new_rsp; + } + } + + ////////////////////////////// + //- rjf: fill & return + // + scratch_end(scratch); + CTRL_UnwindStepResult result = {0}; + if(!is_good) {result.flags |= CTRL_UnwindFlag_Error;} + if(is_stale) {result.flags |= CTRL_UnwindFlag_Stale;} + return result; +} + +//- rjf: abstracted unwind step + +internal CTRL_UnwindStepResult +ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us) +{ + CTRL_UnwindStepResult result = {0}; + switch(arch) + { + default:{}break; + case Architecture_x64: + { + result = ctrl_unwind_step__pe_x64(store, machine_id, process, module, (REGS_RegBlockX64 *)reg_block, endt_us); + }break; + } + return result; +} + +//- rjf: abstracted full unwind + internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); CTRL_Unwind unwind = {0}; - unwind.error = 1; + unwind.flags |= CTRL_UnwindFlag_Error; //- rjf: unpack args CTRL_Entity *thread_entity = ctrl_entity_from_machine_id_handle(store, machine_id, thread); @@ -1448,52 +2550,26 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma U64 arch_reg_block_size = regs_block_size_from_architecture(arch); //- rjf: grab initial register block - void *regs_block = push_array(scratch.arena, U8, arch_reg_block_size); - B32 regs_block_good = dmn_thread_read_reg_block(thread, regs_block); - - //- rjf: grab initial memory view - B32 stack_memview_good = 0; - UNW_MemView stack_memview = {0}; - { - U64 stack_base_unrounded = dmn_stack_base_vaddr_from_thread(thread); - U64 stack_top_unrounded = regs_rsp_from_arch_block(arch, regs_block); - U64 stack_base = AlignPow2(stack_base_unrounded, KB(4)); - U64 stack_top = AlignDownPow2(stack_top_unrounded, KB(4)); - U64 stack_size = stack_base - stack_top; - if(stack_base >= stack_top) - { - U8 *stack_memory_base = push_array(scratch.arena, U8, stack_size); - U64 actual_stack_bytes_read = dmn_process_read(process_entity->handle, r1u64(stack_top, stack_top+stack_size), stack_memory_base); - String8 stack_memory = str8(stack_memory_base, actual_stack_bytes_read); - if(stack_memory.size >= stack_size) - { - stack_memview_good = 1; - stack_memview.data = stack_memory.str; - stack_memview.addr_first = stack_top; - stack_memview.addr_opl = stack_base; - } - } - } + void *regs_block = ctrl_query_cached_reg_block_from_thread(scratch.arena, store, machine_id, thread); + B32 regs_block_good = (arch != Architecture_Null && regs_block != 0); //- rjf: loop & unwind - UNW_MemView memview = stack_memview; - if(regs_block_good && stack_memview_good) + CTRL_UnwindFrameNode *first_frame_node = 0; + CTRL_UnwindFrameNode *last_frame_node = 0; + U64 frame_node_count = 0; + if(regs_block_good) { - unwind.error = 0; + unwind.flags = 0; for(;;) { // rjf: regs -> rip*module U64 rip = regs_rip_from_arch_block(arch, regs_block); DMN_Handle module = {0}; - String8 module_name = {0}; - Rng1U64 module_vaddr_range = {0}; for(CTRL_Entity *m = process_entity->first; m != &ctrl_entity_nil; m = m->next) { if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, rip)) { module = m->handle; - module_name = m->string; - module_vaddr_range = m->vaddr_range; break; } } @@ -1504,55 +2580,37 @@ ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID ma break; } - // rjf: module -> all the binary info - String8 binary_full_path = module_name; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_full_path, 0); - String8 binary_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - - // rjf: cancel on bad data - if(binary_data.size == 0) - { - unwind.error = 1; - break; - } - // rjf: valid step -> push frame - CTRL_UnwindFrame *frame = push_array(arena, CTRL_UnwindFrame, 1); - frame->rip = rip; + CTRL_UnwindFrameNode *frame_node = push_array(scratch.arena, CTRL_UnwindFrameNode, 1); + CTRL_UnwindFrame *frame = &frame_node->v; frame->regs = push_array_no_zero(arena, U8, arch_reg_block_size); MemoryCopy(frame->regs, regs_block, arch_reg_block_size); - DLLPushBack(unwind.first, unwind.last, frame); - unwind.count += 1; + DLLPushBack(first_frame_node, last_frame_node, frame_node); + frame_node_count += 1; // rjf: unwind one step - UNW_Step unwind_step = {0}; - switch(arch) - { - default:{unwind_step.dead = 1;}break; - case Architecture_x64: - { - unwind_step = unw_unwind_pe_x64(binary_data, &dbgi->pe, module_vaddr_range.min, &memview, (REGS_RegBlockX64 *)regs_block); - }break; - } - - // rjf: cancel on bad step - if(unwind_step.dead != 0) - { - break; - } - if(unwind_step.missed_read != 0) - { - unwind.error = 1; - break; - } - if(unwind_step.stack_pointer == 0) + CTRL_UnwindStepResult step = ctrl_unwind_step(store, machine_id, process_entity->handle, module, arch, regs_block, endt_us); + unwind.flags |= step.flags; + if(step.flags & CTRL_UnwindFlag_Error || + regs_rsp_from_arch_block(arch, regs_block) == 0 || + regs_rip_from_arch_block(arch, regs_block) == 0) { break; } } } - dbgi_scope_close(scope); + //- rjf: bake frames list into result array + { + unwind.frames.count = frame_node_count; + unwind.frames.v = push_array(arena, CTRL_UnwindFrame, unwind.frames.count); + U64 idx = 0; + for(CTRL_UnwindFrameNode *n = first_frame_node; n != 0; n = n->next, idx += 1) + { + unwind.frames.v[idx] = n->v; + } + } + scratch_end(scratch); ProfEnd(); return unwind; @@ -1792,6 +2850,24 @@ ctrl_thread__entry_point(void *p) str8_list_push(ctrl_state->user_entry_point_arena, &ctrl_state->user_entry_points, n->string); } }break; + case CTRL_MsgKind_SetModuleDebugInfoPath: + { + String8 path = msg->path; + CTRL_Entity *module = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, msg->machine_id, msg->entity); + CTRL_Entity *debug_info_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + DI_Key old_dbgi_key = {debug_info_path->string, module->timestamp}; + di_close(&old_dbgi_key); + ctrl_entity_equip_string(ctrl_state->ctrl_thread_entity_store, debug_info_path, path); + DI_Key new_dbgi_key = {debug_info_path->string, module->timestamp}; + di_open(&new_dbgi_key); + CTRL_EventList evts = {0}; + CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts); + evt->kind = CTRL_EventKind_ModuleDebugInfoPathChange; + evt->machine_id = msg->machine_id; + evt->entity = msg->entity; + evt->string = path; + ctrl_c2u_push_events(&evts); + }break; } } } @@ -1819,11 +2895,11 @@ internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out) { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); CTRL_Entity *module_entity = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); - String8 exe_path = module_entity->string; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + CTRL_Entity *debug_info_path_entity = ctrl_entity_child_from_kind(module_entity, CTRL_EntityKind_DebugInfoPath); + DI_Key dbgi_key = {debug_info_path_entity->string, debug_info_path_entity->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); U64 base_vaddr = module_entity->vaddr_range.min; for(CTRL_UserBreakpointNode *n = user_bps->first; n != 0; n = n->next) { @@ -1912,7 +2988,7 @@ ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID m }break; } } - dbgi_scope_close(scope); + di_scope_close(di_scope); scratch_end(scratch); } @@ -1930,6 +3006,329 @@ ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID } } +//- rjf: module lifetime open/close work + +internal void +ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path, U64 exe_timestamp) +{ + ////////////////////////////// + //- rjf: parse module image info + // + Arena *arena = arena_alloc(); + PE_IntelPdata *pdatas = 0; + U64 pdatas_count = 0; + U64 entry_point_voff = 0; + Rng1U64 tls_vaddr_range = {0}; + String8 builtin_debug_info_path = {0}; + ProfScope("unpack relevant PE info") + { + B32 is_valid = 1; + + //- rjf: read DOS header + PE_DosHeader dos_header = {0}; + if(is_valid) + { + if(!dmn_process_read_struct(process, vaddr_range.min, &dos_header) || + dos_header.magic != PE_DOS_MAGIC) + { + is_valid = 0; + } + } + + //- rjf: read PE magic + U32 pe_magic = 0; + if(is_valid) + { + if(!dmn_process_read_struct(process, vaddr_range.min + dos_header.coff_file_offset, &pe_magic) || + pe_magic != PE_MAGIC) + { + is_valid = 0; + } + } + + //- rjf: read COFF header + U64 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); + COFF_Header coff_header = {0}; + if(is_valid) + { + if(!dmn_process_read_struct(process, vaddr_range.min + coff_header_off, &coff_header)) + { + is_valid = 0; + } + } + + //- rjf: unpack range of optional extension header + U32 opt_ext_size = coff_header.optional_header_size; + Rng1U64 opt_ext_off_range = r1u64(coff_header_off + sizeof(coff_header), + coff_header_off + sizeof(coff_header) + opt_ext_size); + + //- rjf: read optional header + U16 optional_magic = 0; + U64 image_base = 0; + U64 entry_point = 0; + U32 data_dir_count = 0; + U64 virt_section_align = 0; + U64 file_section_align = 0; + Rng1U64 *data_dir_franges = 0; + if(opt_ext_size > 0) + { + // rjf: read magic number + U16 opt_ext_magic = 0; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &opt_ext_magic); + + // rjf: read info + U32 reported_data_dir_offset = 0; + U32 reported_data_dir_count = 0; + switch(opt_ext_magic) + { + case PE_PE32_MAGIC: + { + PE_OptionalHeader32 pe_optional = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &pe_optional); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + case PE_PE32PLUS_MAGIC: + { + PE_OptionalHeader32Plus pe_optional = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &pe_optional); + image_base = pe_optional.image_base; + entry_point = pe_optional.entry_point_va; + virt_section_align = pe_optional.section_alignment; + file_section_align = pe_optional.file_alignment; + reported_data_dir_offset = sizeof(pe_optional); + reported_data_dir_count = pe_optional.data_dir_count; + }break; + } + + // rjf: find number of data directories + U32 data_dir_max = (opt_ext_size - reported_data_dir_offset) / sizeof(PE_DataDirectory); + data_dir_count = ClampTop(reported_data_dir_count, data_dir_max); + + // rjf: grab pdatas from exceptions section + if(data_dir_count > PE_DataDirectoryIndex_EXCEPTIONS) + { + PE_DataDirectory dir = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_EXCEPTIONS, &dir); + Rng1U64 pdatas_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); + pdatas_count = dim_1u64(pdatas_voff_range)/sizeof(PE_IntelPdata); + pdatas = push_array(arena, PE_IntelPdata, pdatas_count); + dmn_process_read(process, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), pdatas); + } + + // rjf: extract tls header + PE_TLSHeader64 tls_header = {0}; + if(data_dir_count > PE_DataDirectoryIndex_TLS) + { + PE_DataDirectory dir = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, &dir); + Rng1U64 tls_voff_range = r1u64((U64)dir.virt_off, (U64)dir.virt_off + (U64)dir.virt_size); + switch(coff_header.machine) + { + default:{}break; + case COFF_MachineType_X86: + { + PE_TLSHeader32 tls_header32 = {0}; + dmn_process_read_struct(process, vaddr_range.min + tls_voff_range.min, &tls_header32); + tls_header.raw_data_start = (U64)tls_header32.raw_data_start; + tls_header.raw_data_end = (U64)tls_header32.raw_data_end; + tls_header.index_address = (U64)tls_header32.index_address; + tls_header.callbacks_address = (U64)tls_header32.callbacks_address; + tls_header.zero_fill_size = (U64)tls_header32.zero_fill_size; + tls_header.characteristics = (U64)tls_header32.characteristics; + }break; + case COFF_MachineType_X64: + { + dmn_process_read_struct(process, vaddr_range.min + tls_voff_range.min, &tls_header); + }break; + } + } + + // rjf: grab entry point vaddr + entry_point_voff = entry_point; + + // rjf: calculate TLS vaddr range + tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32)); + + // rjf: grab data about debug info + U32 dbg_time = 0; + U32 dbg_age = 0; + OS_Guid dbg_guid = {0}; + if(data_dir_count > PE_DataDirectoryIndex_DEBUG) + { + // rjf: read data dir + PE_DataDirectory dir = {0}; + dmn_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DEBUG, &dir); + + // rjf: read debug directory + PE_DebugDirectory dbg_data = {0}; + dmn_process_read_struct(process, vaddr_range.min+(U64)dir.virt_off, &dbg_data); + + // rjf: extract external file info from codeview header + if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW) + { + U64 dbg_path_off = 0; + U64 dbg_path_size = 0; + U64 cv_offset = dbg_data.voff; + U32 cv_magic = 0; + dmn_process_read_struct(process, vaddr_range.min+cv_offset, &cv_magic); + switch(cv_magic) + { + default:break; + case PE_CODEVIEW_PDB20_MAGIC: + { + PE_CvHeaderPDB20 cv = {0}; + dmn_process_read_struct(process, vaddr_range.min+cv_offset, &cv); + dbg_time = cv.time; + dbg_age = cv.age; + dbg_path_off = cv_offset + sizeof(cv); + }break; + case PE_CODEVIEW_PDB70_MAGIC: + { + PE_CvHeaderPDB70 cv = {0}; + dmn_process_read_struct(process, vaddr_range.min+cv_offset, &cv); + dbg_guid = cv.guid; + dbg_age = cv.age; + dbg_path_off = cv_offset + sizeof(cv); + }break; + } + if(dbg_path_off > 0) + { + Temp scratch = scratch_begin(0, 0); + String8List parts = {0}; + for(U64 off = dbg_path_off;; off += 256) + { + U8 bytes[256] = {0}; + dmn_process_read(process, r1u64(vaddr_range.min+off, vaddr_range.min+off+sizeof(bytes)), bytes); + U64 size = cstring8_length(&bytes[0]); + String8 part = str8(bytes, size); + str8_list_push(scratch.arena, &parts, part); + if(size < sizeof(bytes)) + { + break; + } + } + builtin_debug_info_path = str8_list_join(arena, &parts, 0); + scratch_end(scratch); + } + } + } + } + } + + ////////////////////////////// + //- rjf: pick default initial debug info path + // + String8 initial_debug_info_path = builtin_debug_info_path; + { + Temp scratch = scratch_begin(0, 0); + String8 exe_folder = str8_chop_last_slash(path); + String8 builtin_debug_info_path__absolute = builtin_debug_info_path; + String8 builtin_debug_info_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, builtin_debug_info_path); + String8 dbg_path_candidates[] = + { + /* inferred (treated as absolute): */ builtin_debug_info_path__absolute, + /* inferred (treated as relative): */ builtin_debug_info_path__relative, + /* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(path)), + /* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", path), + }; + for(U64 idx = 0; idx < ArrayCount(dbg_path_candidates); idx += 1) + { + FileProperties props = os_properties_from_file_path(dbg_path_candidates[idx]); + if(props.modified != 0 && props.size != 0) + { + initial_debug_info_path = push_str8_copy(arena, dbg_path_candidates[idx]); + break; + } + } + scratch_end(scratch); + } + + ////////////////////////////// + //- rjf: insert info into cache + // + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + CTRL_ModuleImageInfoCacheNode *node = 0; + for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module)) + { + node = n; + break; + } + } + if(!node) + { + node = push_array(arena, CTRL_ModuleImageInfoCacheNode, 1); + DLLPushBack(slot->first, slot->last, node); + node->machine_id = machine_id; + node->module = module; + node->arena = arena; + node->pdatas = pdatas; + node->pdatas_count = pdatas_count; + node->entry_point_voff = entry_point_voff; + node->initial_debug_info_path = initial_debug_info_path; + } + } + } +} + +internal void +ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 path) +{ + ////////////////////////////// + //- rjf: evict module image info from cache + // + { + U64 hash = ctrl_hash_from_machine_id_handle(machine_id, module); + U64 slot_idx = hash%ctrl_state->module_image_info_cache.slots_count; + U64 stripe_idx = slot_idx%ctrl_state->module_image_info_cache.stripes_count; + CTRL_ModuleImageInfoCacheSlot *slot = &ctrl_state->module_image_info_cache.slots[slot_idx]; + CTRL_ModuleImageInfoCacheStripe *stripe = &ctrl_state->module_image_info_cache.stripes[stripe_idx]; + OS_MutexScopeW(stripe->rw_mutex) + { + CTRL_ModuleImageInfoCacheNode *node = 0; + for(CTRL_ModuleImageInfoCacheNode *n = slot->first; n != 0; n = n->next) + { + if(n->machine_id == machine_id && dmn_handle_match(n->module, module)) + { + node = n; + break; + } + } + if(node) + { + DLLRemove(slot->first, slot->last, node); + arena_release(node->arena); + } + } + } + + ////////////////////////////// + //- rjf: close debug info + // + { + CTRL_Entity *module_ent = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, machine_id, module); + CTRL_Entity *debug_info_path_ent = ctrl_entity_child_from_kind(module_ent, CTRL_EntityKind_DebugInfoPath); + if(debug_info_path_ent != &ctrl_entity_nil) + { + DI_Key dbgi_key = {debug_info_path_ent->string, debug_info_path_ent->timestamp}; + di_close(&dbgi_key); + } + } +} + //- rjf: attached process running/event gathering internal DMN_Event * @@ -2007,7 +3406,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, if(!should_filter_event && ev->code == 0xc0000005 && (spoof == 0 || ev->instruction_pointer != spoof->new_ip_value)) { - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, ev->process); CTRL_Entity *module = &ctrl_entity_nil; for(CTRL_Entity *child = process->first; child != &ctrl_entity_nil; child = child->next) @@ -2023,9 +3422,9 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, // rjf: determine base address of asan shadow space U64 asan_shadow_base_vaddr = 0; B32 asan_shadow_variable_exists_but_is_zero = 0; - String8 module_path = module->string; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, module_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_GlobalVariables); if(rdi->global_variables != 0 && unparsed_map != 0) { @@ -2068,7 +3467,7 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, } } - dbgi_scope_close(scope); + di_scope_close(di_scope); } }break; } @@ -2193,19 +3592,32 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, }break; case DMN_EventKind_LoadModule: { - CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); + CTRL_Event *out_evt1 = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; - dbgi_binary_open(module_path); - out_evt->kind = CTRL_EventKind_NewModule; - out_evt->msg_id = msg->msg_id; - out_evt->machine_id = CTRL_MachineID_Local; - out_evt->entity = event->module; - out_evt->parent = event->process; - out_evt->arch = event->arch; - out_evt->entity_id = event->code; - out_evt->vaddr_rng = r1u64(event->address, event->address+event->size); - out_evt->rip_vaddr = event->address; - out_evt->string = module_path; + U64 timestamp = os_properties_from_file_path(module_path).modified; + ctrl_thread__module_open(CTRL_MachineID_Local, event->process, event->module, r1u64(event->address, event->address+event->size), module_path, timestamp); + out_evt1->kind = CTRL_EventKind_NewModule; + out_evt1->msg_id = msg->msg_id; + out_evt1->machine_id = CTRL_MachineID_Local; + out_evt1->entity = event->module; + out_evt1->parent = event->process; + out_evt1->arch = event->arch; + out_evt1->entity_id = event->code; + out_evt1->vaddr_rng = r1u64(event->address, event->address+event->size); + out_evt1->rip_vaddr = event->address; + out_evt1->timestamp = timestamp; + out_evt1->string = module_path; + CTRL_Event *out_evt2 = ctrl_event_list_push(scratch.arena, &evts); + String8 initial_debug_info_path = ctrl_initial_debug_info_path_from_module(scratch.arena, CTRL_MachineID_Local, event->module); + out_evt2->kind = CTRL_EventKind_ModuleDebugInfoPathChange; + out_evt2->msg_id = msg->msg_id; + out_evt2->machine_id = CTRL_MachineID_Local; + out_evt2->entity = event->module; + out_evt2->parent = event->process; + out_evt2->timestamp = timestamp; + out_evt2->string = initial_debug_info_path; + DI_Key initial_dbgi_key = {initial_debug_info_path, timestamp}; + di_open(&initial_dbgi_key); }break; case DMN_EventKind_ExitProcess: { @@ -2230,11 +3642,12 @@ ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, { CTRL_Event *out_evt = ctrl_event_list_push(scratch.arena, &evts); String8 module_path = event->string; - dbgi_binary_close(module_path); + ctrl_thread__module_close(CTRL_MachineID_Local, event->module, module_path); out_evt->kind = CTRL_EventKind_EndModule; out_evt->msg_id = msg->msg_id; out_evt->machine_id = CTRL_MachineID_Local; out_evt->entity = event->module; + out_evt->string = module_path; }break; case DMN_EventKind_DebugString: { @@ -2350,7 +3763,6 @@ ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); //- rjf: attach B32 attach_successful = dmn_ctrl_attach(ctrl_ctx, msg->entity_id); @@ -2397,7 +3809,6 @@ ctrl_thread__attach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -2407,7 +3818,6 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); DMN_Handle process = msg->entity; U32 exit_code = msg->exit_code; @@ -2451,7 +3861,6 @@ ctrl_thread__kill(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -2461,7 +3870,6 @@ ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); DMN_Handle process = msg->entity; //- rjf: detach @@ -2504,7 +3912,6 @@ ctrl_thread__detach(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -2514,7 +3921,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); DMN_Event *stop_event = 0; CTRL_EventCause stop_cause = CTRL_EventCause_Null; DMN_Handle target_thread = msg->entity; @@ -2816,9 +4223,9 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) } } U64 module_base_vaddr = module->vaddr_range.min; - String8 exe_path = module->string; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); RDI_NameMap *unparsed_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Procedures); RDI_ParsedNameMap map = {0}; rdi_name_map_parse(rdi, unparsed_map, &map); @@ -2941,7 +4348,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) //- rjf: add trap for PE header entry if(!entries_found) { - U64 voff = dbgi->pe.entry_point; + U64 voff = ctrl_entry_point_voff_from_module(CTRL_MachineID_Local, module->handle); if(voff != 0) { DMN_Trap trap = {process->handle, module_base_vaddr + voff}; @@ -2998,24 +4405,25 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) CTRL_Entity *thread = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->thread); Architecture arch = thread->arch; U64 thread_rip_vaddr = dmn_rip_from_thread(event->thread); - DMN_Handle module = {0}; - String8 module_name = {0}; - U64 module_base_vaddr = 0; - U64 thread_rip_voff = 0; + CTRL_Entity *module = &ctrl_entity_nil; { CTRL_Entity *process = ctrl_entity_from_machine_id_handle(ctrl_state->ctrl_thread_entity_store, CTRL_MachineID_Local, event->process); - for(CTRL_Entity *module = process->first; module != &ctrl_entity_nil; module = module->next) + for(CTRL_Entity *m = process->first; m != &ctrl_entity_nil; m = m->next) { - if(module->kind == CTRL_EntityKind_Module && contains_1u64(module->vaddr_range, thread_rip_vaddr)) + if(m->kind == CTRL_EntityKind_Module && contains_1u64(m->vaddr_range, thread_rip_vaddr)) { - module_name = module->string; - module_base_vaddr = module->vaddr_range.min; - thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; + module = m; break; } } } + ////////////////////////// + //- rjf: extract module-dependent info + // + CTRL_Entity *dbg_path = ctrl_entity_child_from_kind(module, CTRL_EntityKind_DebugInfoPath); + U64 thread_rip_voff = thread_rip_vaddr - module->vaddr_range.min; + ////////////////////////// //- rjf: stepping logic // @@ -3110,9 +4518,8 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) // rjf: evaluate hit stop conditions if(conditions.node_count != 0) { - String8 exe_path = module_name; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Key dbgi_key = {dbg_path->string, dbg_path->timestamp}; + RDI_Parsed *rdi = di_rdi_from_key(di_scope, &dbgi_key, max_U64); for(String8Node *condition_n = conditions.first; condition_n != 0; condition_n = condition_n->next) { String8 string = condition_n->string; @@ -3150,7 +4557,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) EVAL_Result eval = {0}; if(bytecode.size != 0) { - U64 module_base = module_base_vaddr; + U64 module_base = module->vaddr_range.min; U64 tls_base = dmn_tls_root_vaddr_from_thread(event->thread); EVAL_Machine machine = {0}; machine.u = &event->process; @@ -3457,7 +4864,7 @@ ctrl_thread__run(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); + di_scope_close(di_scope); scratch_end(scratch); ProfEnd(); } @@ -3467,7 +4874,6 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); //- rjf: record start { @@ -3520,7 +4926,6 @@ ctrl_thread__single_step(DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg) ctrl_c2u_push_events(&evts); } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -3633,8 +5038,9 @@ ctrl_mem_stream_thread__entry_point(void *p) Arena *range_arena = 0; void *range_base = 0; U64 zero_terminated_size = 0; - U64 mem_gen = dmn_mem_gen(); - if(got_task && mem_gen != preexisting_mem_gen) + U64 pre_read_mem_gen = dmn_mem_gen(); + U64 post_read_mem_gen = 0; + if(got_task && pre_read_mem_gen != preexisting_mem_gen) { range_size = dim_1u64(vaddr_range_clamped); U64 arena_size = AlignPow2(range_size + ARENA_HEADER_SIZE, os_page_size()); @@ -3653,7 +5059,12 @@ ctrl_mem_stream_thread__entry_point(void *p) bytes_read = dmn_process_read(process, vaddr_range_clamped_retry, range_base); if(bytes_read == 0 && vaddr_range_clamped_retry.max > vaddr_range_clamped_retry.min) { - vaddr_range_clamped_retry.max -= (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + U64 diff = (vaddr_range_clamped_retry.max-vaddr_range_clamped_retry.min)/2; + vaddr_range_clamped_retry.max -= diff; + if(diff == 0) + { + break; + } } else { @@ -3684,6 +5095,7 @@ ctrl_mem_stream_thread__entry_point(void *p) } } } + post_read_mem_gen = dmn_mem_gen(); } //- rjf: read successful -> submit to hash store @@ -3709,7 +5121,10 @@ ctrl_mem_stream_thread__entry_point(void *p) if(!u128_match(u128_zero(), hash)) { range_n->hash = hash; - range_n->mem_gen = mem_gen; + } + if(!u128_match(u128_zero(), hash)) + { + range_n->mem_gen = post_read_mem_gen; } ins_atomic_u32_eval_assign(&range_n->is_taken, 0); goto commit__break_all; diff --git a/src/ctrl/ctrl_core.h b/src/ctrl/ctrl_core.h index 0666e237..995d6b66 100644 --- a/src/ctrl/ctrl_core.h +++ b/src/ctrl/ctrl_core.h @@ -49,6 +49,7 @@ typedef enum CTRL_EntityKind CTRL_EntityKind_Thread, CTRL_EntityKind_Module, CTRL_EntityKind_EntryPoint, + CTRL_EntityKind_DebugInfoPath, CTRL_EntityKind_COUNT } CTRL_EntityKind; @@ -67,6 +68,7 @@ struct CTRL_Entity DMN_Handle handle; U64 id; Rng1U64 vaddr_range; + U64 timestamp; String8 string; }; @@ -107,22 +109,45 @@ struct CTRL_EntityStore //////////////////////////////// //~ rjf: Unwind Types +typedef U32 CTRL_UnwindFlags; +enum +{ + CTRL_UnwindFlag_Error = (1<<0), + CTRL_UnwindFlag_Stale = (1<<1), +}; + +typedef struct CTRL_UnwindStepResult CTRL_UnwindStepResult; +struct CTRL_UnwindStepResult +{ + CTRL_UnwindFlags flags; +}; + typedef struct CTRL_UnwindFrame CTRL_UnwindFrame; struct CTRL_UnwindFrame { - CTRL_UnwindFrame *next; - CTRL_UnwindFrame *prev; - U64 rip; void *regs; }; +typedef struct CTRL_UnwindFrameNode CTRL_UnwindFrameNode; +struct CTRL_UnwindFrameNode +{ + CTRL_UnwindFrameNode *next; + CTRL_UnwindFrameNode *prev; + CTRL_UnwindFrame v; +}; + +typedef struct CTRL_UnwindFrameArray CTRL_UnwindFrameArray; +struct CTRL_UnwindFrameArray +{ + CTRL_UnwindFrame *v; + U64 count; +}; + typedef struct CTRL_Unwind CTRL_Unwind; struct CTRL_Unwind { - CTRL_UnwindFrame *first; - CTRL_UnwindFrame *last; - U64 count; - B32 error; + CTRL_UnwindFrameArray frames; + CTRL_UnwindFlags flags; }; //////////////////////////////// @@ -224,6 +249,7 @@ typedef enum CTRL_MsgKind CTRL_MsgKind_Run, CTRL_MsgKind_SingleStep, CTRL_MsgKind_SetUserEntryPoints, + CTRL_MsgKind_SetModuleDebugInfoPath, CTRL_MsgKind_COUNT, } CTRL_MsgKind; @@ -292,6 +318,9 @@ typedef enum CTRL_EventKind CTRL_EventKind_EndThread, CTRL_EventKind_EndModule, + //- rjf: debug info changes + CTRL_EventKind_ModuleDebugInfoPathChange, + //- rjf: debug strings CTRL_EventKind_DebugString, CTRL_EventKind_ThreadName, @@ -348,6 +377,7 @@ struct CTRL_Event U64 rip_vaddr; U64 stack_base; U64 tls_root; + U64 timestamp; U32 exception_code; String8 string; }; @@ -474,6 +504,47 @@ struct CTRL_ThreadRegCache CTRL_ThreadRegCacheStripe *stripes; }; +//////////////////////////////// +//~ rjf: Module Image Info Cache Types + +typedef struct CTRL_ModuleImageInfoCacheNode CTRL_ModuleImageInfoCacheNode; +struct CTRL_ModuleImageInfoCacheNode +{ + CTRL_ModuleImageInfoCacheNode *next; + CTRL_ModuleImageInfoCacheNode *prev; + CTRL_MachineID machine_id; + DMN_Handle module; + Arena *arena; + PE_IntelPdata *pdatas; + U64 pdatas_count; + U64 entry_point_voff; + Rng1U64 tls_vaddr_range; + String8 initial_debug_info_path; +}; + +typedef struct CTRL_ModuleImageInfoCacheSlot CTRL_ModuleImageInfoCacheSlot; +struct CTRL_ModuleImageInfoCacheSlot +{ + CTRL_ModuleImageInfoCacheNode *first; + CTRL_ModuleImageInfoCacheNode *last; +}; + +typedef struct CTRL_ModuleImageInfoCacheStripe CTRL_ModuleImageInfoCacheStripe; +struct CTRL_ModuleImageInfoCacheStripe +{ + Arena *arena; + OS_Handle rw_mutex; +}; + +typedef struct CTRL_ModuleImageInfoCache CTRL_ModuleImageInfoCache; +struct CTRL_ModuleImageInfoCache +{ + U64 slots_count; + CTRL_ModuleImageInfoCacheSlot *slots; + U64 stripes_count; + CTRL_ModuleImageInfoCacheStripe *stripes; +}; + //////////////////////////////// //~ rjf: Wakeup Hook Function Types @@ -496,6 +567,7 @@ struct CTRL_State // rjf: caches CTRL_ProcessMemoryCache process_memory_cache; CTRL_ThreadRegCache thread_reg_cache; + CTRL_ModuleImageInfoCache module_image_info_cache; // rjf: user -> ctrl msg ring buffer U64 u2c_ring_size; @@ -615,6 +687,7 @@ internal CTRL_EntityStore *ctrl_entity_store_alloc(void); internal void ctrl_entity_store_release(CTRL_EntityStore *store); //- rjf: string allocation/deletion +internal U64 ctrl_name_bucket_idx_from_string_size(U64 size); internal String8 ctrl_entity_string_alloc(CTRL_EntityStore *store, String8 string); internal void ctrl_entity_string_release(CTRL_EntityStore *store, String8 string); @@ -627,6 +700,7 @@ internal void ctrl_entity_equip_string(CTRL_EntityStore *store, CTRL_Entity *ent //- rjf: entity store lookups internal CTRL_Entity *ctrl_entity_from_machine_id_handle(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle handle); +internal CTRL_Entity *ctrl_entity_child_from_kind(CTRL_Entity *parent, CTRL_EntityKind kind); //- rjf: applying events to entity caches internal void ctrl_entity_store_apply_events(CTRL_EntityStore *store, CTRL_EventList *list); @@ -654,6 +728,8 @@ internal U128 ctrl_hash_store_key_from_process_vaddr_range(CTRL_MachineID machin //- rjf: process memory cache reading helpers internal CTRL_ProcessMemorySlice ctrl_query_cached_data_from_process_vaddr_range(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, U64 endt_us); internal CTRL_ProcessMemorySlice ctrl_query_cached_zero_terminated_data_from_process_vaddr_limit(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, U64 vaddr, U64 limit, U64 element_size, U64 endt_us); +internal B32 ctrl_read_cached_process_memory(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, B32 *is_stale_out, void *out, U64 endt_us); +#define ctrl_read_cached_process_memory_struct(machine_id, process, vaddr, is_stale_out, ptr, endt_us) ctrl_read_cached_process_memory((machine_id), (process), r1u64((vaddr), (vaddr)+(sizeof(*(ptr)))), (is_stale_out), (ptr), (endt_us)) //- rjf: process memory writing internal B32 ctrl_process_write(CTRL_MachineID machine_id, DMN_Handle process, Rng1U64 range, void *src); @@ -669,9 +745,29 @@ internal U64 ctrl_query_cached_rip_from_thread(CTRL_EntityStore *store, CTRL_Mac //- rjf: thread register writing internal B32 ctrl_thread_write_reg_block(CTRL_MachineID machine_id, DMN_Handle thread, void *block); +//////////////////////////////// +//~ rjf: Module Image Info Functions + +//- rjf: cache lookups +internal PE_IntelPdata *ctrl_intel_pdata_from_module_voff(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle, U64 voff); +internal U64 ctrl_entry_point_voff_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); +internal Rng1U64 ctrl_tls_vaddr_range_from_module(CTRL_MachineID machine_id, DMN_Handle module_handle); +internal String8 ctrl_initial_debug_info_path_from_module(Arena *arena, CTRL_MachineID machine_id, DMN_Handle module_handle); + //////////////////////////////// //~ rjf: Unwinding Functions +//- rjf: unwind deep copier +internal CTRL_Unwind ctrl_unwind_deep_copy(Arena *arena, Architecture arch, CTRL_Unwind *src); + +//- rjf: [x64] +internal REGS_Reg64 *ctrl_unwind_reg_from_pe_gpr_reg__pe_x64(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 gpr_reg); +internal CTRL_UnwindStepResult ctrl_unwind_step__pe_x64(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process_handle, DMN_Handle module, REGS_RegBlockX64 *regs, U64 endt_us); + +//- rjf: abstracted unwind step +internal CTRL_UnwindStepResult ctrl_unwind_step(CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle process_handle, DMN_Handle module, Architecture arch, void *reg_block, U64 endt_us); + +//- rjf: abstracted full unwind internal CTRL_Unwind ctrl_unwind_from_thread(Arena *arena, CTRL_EntityStore *store, CTRL_MachineID machine_id, DMN_Handle thread, U64 endt_us); //////////////////////////////// @@ -709,6 +805,10 @@ internal void ctrl_thread__entry_point(void *p); internal void ctrl_thread__append_resolved_module_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); internal void ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena, CTRL_MachineID machine_id, DMN_Handle process, CTRL_UserBreakpointList *user_bps, DMN_TrapChunkList *traps_out); +//- rjf: module lifetime open/close work +internal void ctrl_thread__module_open(CTRL_MachineID machine_id, DMN_Handle process, DMN_Handle module, Rng1U64 vaddr_range, String8 path, U64 exe_timestamp); +internal void ctrl_thread__module_close(CTRL_MachineID machine_id, DMN_Handle module, String8 path); + //- rjf: attached process running/event gathering internal DMN_Event *ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, CTRL_Msg *msg, DMN_RunCtrls *run_ctrls, CTRL_Spoof *spoof); diff --git a/src/dasm_cache/dasm_cache.c b/src/dasm_cache/dasm_cache.c index b150acd7..ffbea99b 100644 --- a/src/dasm_cache/dasm_cache.c +++ b/src/dasm_cache/dasm_cache.c @@ -24,7 +24,7 @@ dasm_params_match(DASM_Params *a, DASM_Params *b) a->style_flags == b->style_flags && a->syntax == b->syntax && a->base_vaddr == b->base_vaddr && - str8_match(a->exe_path, b->exe_path, 0)); + di_key_match(&a->dbgi_key, &b->dbgi_key)); return result; } @@ -189,7 +189,7 @@ dasm_scope_touch_node__stripe_r_guarded(DASM_Scope *scope, DASM_Node *node) ins_atomic_u64_eval_assign(&node->last_user_clock_idx_touched, dasm_user_clock_idx()); touch->hash = node->hash; MemoryCopyStruct(&touch->params, &node->params); - touch->params.exe_path = push_str8_copy(dasm_tctx->arena, touch->params.exe_path); + touch->params.dbgi_key = di_key_copy(dasm_tctx->arena, &touch->params.dbgi_key); SLLStackPush(scope->top_touch, touch); } @@ -236,6 +236,14 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) } if(node == 0) { + log_infof("[dasm] cache miss, creating node...\n"); + log_infof(" hash: [0x%I64x 0x%I64x]\n", hash.u64[0], hash.u64[1]); + log_infof(" vaddr: 0x%I64x\n", params->vaddr); + log_infof(" arch: %S\n", string_from_architecture(params->arch)); + log_infof(" style_flags: 0x%x\n", params->style_flags); + log_infof(" syntax: %i\n", params->syntax); + log_infof(" base_vaddr: 0x%I64x\n", params->base_vaddr); + log_infof(" dbgi_key: [%S 0x%I64x]\n", params->dbgi_key.path, params->dbgi_key.min_timestamp); node = stripe->free_node; if(node) { @@ -250,7 +258,7 @@ dasm_info_from_hash_params(DASM_Scope *scope, U128 hash, DASM_Params *params) node->hash = hash; MemoryCopyStruct(&node->params, params); // TODO(rjf): need to make this releasable - currently all exe_paths just leak - node->params.exe_path = push_str8_copy(stripe->arena, node->params.exe_path); + node->params.dbgi_key = di_key_copy(stripe->arena, &node->params.dbgi_key); node_is_new = 1; } } @@ -294,7 +302,7 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; U64 available_size = dasm_shared->u2p_ring_size - unconsumed_size; - if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->exe_path.size) + if(available_size >= sizeof(hash)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+params->dbgi_key.path.size+sizeof(U64)) { good = 1; dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, &hash); @@ -303,8 +311,9 @@ dasm_u2p_enqueue_req(U128 hash, DASM_Params *params, U64 endt_us) dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->style_flags); dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->syntax); dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->base_vaddr); - dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->exe_path.size); - dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->exe_path.str, params->exe_path.size); + dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.path.size); + dasm_shared->u2p_ring_write_pos += ring_write(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, params->dbgi_key.path.str, params->dbgi_key.path.size); + dasm_shared->u2p_ring_write_pos += ring_write_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_write_pos, ¶ms->dbgi_key.min_timestamp); dasm_shared->u2p_ring_write_pos += 7; dasm_shared->u2p_ring_write_pos -= dasm_shared->u2p_ring_write_pos%8; break; @@ -328,7 +337,7 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out) OS_MutexScope(dasm_shared->u2p_ring_mutex) for(;;) { U64 unconsumed_size = dasm_shared->u2p_ring_write_pos - dasm_shared->u2p_ring_read_pos; - if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)) + if(unconsumed_size >= sizeof(*hash_out)+sizeof(U64)+sizeof(Architecture)+sizeof(DASM_StyleFlags)+sizeof(DASM_Syntax)+sizeof(U64)+sizeof(U64)+sizeof(U64)) { dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, hash_out); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->vaddr); @@ -336,9 +345,10 @@ dasm_u2p_dequeue_req(Arena *arena, U128 *hash_out, DASM_Params *params_out) dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->style_flags); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->syntax); dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->base_vaddr); - dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->exe_path.size); - params_out->exe_path.str = push_array(arena, U8, params_out->exe_path.size); - dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->exe_path.str, params_out->exe_path.size); + dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.path.size); + params_out->dbgi_key.path.str = push_array(arena, U8, params_out->dbgi_key.path.size); + dasm_shared->u2p_ring_read_pos += ring_read(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, params_out->dbgi_key.path.str, params_out->dbgi_key.path.size); + dasm_shared->u2p_ring_read_pos += ring_read_struct(dasm_shared->u2p_ring_base, dasm_shared->u2p_ring_size, dasm_shared->u2p_ring_read_pos, ¶ms_out->dbgi_key.min_timestamp); dasm_shared->u2p_ring_read_pos += 7; dasm_shared->u2p_ring_read_pos -= dasm_shared->u2p_ring_read_pos%8; break; @@ -362,7 +372,7 @@ dasm_parse_thread__entry_point(void *p) dasm_u2p_dequeue_req(scratch.arena, &hash, ¶ms); U64 change_gen = fs_change_gen(); HS_Scope *hs_scope = hs_scope_open(); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); //- rjf: unpack hash @@ -386,12 +396,11 @@ dasm_parse_thread__entry_point(void *p) } //- rjf: get dbg info - DBGI_Parse *dbgi = &dbgi_parse_nil; - if(got_task && params.exe_path.size != 0) + RDI_Parsed *rdi = &di_rdi_parsed_nil; + if(got_task && params.dbgi_key.path.size != 0) { - dbgi = dbgi_parse_from_exe_path(dbgi_scope, params.exe_path, max_U64); + rdi = di_rdi_from_key(di_scope, ¶ms.dbgi_key, max_U64); } - RDI_Parsed *rdi = &dbgi->rdi; //- rjf: hash -> data String8 data = {0}; @@ -442,7 +451,7 @@ dasm_parse_thread__entry_point(void *p) // rjf: push strings derived from voff -> line info if(params.style_flags & (DASM_StyleFlag_SourceFilesNames|DASM_StyleFlag_SourceLines)) { - if(dbgi != &dbgi_parse_nil) + if(rdi != &di_rdi_parsed_nil) { U64 voff = (params.vaddr+off) - params.base_vaddr; U32 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, voff); @@ -517,7 +526,7 @@ dasm_parse_thread__entry_point(void *p) String8 addr_part = {0}; if(params.style_flags & DASM_StyleFlag_Addresses) { - addr_part = push_str8f(scratch.arena, "%s%016I64X ", dbgi != &dbgi_parse_nil ? " " : "", params.vaddr+off); + addr_part = push_str8f(scratch.arena, "%s%016I64X ", rdi != &di_rdi_parsed_nil ? " " : "", params.vaddr+off); } String8 code_bytes_part = {0}; if(params.style_flags & DASM_StyleFlag_CodeBytes) @@ -539,7 +548,7 @@ dasm_parse_thread__entry_point(void *p) code_bytes_part = str8_list_join(scratch.arena, &code_bytes_strings, 0); } String8 symbol_part = {0}; - if(jump_dst_vaddr != 0 && dbgi != &dbgi_parse_nil && params.style_flags & DASM_StyleFlag_SymbolNames) + if(jump_dst_vaddr != 0 && rdi != &di_rdi_parsed_nil && params.style_flags & DASM_StyleFlag_SymbolNames) { RDI_U32 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, jump_dst_vaddr-params.base_vaddr); if(scope_idx != 0) @@ -590,7 +599,7 @@ dasm_parse_thread__entry_point(void *p) (U64)params.arch, (U64)params.style_flags, (U64)params.syntax, - (U64)dbgi, + (U64)rdi, 0x4d534144, }; text_key = hs_hash_from_data(str8((U8 *)hash_data, sizeof(hash_data))); @@ -614,7 +623,7 @@ dasm_parse_thread__entry_point(void *p) { n->info_arena = info_arena; MemoryCopyStruct(&n->info, &info); - if(dbgi != &dbgi_parse_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) + if(rdi != &di_rdi_parsed_nil && params.style_flags & (DASM_StyleFlag_SourceLines|DASM_StyleFlag_SourceFilesNames)) { n->change_gen = change_gen; } @@ -630,7 +639,7 @@ dasm_parse_thread__entry_point(void *p) } txt_scope_close(txt_scope); - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); hs_scope_close(hs_scope); scratch_end(scratch); } diff --git a/src/dasm_cache/dasm_cache.h b/src/dasm_cache/dasm_cache.h index 3e5d4e9f..5c588b56 100644 --- a/src/dasm_cache/dasm_cache.h +++ b/src/dasm_cache/dasm_cache.h @@ -36,7 +36,7 @@ struct DASM_Params DASM_StyleFlags style_flags; DASM_Syntax syntax; U64 base_vaddr; - String8 exe_path; + DI_Key dbgi_key; }; //////////////////////////////// diff --git a/src/dbgi/dbgi.c b/src/dbgi/dbgi.c index 1a341c20..0b8811cb 100644 --- a/src/dbgi/dbgi.c +++ b/src/dbgi/dbgi.c @@ -2,90 +2,10 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: Main Layer Initialization - -internal void -dbgi_init(void) -{ - Arena *arena = arena_alloc(); - dbgi_shared = push_array(arena, DBGI_Shared, 1); - dbgi_shared->arena = arena; - dbgi_shared->force_slots_count = 1024; - dbgi_shared->force_stripes_count = Min(dbgi_shared->force_slots_count, os_logical_core_count()); - dbgi_shared->force_slots = push_array(arena, DBGI_ForceSlot, dbgi_shared->force_slots_count); - dbgi_shared->force_stripes = push_array(arena, DBGI_ForceStripe, dbgi_shared->force_stripes_count); - for(U64 idx = 0; idx < dbgi_shared->force_stripes_count; idx += 1) - { - dbgi_shared->force_stripes[idx].arena = arena_alloc(); - dbgi_shared->force_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - dbgi_shared->force_stripes[idx].cv = os_condition_variable_alloc(); - } - dbgi_shared->binary_slots_count = 1024; - dbgi_shared->binary_stripes_count = Min(dbgi_shared->binary_slots_count, os_logical_core_count()); - dbgi_shared->binary_slots = push_array(arena, DBGI_BinarySlot, dbgi_shared->binary_slots_count); - dbgi_shared->binary_stripes = push_array(arena, DBGI_BinaryStripe, dbgi_shared->binary_stripes_count); - for(U64 idx = 0; idx < dbgi_shared->binary_stripes_count; idx += 1) - { - dbgi_shared->binary_stripes[idx].arena = arena_alloc(); - dbgi_shared->binary_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - dbgi_shared->binary_stripes[idx].cv = os_condition_variable_alloc(); - } - dbgi_shared->fuzzy_search_slots_count = 64; - dbgi_shared->fuzzy_search_stripes_count = Min(dbgi_shared->fuzzy_search_slots_count, os_logical_core_count()); - dbgi_shared->fuzzy_search_slots = push_array(arena, DBGI_FuzzySearchSlot, dbgi_shared->fuzzy_search_slots_count); - dbgi_shared->fuzzy_search_stripes = push_array(arena, DBGI_FuzzySearchStripe, dbgi_shared->fuzzy_search_stripes_count); - for(U64 idx = 0; idx < dbgi_shared->fuzzy_search_stripes_count; idx += 1) - { - dbgi_shared->fuzzy_search_stripes[idx].arena = arena_alloc(); - dbgi_shared->fuzzy_search_stripes[idx].rw_mutex = os_rw_mutex_alloc(); - dbgi_shared->fuzzy_search_stripes[idx].cv = os_condition_variable_alloc(); - } - dbgi_shared->u2p_ring_mutex = os_mutex_alloc(); - dbgi_shared->u2p_ring_cv = os_condition_variable_alloc(); - dbgi_shared->u2p_ring_size = KB(64); - dbgi_shared->u2p_ring_base = push_array_no_zero(arena, U8, dbgi_shared->u2p_ring_size); - dbgi_shared->p2u_ring_mutex = os_mutex_alloc(); - dbgi_shared->p2u_ring_cv = os_condition_variable_alloc(); - dbgi_shared->p2u_ring_size = KB(64); - dbgi_shared->p2u_ring_base = push_array_no_zero(arena, U8, dbgi_shared->p2u_ring_size); - dbgi_shared->parse_thread_count = Max(os_logical_core_count()-1, 1); - dbgi_shared->parse_threads = push_array(arena, OS_Handle, dbgi_shared->parse_thread_count); - for(U64 idx = 0; idx < dbgi_shared->parse_thread_count; idx += 1) - { - dbgi_shared->parse_threads[idx] = os_launch_thread(dbgi_parse_thread_entry_point, (void *)idx, 0); - } - dbgi_shared->fuzzy_thread_count = Clamp(1, os_logical_core_count()-1, 1); - dbgi_shared->fuzzy_threads = push_array(arena, DBGI_FuzzySearchThread, dbgi_shared->fuzzy_thread_count); - for(U64 idx = 0; idx < dbgi_shared->fuzzy_thread_count; idx += 1) - { - DBGI_FuzzySearchThread *thread = &dbgi_shared->fuzzy_threads[idx]; - thread->u2f_ring_mutex = os_mutex_alloc(); - thread->u2f_ring_cv = os_condition_variable_alloc(); - thread->u2f_ring_size = KB(64); - thread->u2f_ring_base = push_array_no_zero(dbgi_shared->arena, U8, thread->u2f_ring_size); - thread->thread = os_launch_thread(dbgi_fuzzy_thread__entry_point, (void *)idx, 0); - } -} - -//////////////////////////////// -//~ rjf: Thread-Context Idempotent Initialization - -internal void -dbgi_ensure_tctx_inited(void) -{ - if(dbgi_tctx == 0) - { - Arena *arena = arena_alloc(); - dbgi_tctx = push_array(arena, DBGI_ThreadCtx, 1); - dbgi_tctx->arena = arena; - } -} - -//////////////////////////////// -//~ rjf: Helpers +//~ rjf: Basic Helpers internal U64 -dbgi_hash_from_string(String8 string, StringMatchFlags match_flags) +di_hash_from_string(String8 string, StringMatchFlags match_flags) { U64 result = 5381; for(U64 i = 0; i < string.size; i += 1) @@ -96,458 +16,471 @@ dbgi_hash_from_string(String8 string, StringMatchFlags match_flags) } internal U64 -dbgi_fuzzy_item_num_from_array_element_idx__linear_search(DBGI_FuzzySearchItemArray *array, U64 element_idx) +di_hash_from_key(DI_Key *k) { - U64 fuzzy_item_num = 0; - for(U64 idx = 0; idx < array->count; idx += 1) - { - if(array->v[idx].idx == element_idx) - { - fuzzy_item_num = idx+1; - break; - } - } - return fuzzy_item_num; + U64 hash = di_hash_from_string(k->path, StringMatchFlag_CaseInsensitive); + return hash; } -internal String8 -dbgi_fuzzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, DBGI_FuzzySearchTarget target, U64 element_idx) +internal B32 +di_key_match(DI_Key *a, DI_Key *b) { - String8 result = {0}; - switch(target) + return (str8_match(a->path, b->path, StringMatchFlag_CaseInsensitive) && a->min_timestamp == b->min_timestamp); +} + +internal DI_Key +di_key_copy(Arena *arena, DI_Key *src) +{ + DI_Key dst = {0}; + MemoryCopyStruct(&dst, src); + dst.path = push_str8_copy(arena, src->path); + return dst; +} + +internal DI_Key +di_normalized_key_from_key(Arena *arena, DI_Key *src) +{ + DI_Key dst = {path_normalized_from_string(arena, src->path), src->min_timestamp}; + return dst; +} + +internal void +di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key) +{ + DI_KeyNode *n = push_array(arena, DI_KeyNode, 1); + MemoryCopyStruct(&n->v, key); + SLLQueuePush(list->first, list->last, n); + list->count += 1; +} + +internal DI_KeyArray +di_key_array_from_list(Arena *arena, DI_KeyList *list) +{ + DI_KeyArray array = {0}; + array.count = list->count; + array.v = push_array_no_zero(arena, DI_Key, array.count); + U64 idx = 0; + for(DI_KeyNode *n = list->first; n != 0; n = n->next, idx += 1) { - // NOTE(rjf): no default - warn if we miss a case - case DBGI_FuzzySearchTarget_Procedures: - { - RDI_Procedure *proc = rdi_element_from_idx(rdi, procedures, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_GlobalVariables: - { - RDI_GlobalVariable *gvar = rdi_element_from_idx(rdi, global_variables, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_ThreadVariables: - { - RDI_ThreadVariable *tvar = rdi_element_from_idx(rdi, thread_variables, element_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_UDTs: - { - RDI_UDT *udt = rdi_element_from_idx(rdi, udts, element_idx); - RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size); - result = str8(name_base, name_size); - }break; - case DBGI_FuzzySearchTarget_COUNT:{}break; + MemoryCopyStruct(&array.v[idx], &n->v); } - return result; + return array; } //////////////////////////////// -//~ rjf: Forced Override Cache Functions +//~ rjf: Main Layer Initialization internal void -dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path) +di_init(void) { - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->force_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; - DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; - DBGI_ForceStripe *stripe = &dbgi_shared->force_stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) + Arena *arena = arena_alloc(); + di_shared = push_array(arena, DI_Shared, 1); + di_shared->arena = arena; + di_shared->slots_count = 1024; + di_shared->slots = push_array(arena, DI_Slot, di_shared->slots_count); + di_shared->stripes_count = Min(di_shared->slots_count, os_logical_core_count()); + di_shared->stripes = push_array(arena, DI_Stripe, di_shared->stripes_count); + for(U64 idx = 0; idx < di_shared->stripes_count; idx += 1) { - DBGI_ForceNode *node = 0; - for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) - { - if(str8_match(n->exe_path, exe_path, match_flags)) - { - node = n; - break; - } - } - if(node == 0) - { - node = push_array(stripe->arena, DBGI_ForceNode, 1); - SLLQueuePush(slot->first, slot->first, node); - node->exe_path = push_str8_copy(stripe->arena, exe_path); - node->dbg_path_cap = 1024; - node->dbg_path_base = push_array_no_zero(stripe->arena, U8, node->dbg_path_cap); - } - String8 dbg_path_clamped = dbg_path; - dbg_path_clamped.size = Min(dbg_path_clamped.size, node->dbg_path_cap); - MemoryCopy(node->dbg_path_base, dbg_path_clamped.str, dbg_path_clamped.size); - node->dbg_path_size = dbg_path_clamped.size; + di_shared->stripes[idx].arena = arena_alloc(); + di_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + di_shared->stripes[idx].cv = os_condition_variable_alloc(); } -} - -internal String8 -dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path) -{ - String8 result = {0}; - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->force_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->force_stripes_count; - DBGI_ForceSlot *slot = &dbgi_shared->force_slots[slot_idx]; - DBGI_ForceStripe *stripe = &dbgi_shared->force_stripes[stripe_idx]; - OS_MutexScopeR(stripe->rw_mutex) + di_shared->u2p_ring_mutex = os_mutex_alloc(); + di_shared->u2p_ring_cv = os_condition_variable_alloc(); + di_shared->u2p_ring_size = KB(64); + di_shared->u2p_ring_base = push_array_no_zero(arena, U8, di_shared->u2p_ring_size); + di_shared->p2u_ring_mutex = os_mutex_alloc(); + di_shared->p2u_ring_cv = os_condition_variable_alloc(); + di_shared->p2u_ring_size = KB(64); + di_shared->p2u_ring_base = push_array_no_zero(arena, U8, di_shared->p2u_ring_size); + di_shared->parse_thread_count = Max(2, os_logical_core_count()/2); + di_shared->parse_threads = push_array(arena, OS_Handle, di_shared->parse_thread_count); + for(U64 idx = 0; idx < di_shared->parse_thread_count; idx += 1) { - DBGI_ForceNode *node = 0; - for(DBGI_ForceNode *n = slot->first; n != 0; n = n->next) - { - if(str8_match(exe_path, n->exe_path, match_flags)) - { - node = n; - break; - } - } - if(node != 0) - { - String8 dbg_path = str8(node->dbg_path_base, node->dbg_path_size); - result = push_str8_copy(arena, dbg_path); - } + di_shared->parse_threads[idx] = os_launch_thread(di_parse_thread__entry_point, (void *)idx, 0); } - return result; } //////////////////////////////// //~ rjf: Scope Functions -internal DBGI_Scope * -dbgi_scope_open(void) +internal DI_Scope * +di_scope_open(void) { - dbgi_ensure_tctx_inited(); - DBGI_Scope *scope = dbgi_tctx->free_scope; + if(di_tctx == 0) + { + Arena *arena = arena_alloc(); + di_tctx = push_array(arena, DI_TCTX, 1); + di_tctx->arena = arena; + } + DI_Scope *scope = di_tctx->free_scope; if(scope != 0) { - SLLStackPop(dbgi_tctx->free_scope); - MemoryZeroStruct(scope); + SLLStackPop(di_tctx->free_scope); } else { - scope = push_array(dbgi_tctx->arena, DBGI_Scope, 1); + scope = push_array_no_zero(di_tctx->arena, DI_Scope, 1); } + MemoryZeroStruct(scope); return scope; } internal void -dbgi_scope_close(DBGI_Scope *scope) +di_scope_close(DI_Scope *scope) { - for(DBGI_TouchedBinary *tb = scope->first_tb, *next = 0; tb != 0; tb = next) + for(DI_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) { - next = tb->next; - ins_atomic_u64_dec_eval(&tb->binary->scope_touch_count); - SLLStackPush(dbgi_tctx->free_tb, tb); + next = t->next; + SLLStackPush(di_tctx->free_touch, t); + if(t->node != 0) + { + ins_atomic_u64_dec_eval(&t->node->touch_count); + } } - for(DBGI_TouchedFuzzySearch *tfs = scope->first_tfs, *next = 0; tfs != 0; tfs = next) - { - next = tfs->next; - ins_atomic_u64_dec_eval(&tfs->node->scope_touch_count); - SLLStackPush(dbgi_tctx->free_tfs, tfs); - } - SLLStackPush(dbgi_tctx->free_scope, scope); + SLLStackPush(di_tctx->free_scope, scope); } internal void -dbgi_scope_touch_binary__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_Binary *binary) +di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node) { - DBGI_TouchedBinary *tb = dbgi_tctx->free_tb; - ins_atomic_u64_inc_eval(&binary->scope_touch_count); - if(tb != 0) + if(node != 0) { - SLLStackPop(dbgi_tctx->free_tb); + ins_atomic_u64_inc_eval(&node->touch_count); + } + DI_Touch *touch = di_tctx->free_touch; + if(touch != 0) + { + SLLStackPop(di_tctx->free_touch); } else { - tb = push_array(dbgi_tctx->arena, DBGI_TouchedBinary, 1); + touch = push_array_no_zero(di_tctx->arena, DI_Touch, 1); } - tb->binary = binary; - SLLQueuePush(scope->first_tb, scope->last_tb, tb); -} - -internal void -dbgi_scope_touch_fuzzy_search__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_FuzzySearchNode *node) -{ - DBGI_TouchedFuzzySearch *tfs = dbgi_tctx->free_tfs; - ins_atomic_u64_inc_eval(&node->scope_touch_count); - if(tfs != 0) - { - SLLStackPop(dbgi_tctx->free_tfs); - } - else - { - tfs = push_array(dbgi_tctx->arena, DBGI_TouchedFuzzySearch, 1); - } - tfs->node = node; - SLLQueuePush(scope->first_tfs, scope->last_tfs, tfs); + MemoryZeroStruct(touch); + SLLQueuePush(scope->first_touch, scope->last_touch, touch); + touch->node = node; } //////////////////////////////// -//~ rjf: Binary Cache Functions +//~ rjf: Per-Slot Functions -internal void -dbgi_binary_open(String8 exe_path) +internal DI_Node * +di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key) { - Temp scratch = scratch_begin(0, 0); - exe_path = path_normalized_from_string(scratch.arena, exe_path); + DI_Node *node = 0; StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; - B32 is_new = 0; - OS_MutexScopeW(stripe->rw_mutex) + U64 most_recent_timestamp = max_U64; + for(DI_Node *n = slot->first; n != 0; n = n->next) { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + if(str8_match(n->key.path, key->path, match_flags) && + key->min_timestamp <= n->key.min_timestamp && + (n->key.min_timestamp - key->min_timestamp) <= most_recent_timestamp) { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - if(binary == 0) - { - binary = push_array(stripe->arena, DBGI_Binary, 1); - SLLQueuePush(slot->first, slot->last, binary); - binary->exe_path = push_str8_copy(stripe->arena, exe_path); - binary->gen += 1; - } - binary->refcount += 1; - is_new = (binary->refcount == 1); - } - if(is_new) - { - dbgi_u2p_enqueue_exe_path(exe_path, 0); - } - scratch_end(scratch); -} - -internal void -dbgi_binary_close(String8 exe_path) -{ - Temp scratch = scratch_begin(0, 0); - exe_path = path_normalized_from_string(scratch.arena, exe_path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; - OS_MutexScopeW(stripe->rw_mutex) - { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - B32 need_deletion = 0; - if(binary != 0 && binary->refcount>0) - { - 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; - } + node = n; + most_recent_timestamp = (n->key.min_timestamp - key->min_timestamp); } } - scratch_end(scratch); -} - -internal DBGI_Parse * -dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us) -{ - Temp scratch = scratch_begin(0, 0); - exe_path = path_normalized_from_string(scratch.arena, exe_path); - DBGI_Parse *parse = &dbgi_parse_nil; - if(exe_path.size != 0) - { - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - U64 hash = dbgi_hash_from_string(exe_path, match_flags); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; - B32 sent = 0; - OS_MutexScopeR(stripe->rw_mutex) for(;;) - { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - if(binary != 0 && !(binary->flags & DBGI_BinaryFlag_ParseInFlight)) - { - if(binary->parse.gen == binary->gen) - { - dbgi_scope_touch_binary__stripe_mutex_r_guarded(scope, binary); - parse = &binary->parse; - break; - } - else if(!sent && - ins_atomic_u64_eval(&binary->last_time_enqueued_for_parse_us) == 0 && - dbgi_u2p_enqueue_exe_path(exe_path, endt_us)) - { - sent = 1; - ins_atomic_u64_eval_assign(&binary->last_time_enqueued_for_parse_us, os_now_microseconds()); - } - } - if(os_now_microseconds() >= endt_us) - { - break; - } - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); - } - } - scratch_end(scratch); - return parse; + return node; } //////////////////////////////// -//~ rjf: Fuzzy Search Cache Functions +//~ rjf: Per-Stripe Functions -internal DBGI_FuzzySearchItemArray -dbgi_fuzzy_search_items_from_key_exe_query(DBGI_Scope *scope, U128 key, String8 exe_path, String8 query, DBGI_FuzzySearchTarget target, U64 endt_us, B32 *stale_out) +internal U64 +di_string_bucket_idx_from_string_size(U64 size) { - Temp scratch = scratch_begin(0, 0); - DBGI_FuzzySearchItemArray items = {0}; - exe_path = path_normalized_from_string(scratch.arena, exe_path); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); + U64 size_rounded = u64_up_to_pow2(size+1); + size_rounded = ClampBot((1<<4), size_rounded); + U64 bucket_idx = 0; + switch(size_rounded) { - //- rjf: unpack key - U64 slot_idx = key.u64[1]%dbgi_shared->fuzzy_search_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->fuzzy_search_stripes_count; - DBGI_FuzzySearchSlot *slot = &dbgi_shared->fuzzy_search_slots[slot_idx]; - DBGI_FuzzySearchStripe *stripe = &dbgi_shared->fuzzy_search_stripes[stripe_idx]; - - //- rjf: query and/or request - OS_MutexScopeR(stripe->rw_mutex) for(;;) + case 1<<4: {bucket_idx = 0;}break; + case 1<<5: {bucket_idx = 1;}break; + case 1<<6: {bucket_idx = 2;}break; + case 1<<7: {bucket_idx = 3;}break; + case 1<<8: {bucket_idx = 4;}break; + case 1<<9: {bucket_idx = 5;}break; + case 1<<10:{bucket_idx = 6;}break; + default:{bucket_idx = ArrayCount(((DI_Stripe *)0)->free_string_chunks)-1;}break; + } + return bucket_idx; +} + +internal String8 +di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) +{ + if(string.size == 0) {return str8_zero();} + U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); + DI_StringChunkNode *node = stripe->free_string_chunks[bucket_idx]; + + // rjf: pull from bucket free list + if(node != 0) + { + if(bucket_idx == ArrayCount(stripe->free_string_chunks)-1) { - // rjf: map key -> node - DBGI_FuzzySearchNode *node = 0; - for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) + node = 0; + DI_StringChunkNode *prev = 0; + for(DI_StringChunkNode *n = stripe->free_string_chunks[bucket_idx]; + n != 0; + prev = n, n = n->next) { - if(u128_match(n->key, key)) + if(n->size >= string.size+1) { + if(prev == 0) + { + stripe->free_string_chunks[bucket_idx] = n->next; + } + else + { + prev->next = n->next; + } node = n; break; } } + } + else + { + SLLStackPop(stripe->free_string_chunks[bucket_idx]); + } + } + + // rjf: no found node -> allocate new + if(node == 0) + { + U64 chunk_size = 0; + if(bucket_idx < ArrayCount(stripe->free_string_chunks)-1) + { + chunk_size = 1<<(bucket_idx+4); + } + else + { + chunk_size = u64_up_to_pow2(string.size); + } + U8 *chunk_memory = push_array(stripe->arena, U8, chunk_size); + node = (DI_StringChunkNode *)chunk_memory; + } + + // rjf: fill string & return + String8 allocated_string = str8((U8 *)node, string.size); + MemoryCopy((U8 *)node, string.str, string.size); + return allocated_string; +} + +internal void +di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string) +{ + if(string.size == 0) {return;} + U64 bucket_idx = di_string_bucket_idx_from_string_size(string.size); + DI_StringChunkNode *node = (DI_StringChunkNode *)string.str; + node->size = u64_up_to_pow2(string.size); + SLLStackPush(stripe->free_string_chunks[bucket_idx], node); +} + +//////////////////////////////// +//~ rjf: Key Opening/Closing + +internal void +di_open(DI_Key *key) +{ + Temp scratch = scratch_begin(0, 0); + if(key->path.size != 0) + { + DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key); + U64 hash = di_hash_from_key(&key_normalized); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + log_infof("opening debug info: %S [0x%I64x]\n", key_normalized.path, key_normalized.min_timestamp); + OS_MutexScopeW(stripe->rw_mutex) + { + //- rjf: find existing node + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized); - // rjf: no node? -> allocate - if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) + //- rjf: allocate node if none exists; insert into slot + if(node == 0) { - node = push_array(stripe->arena, DBGI_FuzzySearchNode, 1); - SLLQueuePush(slot->first, slot->last, node); - node->key = key; - for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1) + U64 current_timestamp = os_properties_from_file_path(key_normalized.path).modified; + if(current_timestamp == 0) { - node->buckets[idx].arena = arena_alloc(); + current_timestamp = key_normalized.min_timestamp; } + node = stripe->free_node; + if(node != 0) + { + SLLStackPop(stripe->free_node); + } + else + { + node = push_array_no_zero(stripe->arena, DI_Node, 1); + } + MemoryZeroStruct(node); + DLLPushBack(slot->first, slot->last, node); + String8 path_stored = di_string_alloc__stripe_mutex_w_guarded(stripe, key_normalized.path); + node->key.path = path_stored; + node->key.min_timestamp = current_timestamp; } - // rjf: try to grab last valid results for this key/query; determine if stale - B32 stale = 1; - if(str8_match(exe_path, node->buckets[node->gen%ArrayCount(node->buckets)].exe_path, match_flags) && - target == node->buckets[node->gen%ArrayCount(node->buckets)].target && - node->gen != 0) + //- rjf: increment node reference count + if(node != 0) { - dbgi_scope_touch_fuzzy_search__stripe_mutex_r_guarded(scope, node); - items = node->gen_items; - stale = !str8_match(query, node->buckets[node->gen%ArrayCount(node->buckets)].query, 0); - *stale_out = stale; - } - - // rjf: if stale -> request again - if(stale) OS_MutexScopeRWPromote(stripe->rw_mutex) - { - if(node->gen <= node->submit_gen && node->submit_gen < node->gen + ArrayCount(node->buckets)-1) + node->ref_count += 1; + if(node->ref_count == 1) { - node->submit_gen += 1; - arena_clear(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena); - node->buckets[node->submit_gen%ArrayCount(node->buckets)].exe_path = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, exe_path); - node->buckets[node->submit_gen%ArrayCount(node->buckets)].query = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, query); - node->buckets[node->submit_gen%ArrayCount(node->buckets)].target = target; - } - if((node->submit_gen > node->gen+1 || os_now_microseconds() >= node->last_time_submitted_us+100000) && - dbgi_u2f_enqueue_req(key, endt_us)) - { - node->last_time_submitted_us = os_now_microseconds(); + di_u2p_enqueue_key(&key_normalized, max_U64); } } + } + } + scratch_end(scratch); +} + +internal void +di_close(DI_Key *key) +{ + Temp scratch = scratch_begin(0, 0); + if(key->path.size != 0) + { + DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key); + U64 hash = di_hash_from_key(&key_normalized); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + log_infof("closing debug info: %S [0x%I64x]\n", key_normalized.path, key_normalized.min_timestamp); + OS_MutexScopeW(stripe->rw_mutex) + { + //- rjf: find existing node + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized); - // rjf: not stale, or timeout -> break - if(!stale || os_now_microseconds() >= endt_us) + //- rjf: node exists -> decrement reference count; release + if(node != 0) + { + node->ref_count -= 1; + if(node->ref_count == 0) for(;;) + { + //- rjf: wait for touch count to go to 0 + if(ins_atomic_u64_eval(&node->touch_count) != 0) + { + os_rw_mutex_drop_w(stripe->rw_mutex); + for(U64 start_t = os_now_microseconds(); os_now_microseconds() <= start_t + 250;); + os_rw_mutex_take_w(stripe->rw_mutex); + } + + //- rjf: release + if(node->ref_count == 0 && ins_atomic_u64_eval(&node->touch_count) == 0) + { + di_string_release__stripe_mutex_w_guarded(stripe, node->key.path); + if(node->file_base != 0) + { + os_file_map_view_close(node->file_map, node->file_base); + } + if(!os_handle_match(node->file_map, os_handle_zero())) + { + os_file_map_close(node->file_map); + } + if(!os_handle_match(node->file, os_handle_zero())) + { + os_file_close(node->file); + } + if(node->arena != 0) + { + arena_release(node->arena); + } + DLLRemove(slot->first, slot->last, node); + SLLStackPush(stripe->free_node, node); + break; + } + } + } + } + } + scratch_end(scratch); +} + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal RDI_Parsed * +di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us) +{ + RDI_Parsed *result = &di_rdi_parsed_nil; + if(key->path.size != 0) + { + Temp scratch = scratch_begin(0, 0); + DI_Key key_normalized = di_normalized_key_from_key(scratch.arena, key); + U64 hash = di_hash_from_key(&key_normalized); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + //- rjf: find existing node + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key_normalized); + + //- rjf: no node? this path is not opened + if(node == 0) { break; } - // rjf: no results, but have time to wait -> wait - os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + //- rjf: parse done -> touch, grab result + if(node != 0 && node->parse_done) + { + di_scope_touch_node__stripe_mutex_r_guarded(scope, node); + result = &node->rdi; + break; + } + + //- rjf: parse not done, not working, asked a while ago -> ask for parse + B32 sent = 0; + if(node != 0 && !node->parse_done && !node->is_working && ins_atomic_u64_eval(&node->last_time_requested_us)+1000000last_time_requested_us, os_now_microseconds()); + } + } + + //- rjf: time expired -> break + if(os_now_microseconds() >= endt_us) + { + break; + } + + //- rjf: wait on this stripe + { + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } } + scratch_end(scratch); } - scratch_end(scratch); - return items; + return result; } //////////////////////////////// -//~ rjf: Analysis Threads +//~ rjf: Parse Threads internal B32 -dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us) +di_u2p_enqueue_key(DI_Key *key, U64 endt_us) { B32 sent = 0; - OS_MutexScope(dbgi_shared->u2p_ring_mutex) for(;;) + OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->u2p_ring_write_pos-dbgi_shared->u2p_ring_read_pos); - U64 available_size = dbgi_shared->u2p_ring_size-unconsumed_size; - U64 needed_size = sizeof(U64)+exe_path.size; - needed_size += 7; - needed_size -= needed_size%8; - if(available_size >= needed_size) + U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; + U64 available_size = di_shared->u2p_ring_size - unconsumed_size; + if(available_size >= sizeof(key->path.size) + key->path.size + sizeof(key->min_timestamp)) { - dbgi_shared->u2p_ring_write_pos += ring_write_struct(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_write_pos, &exe_path.size); - dbgi_shared->u2p_ring_write_pos += ring_write(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_write_pos, exe_path.str, exe_path.size); - dbgi_shared->u2p_ring_write_pos += 7; - dbgi_shared->u2p_ring_write_pos -= dbgi_shared->u2p_ring_write_pos%8; + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &key->path.size); + di_shared->u2p_ring_write_pos += ring_write(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, key->path.str, key->path.size); + di_shared->u2p_ring_write_pos += ring_write_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_write_pos, &key->min_timestamp); + di_shared->u2p_ring_write_pos += 7; + di_shared->u2p_ring_write_pos -= di_shared->u2p_ring_write_pos%8; sent = 1; break; } @@ -555,210 +488,142 @@ dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us) { break; } - os_condition_variable_wait(dbgi_shared->u2p_ring_cv, dbgi_shared->u2p_ring_mutex, endt_us); + os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, endt_us); + } + if(sent) + { + os_condition_variable_broadcast(di_shared->u2p_ring_cv); } - os_condition_variable_broadcast(dbgi_shared->u2p_ring_cv); return sent; } -internal String8 -dbgi_u2p_dequeue_exe_path(Arena *arena) +internal void +di_u2p_dequeue_key(Arena *arena, DI_Key *out_key) { - String8 result = {0}; - OS_MutexScope(dbgi_shared->u2p_ring_mutex) for(;;) + OS_MutexScope(di_shared->u2p_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->u2p_ring_write_pos-dbgi_shared->u2p_ring_read_pos); - if(unconsumed_size != 0) + U64 unconsumed_size = di_shared->u2p_ring_write_pos - di_shared->u2p_ring_read_pos; + if(unconsumed_size >= sizeof(out_key->path.size) + sizeof(out_key->min_timestamp)) { - dbgi_shared->u2p_ring_read_pos += ring_read_struct(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_read_pos, &result.size); - result.str = push_array_no_zero(arena, U8, result.size); - dbgi_shared->u2p_ring_read_pos += ring_read(dbgi_shared->u2p_ring_base, dbgi_shared->u2p_ring_size, dbgi_shared->u2p_ring_read_pos, result.str, result.size); - dbgi_shared->u2p_ring_read_pos += 7; - dbgi_shared->u2p_ring_read_pos -= dbgi_shared->u2p_ring_read_pos%8; + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_key->path.size); + out_key->path.str = push_array(arena, U8, out_key->path.size); + di_shared->u2p_ring_read_pos += ring_read(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, out_key->path.str, out_key->path.size); + di_shared->u2p_ring_read_pos += ring_read_struct(di_shared->u2p_ring_base, di_shared->u2p_ring_size, di_shared->u2p_ring_read_pos, &out_key->min_timestamp); + di_shared->u2p_ring_read_pos += 7; + di_shared->u2p_ring_read_pos -= di_shared->u2p_ring_read_pos%8; break; } - os_condition_variable_wait(dbgi_shared->u2p_ring_cv, dbgi_shared->u2p_ring_mutex, max_U64); + os_condition_variable_wait(di_shared->u2p_ring_cv, di_shared->u2p_ring_mutex, max_U64); } - os_condition_variable_broadcast(dbgi_shared->u2p_ring_cv); - return result; + os_condition_variable_broadcast(di_shared->u2p_ring_cv); } internal void -dbgi_p2u_push_event(DBGI_Event *event) +di_p2u_push_event(DI_Event *event) { - OS_MutexScope(dbgi_shared->p2u_ring_mutex) for(;;) + OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->p2u_ring_write_pos-dbgi_shared->p2u_ring_read_pos); - U64 available_size = dbgi_shared->p2u_ring_size-unconsumed_size; - U64 needed_size = sizeof(DBGI_EventKind) + sizeof(U64) + event->string.size; + U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); + U64 available_size = di_shared->p2u_ring_size-unconsumed_size; + U64 needed_size = sizeof(DI_EventKind) + sizeof(U64) + event->string.size; if(available_size >= needed_size) { - dbgi_shared->p2u_ring_write_pos += ring_write_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, &event->kind); - dbgi_shared->p2u_ring_write_pos += ring_write_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, &event->string.size); - dbgi_shared->p2u_ring_write_pos += ring_write(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_write_pos, event->string.str, event->string.size); - dbgi_shared->p2u_ring_write_pos += 7; - dbgi_shared->p2u_ring_write_pos -= dbgi_shared->p2u_ring_write_pos%8; + di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->kind); + di_shared->p2u_ring_write_pos += ring_write_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, &event->string.size); + di_shared->p2u_ring_write_pos += ring_write(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_write_pos, event->string.str, event->string.size); + di_shared->p2u_ring_write_pos += 7; + di_shared->p2u_ring_write_pos -= di_shared->p2u_ring_write_pos%8; break; } - os_condition_variable_wait(dbgi_shared->p2u_ring_cv, dbgi_shared->p2u_ring_mutex, max_U64); + os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, max_U64); } - os_condition_variable_broadcast(dbgi_shared->p2u_ring_cv); + os_condition_variable_broadcast(di_shared->p2u_ring_cv); } -internal DBGI_EventList -dbgi_p2u_pop_events(Arena *arena, U64 endt_us) +internal DI_EventList +di_p2u_pop_events(Arena *arena, U64 endt_us) { - DBGI_EventList events = {0}; - OS_MutexScope(dbgi_shared->p2u_ring_mutex) for(;;) + DI_EventList events = {0}; + OS_MutexScope(di_shared->p2u_ring_mutex) for(;;) { - U64 unconsumed_size = (dbgi_shared->p2u_ring_write_pos-dbgi_shared->p2u_ring_read_pos); - if(unconsumed_size >= sizeof(DBGI_EventKind) + sizeof(U64)) + U64 unconsumed_size = (di_shared->p2u_ring_write_pos-di_shared->p2u_ring_read_pos); + if(unconsumed_size >= sizeof(DI_EventKind) + sizeof(U64)) { - DBGI_EventNode *n = push_array(arena, DBGI_EventNode, 1); + DI_EventNode *n = push_array(arena, DI_EventNode, 1); SLLQueuePush(events.first, events.last, n); events.count += 1; - dbgi_shared->p2u_ring_read_pos += ring_read_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, &n->v.kind); - dbgi_shared->p2u_ring_read_pos += ring_read_struct(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, &n->v.string.size); + di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.kind); + di_shared->p2u_ring_read_pos += ring_read_struct(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, &n->v.string.size); n->v.string.str = push_array_no_zero(arena, U8, n->v.string.size); - dbgi_shared->p2u_ring_read_pos += ring_read(dbgi_shared->p2u_ring_base, dbgi_shared->p2u_ring_size, dbgi_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); - dbgi_shared->p2u_ring_read_pos += 7; - dbgi_shared->p2u_ring_read_pos -= dbgi_shared->p2u_ring_read_pos%8; + di_shared->p2u_ring_read_pos += ring_read(di_shared->p2u_ring_base, di_shared->p2u_ring_size, di_shared->p2u_ring_read_pos, n->v.string.str, n->v.string.size); + di_shared->p2u_ring_read_pos += 7; + di_shared->p2u_ring_read_pos -= di_shared->p2u_ring_read_pos%8; } else if(os_now_microseconds() >= endt_us) { break; } - os_condition_variable_wait(dbgi_shared->p2u_ring_cv, dbgi_shared->p2u_ring_mutex, endt_us); + os_condition_variable_wait(di_shared->p2u_ring_cv, di_shared->p2u_ring_mutex, endt_us); } - os_condition_variable_broadcast(dbgi_shared->p2u_ring_cv); + os_condition_variable_broadcast(di_shared->p2u_ring_cv); return events; } internal void -dbgi_parse_thread_entry_point(void *p) +di_parse_thread__entry_point(void *p) { - ThreadNameF("[dbgi] parse #%I64U", (U64)p); + ThreadNameF("[di] parse #%I64u", (U64)p); for(;;) { Temp scratch = scratch_begin(0, 0); - //- rjf: grab next path & unpack - String8 exe_path = dbgi_u2p_dequeue_exe_path(scratch.arena); - StringMatchFlags match_flags = path_match_flags_from_os(operating_system_from_context()); - ProfBegin("begin task for \"%.*s\"", str8_varg(exe_path)); - U64 hash = dbgi_hash_from_string(exe_path, path_match_flags_from_os(operating_system_from_context())); - U64 slot_idx = hash%dbgi_shared->binary_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->binary_stripes_count; - DBGI_BinarySlot *slot = &dbgi_shared->binary_slots[slot_idx]; - DBGI_BinaryStripe *stripe = &dbgi_shared->binary_stripes[stripe_idx]; + //////////////////////////// + //- rjf: grab next key + // + DI_Key key = {0}; + di_u2p_dequeue_key(scratch.arena, &key); + String8 og_path = key.path; + U64 min_timestamp = key.min_timestamp; - //- rjf: determine if binary's analysis work is taken by another thread. - // if not, take it - B32 task_is_taken_by_other_thread = 0; - OS_MutexScopeW(stripe->rw_mutex) + //////////////////////////// + //- rjf: unpack key + // + U64 hash = di_hash_from_string(og_path, StringMatchFlag_CaseInsensitive); + U64 slot_idx = hash%di_shared->slots_count; + U64 stripe_idx = slot_idx%di_shared->stripes_count; + DI_Slot *slot = &di_shared->slots[slot_idx]; + DI_Stripe *stripe = &di_shared->stripes[stripe_idx]; + + //////////////////////////// + //- rjf: take task + // + B32 got_task = 0; + OS_MutexScopeR(stripe->rw_mutex) { - DBGI_Binary *binary = 0; - for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key); + if(node != 0) { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - binary = bin; - break; - } - } - if(binary == 0 || binary->flags&DBGI_BinaryFlag_ParseInFlight || binary->refcount == 0) - { - task_is_taken_by_other_thread = 1; - } - else if(binary != 0) - { - binary->flags |= DBGI_BinaryFlag_ParseInFlight; + got_task = !ins_atomic_u64_eval_cond_assign(&node->is_working, 1, 0); } } - //- rjf: is the work taken? -> abort - B32 do_task = 1; - if(task_is_taken_by_other_thread) + //////////////////////////// + //- rjf: got task -> open O.G. file (may or may not be RDI) + // + B32 og_format_is_known = 0; + B32 og_is_pe = 0; + B32 og_is_pdb = 0; + B32 og_is_elf = 0; + B32 og_is_rdi = 0; + FileProperties og_props = {0}; + if(got_task) ProfScope("analyze %.*s", str8_varg(og_path)) { - do_task = 0; - } - - //- rjf: open exe file & map into address space - OS_Handle exe_file = {0}; - FileProperties exe_file_props = {0}; - OS_Handle exe_file_map = {0}; - void *exe_file_base = 0; - if(do_task) - { - exe_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, exe_path); - exe_file_props = os_properties_from_file(exe_file); - exe_file_map = os_file_map_open(OS_AccessFlag_Read, exe_file); - exe_file_base = os_file_map_view_open(exe_file_map, OS_AccessFlag_Read, r1u64(0, exe_file_props.size)); - } - - //- rjf: parse exe file info - Arena *parse_arena = 0; - PE_BinInfo exe_pe_info = {0}; - String8 exe_dbg_path_embedded_absolute = {0}; - String8 exe_dbg_path_embedded_relative = {0}; - if(do_task) - { - parse_arena = arena_alloc(); - if(exe_file_props.size >= 2 && *(U16 *)exe_file_base == PE_DOS_MAGIC) - { - String8 exe_data = str8((U8 *)exe_file_base, exe_file_props.size); - exe_pe_info = pe_bin_info_from_data(parse_arena, exe_data); - exe_dbg_path_embedded_absolute = str8_cstring_capped((char *)exe_data.str+exe_pe_info.dbg_path_off, (char *)exe_data.str+exe_pe_info.dbg_path_off+Min(exe_data.size-exe_pe_info.dbg_path_off, 4096)); - String8 exe_folder = str8_chop_last_slash(exe_path); - exe_dbg_path_embedded_relative = push_str8f(scratch.arena, "%S/%S", exe_folder, exe_dbg_path_embedded_absolute); - } - } - - //- rjf: determine O.G. (may or may not be RADDBG) dbg path - String8 og_dbg_path = {0}; - if(do_task) ProfScope("determine O.G. dbg path") - { - String8 forced_og_dbg_path = dbgi_forced_dbg_path_from_exe_path(scratch.arena, exe_path); - if(forced_og_dbg_path.size != 0) - { - og_dbg_path = forced_og_dbg_path; - } - else - { - String8 possible_og_dbg_paths[] = - { - /* inferred (treated as absolute): */ exe_dbg_path_embedded_absolute, - /* inferred (treated as relative): */ exe_dbg_path_embedded_relative, - /* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(exe_path)), - /* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", exe_path), - }; - for(U64 idx = 0; idx < ArrayCount(possible_og_dbg_paths); idx += 1) - { - FileProperties props = os_properties_from_file_path(possible_og_dbg_paths[idx]); - if(props.modified != 0 && props.size != 0) - { - og_dbg_path = possible_og_dbg_paths[idx]; - break; - } - } - } - } - - //- rjf: analyze O.G. dbg file - B32 og_dbg_format_is_known = 0; - B32 og_dbg_is_pe = 0; - B32 og_dbg_is_pdb = 0; - B32 og_dbg_is_elf = 0; - B32 og_dbg_is_raddbg = 0; - FileProperties og_dbg_props = {0}; - if(do_task) ProfScope("analyze O.G. dbg file") - { - OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, og_dbg_path); + OS_Handle file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, og_path); OS_Handle file_map = os_file_map_open(OS_AccessFlag_Read, file); - FileProperties props = og_dbg_props = os_properties_from_file(file); + FileProperties props = og_props = os_properties_from_file(file); void *base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, props.size)); String8 data = str8((U8 *)base, props.size); - if(!og_dbg_format_is_known) + if(!og_format_is_known) { String8 msf20_magic = str8_lit("Microsoft C/C++ program database 2.00\r\n\x1aJG\0\0"); String8 msf70_magic = str8_lit("Microsoft C/C++ MSF 7.00\r\n\032DS\0\0"); @@ -767,19 +632,19 @@ dbgi_parse_thread_entry_point(void *p) (data.size >= msf70_magic.size && str8_match(data, msf70_magic, StringMatchFlag_RightSideSloppy)) || (data.size >= msfxx_magic.size && str8_match(data, msfxx_magic, StringMatchFlag_RightSideSloppy))) { - og_dbg_format_is_known = 1; - og_dbg_is_pdb = 1; + og_format_is_known = 1; + og_is_pdb = 1; } } - if(!og_dbg_format_is_known) + if(!og_format_is_known) { if(data.size >= 8 && *(U64 *)data.str == RDI_MAGIC_CONSTANT) { - og_dbg_format_is_known = 1; - og_dbg_is_raddbg = 1; + og_format_is_known = 1; + og_is_rdi = 1; } } - if(!og_dbg_format_is_known) + if(!og_format_is_known) { if(data.size >= 4 && data.str[0] == 0x7f && @@ -787,16 +652,16 @@ dbgi_parse_thread_entry_point(void *p) data.str[2] == 'L' && data.str[3] == 'F') { - og_dbg_format_is_known = 1; - og_dbg_is_elf = 1; + og_format_is_known = 1; + og_is_elf = 1; } } - if(!og_dbg_format_is_known) + if(!og_format_is_known) { - if(data.size >= 2 && *(U16 *)data.str == PE_DOS_MAGIC) + if(data.size >= 2 && *(U16 *)data.str == 0x5a4d) { - og_dbg_format_is_known = 1; - og_dbg_is_pe = 1; + og_format_is_known = 1; + og_is_pe = 1; } } os_file_map_view_close(file_map, base); @@ -804,41 +669,47 @@ dbgi_parse_thread_entry_point(void *p) os_file_close(file); } - //- rjf: given O.G. path & analysis, determine RADDBG file path - String8 raddbgi_path = {0}; - if(do_task) + //////////////////////////// + //- rjf: given O.G. path & analysis, determine RDI path + // + String8 rdi_path = {0}; + if(got_task) { - if(og_dbg_is_raddbg) + if(og_is_rdi) { - raddbgi_path = og_dbg_path; + rdi_path = og_path; } - else if(og_dbg_format_is_known && og_dbg_is_pdb) + else if(og_format_is_known && og_is_pdb) { - raddbgi_path = push_str8f(scratch.arena, "%S.raddbgi", str8_chop_last_dot(og_dbg_path)); + rdi_path = push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(og_path)); } } - //- rjf: check if raddbg file is up-to-date - B32 raddbgi_file_is_up_to_date = 0; - if(do_task) + //////////////////////////// + //- rjf: check if rdi file is up-to-date + // + B32 rdi_file_is_up_to_date = 0; + if(got_task) { - if(raddbgi_path.size != 0) + if(rdi_path.size != 0) ProfScope("check %.*s is up-to-date", str8_varg(rdi_path)) { - FileProperties props = os_properties_from_file_path(raddbgi_path); - raddbgi_file_is_up_to_date = (props.modified > og_dbg_props.modified); + FileProperties props = os_properties_from_file_path(rdi_path); + rdi_file_is_up_to_date = (props.modified > og_props.modified); } } + //////////////////////////// //- rjf: if raddbg file is up to date based on timestamp, check the // encoding generation number & size, to see if we need to regenerate it // regardless - if(do_task && raddbgi_file_is_up_to_date) + // + if(got_task && rdi_file_is_up_to_date) ProfScope("check %.*s version matches our's", str8_varg(rdi_path)) { OS_Handle file = {0}; OS_Handle file_map = {0}; FileProperties file_props = {0}; void *file_base = 0; - file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, raddbgi_path); + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead, rdi_path); file_map = os_file_map_open(OS_AccessFlag_Read, file); file_props = os_properties_from_file(file); file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); @@ -847,213 +718,140 @@ dbgi_parse_thread_entry_point(void *p) RDI_Header *header = (RDI_Header*)file_base; if(header->encoding_version != RDI_ENCODING_VERSION) { - raddbgi_file_is_up_to_date = 0; + rdi_file_is_up_to_date = 0; } } else { - raddbgi_file_is_up_to_date = 0; + rdi_file_is_up_to_date = 0; } os_file_map_view_close(file_map, file_base); os_file_map_close(file_map); os_file_close(file); } + //////////////////////////// //- rjf: heuristically choose compression settings + // B32 should_compress = 0; +#if 0 if(og_dbg_props.size > MB(64)) { should_compress = 1; } +#endif - //- rjf: raddbg file not up-to-date? we need to generate it - if(do_task) + //////////////////////////// + //- rjf: rdi file not up-to-date? we need to generate it + // + if(got_task && !rdi_file_is_up_to_date) ProfScope("generate %.*s", str8_varg(rdi_path)) { - if(!raddbgi_file_is_up_to_date) ProfScope("generate raddbg file") + if(og_is_pdb) { - if(og_dbg_is_pdb) + //- rjf: push conversion task begin event { - // rjf: push conversion task begin event + DI_Event event = {DI_EventKind_ConversionStarted}; + event.string = rdi_path; + di_p2u_push_event(&event); + } + + //- rjf: kick off process + OS_Handle process = {0}; + { + OS_LaunchOptions opts = {0}; + opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); + opts.inherit_env = 1; + opts.consoleless = 1; + str8_list_pushf(scratch.arena, &opts.cmd_line, "raddbg"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--convert"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--quiet"); + if(should_compress) { - DBGI_Event event = {DBGI_EventKind_ConversionStarted}; - event.string = raddbgi_path; - dbgi_p2u_push_event(&event); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--compress"); } - - // rjf: kick off process - OS_Handle process = {0}; + //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_path); + str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", rdi_path); + os_launch_process(&opts, &process); + } + + //- rjf: wait for process to complete + { + U64 start_wait_t = os_now_microseconds(); + for(;;) { - OS_LaunchOptions opts = {0}; - opts.path = os_string_from_system_path(scratch.arena, OS_SystemPath_Binary); - opts.inherit_env = 1; - opts.consoleless = 1; - str8_list_pushf(scratch.arena, &opts.cmd_line, "raddbg"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--convert"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--quiet"); - if(should_compress) + B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); + if(wait_done) { - str8_list_pushf(scratch.arena, &opts.cmd_line, "--compress"); - } - //str8_list_pushf(scratch.arena, &opts.cmd_line, "--capture"); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--exe:%S", exe_path); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--pdb:%S", og_dbg_path); - str8_list_pushf(scratch.arena, &opts.cmd_line, "--out:%S", raddbgi_path); - os_launch_process(&opts, &process); - } - - // rjf: wait for process to complete - { - U64 start_wait_t = os_now_microseconds(); - for(;;) - { - B32 wait_done = os_process_wait(process, os_now_microseconds()+1000); - if(wait_done) - { - raddbgi_file_is_up_to_date = 1; - break; - } - if(os_now_microseconds()-start_wait_t > 10000000 && og_dbg_props.size < MB(64)) - { - // os_graphical_message(1, str8_lit("RADDBG INTERNAL DEVELOPMENT MESSAGE"), str8_lit("this is taking a while... indicative of something that seemed like a bug that Jeff hit before. attach with debugger now & see where the callstack is?")); - } + rdi_file_is_up_to_date = 1; + break; } } - - // rjf: push conversion task end event - { - DBGI_Event event = {DBGI_EventKind_ConversionEnded}; - event.string = raddbgi_path; - dbgi_p2u_push_event(&event); - } } - else + + //- rjf: push conversion task end event { - // NOTE(rjf): we cannot convert from this O.G. debug info format right now. - // rjf: push conversion task failure event - { - DBGI_Event event = {DBGI_EventKind_ConversionFailureUnsupportedFormat}; - event.string = raddbgi_path; - dbgi_p2u_push_event(&event); - } + DI_Event event = {DI_EventKind_ConversionEnded}; + event.string = rdi_path; + di_p2u_push_event(&event); } } - } - - //- rjf: open raddbg file & gather info - OS_Handle raddbgi_file = {0}; - OS_Handle raddbgi_file_map = {0}; - FileProperties raddbgi_file_props = {0}; - void *raddbgi_file_base = 0; - if(do_task && raddbgi_file_is_up_to_date) - { - raddbgi_file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, raddbgi_path); - raddbgi_file_map = os_file_map_open(OS_AccessFlag_Read, raddbgi_file); - raddbgi_file_props = os_properties_from_file(raddbgi_file); - raddbgi_file_base = os_file_map_view_open(raddbgi_file_map, OS_AccessFlag_Read, r1u64(0, raddbgi_file_props.size)); - } - - //- rjf: cache write, step 0: busy-loop-wait for all scope touches to be done - if(do_task) ProfScope("cache write, step 0: busy-loop-wait for all scope touches to be done") - { - for(B32 done = 0; done == 0;) + else { - OS_MutexScopeR(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + // NOTE(rjf): we cannot convert from this O.G. debug info format right now. + //- rjf: push conversion task failure event { - if(str8_match(bin->exe_path, exe_path, match_flags) && - bin->scope_touch_count == 0) - { - done = 1; - break; - } + DI_Event event = {DI_EventKind_ConversionFailureUnsupportedFormat}; + event.string = rdi_path; + di_p2u_push_event(&event); } } } - //- rjf: cache write, step 1: check if refcount is still nonzero, & - // 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 raddbgi_or_exe_file_is_updated = 0; - if(do_task) ProfScope("cache write, step 1: check if raddbg is new & clear") + //////////////////////////// + //- rjf: got task -> open file + // + OS_Handle file = {0}; + OS_Handle file_map = {0}; + FileProperties file_props = {0}; + void *file_base = 0; + if(got_task) { - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - if(bin->refcount == 0) - { - binary_refcount_is_zero = 1; - break; - } - if(bin->parse.dbg_props.modified != raddbgi_file_props.modified || - bin->parse.exe_props.modified != exe_file_props.modified) - { - raddbgi_or_exe_file_is_updated = 1; - - // rjf: clean up old stuff - 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);} - MemoryZeroStruct(&bin->parse); - bin->last_time_enqueued_for_parse_us = 0; - - // rjf: store new handles & props - bin->exe_file = exe_file; - bin->exe_file_map = exe_file_map; - bin->parse.exe_base = exe_file_base; - bin->parse.exe_props = exe_file_props; - bin->dbg_file = raddbgi_file; - bin->dbg_file_map = raddbgi_file_map; - bin->parse.dbg_base = raddbgi_file_base; - bin->parse.dbg_props = raddbgi_file_props; - bin->gen += 1; - } - break; - } - } + file = os_file_open(OS_AccessFlag_Read|OS_AccessFlag_ShareRead|OS_AccessFlag_ShareWrite, rdi_path); + file_map = os_file_map_open(OS_AccessFlag_Read, file); + file_props = os_properties_from_file(file); + file_base = os_file_map_view_open(file_map, OS_AccessFlag_Read, r1u64(0, file_props.size)); } - //- rjf: raddbg file or exe is not new? cache can stay unmodified, close - // handles & skip to end. - if(do_task) if((!raddbgi_or_exe_file_is_updated && raddbgi_file_is_up_to_date) || binary_refcount_is_zero) + //////////////////////////// + //- rjf: do initial parse of rdi + // + RDI_Parsed rdi_parsed_maybe_compressed = di_rdi_parsed_nil; + if(got_task) { - os_file_map_view_close(raddbgi_file_map, raddbgi_file_base); - os_file_map_close(raddbgi_file_map); - os_file_close(raddbgi_file); - os_file_map_view_close(exe_file_map, exe_file_base); - os_file_map_close(exe_file_map); - os_file_close(exe_file); - arena_release(parse_arena); - do_task = 0; - } - - //- rjf: initial parse of raddbg info - RDI_Parsed rdi_parsed_maybe_compressed = dbgi_parse_nil.rdi; - if(do_task) - { - RDI_ParseStatus parse_status = rdi_parse((U8 *)raddbgi_file_base, raddbgi_file_props.size, &rdi_parsed_maybe_compressed); + RDI_ParseStatus parse_status = rdi_parse((U8 *)file_base, file_props.size, &rdi_parsed_maybe_compressed); (void)parse_status; } - //- rjf: decompress, if necessary + //////////////////////////// + //- rjf: decompress & re-parse, if necessary + // + Arena *rdi_parsed_arena = 0; RDI_Parsed rdi_parsed = rdi_parsed_maybe_compressed; - if(do_task) + if(got_task) { - U64 decompressed_size = raddbgi_file_props.size; + U64 decompressed_size = file_props.size; for(U64 dsec_idx = 0; dsec_idx < rdi_parsed_maybe_compressed.dsec_count; dsec_idx += 1) { decompressed_size += (rdi_parsed_maybe_compressed.dsecs[dsec_idx].unpacked_size - rdi_parsed_maybe_compressed.dsecs[dsec_idx].encoded_size); } - if(decompressed_size > raddbgi_file_props.size) + if(decompressed_size > file_props.size) { - U8 *decompressed_data = push_array_no_zero(parse_arena, U8, decompressed_size); + rdi_parsed_arena = arena_alloc(); + U8 *decompressed_data = push_array_no_zero(rdi_parsed_arena, U8, decompressed_size); // rjf: copy header - RDI_Header *src_header = (RDI_Header *)raddbgi_file_base; + RDI_Header *src_header = (RDI_Header *)file_base; RDI_Header *dst_header = (RDI_Header *)decompressed_data; { MemoryCopy(dst_header, src_header, sizeof(RDI_Header)); @@ -1063,7 +861,7 @@ dbgi_parse_thread_entry_point(void *p) if(rdi_parsed_maybe_compressed.dsec_count != 0) { RDI_DataSection *dsec_base = (RDI_DataSection *)(decompressed_data + dst_header->data_section_off); - MemoryCopy(dsec_base, (U8 *)raddbgi_file_base + src_header->data_section_off, sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count); + MemoryCopy(dsec_base, (U8 *)file_base + src_header->data_section_off, sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count); U64 off = dst_header->data_section_off + sizeof(RDI_DataSection) * rdi_parsed_maybe_compressed.dsec_count; off += 7; off -= off%8; @@ -1089,8 +887,8 @@ dbgi_parse_thread_entry_point(void *p) src < src_opl && dst < dst_opl; src += 1, dst += 1) { - rr_lzb_simple_decode((U8*)raddbgi_file_base + src->off, src->encoded_size, - decompressed_data + dst->off, dst->unpacked_size); + rr_lzb_simple_decode((U8*)file_base + src->off, src->encoded_size, + decompressed_data + dst->off, dst->unpacked_size); } } @@ -1100,312 +898,26 @@ dbgi_parse_thread_entry_point(void *p) } } - //- rjf: cache write, step 2: store parse artifacts - B32 parse_store_good = 0; - if(do_task) ProfScope("cache write, step 2: store parse") + //////////////////////////// + //- rjf: commit parsed info to cache + // + if(got_task) OS_MutexScopeW(stripe->rw_mutex) { - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) + DI_Node *node = di_node_from_key_slot__stripe_mutex_r_guarded(slot, &key); + if(node != 0) { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - String8 dbg_path = og_dbg_path; - if(dbg_path.size == 0) - { - dbg_path = exe_dbg_path_embedded_absolute; - } - if(dbg_path.size == 0) - { - dbg_path = exe_dbg_path_embedded_relative; - } - if(dbg_path.size == 0) - { - dbg_path = push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(exe_path)); - } - parse_store_good = 1; - bin->parse.arena = parse_arena; - bin->parse.dbg_path = push_str8_copy(parse_arena, dbg_path); - MemoryCopyStruct(&bin->parse.pe, &exe_pe_info); - MemoryCopyStruct(&bin->parse.rdi, &rdi_parsed); - bin->parse.gen = bin->gen; - break; - } + node->is_working = 0; + node->file = file; + node->file_map = file_map; + node->file_base = file_base; + node->file_props = file_props; + node->arena = rdi_parsed_arena; + node->rdi = rdi_parsed; + node->parse_done = 1; } } + os_condition_variable_broadcast(stripe->cv); - //- rjf: bad parse store? abort - if(do_task && !parse_store_good) - { - arena_release(parse_arena); - } - - //- rjf: cache write, step 3: mark binary work as complete - if(!task_is_taken_by_other_thread) ProfScope("cache write, step 4: mark binary work as complete") - { - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_Binary *bin = slot->first; bin != 0; bin = bin->next) - { - if(str8_match(bin->exe_path, exe_path, match_flags)) - { - bin->flags &= ~DBGI_BinaryFlag_ParseInFlight; - break; - } - } - os_condition_variable_broadcast(stripe->cv); - } - - ProfEnd(); - scratch_end(scratch); - } -} - -//////////////////////////////// -//~ rjf: Fuzzy Searching Threads - -internal B32 -dbgi_u2f_enqueue_req(U128 key, U64 endt_us) -{ - B32 sent = 0; - DBGI_FuzzySearchThread *thread = &dbgi_shared->fuzzy_threads[key.u64[1]%dbgi_shared->fuzzy_thread_count]; - OS_MutexScope(thread->u2f_ring_mutex) for(;;) - { - U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; - U64 available_size = thread->u2f_ring_size - unconsumed_size; - if(available_size >= sizeof(U128)) - { - sent = 1; - thread->u2f_ring_write_pos += ring_write_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_write_pos, &key); - break; - } - os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, endt_us); - } - if(sent) - { - os_condition_variable_broadcast(thread->u2f_ring_cv); - } - return sent; -} - -internal void -dbgi_u2f_dequeue_req(Arena *arena, DBGI_FuzzySearchThread *thread, U128 *key_out) -{ - OS_MutexScope(thread->u2f_ring_mutex) for(;;) - { - U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; - if(unconsumed_size >= sizeof(U128)) - { - thread->u2f_ring_read_pos += ring_read_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_read_pos, key_out); - break; - } - os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, max_U64); - } - os_condition_variable_broadcast(thread->u2f_ring_cv); -} - -internal int -dbgi_qsort_compare_fuzzy_search_items(DBGI_FuzzySearchItem *a, DBGI_FuzzySearchItem *b) -{ - int result = 0; - if(a->match_ranges.count > b->match_ranges.count) - { - result = -1; - } - else if(a->match_ranges.count < b->match_ranges.count) - { - result = +1; - } - else if(a->missed_size < b->missed_size) - { - result = -1; - } - else if(a->missed_size > b->missed_size) - { - result = +1; - } - return result; -} - -internal void -dbgi_fuzzy_thread__entry_point(void *p) -{ - ThreadNameF("[dbgi] fuzzy search #%I64U", (U64)p); - DBGI_FuzzySearchThread *thread = &dbgi_shared->fuzzy_threads[(U64)p]; - for(;;) - { - Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); - - //- rjf: dequeue next request - U128 key = {0}; - dbgi_u2f_dequeue_req(scratch.arena, thread, &key); - U64 slot_idx = key.u64[1]%dbgi_shared->fuzzy_search_slots_count; - U64 stripe_idx = slot_idx%dbgi_shared->fuzzy_search_stripes_count; - DBGI_FuzzySearchSlot *slot = &dbgi_shared->fuzzy_search_slots[slot_idx]; - DBGI_FuzzySearchStripe *stripe = &dbgi_shared->fuzzy_search_stripes[stripe_idx]; - - //- rjf: grab next exe_path/query for this key - B32 task_is_good = 0; - Arena *task_arena = 0; - String8 exe_path = {0}; - String8 query = {0}; - DBGI_FuzzySearchTarget target = DBGI_FuzzySearchTarget_Procedures; - U64 initial_submit_gen = 0; - OS_MutexScopeW(stripe->rw_mutex) - { - for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - task_is_good = 1; - initial_submit_gen = n->submit_gen; - task_arena = n->buckets[n->submit_gen%ArrayCount(n->buckets)].arena; - exe_path = n->buckets[n->submit_gen%ArrayCount(n->buckets)].exe_path; - query = n->buckets[n->submit_gen%ArrayCount(n->buckets)].query; - target = n->buckets[n->submit_gen%ArrayCount(n->buckets)].target; - break; - } - } - } - - //- rjf: exe_path -> dbgi_parse, raddbg - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64); - RDI_Parsed *rdi = &dbgi->rdi; - - //- rjf: rdi * query -> item list - U64 table_ptr_off = 0; - U64 element_name_idx_off = 0; - U64 element_count = 0; - U64 element_size = 0; - switch(target) - { - // NOTE(rjf): no default! - case DBGI_FuzzySearchTarget_COUNT:{}break; - case DBGI_FuzzySearchTarget_Procedures: - { - table_ptr_off = OffsetOf(RDI_Parsed, procedures); - element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); - element_count = rdi->procedures_count; - element_size = sizeof(RDI_Procedure); - }break; - case DBGI_FuzzySearchTarget_GlobalVariables: - { - table_ptr_off = OffsetOf(RDI_Parsed, global_variables); - element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); - element_count = rdi->global_variables_count; - element_size = sizeof(RDI_GlobalVariable); - }break; - case DBGI_FuzzySearchTarget_ThreadVariables: - { - table_ptr_off = OffsetOf(RDI_Parsed, thread_variables); - element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); - element_count = rdi->thread_variables_count; - element_size = sizeof(RDI_ThreadVariable); - }break; - case DBGI_FuzzySearchTarget_UDTs: - { - table_ptr_off = OffsetOf(RDI_Parsed, udts); - element_count = rdi->udts_count; - element_size = sizeof(RDI_UDT); - }break; - } - DBGI_FuzzySearchItemChunkList items_list = {0}; - if(task_is_good) - { - void *table_base = (U8*)rdi + table_ptr_off; - for(U64 idx = 1; task_is_good && idx < element_count; idx += 1) - { - void *element = (U8 *)(*(void **)table_base) + element_size*idx; - U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off); - if(target == DBGI_FuzzySearchTarget_UDTs) - { - RDI_UDT *udt = (RDI_UDT *)element; - RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); - name_idx_ptr = &type_node->user_defined.name_string_idx; - } - U32 name_idx = *name_idx_ptr; - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); - String8 name = str8(name_base, name_size); - if(name.size == 0) { continue; } - FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name); - if(matches.count == matches.needle_part_count) - { - DBGI_FuzzySearchItemChunk *chunk = items_list.last; - if(chunk == 0 || chunk->count >= chunk->cap) - { - chunk = push_array(scratch.arena, DBGI_FuzzySearchItemChunk, 1); - chunk->cap = 512; - chunk->count = 0; - chunk->v = push_array_no_zero(scratch.arena, DBGI_FuzzySearchItem, chunk->cap); - SLLQueuePush(items_list.first, items_list.last, chunk); - items_list.chunk_count += 1; - } - chunk->v[chunk->count].idx = idx; - chunk->v[chunk->count].match_ranges = matches; - chunk->v[chunk->count].missed_size = (name_size > matches.total_dim) ? (name_size-matches.total_dim) : 0; - chunk->count += 1; - items_list.total_count += 1; - } - if(idx%100 == 99) OS_MutexScopeR(stripe->rw_mutex) - { - for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key) && n->submit_gen > initial_submit_gen) - { - task_is_good = 0; - break; - } - } - } - } - } - - //- rjf: item list -> item array - DBGI_FuzzySearchItemArray items = {0}; - if(task_is_good) - { - items.count = items_list.total_count; - items.v = push_array_no_zero(task_arena, DBGI_FuzzySearchItem, items.count); - U64 idx = 0; - for(DBGI_FuzzySearchItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next) - { - MemoryCopy(items.v+idx, chunk->v, sizeof(DBGI_FuzzySearchItem)*chunk->count); - idx += chunk->count; - } - } - - //- rjf: sort item array - if(items.count != 0 && query.size != 0) - { - qsort(items.v, items.count, sizeof(DBGI_FuzzySearchItem), (int (*)(const void *, const void *))dbgi_qsort_compare_fuzzy_search_items); - } - - //- rjf: commit to cache - busyloop on scope touches - if(task_is_good) - { - for(B32 done = 0; !done;) - { - B32 found = 0; - OS_MutexScopeW(stripe->rw_mutex) for(DBGI_FuzzySearchNode *n = slot->first; n != 0; n = n->next) - { - if(u128_match(n->key, key)) - { - if(n->scope_touch_count == 0) - { - n->gen = initial_submit_gen; - n->gen_items = items; - done = 1; - } - found = 1; - break; - } - } - if(!found) - { - break; - } - } - } - - dbgi_scope_close(scope); scratch_end(scratch); } } diff --git a/src/dbgi/dbgi.h b/src/dbgi/dbgi.h index 2ca9952e..ece98ae6 100644 --- a/src/dbgi/dbgi.h +++ b/src/dbgi/dbgi.h @@ -1,294 +1,170 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef DBGI_H -#define DBGI_H +#ifndef DI_H +#define DI_H //////////////////////////////// -//~ rjf: Info Bundle Types +//~ rjf: Cache Key Type -typedef struct DBGI_Parse DBGI_Parse; -struct DBGI_Parse +typedef struct DI_Key DI_Key; +struct DI_Key { - U64 gen; - Arena *arena; - void *exe_base; - FileProperties exe_props; - String8 dbg_path; - void *dbg_base; - FileProperties dbg_props; - PE_BinInfo pe; - RDI_Parsed rdi; + String8 path; + U64 min_timestamp; }; -//////////////////////////////// -//~ rjf: Exe -> Debug Forced Override Cache Types - -typedef struct DBGI_ForceNode DBGI_ForceNode; -struct DBGI_ForceNode +typedef struct DI_KeyNode DI_KeyNode; +struct DI_KeyNode { - DBGI_ForceNode *next; - String8 exe_path; - U64 dbg_path_cap; - U64 dbg_path_size; - U8 *dbg_path_base; + DI_KeyNode *next; + DI_Key v; }; -typedef struct DBGI_ForceSlot DBGI_ForceSlot; -struct DBGI_ForceSlot +typedef struct DI_KeyList DI_KeyList; +struct DI_KeyList { - DBGI_ForceNode *first; - DBGI_ForceNode *last; -}; - -typedef struct DBGI_ForceStripe DBGI_ForceStripe; -struct DBGI_ForceStripe -{ - Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; -}; - -//////////////////////////////// -//~ rjf: Binary Cache State Types - -typedef U32 DBGI_BinaryFlags; -enum -{ - DBGI_BinaryFlag_ParseInFlight = (1<<0), -}; - -typedef struct DBGI_Binary DBGI_Binary; -struct DBGI_Binary -{ - // rjf: links & metadata - DBGI_Binary *next; - String8 exe_path; - U64 refcount; - U64 scope_touch_count; - U64 last_time_enqueued_for_parse_us; - DBGI_BinaryFlags flags; - U64 gen; - - // rjf: exe handles - OS_Handle exe_file; - OS_Handle exe_file_map; - - // rjf: debug handles - OS_Handle dbg_file; - OS_Handle dbg_file_map; - - // rjf: analysis results - DBGI_Parse parse; -}; - -typedef struct DBGI_BinarySlot DBGI_BinarySlot; -struct DBGI_BinarySlot -{ - DBGI_Binary *first; - DBGI_Binary *last; -}; - -typedef struct DBGI_BinaryStripe DBGI_BinaryStripe; -struct DBGI_BinaryStripe -{ - Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; -}; - -//////////////////////////////// -//~ rjf: Fuzzy Search Cache Types - -typedef enum DBGI_FuzzySearchTarget -{ - DBGI_FuzzySearchTarget_Procedures, - DBGI_FuzzySearchTarget_GlobalVariables, - DBGI_FuzzySearchTarget_ThreadVariables, - DBGI_FuzzySearchTarget_UDTs, - DBGI_FuzzySearchTarget_COUNT -} -DBGI_FuzzySearchTarget; - -typedef struct DBGI_FuzzySearchItem DBGI_FuzzySearchItem; -struct DBGI_FuzzySearchItem -{ - U64 idx; - U64 missed_size; - FuzzyMatchRangeList match_ranges; -}; - -typedef struct DBGI_FuzzySearchItemChunk DBGI_FuzzySearchItemChunk; -struct DBGI_FuzzySearchItemChunk -{ - DBGI_FuzzySearchItemChunk *next; - DBGI_FuzzySearchItem *v; - U64 count; - U64 cap; -}; - -typedef struct DBGI_FuzzySearchItemChunkList DBGI_FuzzySearchItemChunkList; -struct DBGI_FuzzySearchItemChunkList -{ - DBGI_FuzzySearchItemChunk *first; - DBGI_FuzzySearchItemChunk *last; - U64 chunk_count; - U64 total_count; -}; - -typedef struct DBGI_FuzzySearchItemArray DBGI_FuzzySearchItemArray; -struct DBGI_FuzzySearchItemArray -{ - DBGI_FuzzySearchItem *v; + DI_KeyNode *first; + DI_KeyNode *last; U64 count; }; -typedef struct DBGI_FuzzySearchBucket DBGI_FuzzySearchBucket; -struct DBGI_FuzzySearchBucket +typedef struct DI_KeyArray DI_KeyArray; +struct DI_KeyArray { - Arena *arena; - String8 exe_path; - String8 query; - DBGI_FuzzySearchTarget target; -}; - -typedef struct DBGI_FuzzySearchNode DBGI_FuzzySearchNode; -struct DBGI_FuzzySearchNode -{ - DBGI_FuzzySearchNode *next; - U128 key; - U64 scope_touch_count; - U64 last_time_submitted_us; - DBGI_FuzzySearchBucket buckets[3]; - U64 gen; - U64 submit_gen; - DBGI_FuzzySearchItemArray gen_items; -}; - -typedef struct DBGI_FuzzySearchSlot DBGI_FuzzySearchSlot; -struct DBGI_FuzzySearchSlot -{ - DBGI_FuzzySearchNode *first; - DBGI_FuzzySearchNode *last; -}; - -typedef struct DBGI_FuzzySearchStripe DBGI_FuzzySearchStripe; -struct DBGI_FuzzySearchStripe -{ - Arena *arena; - OS_Handle rw_mutex; - OS_Handle cv; -}; - -typedef struct DBGI_FuzzySearchThread DBGI_FuzzySearchThread; -struct DBGI_FuzzySearchThread -{ - OS_Handle thread; - OS_Handle u2f_ring_mutex; - OS_Handle u2f_ring_cv; - U64 u2f_ring_size; - U8 *u2f_ring_base; - U64 u2f_ring_write_pos; - U64 u2f_ring_read_pos; -}; - -//////////////////////////////// -//~ rjf: Weak Access Scope Types - -typedef struct DBGI_TouchedBinary DBGI_TouchedBinary; -struct DBGI_TouchedBinary -{ - DBGI_TouchedBinary *next; - DBGI_Binary *binary; -}; - -typedef struct DBGI_TouchedFuzzySearch DBGI_TouchedFuzzySearch; -struct DBGI_TouchedFuzzySearch -{ - DBGI_TouchedFuzzySearch *next; - DBGI_FuzzySearchNode *node; -}; - -typedef struct DBGI_Scope DBGI_Scope; -struct DBGI_Scope -{ - DBGI_Scope *next; - DBGI_TouchedBinary *first_tb; - DBGI_TouchedBinary *last_tb; - DBGI_TouchedFuzzySearch *first_tfs; - DBGI_TouchedFuzzySearch *last_tfs; -}; - -typedef struct DBGI_ThreadCtx DBGI_ThreadCtx; -struct DBGI_ThreadCtx -{ - Arena *arena; - DBGI_Scope *free_scope; - DBGI_TouchedBinary *free_tb; - DBGI_TouchedFuzzySearch *free_tfs; + DI_Key *v; + U64 count; }; //////////////////////////////// //~ rjf: Event Types -typedef enum DBGI_EventKind +typedef enum DI_EventKind { - DBGI_EventKind_Null, - DBGI_EventKind_ConversionStarted, - DBGI_EventKind_ConversionEnded, - DBGI_EventKind_ConversionFailureUnsupportedFormat, - DBGI_EventKind_COUNT + DI_EventKind_Null, + DI_EventKind_ConversionStarted, + DI_EventKind_ConversionEnded, + DI_EventKind_ConversionFailureUnsupportedFormat, + DI_EventKind_COUNT } -DBGI_EventKind; +DI_EventKind; -typedef struct DBGI_Event DBGI_Event; -struct DBGI_Event +typedef struct DI_Event DI_Event; +struct DI_Event { - DBGI_EventKind kind; + DI_EventKind kind; String8 string; }; -typedef struct DBGI_EventNode DBGI_EventNode; -struct DBGI_EventNode +typedef struct DI_EventNode DI_EventNode; +struct DI_EventNode { - DBGI_EventNode *next; - DBGI_Event v; + DI_EventNode *next; + DI_Event v; }; -typedef struct DBGI_EventList DBGI_EventList; -struct DBGI_EventList +typedef struct DI_EventList DI_EventList; +struct DI_EventList { - DBGI_EventNode *first; - DBGI_EventNode *last; + DI_EventNode *first; + DI_EventNode *last; U64 count; }; //////////////////////////////// -//~ rjf: Cross-Thread Shared State +//~ rjf: Cache Types -typedef struct DBGI_Shared DBGI_Shared; -struct DBGI_Shared +typedef struct DI_StringChunkNode DI_StringChunkNode; +struct DI_StringChunkNode +{ + DI_StringChunkNode *next; + U64 size; +}; + +typedef struct DI_Node DI_Node; +struct DI_Node +{ + // rjf: links + DI_Node *next; + DI_Node *prev; + + // rjf: metadata + U64 ref_count; + U64 touch_count; + U64 is_working; + U64 last_time_requested_us; + + // rjf: key + DI_Key key; + + // rjf: file handles + OS_Handle file; + OS_Handle file_map; + void *file_base; + FileProperties file_props; + + // rjf: parse artifacts + Arena *arena; + RDI_Parsed rdi; + B32 parse_done; +}; + +typedef struct DI_Slot DI_Slot; +struct DI_Slot +{ + DI_Node *first; + DI_Node *last; +}; + +typedef struct DI_Stripe DI_Stripe; +struct DI_Stripe +{ + Arena *arena; + DI_Node *free_node; + DI_StringChunkNode *free_string_chunks[8]; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access Types + +typedef struct DI_Touch DI_Touch; +struct DI_Touch +{ + DI_Touch *next; + DI_Node *node; +}; + +typedef struct DI_Scope DI_Scope; +struct DI_Scope +{ + DI_Scope *next; + DI_Touch *first_touch; + DI_Touch *last_touch; +}; + +typedef struct DI_TCTX DI_TCTX; +struct DI_TCTX +{ + Arena *arena; + DI_Scope *free_scope; + DI_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State Types + +typedef struct DI_Shared DI_Shared; +struct DI_Shared { - // rjf: arena Arena *arena; - // rjf: forced override table - U64 force_slots_count; - U64 force_stripes_count; - DBGI_ForceSlot *force_slots; - DBGI_ForceStripe *force_stripes; - - // rjf: binary table - U64 binary_slots_count; - U64 binary_stripes_count; - DBGI_BinarySlot *binary_slots; - DBGI_BinaryStripe *binary_stripes; - - // rjf: fuzzy search cache table - U64 fuzzy_search_slots_count; - U64 fuzzy_search_stripes_count; - DBGI_FuzzySearchSlot *fuzzy_search_slots; - DBGI_FuzzySearchStripe *fuzzy_search_stripes; + // rjf: node cache + U64 slots_count; + DI_Slot *slots; + U64 stripes_count; + DI_Stripe *stripes; // rjf: user -> parse ring OS_Handle u2p_ring_mutex; @@ -309,123 +185,104 @@ struct DBGI_Shared // rjf: threads U64 parse_thread_count; OS_Handle *parse_threads; - U64 fuzzy_thread_count; - DBGI_FuzzySearchThread *fuzzy_threads; }; //////////////////////////////// //~ rjf: Globals -global DBGI_Shared *dbgi_shared = 0; -thread_static DBGI_ThreadCtx *dbgi_tctx = 0; -global DBGI_Parse dbgi_parse_nil = +global DI_Shared *di_shared = 0; +thread_static DI_TCTX *di_tctx = 0; +global RDI_Parsed di_rdi_parsed_nil = { 0, 0, 0, - {0}, - {0}, 0, {0}, - {0}, - { - 0, - 0, - 0, - 0, - {0}, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - &rdi_binary_section_nil, 1, - &rdi_file_path_node_nil, 1, - &rdi_source_file_nil, 1, - &rdi_unit_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_type_node_nil, 1, - &rdi_udt_nil, 1, - &rdi_member_nil, 1, - &rdi_enum_member_nil, 1, - &rdi_global_variable_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_thread_variable_nil, 1, - &rdi_procedure_nil, 1, - &rdi_scope_nil, 1, - &rdi_voff_nil, 1, - &rdi_vmap_entry_nil, 1, - &rdi_local_nil, 1, - &rdi_location_block_nil, 1, - 0, 0, - 0, 0, - }, + 0, + 0, + 0, + 0, + 0, + 0, + &rdi_top_level_info_nil, + &rdi_binary_section_nil, 1, + &rdi_file_path_node_nil, 1, + &rdi_source_file_nil, 1, + &rdi_unit_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_type_node_nil, 1, + &rdi_udt_nil, 1, + &rdi_member_nil, 1, + &rdi_enum_member_nil, 1, + &rdi_global_variable_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_thread_variable_nil, 1, + &rdi_procedure_nil, 1, + &rdi_scope_nil, 1, + &rdi_voff_nil, 1, + &rdi_vmap_entry_nil, 1, + &rdi_local_nil, 1, + &rdi_location_block_nil, 1, + 0, 0, + 0, 0, }; +//////////////////////////////// +//~ rjf: Basic Helpers + +internal U64 di_hash_from_string(String8 string, StringMatchFlags match_flags); +internal U64 di_hash_from_key(DI_Key *k); +internal B32 di_key_match(DI_Key *a, DI_Key *b); +internal DI_Key di_key_copy(Arena *arena, DI_Key *src); +internal DI_Key di_normalized_key_from_key(Arena *arena, DI_Key *src); +internal void di_key_list_push(Arena *arena, DI_KeyList *list, DI_Key *key); +internal DI_KeyArray di_key_array_from_list(Arena *arena, DI_KeyList *list); + //////////////////////////////// //~ rjf: Main Layer Initialization -internal void dbgi_init(void); - -//////////////////////////////// -//~ rjf: Thread-Context Idempotent Initialization - -internal void dbgi_ensure_tctx_inited(void); - -//////////////////////////////// -//~ rjf: Helpers - -internal U64 dbgi_hash_from_string(String8 string, StringMatchFlags match_flags); -internal U64 dbgi_fuzzy_item_num_from_array_element_idx__linear_search(DBGI_FuzzySearchItemArray *array, U64 element_idx); -internal String8 dbgi_fuzzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, DBGI_FuzzySearchTarget target, U64 element_idx); - -//////////////////////////////// -//~ rjf: Forced Override Cache Functions - -internal void dbgi_force_exe_path_dbg_path(String8 exe_path, String8 dbg_path); -internal String8 dbgi_forced_dbg_path_from_exe_path(Arena *arena, String8 exe_path); +internal void di_init(void); //////////////////////////////// //~ rjf: Scope Functions -internal DBGI_Scope *dbgi_scope_open(void); -internal void dbgi_scope_close(DBGI_Scope *scope); -internal void dbgi_scope_touch_binary__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_Binary *binary); -internal void dbgi_scope_touch_fuzzy_search__stripe_mutex_r_guarded(DBGI_Scope *scope, DBGI_FuzzySearchNode *node); +internal DI_Scope *di_scope_open(void); +internal void di_scope_close(DI_Scope *scope); +internal void di_scope_touch_node__stripe_mutex_r_guarded(DI_Scope *scope, DI_Node *node); //////////////////////////////// -//~ rjf: Binary Cache Functions +//~ rjf: Per-Slot Functions -internal void dbgi_binary_open(String8 exe_path); -internal void dbgi_binary_close(String8 exe_path); -internal DBGI_Parse *dbgi_parse_from_exe_path(DBGI_Scope *scope, String8 exe_path, U64 endt_us); +internal DI_Node *di_node_from_key_slot__stripe_mutex_r_guarded(DI_Slot *slot, DI_Key *key); //////////////////////////////// -//~ rjf: Fuzzy Search Cache Functions +//~ rjf: Per-Stripe Functions -internal DBGI_FuzzySearchItemArray dbgi_fuzzy_search_items_from_key_exe_query(DBGI_Scope *scope, U128 key, String8 exe_path, String8 query, DBGI_FuzzySearchTarget target, U64 endt_us, B32 *stale_out); +internal U64 di_string_bucket_idx_from_string_size(U64 size); +internal String8 di_string_alloc__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); +internal void di_string_release__stripe_mutex_w_guarded(DI_Stripe *stripe, String8 string); + +//////////////////////////////// +//~ rjf: Key Opening/Closing + +internal void di_open(DI_Key *key); +internal void di_close(DI_Key *key); + +//////////////////////////////// +//~ rjf: Cache Lookups + +internal RDI_Parsed *di_rdi_from_key(DI_Scope *scope, DI_Key *key, U64 endt_us); //////////////////////////////// //~ rjf: Parse Threads -internal B32 dbgi_u2p_enqueue_exe_path(String8 exe_path, U64 endt_us); -internal String8 dbgi_u2p_dequeue_exe_path(Arena *arena); +internal B32 di_u2p_enqueue_key(DI_Key *key, U64 endt_us); +internal void di_u2p_dequeue_key(Arena *arena, DI_Key *out_key); -internal void dbgi_p2u_push_event(DBGI_Event *event); -internal DBGI_EventList dbgi_p2u_pop_events(Arena *arena, U64 endt_us); +internal void di_p2u_push_event(DI_Event *event); +internal DI_EventList di_p2u_pop_events(Arena *arena, U64 endt_us); -internal void dbgi_parse_thread_entry_point(void *p); +internal void di_parse_thread__entry_point(void *p); -//////////////////////////////// -//~ rjf: Fuzzy Searching Threads - -internal B32 dbgi_u2f_enqueue_req(U128 key, U64 endt_us); -internal void dbgi_u2f_dequeue_req(Arena *arena, DBGI_FuzzySearchThread *thread, U128 *key_out); - -internal int dbgi_qsort_compare_fuzzy_search_items(DBGI_FuzzySearchItem *a, DBGI_FuzzySearchItem *b); - -internal void dbgi_fuzzy_thread__entry_point(void *p); - -#endif //DBGI_H +#endif // DI_H diff --git a/src/df/core/df_core.c b/src/df/core/df_core.c index 26f5bbfd..ad1de92e 100644 --- a/src/df/core/df_core.c +++ b/src/df/core/df_core.c @@ -1077,7 +1077,7 @@ df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams use_numeric_eval: { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); U64 vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx->unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -1121,7 +1121,7 @@ df_cmd_params_apply_spec_query(Arena *arena, DF_CtrlCtx *ctrl_ctx, DF_CmdParams { error = push_str8f(scratch.arena, "Couldn't evaluate \"%S\" as an address", query); } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); }break; } @@ -1535,13 +1535,14 @@ df_search_tags_from_entity(Arena *arena, DF_Entity *entity) DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(entity); String8List strings = {0}; - for(CTRL_UnwindFrame *f = unwind.last; f != 0; f = f->prev) + for(U64 frame_num = unwind.frames.count; frame_num > 0; frame_num -= 1) { - U64 rip_vaddr = f->rip; + CTRL_UnwindFrame *f = &unwind.frames.v[frame_num-1]; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 procedure_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + String8 procedure_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); if(procedure_name.size != 0) { str8_list_push(scratch.arena, &strings, procedure_name); @@ -2007,6 +2008,14 @@ df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src) df_entity_notify_mutation(entity); } +internal void +df_entity_equip_timestamp(DF_Entity *entity, U64 timestamp) +{ + df_require_entity_nonnil(entity, return); + entity->timestamp = timestamp; + df_entity_notify_mutation(entity); +} + //- rjf: control layer correllation equipment internal void @@ -2176,7 +2185,7 @@ df_entity_from_path(String8 path, DF_EntityFromPathFlags flags) // rjf: next parent -> follow it parent = next_parent; } - file_no_override = parent; + file_no_override = (parent != df_entity_root() ? parent : &df_g_nil_entity); } //- rjf: pass 2: follow overrides @@ -2235,7 +2244,7 @@ df_entity_from_path(String8 path, DF_EntityFromPathFlags flags) // rjf: next parent -> follow it parent = next_parent; } - file_overrides_applied = parent; + file_overrides_applied = (parent != df_entity_root() ? parent : &df_g_nil_entity);; } //- rjf: pick & return result @@ -2691,29 +2700,6 @@ df_core_view_rule_spec_from_string(String8 string) return spec; } -//////////////////////////////// -//~ rjf: Debug Info Mapping - -internal String8 -df_debug_info_path_from_module(Arena *arena, DF_Entity *module) -{ - ProfBeginFunction(); - String8 result = {0}; - DF_Entity *override_entity = df_entity_child_from_kind(module, DF_EntityKind_DebugInfoOverride); - if(!df_entity_is_nil(override_entity) && override_entity->name.size != 0) - { - result = override_entity->name; - } - else - { - String8 exe_path = module->name; - String8 dbg_path = push_str8f(arena, "%S.pdb", str8_chop_last_dot(exe_path)); - result = dbg_path; - } - ProfEnd(); - return result; -} - //////////////////////////////// //~ rjf: Stepping "Trap Net" Builders @@ -2855,7 +2841,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) // rjf: thread => info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_thread(thread); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); Architecture arch = df_architecture_from_entity(thread); U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); @@ -2863,7 +2849,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, ip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, ip_voff); Rng1U64 line_voff_rng = line_info.voff_range; if(line_voff_rng.max != 0) { @@ -2877,7 +2863,7 @@ df_trap_net_from_thread__step_over_line(Arena *arena, DF_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = df_voff_from_vaddr(module, line_vaddr_rng.max); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, opl_line_voff_rng); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, opl_line_voff_rng); if(line_info.pt.line == 0xf00f00 || line_info.pt.line == 0xfeefee) { line_vaddr_rng.max = df_vaddr_from_voff(module, line_info.voff_range.max); @@ -2980,7 +2966,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) // rjf: thread => info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_thread(thread); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); Architecture arch = df_architecture_from_entity(thread); U64 ip_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle); @@ -2988,7 +2974,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) Rng1U64 line_vaddr_rng = {0}; { U64 ip_voff = df_voff_from_vaddr(module, ip_vaddr); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, ip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, ip_voff); Rng1U64 line_voff_rng = line_info.voff_range; if(line_voff_rng.max != 0) { @@ -3002,7 +2988,7 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) // is enabled. This is enabled by default normally. { U64 opl_line_voff_rng = df_voff_from_vaddr(module, line_vaddr_rng.max); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, opl_line_voff_rng); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, opl_line_voff_rng); if(line_info.pt.line == 0xf00f00 || line_info.pt.line == 0xfeefee) { line_vaddr_rng.max = df_vaddr_from_voff(module, line_info.voff_range.max); @@ -3093,25 +3079,26 @@ df_trap_net_from_thread__step_into_line(Arena *arena, DF_Entity *thread) //////////////////////////////// //~ rjf: Modules & Debug Info Mappings -//- rjf: module <=> binary file +//- rjf: module <=> debug info keys -internal DF_Entity * -df_binary_file_from_module(DF_Entity *module) +internal DI_Key +df_dbgi_key_from_module(DF_Entity *module) { - DF_Entity *binary = df_entity_from_handle(module->entity_handle); - return binary; + DF_Entity *debug_info_path = df_entity_child_from_kind(module, DF_EntityKind_DebugInfoPath); + DI_Key key = {debug_info_path->name, debug_info_path->timestamp}; + return key; } internal DF_EntityList -df_modules_from_binary_file(Arena *arena, DF_Entity *binary_info) +df_modules_from_dbgi_key(Arena *arena, DI_Key *dbgi_key) { DF_EntityList list = {0}; DF_EntityList all_modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); for(DF_EntityNode *n = all_modules.first; n != 0; n = n->next) { DF_Entity *module = n->entity; - DF_Entity *module_binary_info = df_binary_file_from_module(module); - if(module_binary_info == binary_info) + DI_Key module_dbgi_key = df_dbgi_key_from_module(module); + if(di_key_match(&module_dbgi_key, dbgi_key)) { df_entity_list_push(arena, &list, module); } @@ -3167,30 +3154,16 @@ df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_rng) //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: binary file -> dbgi parse - -internal DBGI_Parse * -df_dbgi_parse_from_binary_file(DBGI_Scope *scope, DF_Entity *binary) -{ - Temp scratch = scratch_begin(0, 0); - String8 exe_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, 0); - scratch_end(scratch); - return dbgi; -} - //- rjf: symbol lookups internal String8 -df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff) +df_symbol_name_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff) { String8 result = {0}; { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); - String8 path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Scope *scope = di_scope_open(); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); if(result.size == 0 && rdi->scope_vmap != 0) { U64 scope_idx = rdi_vmap_idx_from_voff(rdi->scope_vmap, rdi->scope_vmap_count, voff); @@ -3209,7 +3182,7 @@ df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff) U8 *name_ptr = rdi_string_from_idx(rdi, global_var->name_string_idx, &name_size); result = push_str8_copy(arena, str8(name_ptr, name_size)); } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); } return result; @@ -3221,9 +3194,9 @@ df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr) String8 result = {0}; { DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - result = df_symbol_name_from_binary_voff(arena, binary, voff); + result = df_symbol_name_from_dbgi_key_voff(arena, &dbgi_key, voff); } return result; } @@ -3239,8 +3212,8 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit src2dasm_array.v = push_array(arena, DF_TextLineSrc2DasmInfoList, src2dasm_array.count); } Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + DI_Scope *scope = di_scope_open(); + DI_KeyList dbgi_keys = df_push_active_dbgi_key_list(scratch.arena); DF_EntityList overrides = df_possible_overrides_from_entity(scratch.arena, file); for(DF_EntityNode *override_n = overrides.first; override_n != 0; @@ -3249,20 +3222,18 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit DF_Entity *override = override_n->entity; String8 file_path = df_full_path_from_entity(scratch.arena, override); String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); - for(DF_EntityNode *binary_n = binaries.first; - binary_n != 0; - binary_n = binary_n->next) + for(DI_KeyNode *dbgi_key_n = dbgi_keys.first; + dbgi_key_n != 0; + dbgi_key_n = dbgi_key_n->next) { // rjf: binary -> rdi - DF_Entity *binary = binary_n->entity; - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Key key = dbgi_key_n->v; + RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; U32 src_id = 0; - if(dbgi != &dbgi_parse_nil) + if(rdi != &di_rdi_parsed_nil) { RDI_NameMap *mapptr = rdi_name_map_from_kind(rdi, RDI_NameMapKind_NormalSourcePaths); if(mapptr != 0) @@ -3312,7 +3283,7 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(arena, DF_TextLineSrc2DasmInfoNode, 1); src2dasm_n->v.voff_range = range; src2dasm_n->v.remap_line = (S64)actual_line; - src2dasm_n->v.binary = binary; + src2dasm_n->v.dbgi_key = key; SLLQueuePush(src2dasm_list->first, src2dasm_list->last, src2dasm_n); src2dasm_list->count += 1; } @@ -3320,14 +3291,14 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit } } - // rjf: good src id -> push to relevant binaries + // rjf: good src id -> push to relevant dbgi keys if(good_src_id) { - df_entity_list_push(arena, &src2dasm_array.binaries, binary); + di_key_list_push(arena, &src2dasm_array.dbgi_keys, &key); } } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); return src2dasm_array; } @@ -3335,15 +3306,13 @@ df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entit //- rjf: voff -> src lookups internal DF_TextLineDasm2SrcInfo -df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) +df_text_line_dasm2src_info_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); - String8 path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Scope *scope = di_scope_open(); + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); DF_TextLineDasm2SrcInfo result = {0}; - result.file = result.binary = &df_g_nil_entity; + result.file = &df_g_nil_entity; if(rdi->unit_vmap != 0 && rdi->units != 0 && rdi->source_files != 0) { U64 unit_idx = rdi_vmap_idx_from_voff(rdi->unit_vmap, rdi->unit_vmap_count, voff); @@ -3358,7 +3327,7 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) RDI_SourceFile *file = &rdi->source_files[line->file_idx]; String8 file_normalized_full_path = {0}; file_normalized_full_path.str = rdi_string_from_idx(rdi, file->normal_full_path_string_idx, &file_normalized_full_path.size); - result.binary = binary; + MemoryCopyStruct(&result.dbgi_key, dbgi_key); if(line->file_idx != 0 && file_normalized_full_path.size != 0) { result.file = df_entity_from_path(file_normalized_full_path, DF_EntityFromPathFlag_All); @@ -3367,8 +3336,7 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) result.voff_range = r1u64(unit_line_info.voffs[line_info_idx], unit_line_info.voffs[line_info_idx+1]); } } - - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); return result; } @@ -3376,22 +3344,20 @@ df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff) //- rjf: symbol -> voff lookups internal U64 -df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) +df_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); U64 result = 0; { - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); RDI_NameMapKind name_map_kinds[] = { RDI_NameMapKind_GlobalVariables, RDI_NameMapKind_Procedures, }; - if(dbgi != &dbgi_parse_nil) + if(rdi != &di_rdi_parsed_nil) { for(U64 name_map_kind_idx = 0; name_map_kind_idx < ArrayCount(name_map_kinds); @@ -3452,23 +3418,20 @@ df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name) } } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); ProfEnd(); return result; } internal U64 -df_type_num_from_binary_name(DF_Entity *binary, String8 name) +df_type_num_from_dbgi_key_name(DI_Key *dbgi_key, String8 name) { ProfBeginFunction(); - DBGI_Scope *scope = dbgi_scope_open(); - Temp scratch = scratch_begin(0, 0); + DI_Scope *scope = di_scope_open(); U64 result = 0; { - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); RDI_NameMap *name_map = rdi_name_map_from_kind(rdi, RDI_NameMapKind_Types); RDI_ParsedNameMap parsed_name_map = {0}; rdi_name_map_parse(rdi, name_map, &parsed_name_map); @@ -3495,16 +3458,13 @@ df_type_num_from_binary_name(DF_Entity *binary, String8 name) } result = entity_num; } - scratch_end(scratch); - dbgi_scope_close(scope); + di_scope_close(scope); ProfEnd(); return result; } //////////////////////////////// -//~ rjf: Process/Thread Info Lookups - -//- rjf: thread info extraction helpers +//~ rjf: Process/Thread/Module Info Lookups internal DF_Entity * df_module_from_process_vaddr(DF_Entity *process, U64 vaddr) @@ -3537,23 +3497,16 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 ProfBeginFunction(); U64 base_vaddr = 0; Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); if(!df_ctrl_targets_running()) { - //- rjf: unpack thread info + //- rjf: unpack module info DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - String8 bin_data = str8((U8 *)dbgi->exe_base, dbgi->exe_props.size); - PE_BinInfo *bin = &dbgi->pe; - B32 bin_is_pe = 1; // TODO(rjf): this path needs to change for ELF - U64 addr_size = bit_size_from_arch(bin->arch)/8; - - //- rjf: grab tls range - Rng1U64 tls_vaddr_range = pe_tls_rng_from_bin_base_vaddr(bin_data, bin, df_base_vaddr_from_module(module)); + Rng1U64 tls_vaddr_range = ctrl_tls_vaddr_range_from_module(module->ctrl_machine_id, module->ctrl_handle); + U64 addr_size = bit_size_from_arch(process->arch)/8; //- rjf: read module's TLS index U64 tls_index = 0; + if(addr_size != 0) { CTRL_ProcessMemorySlice tls_index_slice = ctrl_query_cached_data_from_process_vaddr_range(scratch.arena, process->ctrl_machine_id, process->ctrl_handle, tls_vaddr_range, 0); if(tls_index_slice.data.size >= addr_size) @@ -3563,7 +3516,7 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 } //- rjf: PE path - if(bin_is_pe) + if(addr_size != 0) { U64 thread_info_addr = root_vaddr; U64 tls_addr_off = tls_index*addr_size; @@ -3583,10 +3536,10 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 } //- rjf: non-PE path (not implemented) +#if 0 if(!bin_is_pe) { // TODO(rjf): not supported. old code from the prototype that Nick had sketched out: -#if 0 // TODO(nick): This code works only if the linked c runtime library is glibc. // Implement CRT detection here. @@ -3613,10 +3566,9 @@ df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 { demon_read_memory(process->demon_handle, &result, dtv_addr + dtv_size*tls_index, addr_size); } -#endif } +#endif } - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); return base_vaddr; @@ -3629,26 +3581,18 @@ df_architecture_from_entity(DF_Entity *entity) } internal EVAL_String2NumMap * -df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) +df_push_locals_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff) { - Temp scratch = scratch_begin(&arena, 1); - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); EVAL_String2NumMap *result = eval_push_locals_map_from_rdi_voff(arena, rdi, voff); - scratch_end(scratch); return result; } internal EVAL_String2NumMap * -df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff) +df_push_member_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff) { - Temp scratch = scratch_begin(&arena, 1); - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + RDI_Parsed *rdi = di_rdi_from_key(scope, dbgi_key, 0); EVAL_String2NumMap *result = eval_push_member_map_from_rdi_voff(arena, rdi, voff); - scratch_end(scratch); return result; } @@ -3663,18 +3607,18 @@ df_set_thread_rip(DF_Entity *thread, U64 vaddr) // rjf: early mutation of unwind cache for immediate frontend effect if(result) { - DF_RunUnwindCache *unwind_cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; - if(unwind_cache->slots_count != 0) + DF_UnwindCache *cache = &df_state->unwind_cache; + if(cache->slots_count != 0) { DF_Handle thread_handle = df_handle_from_entity(thread); U64 hash = df_hash_from_string(str8_struct(&thread_handle)); - U64 slot_idx = hash % unwind_cache->slots_count; - DF_RunUnwindCacheSlot *slot = &unwind_cache->slots[slot_idx]; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + U64 slot_idx = hash%cache->slots_count; + DF_UnwindCacheSlot *slot = &cache->slots[slot_idx]; + for(DF_UnwindCacheNode *n = slot->first; n != 0; n = n->next) { - if(df_handle_match(n->thread, thread_handle) && n->unwind.first != 0) + if(df_handle_match(n->thread, thread_handle) && n->unwind.frames.count != 0) { - n->unwind.first->rip = vaddr; + regs_arch_block_write_rip(thread->arch, n->unwind.frames.v[0].regs, vaddr); break; } } @@ -3770,7 +3714,6 @@ df_push_ctrl_msg(CTRL_Msg *msg) internal void df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_RunFlags flags, CTRL_TrapList *run_traps) { - DBGI_Scope *scope = dbgi_scope_open(); Temp scratch = scratch_begin(0, 0); // rjf: build run message @@ -3886,7 +3829,6 @@ df_ctrl_run(DF_RunKind run, DF_Entity *run_thread, CTRL_RunFlags flags, CTRL_Tra df_state->ctrl_ctx.unwind_count = 0; scratch_end(scratch); - dbgi_scope_close(scope); } //- rjf: stopped info from the control thread @@ -3919,22 +3861,20 @@ df_eval_memory_read(void *u, void *out, U64 addr, U64 size) } internal EVAL_ParseCtx -df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 vaddr) +df_eval_parse_ctx_from_process_vaddr(DI_Scope *scope, DF_Entity *process, U64 vaddr) { Temp scratch = scratch_begin(0, 0); //- rjf: extract info DF_Entity *module = df_module_from_process_vaddr(process, vaddr); U64 voff = df_voff_from_vaddr(module, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Key dbgi_key = df_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); Architecture arch = df_architecture_from_entity(process); EVAL_String2NumMap *reg_map = ctrl_string2reg_from_arch(arch); EVAL_String2NumMap *reg_alias_map = ctrl_string2alias_from_arch(arch); - EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, voff); - EVAL_String2NumMap *member_map = df_query_cached_member_map_from_binary_voff(binary, voff); + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_key_voff(&dbgi_key, voff); + EVAL_String2NumMap *member_map = df_query_cached_member_map_from_dbgi_key_voff(&dbgi_key, voff); //- rjf: build ctx EVAL_ParseCtx ctx = zero_struct; @@ -3953,11 +3893,11 @@ df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 } internal EVAL_ParseCtx -df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) +df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt) { Temp scratch = scratch_begin(0, 0); EVAL_ParseCtx ctx = zero_struct; - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); + DI_KeyList dbgi_keys = df_push_active_dbgi_key_list(scratch.arena); DF_TextLineSrc2DasmInfoList src2dasm_list = {0}; //- rjf: search for line info in all binaries for this file:pt @@ -3969,15 +3909,13 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) DF_Entity *override = override_n->entity; String8 file_path = df_full_path_from_entity(scratch.arena, override); String8 file_path_normalized = lower_from_str8(scratch.arena, file_path); - for(DF_EntityNode *binary_n = binaries.first; - binary_n != 0; - binary_n = binary_n->next) + for(DI_KeyNode *dbgi_key_n = dbgi_keys.first; + dbgi_key_n != 0; + dbgi_key_n = dbgi_key_n->next) { - // rjf: binary -> rdi - DF_Entity *binary = binary_n->entity; - String8 binary_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, binary_path, 0); - RDI_Parsed *rdi = &dbgi->rdi; + // rjf: key -> rdi + DI_Key key = dbgi_key_n->v; + RDI_Parsed *rdi = di_rdi_from_key(scope, &key, 0); // rjf: file_path_normalized * rdi -> src_id B32 good_src_id = 0; @@ -4023,7 +3961,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) DF_TextLineSrc2DasmInfoNode *src2dasm_n = push_array(scratch.arena, DF_TextLineSrc2DasmInfoNode, 1); src2dasm_n->v.voff_range = range; src2dasm_n->v.remap_line = (S64)actual_line; - src2dasm_n->v.binary = binary; + src2dasm_n->v.dbgi_key = key; SLLQueuePush(src2dasm_list.first, src2dasm_list.last, src2dasm_n); src2dasm_list.count += 1; } @@ -4038,7 +3976,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list.first; n != 0; n = n->next) { DF_TextLineSrc2DasmInfo *src2dasm = &n->v; - DF_EntityList modules = df_modules_from_binary_file(scratch.arena, src2dasm->binary); + DF_EntityList modules = df_modules_from_dbgi_key(scratch.arena, &src2dasm->dbgi_key); if(modules.count != 0) { DF_Entity *module = modules.first->entity; @@ -4055,7 +3993,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) //- rjf: bad ctx -> reset with graceful defaults if(good_ctx == 0) { - ctx.rdi = &dbgi_parse_nil.rdi; + ctx.rdi = &di_rdi_parsed_nil; ctx.type_graph = tg_graph_begin(8, 256); ctx.regs_map = &eval_string2num_map_nil; ctx.regs_map = &eval_string2num_map_nil; @@ -4069,7 +4007,7 @@ df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt) } internal DF_Eval -df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string) +df_eval_from_string(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -4084,17 +4022,10 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ U64 reg_size = regs_block_size_from_architecture(arch); U64 thread_unwind_ip_vaddr = 0; void *thread_unwind_regs_block = push_array(scratch.arena, U8, reg_size); + if(unwind.frames.count != 0) { - U64 idx = 0; - for(CTRL_UnwindFrame *f = unwind.first; f != 0; f = f->next, idx += 1) - { - if(idx == unwind_count) - { - thread_unwind_ip_vaddr = f->rip; - thread_unwind_regs_block = f->regs; - break; - } - } + thread_unwind_regs_block = unwind.frames.v[unwind_count%unwind.frames.count].regs; + thread_unwind_ip_vaddr = regs_rip_from_arch_block(arch, thread_unwind_regs_block); } //- rjf: unpack module info & produce eval machine @@ -4191,9 +4122,9 @@ df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ { U64 vaddr = result.imm_u64; DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - String8 symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, voff); + String8 symbol_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, voff); if(symbol_name.size != 0) { result.type_key = tg_cons_type_make(parse_ctx->type_graph, TG_Kind_Ptr, tg_key_basic(TG_Kind_Void), 0); @@ -4269,17 +4200,10 @@ df_value_mode_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ U64 type_byte_size = tg_byte_size_from_graph_rdi_key(graph, rdi, type_key); U64 reg_off = eval.offset; CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - if(unwind.first != 0) + if(unwind.frames.count != 0) { - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) - { - if(unwind_idx == ctrl_ctx->unwind_count && frame->regs != 0) - { - MemoryCopy(&eval.imm_u128[0], ((U8 *)frame->regs + reg_off), Min(type_byte_size, sizeof(U64)*2)); - break; - } - } + CTRL_UnwindFrame *frame = &unwind.frames.v[ctrl_ctx->unwind_count%unwind.frames.count]; + MemoryCopy(&eval.imm_u128[0], ((U8 *)frame->regs + reg_off), Min(type_byte_size, sizeof(U64)*2)); } eval.mode = EVAL_EvalMode_Value; }break; @@ -4358,7 +4282,7 @@ df_dynamically_typed_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx } internal DF_Eval -df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg) +df_eval_from_eval_cfg_table(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg) { ProfBeginFunction(); @@ -4569,6 +4493,12 @@ df_string_from_simple_typed_eval(Arena *arena, TG_Graph *graph, RDI_Parsed *rdi, { default:{}break; + case TG_Kind_Handle: + { + U64 min_digits = (radix == 16) ? type_byte_size*2 : 0; + result = str8_from_s64(arena, eval.imm_s64, radix, 0, digit_group_separator); + }break; + case TG_Kind_Char8: case TG_Kind_Char16: case TG_Kind_Char32: @@ -4790,11 +4720,11 @@ df_commit_eval_value(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_ CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); Architecture arch = df_architecture_from_entity(thread); U64 reg_block_size = regs_block_size_from_architecture(arch); - if(unwind.first != 0 && + if(unwind.frames.count != 0 && (0 <= dst_eval.offset && dst_eval.offset+commit_data.size < reg_block_size)) { void *new_regs = push_array(scratch.arena, U8, reg_block_size); - MemoryCopy(new_regs, unwind.first->regs, reg_block_size); + MemoryCopy(new_regs, unwind.frames.v[0].regs, reg_block_size); MemoryCopy((U8 *)new_regs+dst_eval.offset, commit_data.str, commit_data.size); result = ctrl_thread_write_reg_block(thread->ctrl_machine_id, thread->ctrl_handle, new_regs); } @@ -4988,8 +4918,8 @@ df_eval_viz_block_split_and_continue(Arena *arena, DF_EvalVizBlockList *list, DF continue_block->string = split_block->string; continue_block->member = split_block->member; continue_block->visual_idx_range = continue_block->semantic_idx_range = r1u64(split_idx+1, total_count); - continue_block->backing_search_items = split_block->backing_search_items; - continue_block->dbgi_target = split_block->dbgi_target; + continue_block->fzy_backing_items = split_block->fzy_backing_items; + continue_block->fzy_target = split_block->fzy_target; continue_block->cfg_table = split_block->cfg_table; continue_block->link_member_type_key = split_block->link_member_type_key; continue_block->link_member_off = split_block->link_member_off; @@ -5007,7 +4937,7 @@ df_eval_viz_block_end(DF_EvalVizBlockList *list, DF_EvalVizBlock *block) } internal void -df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalView *eval_view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out) +df_append_viz_blocks_for_parent__rec(Arena *arena, DI_Scope *scope, DF_EvalView *eval_view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -5413,7 +5343,7 @@ df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalVie } internal DF_EvalVizBlockList -df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key) +df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key) { ProfBeginFunction(); DF_EvalVizBlockList blocks = {0}; @@ -5494,9 +5424,9 @@ df_row_num_from_viz_block_list_key(DF_EvalVizBlockList *blocks, DF_ExpandKey key { B32 this_block_contains_this_key = 0; { - if(block->backing_search_items.v != 0) + if(block->fzy_backing_items.v != 0) { - U64 item_num = dbgi_fuzzy_item_num_from_array_element_idx__linear_search(&block->backing_search_items, key.child_num); + U64 item_num = fzy_item_num_from_array_element_idx__linear_search(&block->fzy_backing_items, key.child_num); this_block_contains_this_key = (item_num != 0 && contains_1u64(block->semantic_idx_range, item_num-1)); } else @@ -5507,9 +5437,9 @@ df_row_num_from_viz_block_list_key(DF_EvalVizBlockList *blocks, DF_ExpandKey key if(this_block_contains_this_key) { found = 1; - if(block->backing_search_items.v != 0) + if(block->fzy_backing_items.v != 0) { - U64 item_num = dbgi_fuzzy_item_num_from_array_element_idx__linear_search(&block->backing_search_items, key.child_num); + U64 item_num = fzy_item_num_from_array_element_idx__linear_search(&block->fzy_backing_items, key.child_num); row_num += item_num-1-block->semantic_idx_range.min; } else @@ -5543,12 +5473,12 @@ df_key_from_viz_block_list_row_num(DF_EvalVizBlockList *blocks, S64 row_num) if(contains_1s64(vb_row_num_range, row_num)) { key = vb->key; - if(vb->backing_search_items.v != 0) + if(vb->fzy_backing_items.v != 0) { U64 item_idx = (U64)((row_num - vb_row_num_range.min) + vb->semantic_idx_range.min); - if(item_idx < vb->backing_search_items.count) + if(item_idx < vb->fzy_backing_items.count) { - key.child_num = vb->backing_search_items.v[item_idx].idx; + key.child_num = vb->fzy_backing_items.v[item_idx].idx; } } else @@ -6177,18 +6107,20 @@ df_query_cached_entity_list_with_kind(DF_EntityKind kind) return result; } -internal DF_EntityList -df_push_active_binary_list(Arena *arena) +//- rjf: active entity based queries + +internal DI_KeyList +df_push_active_dbgi_key_list(Arena *arena) { - DF_EntityList binaries = {0}; + DI_KeyList dbgis = {0}; DF_EntityList modules = df_query_cached_entity_list_with_kind(DF_EntityKind_Module); for(DF_EntityNode *n = modules.first; n != 0; n = n->next) { DF_Entity *module = n->entity; - DF_Entity *binary = df_binary_file_from_module(module); - df_entity_list_push(arena, &binaries, binary); + DI_Key key = df_dbgi_key_from_module(module); + di_key_list_push(arena, &dbgis, &key); } - return binaries; + return dbgis; } internal DF_EntityList @@ -6211,50 +6143,56 @@ df_push_active_target_list(Arena *arena) internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread) { + Temp scratch = scratch_begin(0, 0); CTRL_Unwind result = {0}; - DF_Handle handle = df_handle_from_entity(thread); - U64 hash = df_hash_from_string(str8_struct(&handle)); - for(U64 cache_idx = 0; cache_idx < ArrayCount(df_state->unwind_caches); cache_idx += 1) + if(thread->kind == DF_EntityKind_Thread) { - DF_RunUnwindCache *cache = &df_state->unwind_caches[(df_state->unwind_cache_gen+cache_idx)%ArrayCount(df_state->unwind_caches)]; - if(cache_idx == 0 && cache->slots_count == 0) - { - cache->slots_count = 1024; - cache->slots = push_array(cache->arena, DF_RunUnwindCacheSlot, cache->slots_count); - } - else if(cache->slots_count == 0) - { - break; - } + U64 reg_gen = ctrl_reg_gen(); + U64 mem_gen = ctrl_mem_gen(); + DF_UnwindCache *cache = &df_state->unwind_cache; + DF_Handle handle = df_handle_from_entity(thread); + U64 hash = df_hash_from_string(str8_struct(&handle)); U64 slot_idx = hash%cache->slots_count; - DF_RunUnwindCacheSlot *slot = &cache->slots[slot_idx]; - DF_RunUnwindCacheNode *node = 0; - for(DF_RunUnwindCacheNode *n = slot->first; n != 0; n = n->hash_next) + DF_UnwindCacheSlot *slot = &cache->slots[slot_idx]; + DF_UnwindCacheNode *node = 0; + for(DF_UnwindCacheNode *n = slot->first; n != 0; n = n->next) { - if(df_handle_match(n->thread, handle)) + if(df_handle_match(handle, n->thread)) { node = n; break; } } - if(node != 0) + if(node == 0) { - result = node->unwind; - break; - } - else - { - result = ctrl_unwind_from_thread(cache->arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, 0); - if(!result.error) + node = cache->free_node; + if(node != 0) { - node = push_array(cache->arena, DF_RunUnwindCacheNode, 1); - SLLQueuePush_N(slot->first, slot->last, node, hash_next); - node->thread = handle; - node->unwind = result; - break; + SLLStackPop(cache->free_node); + } + else + { + node = push_array_no_zero(df_state->arena, DF_UnwindCacheNode, 1); + } + DLLPushBack(slot->first, slot->last, node); + MemoryZeroStruct(node); + node->arena = arena_alloc(); + node->thread = handle; + } + if(node->reggen != reg_gen || + node->memgen != mem_gen) + { + CTRL_Unwind new_unwind = ctrl_unwind_from_thread(scratch.arena, df_state->ctrl_entity_store, thread->ctrl_machine_id, thread->ctrl_handle, os_now_microseconds()+100); + if(!(new_unwind.flags & (CTRL_UnwindFlag_Error|CTRL_UnwindFlag_Stale))) + { + node->unwind = ctrl_unwind_deep_copy(node->arena, thread->arch, &new_unwind); + node->reggen = reg_gen; + node->memgen = mem_gen; } } + result = node->unwind; } + scratch_end(scratch); return result; } @@ -6276,14 +6214,9 @@ df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count) else { CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - U64 unwind_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, unwind_idx += 1) + if(unwind.frames.count != 0) { - if(unwind_idx == unwind_count) - { - result = frame->rip; - break; - } + result = regs_rip_from_arch_block(thread->arch, unwind.frames.v[unwind_count%unwind.frames.count].regs); } } return result; @@ -6341,7 +6274,7 @@ df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 roo } internal EVAL_String2NumMap * -df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) +df_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; @@ -6357,14 +6290,13 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) { break; } - DF_Handle handle = df_handle_from_entity(binary); - U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 hash = di_hash_from_key(dbgi_key); U64 slot_idx = hash % cache->table_size; DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; DF_RunLocalsCacheNode *node = 0; for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(df_handle_match(n->binary, handle) && n->voff == voff) + if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -6372,17 +6304,17 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) } if(node == 0) { - DBGI_Scope *scope = dbgi_scope_open(); - EVAL_String2NumMap *map = df_push_locals_map_from_binary_voff(cache->arena, scope, binary, voff); + DI_Scope *scope = di_scope_open(); + EVAL_String2NumMap *map = df_push_locals_map_from_dbgi_key_voff(cache->arena, scope, dbgi_key, voff); if(map->slots_count != 0) { node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); - node->binary = handle; + node->dbgi_key = di_key_copy(cache->arena, dbgi_key); node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); } - dbgi_scope_close(scope); + di_scope_close(scope); } if(node != 0 && node->locals_map->slots_count != 0) { @@ -6395,7 +6327,7 @@ df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff) } internal EVAL_String2NumMap * -df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) +df_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff) { ProfBeginFunction(); EVAL_String2NumMap *map = &eval_string2num_map_nil; @@ -6411,14 +6343,13 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) { break; } - DF_Handle handle = df_handle_from_entity(binary); - U64 hash = df_hash_from_string(str8_struct(&handle)); + U64 hash = di_hash_from_key(dbgi_key); U64 slot_idx = hash % cache->table_size; DF_RunLocalsCacheSlot *slot = &cache->table[slot_idx]; DF_RunLocalsCacheNode *node = 0; for(DF_RunLocalsCacheNode *n = slot->first; n != 0; n = n->hash_next) { - if(df_handle_match(n->binary, handle) && n->voff == voff) + if(di_key_match(&n->dbgi_key, dbgi_key) && n->voff == voff) { node = n; break; @@ -6426,17 +6357,17 @@ df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff) } if(node == 0) { - DBGI_Scope *scope = dbgi_scope_open(); - EVAL_String2NumMap *map = df_push_member_map_from_binary_voff(cache->arena, scope, binary, voff); + DI_Scope *scope = di_scope_open(); + EVAL_String2NumMap *map = df_push_member_map_from_dbgi_key_voff(cache->arena, scope, dbgi_key, voff); if(map->slots_count != 0) { node = push_array(cache->arena, DF_RunLocalsCacheNode, 1); - node->binary = handle; + node->dbgi_key = di_key_copy(cache->arena, dbgi_key); node->voff = voff; node->locals_map = map; SLLQueuePush_N(slot->first, slot->last, node, hash_next); } - dbgi_scope_close(scope); + di_scope_close(scope); } if(node != 0 && node->locals_map->slots_count != 0) { @@ -6454,6 +6385,7 @@ internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec) { // rjf: log + if(params->os_event == 0 || params->os_event->kind != OS_EventKind_MouseMove) { Temp scratch = scratch_begin(0, 0); DF_Entity *entity = df_entity_from_handle(params->entity); @@ -6568,11 +6500,9 @@ df_core_init(CmdLine *cmdln, DF_StateDeltaHistory *hist) df_register_core_view_rule_specs(array); } - // rjf: set up per-run caches - for(U64 idx = 0; idx < ArrayCount(df_state->unwind_caches); idx += 1) - { - df_state->unwind_caches[idx].arena = arena_alloc(); - } + // rjf: set up caches + df_state->unwind_cache.slots_count = 1024; + df_state->unwind_cache.slots = push_array(arena, DF_UnwindCacheSlot, df_state->unwind_cache.slots_count); for(U64 idx = 0; idx < ArrayCount(df_state->tls_base_caches); idx += 1) { df_state->tls_base_caches[idx].arena = arena_alloc(); @@ -6731,7 +6661,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } // rjf: select & snap to thread causing stop - if(!df_entity_is_nil(stop_thread)) + if(stop_thread->kind == DF_EntityKind_Thread) { DF_CmdParams params = df_cmd_params_zero(); params.entity = df_handle_from_entity(stop_thread); @@ -6758,9 +6688,9 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) U64 stop_thread_vaddr = ctrl_query_cached_rip_from_thread(df_state->ctrl_entity_store, stop_thread->ctrl_machine_id, stop_thread->ctrl_handle); DF_Entity *process = df_entity_ancestor_from_kind(stop_thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, stop_thread_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 stop_thread_voff = df_voff_from_vaddr(module, stop_thread_vaddr); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, stop_thread_voff); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, stop_thread_voff); DF_EntityList user_bps = df_query_cached_entity_list_with_kind(DF_EntityKind_Breakpoint); for(DF_EntityNode *n = user_bps.first; n != 0; n = n->next) { @@ -6939,11 +6869,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_entity_equip_name(0, module, event->string); df_entity_equip_vaddr_rng(module, event->vaddr_rng); df_entity_equip_vaddr(module, event->rip_vaddr); - - // rjf: create & attach binary file - String8 bin_path = module->name; - DF_Entity *binary = df_entity_from_path(bin_path, DF_EntityFromPathFlag_All); - df_entity_equip_entity_handle(module, df_handle_from_entity(binary)); + df_entity_equip_timestamp(module, event->timestamp); // rjf: is first -> find target, equip process & module & first thread with target color if(is_first) @@ -6990,6 +6916,20 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_entity_mark_for_deletion(module); }break; + //- rjf: debug info changes + + case CTRL_EventKind_ModuleDebugInfoPathChange: + { + DF_Entity *module = df_entity_from_ctrl_handle(event->machine_id, event->entity); + DF_Entity *debug_info = df_entity_child_from_kind(module, DF_EntityKind_DebugInfoPath); + if(df_entity_is_nil(debug_info)) + { + debug_info = df_entity_alloc(0, module, DF_EntityKind_DebugInfoPath); + } + df_entity_equip_name(0, debug_info, event->string); + df_entity_equip_timestamp(debug_info, event->timestamp); + }break; + //- rjf: debug strings case CTRL_EventKind_DebugString: @@ -7047,20 +6987,6 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) } } - //- rjf: clear unwind cache - if((df_state->unwind_cache_memgen_idx != new_mem_gen || - df_state->unwind_cache_reggen_idx != new_reg_gen) && - !df_ctrl_targets_running()) ProfScope("per-thread unwind gather") - { - df_state->unwind_cache_gen += 1; - DF_RunUnwindCache *cache = &df_state->unwind_caches[df_state->unwind_cache_gen%ArrayCount(df_state->unwind_caches)]; - arena_clear(cache->arena); - cache->slots_count = 0; - cache->slots = 0; - df_state->unwind_cache_memgen_idx = new_mem_gen; - df_state->unwind_cache_reggen_idx = new_reg_gen; - } - //- rjf: clear tls base cache if((df_state->tls_base_cache_reggen_idx != new_reg_gen || df_state->tls_base_cache_memgen_idx != new_mem_gen) && @@ -7102,23 +7028,23 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) scratch_end(scratch); } - //- rjf: sync with dbgi parsers - ProfScope("sync with dbgi parsers") + //- rjf: sync with di parsers + ProfScope("sync with di parsers") { Temp scratch = scratch_begin(&arena, 1); - DBGI_EventList events = dbgi_p2u_pop_events(scratch.arena, 0); - for(DBGI_EventNode *n = events.first; n != 0; n = n->next) + DI_EventList events = di_p2u_pop_events(scratch.arena, 0); + for(DI_EventNode *n = events.first; n != 0; n = n->next) { - DBGI_Event *event = &n->v; + DI_Event *event = &n->v; switch(event->kind) { default:{}break; - case DBGI_EventKind_ConversionStarted: + case DI_EventKind_ConversionStarted: { DF_Entity *task = df_entity_alloc(0, df_entity_root(), DF_EntityKind_ConversionTask); df_entity_equip_name(0, task, event->string); }break; - case DBGI_EventKind_ConversionEnded: + case DI_EventKind_ConversionEnded: { DF_Entity *task = df_entity_from_name_and_kind(event->string, DF_EntityKind_ConversionTask); if(!df_entity_is_nil(task)) @@ -7126,7 +7052,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) df_entity_mark_for_deletion(task); } }break; - case DBGI_EventKind_ConversionFailureUnsupportedFormat: + case DI_EventKind_ConversionFailureUnsupportedFormat: { // DF_Entity *task = df_entity_alloc(df_entity_root(), DF_EntityKind_ConversionFail); // df_entity_equip_name(task, event->string); @@ -7436,9 +7362,9 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); // rjf: use first unwind frame to generate trap - if(unwind.first != 0 && unwind.first->next != 0) + if(unwind.frames.count > 1) { - U64 vaddr = unwind.first->next->rip; + U64 vaddr = regs_rip_from_arch_block(thread->arch, unwind.frames.v[1].regs); CTRL_Trap trap = {CTRL_TrapFlag_EndStepping|CTRL_TrapFlag_IgnoreStackPointerCheck, vaddr}; ctrl_trap_list_push(scratch.arena, &traps, &trap); } @@ -7603,7 +7529,7 @@ df_core_begin_frame(Arena *arena, DF_CmdList *cmds, F32 dt) { DF_Entity *thread = df_entity_from_handle(df_state->ctrl_ctx.thread); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); - U64 max_unwind = unwind.count ? unwind.count-1 : 0; + U64 max_unwind = unwind.frames.count ? unwind.frames.count-1 : 0; U64 index = Clamp(0, params.index, max_unwind); df_state->ctrl_ctx.unwind_count = index; }break; @@ -8844,6 +8770,22 @@ df_core_end_frame(void) } } + //- rjf: garbage collect eliminated thread unwinds + for(U64 slot_idx = 0; slot_idx < df_state->unwind_cache.slots_count; slot_idx += 1) + { + DF_UnwindCacheSlot *slot = &df_state->unwind_cache.slots[slot_idx]; + for(DF_UnwindCacheNode *n = slot->first, *next = 0; n != 0; n = next) + { + next = n->next; + if(df_entity_is_nil(df_entity_from_handle(n->thread))) + { + DLLRemove(slot->first, slot->last, n); + arena_release(n->arena); + SLLStackPush(df_state->unwind_cache.free_node, n); + } + } + } + //- rjf: write config changes ProfScope("write config changes") { diff --git a/src/df/core/df_core.h b/src/df/core/df_core.h index 302d030c..406e6795 100644 --- a/src/df/core/df_core.h +++ b/src/df/core/df_core.h @@ -265,10 +265,10 @@ struct DF_Eval //////////////////////////////// //~ rjf: View Rule Hook Types -#define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(name) DF_Eval name(Arena *arena, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, struct DF_CfgVal *val) +#define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(name) DF_Eval name(Arena *arena, DI_Scope *di_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, struct DF_CfgVal *val) #define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(name) df_core_view_rule_eval_resolution__##name #define DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(name) internal DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_NAME(name)) -#define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(name) void name(Arena *arena, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_EvalView *eval_view, DF_Eval eval, String8 string, struct DF_CfgTable *cfg_table, DF_ExpandKey parent_key, DF_ExpandKey key, S32 depth, struct DF_CfgNode *cfg, struct DF_EvalVizBlockList *out) +#define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(name) void name(Arena *arena, DI_Scope *di_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_EvalView *eval_view, DF_Eval eval, String8 string, struct DF_CfgTable *cfg_table, DF_ExpandKey parent_key, DF_ExpandKey key, S32 depth, struct DF_CfgNode *cfg, struct DF_EvalVizBlockList *out) #define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(name) df_core_view_rule_viz_block_prod__##name #define DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_DEF(name) internal DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_SIG(DF_CORE_VIEW_RULE_VIZ_BLOCK_PROD_FUNCTION_NAME(name)) typedef DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_SIG(DF_CoreViewRuleEvalResolutionHookFunctionType); @@ -521,7 +521,7 @@ struct DF_TextLineSrc2DasmInfo { Rng1U64 voff_range; S64 remap_line; - DF_Entity *binary; + DI_Key dbgi_key; }; typedef struct DF_TextLineSrc2DasmInfoNode DF_TextLineSrc2DasmInfoNode; @@ -543,7 +543,7 @@ typedef struct DF_TextLineSrc2DasmInfoListArray DF_TextLineSrc2DasmInfoListArray struct DF_TextLineSrc2DasmInfoListArray { DF_TextLineSrc2DasmInfoList *v; - DF_EntityList binaries; + DI_KeyList dbgi_keys; U64 count; }; @@ -552,7 +552,7 @@ struct DF_TextLineSrc2DasmInfoListArray typedef struct DF_TextLineDasm2SrcInfo DF_TextLineDasm2SrcInfo; struct DF_TextLineDasm2SrcInfo { - DF_Entity *binary; + DI_Key dbgi_key; DF_Entity *file; TxtPt pt; Rng1U64 voff_range; @@ -708,8 +708,8 @@ struct DF_EvalVizBlock // rjf: info about ranges that this block spans Rng1U64 visual_idx_range; Rng1U64 semantic_idx_range; - DBGI_FuzzySearchTarget dbgi_target; - DBGI_FuzzySearchItemArray backing_search_items; + FZY_Target fzy_target; + FZY_ItemArray fzy_backing_items; // rjf: visualization config extensions DF_CfgTable cfg_table; @@ -946,29 +946,33 @@ struct DF_AutoViewRuleMapCache DF_AutoViewRuleSlot *slots; }; -//- rjf: per-run unwind cache +//- rjf: per-thread unwind cache -typedef struct DF_RunUnwindCacheNode DF_RunUnwindCacheNode; -struct DF_RunUnwindCacheNode +typedef struct DF_UnwindCacheNode DF_UnwindCacheNode; +struct DF_UnwindCacheNode { - DF_RunUnwindCacheNode *hash_next; + DF_UnwindCacheNode *next; + DF_UnwindCacheNode *prev; + U64 reggen; + U64 memgen; + Arena *arena; DF_Handle thread; CTRL_Unwind unwind; }; -typedef struct DF_RunUnwindCacheSlot DF_RunUnwindCacheSlot; -struct DF_RunUnwindCacheSlot +typedef struct DF_UnwindCacheSlot DF_UnwindCacheSlot; +struct DF_UnwindCacheSlot { - DF_RunUnwindCacheNode *first; - DF_RunUnwindCacheNode *last; + DF_UnwindCacheNode *first; + DF_UnwindCacheNode *last; }; -typedef struct DF_RunUnwindCache DF_RunUnwindCache; -struct DF_RunUnwindCache +typedef struct DF_UnwindCache DF_UnwindCache; +struct DF_UnwindCache { - Arena *arena; U64 slots_count; - DF_RunUnwindCacheSlot *slots; + DF_UnwindCacheSlot *slots; + DF_UnwindCacheNode *free_node; }; //- rjf: per-run tls-base-vaddr cache @@ -1004,7 +1008,7 @@ typedef struct DF_RunLocalsCacheNode DF_RunLocalsCacheNode; struct DF_RunLocalsCacheNode { DF_RunLocalsCacheNode *hash_next; - DF_Handle binary; + DI_Key dbgi_key; U64 voff; EVAL_String2NumMap *locals_map; }; @@ -1146,10 +1150,7 @@ struct DF_State DF_AutoViewRuleMapCache auto_view_rule_cache; // rjf: per-run caches - U64 unwind_cache_reggen_idx; - U64 unwind_cache_memgen_idx; - DF_RunUnwindCache unwind_caches[2]; - U64 unwind_cache_gen; + DF_UnwindCache unwind_cache; U64 tls_base_cache_reggen_idx; U64 tls_base_cache_memgen_idx; DF_RunTLSBaseCache tls_base_caches[2]; @@ -1459,6 +1460,7 @@ internal void df_entity_equip_color_rgba(DF_Entity *entity, Vec4F32 rgba); internal void df_entity_equip_color_hsva(DF_Entity *entity, Vec4F32 hsva); internal void df_entity_equip_death_timer(DF_Entity *entity, F32 seconds_til_death); internal void df_entity_equip_cfg_src(DF_Entity *entity, DF_CfgSrc cfg_src); +internal void df_entity_equip_timestamp(DF_Entity *entity, U64 timestamp); //- rjf: control layer correllation equipment internal void df_entity_equip_ctrl_machine_id(DF_Entity *entity, CTRL_MachineID machine_id); @@ -1507,11 +1509,6 @@ internal DF_CmdSpecList df_push_cmd_spec_list(Arena *arena); internal void df_register_core_view_rule_specs(DF_CoreViewRuleSpecInfoArray specs); internal DF_CoreViewRuleSpec *df_core_view_rule_spec_from_string(String8 string); -//////////////////////////////// -//~ rjf: Debug Info Mapping - -internal String8 df_debug_info_path_from_module(Arena *arena, DF_Entity *module); - //////////////////////////////// //~ rjf: Stepping "Trap Net" Builders @@ -1522,9 +1519,9 @@ internal CTRL_TrapList df_trap_net_from_thread__step_into_line(Arena *arena, DF_ //////////////////////////////// //~ rjf: Modules & Debug Info Mappings -//- rjf: module <=> binary file -internal DF_Entity *df_binary_file_from_module(DF_Entity *module); -internal DF_EntityList df_modules_from_binary_file(Arena *arena, DF_Entity *binary_info); +//- rjf: module <=> debug info keys +internal DI_Key df_dbgi_key_from_module(DF_Entity *module); +internal DF_EntityList df_modules_from_dbgi_key(Arena *arena, DI_Key *dbgi_key); //- rjf: voff <=> vaddr internal U64 df_base_vaddr_from_module(DF_Entity *module); @@ -1536,33 +1533,29 @@ internal Rng1U64 df_vaddr_range_from_voff_range(DF_Entity *module, Rng1U64 voff_ //////////////////////////////// //~ rjf: Debug Info Lookups -//- rjf: binary file -> dbgi parse -internal DBGI_Parse *df_dbgi_parse_from_binary_file(DBGI_Scope *scope, DF_Entity *binary); - //- rjf: voff|vaddr -> symbol lookups -internal String8 df_symbol_name_from_binary_voff(Arena *arena, DF_Entity *binary, U64 voff); +internal String8 df_symbol_name_from_dbgi_key_voff(Arena *arena, DI_Key *dbgi_key, U64 voff); internal String8 df_symbol_name_from_process_vaddr(Arena *arena, DF_Entity *process, U64 vaddr); //- rjf: src -> voff lookups internal DF_TextLineSrc2DasmInfoListArray df_text_line_src2dasm_info_list_array_from_src_line_range(Arena *arena, DF_Entity *file, Rng1S64 line_num_range); //- rjf: voff -> src lookups -internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_binary_voff(DF_Entity *binary, U64 voff); +internal DF_TextLineDasm2SrcInfo df_text_line_dasm2src_info_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); //- rjf: symbol -> voff lookups -internal U64 df_voff_from_binary_symbol_name(DF_Entity *binary, String8 symbol_name); -internal U64 df_type_num_from_binary_name(DF_Entity *binary, String8 name); +internal U64 df_voff_from_dbgi_key_symbol_name(DI_Key *dbgi_key, String8 symbol_name); +internal U64 df_type_num_from_dbgi_key_name(DI_Key *dbgi_key, String8 name); //////////////////////////////// -//~ rjf: Process/Thread Info Lookups +//~ rjf: Process/Thread/Module Info Lookups -//- rjf: thread info extraction helpers internal DF_Entity *df_module_from_process_vaddr(DF_Entity *process, U64 vaddr); internal DF_Entity *df_module_from_thread(DF_Entity *thread); internal U64 df_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); internal Architecture df_architecture_from_entity(DF_Entity *entity); -internal EVAL_String2NumMap *df_push_locals_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); -internal EVAL_String2NumMap *df_push_member_map_from_binary_voff(Arena *arena, DBGI_Scope *scope, DF_Entity *binary, U64 voff); +internal EVAL_String2NumMap *df_push_locals_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff); +internal EVAL_String2NumMap *df_push_member_map_from_dbgi_key_voff(Arena *arena, DI_Scope *scope, DI_Key *dbgi_key, U64 voff); internal B32 df_set_thread_rip(DF_Entity *thread, U64 vaddr); internal DF_Entity *df_module_from_thread_candidates(DF_Entity *thread, DF_EntityList *candidates); @@ -1587,12 +1580,12 @@ internal CTRL_Event df_ctrl_last_stop_event(void); //~ rjf: Evaluation internal B32 df_eval_memory_read(void *u, void *out, U64 addr, U64 size); -internal EVAL_ParseCtx df_eval_parse_ctx_from_process_vaddr(DBGI_Scope *scope, DF_Entity *process, U64 vaddr); -internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DBGI_Scope *scope, DF_Entity *file, TxtPt pt); -internal DF_Eval df_eval_from_string(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string); +internal EVAL_ParseCtx df_eval_parse_ctx_from_process_vaddr(DI_Scope *scope, DF_Entity *process, U64 vaddr); +internal EVAL_ParseCtx df_eval_parse_ctx_from_src_loc(DI_Scope *scope, DF_Entity *file, TxtPt pt); +internal DF_Eval df_eval_from_string(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, String8 string); internal DF_Eval df_value_mode_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); internal DF_Eval df_dynamically_typed_eval_from_eval(TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, DF_Eval eval); -internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg); +internal DF_Eval df_eval_from_eval_cfg_table(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_Eval eval, DF_CfgTable *cfg); //////////////////////////////// //~ rjf: Evaluation Views @@ -1630,8 +1623,8 @@ internal DF_EvalLinkBaseArray df_eval_link_base_array_from_chunk_list(Arena *are internal DF_EvalVizBlock *df_eval_viz_block_begin(Arena *arena, DF_EvalVizBlockKind kind, DF_ExpandKey parent_key, DF_ExpandKey key, S32 depth); internal DF_EvalVizBlock *df_eval_viz_block_split_and_continue(Arena *arena, DF_EvalVizBlockList *list, DF_EvalVizBlock *split_block, U64 split_idx); internal void df_eval_viz_block_end(DF_EvalVizBlockList *list, DF_EvalVizBlock *block); -internal void df_append_viz_blocks_for_parent__rec(Arena *arena, DBGI_Scope *scope, DF_EvalView *view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out); -internal DF_EvalVizBlockList df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key); +internal void df_append_viz_blocks_for_parent__rec(Arena *arena, DI_Scope *scope, DF_EvalView *view, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_ExpandKey parent_key, DF_ExpandKey key, String8 string, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table, S32 depth, DF_EvalVizBlockList *list_out); +internal DF_EvalVizBlockList df_eval_viz_block_list_from_eval_view_expr_keys(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, String8 expr, DF_ExpandKey parent_key, DF_ExpandKey key); internal void df_eval_viz_block_list_concat__in_place(DF_EvalVizBlockList *dst, DF_EvalVizBlockList *to_push); //- rjf: viz block list <-> table coordinates @@ -1684,7 +1677,9 @@ internal String8 df_info_summary_from_string(Architecture arch, String8 string); //- rjf: entity kind cache internal DF_EntityList df_query_cached_entity_list_with_kind(DF_EntityKind kind); -internal DF_EntityList df_push_active_binary_list(Arena *arena); + +//- rjf: active entity based queries +internal DI_KeyList df_push_active_dbgi_key_list(Arena *arena); internal DF_EntityList df_push_active_target_list(Arena *arena); //- rjf: per-run caches @@ -1692,8 +1687,8 @@ internal CTRL_Unwind df_query_cached_unwind_from_thread(DF_Entity *thread); internal U64 df_query_cached_rip_from_thread(DF_Entity *thread); internal U64 df_query_cached_rip_from_thread_unwind(DF_Entity *thread, U64 unwind_count); internal U64 df_query_cached_tls_base_vaddr_from_process_root_rip(DF_Entity *process, U64 root_vaddr, U64 rip_vaddr); -internal EVAL_String2NumMap *df_query_cached_locals_map_from_binary_voff(DF_Entity *binary, U64 voff); -internal EVAL_String2NumMap *df_query_cached_member_map_from_binary_voff(DF_Entity *binary, U64 voff); +internal EVAL_String2NumMap *df_query_cached_locals_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); +internal EVAL_String2NumMap *df_query_cached_member_map_from_dbgi_key_voff(DI_Key *dbgi_key, U64 voff); //- rjf: top-level command dispatch internal void df_push_cmd__root(DF_CmdParams *params, DF_CmdSpec *spec); diff --git a/src/df/core/df_core.mdesk b/src/df/core/df_core.mdesk index 58ad9ba2..cd66d529 100644 --- a/src/df/core/df_core.mdesk +++ b/src/df/core/df_core.mdesk @@ -26,14 +26,10 @@ DF_EntityKindTable: //- rjf: filesystem modeling {File file 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "File" } {OverrideFileLink override_file_link 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Override File Link" } - {PendingFileChange pending_file_change 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Pending File Change" } //- rjf: auto view rules {AutoViewRule auto_view_rule 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 "Label" Binoculars "Auto View Rule" } - //- rjf: diagnostics log - {DiagLog diag_log 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" FileOutline "Diagnostics Log" } - //- rjf: text attachments {FlashMarker flash_marker 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Flash Marker" } @@ -59,8 +55,8 @@ DF_EntityKindTable: {Process process 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Threads "Process" } {Thread thread 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Thread "Thread" } {Module module 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Module "Module" } - {DebugInfoOverride debug_info_override 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 "Label" Null "Debug Info Override" } {PendingThreadName pending_thread_name 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Threads "Pending Thread Name" } + {DebugInfoPath debug_info_path 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Module "Debug Info Path" } //- rjf: parser task entities {ConversionTask conversion_task 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 "Label" Null "Conversion Task" } @@ -337,7 +333,7 @@ DF_CoreCmdTable:// | | | {DuplicateEntity 1 Null Nil 0 0 0 0 0 0 Null "duplicate_entity" "Duplicate Entity" "Duplicates an entity." "" } //- rjf: breakpoints - {TextBreakpoint 1 Null Nil 0 0 0 0 0 0 CircleFilled "text_breakpoint" "Text Breakpoint" "Places or removes a breakpoint on the specified line of source code." "" } + {TextBreakpoint 1 FilePath Nil 0 0 0 0 0 0 CircleFilled "text_breakpoint" "Text Breakpoint" "Places or removes a breakpoint on the specified line of source code." "" } {AddressBreakpoint 0 VirtualAddr Nil 0 0 0 0 1 1 CircleFilled "address_breakpoint" "Address Breakpoint" "Places or removes a breakpoint on the specified address." "" } {FunctionBreakpoint 0 String Nil 0 0 0 0 1 1 CircleFilled "function_breakpoint" "Function Breakpoint" "Places or removes a breakpoint on the first address(es) of the specified function." "" } {ToggleBreakpointAtCursor 0 Null Nil 0 0 0 0 0 0 CircleFilled "toggle_breakpoint_cursor" "Toggle Breakpoint At Cursor" "Places or removes a breakpoint on the line on which the active cursor sits." "" } diff --git a/src/df/core/generated/df_core.meta.c b/src/df/core/generated/df_core.meta.c index c7d722ab..6b8a2b85 100644 --- a/src/df/core/generated/df_core.meta.c +++ b/src/df/core/generated/df_core.meta.c @@ -29,16 +29,14 @@ Rng1U64 df_g_cmd_param_slot_range_table[21] = {OffsetOf(DF_CmdParams, dir2), OffsetOf(DF_CmdParams, dir2) + sizeof(Dir2)}, }; -DF_IconKind df_g_entity_kind_icon_kind_table[27] = +DF_IconKind df_g_entity_kind_icon_kind_table[25] = { DF_IconKind_Null, DF_IconKind_Null, DF_IconKind_Machine, DF_IconKind_FileOutline, DF_IconKind_FileOutline, -DF_IconKind_FileOutline, DF_IconKind_Binoculars, -DF_IconKind_FileOutline, DF_IconKind_Null, DF_IconKind_Pin, DF_IconKind_CircleFilled, @@ -53,23 +51,21 @@ DF_IconKind_Null, DF_IconKind_Threads, DF_IconKind_Thread, DF_IconKind_Module, -DF_IconKind_Null, DF_IconKind_Threads, +DF_IconKind_Module, DF_IconKind_Null, DF_IconKind_Null, DF_IconKind_Null, }; -String8 df_g_entity_kind_display_string_table[27] = +String8 df_g_entity_kind_display_string_table[25] = { str8_lit_comp("Nil"), str8_lit_comp("Root"), str8_lit_comp("Machine"), str8_lit_comp("File"), str8_lit_comp("Override File Link"), -str8_lit_comp("Pending File Change"), str8_lit_comp("Auto View Rule"), -str8_lit_comp("Diagnostics Log"), str8_lit_comp("Flash Marker"), str8_lit_comp("Watch Pin"), str8_lit_comp("Breakpoint"), @@ -84,14 +80,14 @@ str8_lit_comp("Destination"), str8_lit_comp("Process"), str8_lit_comp("Thread"), str8_lit_comp("Module"), -str8_lit_comp("Debug Info Override"), str8_lit_comp("Pending Thread Name"), +str8_lit_comp("Debug Info Path"), str8_lit_comp("Conversion Task"), str8_lit_comp("Conversion Failure"), str8_lit_comp("EndedProcess"), }; -String8 df_g_entity_kind_name_label_table[27] = +String8 df_g_entity_kind_name_label_table[25] = { str8_lit_comp("Label"), str8_lit_comp("Label"), @@ -100,8 +96,6 @@ str8_lit_comp("Label"), str8_lit_comp("Label"), str8_lit_comp("Label"), str8_lit_comp("Label"), -str8_lit_comp("Label"), -str8_lit_comp("Label"), str8_lit_comp("Expression"), str8_lit_comp("Label"), str8_lit_comp("Expression"), @@ -122,17 +116,15 @@ str8_lit_comp("Label"), str8_lit_comp("Label"), }; -DF_EntityKindFlags df_g_entity_kind_flags_table[27] = +DF_EntityKindFlags df_g_entity_kind_flags_table[25] = { (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (1*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 1*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 1*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 1*DF_EntityKindFlag_NameIsCode | 1*DF_EntityKindFlag_UserDefinedLifetime), @@ -146,14 +138,14 @@ DF_EntityKindFlags df_g_entity_kind_flags_table[27] = (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), -(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 1*DF_EntityKindFlag_LeafMutationSoftHalt | 1*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 1*DF_EntityKindFlag_TreeMutationSoftHalt | 1*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), +(0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), (0*DF_EntityKindFlag_LeafMutationUserConfig | 0*DF_EntityKindFlag_LeafMutationProfileConfig | 0*DF_EntityKindFlag_LeafMutationSoftHalt | 0*DF_EntityKindFlag_LeafMutationDebugInfoMap | 0*DF_EntityKindFlag_TreeMutationUserConfig | 0*DF_EntityKindFlag_TreeMutationProfileConfig | 0*DF_EntityKindFlag_TreeMutationSoftHalt | 0*DF_EntityKindFlag_TreeMutationDebugInfoMap | 0*DF_EntityKindFlag_NameIsCode | 0*DF_EntityKindFlag_UserDefinedLifetime), }; -DF_EntityOpFlags df_g_entity_kind_op_flags_table[27] = +DF_EntityOpFlags df_g_entity_kind_op_flags_table[25] = { (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), @@ -162,8 +154,6 @@ DF_EntityOpFlags df_g_entity_kind_op_flags_table[27] = (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), -(0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), (1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), (1*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (1*DF_EntityOpFlag_Rename) | (1*DF_EntityOpFlag_Enable) | (1*DF_EntityOpFlag_Condition) | (1*DF_EntityOpFlag_Duplicate), (0*DF_EntityOpFlag_Delete) | (0*DF_EntityOpFlag_Freeze) | (0*DF_EntityOpFlag_Edit) | (0*DF_EntityOpFlag_Rename) | (0*DF_EntityOpFlag_Enable) | (0*DF_EntityOpFlag_Condition) | (0*DF_EntityOpFlag_Duplicate), @@ -377,7 +367,7 @@ DF_CmdSpecInfo df_g_core_cmd_kind_spec_info_table[214] = { str8_lit_comp("name_entity"), str8_lit_comp("Equips an entity with a name."), str8_lit_comp(""), str8_lit_comp("Name Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, { str8_lit_comp("edit_entity"), str8_lit_comp("Opens the editor for an entity."), str8_lit_comp(""), str8_lit_comp("Edit Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, { str8_lit_comp("duplicate_entity"), str8_lit_comp("Duplicates an entity."), str8_lit_comp(""), str8_lit_comp("Duplicate Entity"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_Null}, -{ str8_lit_comp("text_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified line of source code."), str8_lit_comp(""), str8_lit_comp("Text Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled}, +{ str8_lit_comp("text_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified line of source code."), str8_lit_comp(""), str8_lit_comp("Text Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*1), {DF_CmdParamSlot_FilePath, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled}, { str8_lit_comp("address_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the specified address."), str8_lit_comp(""), str8_lit_comp("Address Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_VirtualAddr, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CircleFilled}, { str8_lit_comp("function_breakpoint"), str8_lit_comp("Places or removes a breakpoint on the first address(es) of the specified function."), str8_lit_comp(""), str8_lit_comp("Function Breakpoint"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_String, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*1)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*1)}, DF_IconKind_CircleFilled}, { str8_lit_comp("toggle_breakpoint_cursor"), str8_lit_comp("Places or removes a breakpoint on the line on which the active cursor sits."), str8_lit_comp(""), str8_lit_comp("Toggle Breakpoint At Cursor"), (DF_CmdSpecFlag_OmitFromLists*0), {DF_CmdParamSlot_Null, DF_EntityKind_Nil, (DF_CmdQueryFlag_AllowFiles*0)|(DF_CmdQueryFlag_AllowFolders*0)|(DF_CmdQueryFlag_CodeInput*0)|(DF_CmdQueryFlag_KeepOldInput*0)|(DF_CmdQueryFlag_SelectOldInput*0)|(DF_CmdQueryFlag_Required*0)}, DF_IconKind_CircleFilled}, diff --git a/src/df/core/generated/df_core.meta.h b/src/df/core/generated/df_core.meta.h index 5d52eec8..41cec252 100644 --- a/src/df/core/generated/df_core.meta.h +++ b/src/df/core/generated/df_core.meta.h @@ -22,9 +22,7 @@ DF_EntityKind_Root, DF_EntityKind_Machine, DF_EntityKind_File, DF_EntityKind_OverrideFileLink, -DF_EntityKind_PendingFileChange, DF_EntityKind_AutoViewRule, -DF_EntityKind_DiagLog, DF_EntityKind_FlashMarker, DF_EntityKind_WatchPin, DF_EntityKind_Breakpoint, @@ -39,8 +37,8 @@ DF_EntityKind_Dest, DF_EntityKind_Process, DF_EntityKind_Thread, DF_EntityKind_Module, -DF_EntityKind_DebugInfoOverride, DF_EntityKind_PendingThreadName, +DF_EntityKind_DebugInfoPath, DF_EntityKind_ConversionTask, DF_EntityKind_ConversionFail, DF_EntityKind_EndedProcess, @@ -1535,11 +1533,11 @@ struct {B32 *value_ptr; String8 name;} DEV_toggle_table[] = }; C_LINKAGE_BEGIN extern Rng1U64 df_g_cmd_param_slot_range_table[22]; -extern DF_IconKind df_g_entity_kind_icon_kind_table[27]; -extern String8 df_g_entity_kind_display_string_table[27]; -extern String8 df_g_entity_kind_name_label_table[27]; -extern DF_EntityKindFlags df_g_entity_kind_flags_table[27]; -extern DF_EntityOpFlags df_g_entity_kind_op_flags_table[27]; +extern DF_IconKind df_g_entity_kind_icon_kind_table[25]; +extern String8 df_g_entity_kind_display_string_table[25]; +extern String8 df_g_entity_kind_name_label_table[25]; +extern DF_EntityKindFlags df_g_entity_kind_flags_table[25]; +extern DF_EntityOpFlags df_g_entity_kind_op_flags_table[25]; extern String8 df_g_cfg_src_string_table[4]; extern DF_CoreCmdKind df_g_cfg_src_load_cmd_kind_table[4]; extern DF_CoreCmdKind df_g_cfg_src_write_cmd_kind_table[4]; diff --git a/src/df/gfx/df_gfx.c b/src/df/gfx/df_gfx.c index eb993471..6f1ba709 100644 --- a/src/df/gfx/df_gfx.c +++ b/src/df/gfx/df_gfx.c @@ -583,17 +583,18 @@ df_queue_drag_drop(void) } internal void -df_set_hovered_line_info(DF_Entity *binary, U64 voff) +df_set_hovered_line_info(DI_Key *dbgi_key, U64 voff) { - df_gfx_state->hover_line_binary = df_handle_from_entity(binary); + arena_clear(df_gfx_state->hover_line_arena); + df_gfx_state->hover_line_dbgi_key = di_key_copy(df_gfx_state->hover_line_arena, dbgi_key); df_gfx_state->hover_line_voff = voff; df_gfx_state->hover_line_set_this_frame = 1; } -internal DF_Entity * -df_get_hovered_line_info_binary(void) +internal DI_Key +df_get_hovered_line_info_dbgi_key(void) { - return df_entity_from_handle(df_gfx_state->hover_line_binary); + return df_gfx_state->hover_line_dbgi_key; } internal U64 @@ -1038,7 +1039,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) ////////////////////////////// //- rjf: unpack context // - B32 window_is_focused = os_window_is_focused(ws->os); + B32 window_is_focused = os_window_is_focused(ws->os) || ws->window_temporarily_focused_ipc; B32 confirm_open = df_gfx_state->confirm_active; B32 query_is_open = !df_view_is_nil(ws->query_view_stack_top); B32 hover_eval_is_open = (!confirm_open && @@ -1049,6 +1050,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { ws->menu_bar_key_held = 0; } + ws->window_temporarily_focused_ipc = 0; ui_select_state(ws->ui); ////////////////////////////// @@ -2488,7 +2490,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: thread finding case DF_CoreCmdKind_FindThread: { - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_Entity *thread = df_entity_from_handle(params.entity); U64 unwind_count = params.index; if(thread->kind == DF_EntityKind_Thread) @@ -2499,19 +2501,19 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: extract thread/rip info DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, rip_voff); // rjf: snap to resolved line B32 missing_rip = (rip_vaddr == 0); - B32 binary_missing = (binary->flags & DF_EntityFlag_IsMissing); - B32 dbg_info_pending = !binary_missing && dbgi == &dbgi_parse_nil; + B32 dbgi_missing = (dbgi_key.min_timestamp == 0 || dbgi_key.path.size == 0); + B32 dbgi_pending = !dbgi_missing && rdi == &di_rdi_parsed_nil; B32 has_line_info = (line_info.voff_range.max != line_info.voff_range.min); B32 has_module = !df_entity_is_nil(module); - B32 has_dbg_info = has_module && !binary_missing; - if(!dbg_info_pending && (has_line_info || has_module)) + B32 has_dbg_info = has_module && !dbgi_missing; + if(!dbgi_pending && (has_line_info || has_module)) { DF_CmdParams params = df_cmd_params_from_window(ws); if(has_line_info) @@ -2527,17 +2529,33 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) params.index = unwind_count; df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualOff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); + df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); + } + + // rjf: snap to resolved address w/o line info + if(!missing_rip && !dbgi_pending && !has_line_info && !has_module) + { + DF_CmdParams params = df_cmd_params_from_window(ws); + params.entity = df_handle_from_entity(thread); + params.voff = rip_voff; + params.vaddr = rip_vaddr; + params.index = unwind_count; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualOff); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_VirtualAddr); df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Index); df_cmd_list_push(arena, cmds, ¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); } // rjf: retry on stopped, pending debug info - if(!df_ctrl_targets_running() && (dbg_info_pending || missing_rip)) + if(!df_ctrl_targets_running() && (dbgi_pending || missing_rip)) { df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindThread)); } } - dbgi_scope_close(scope); + di_scope_close(scope); }break; case DF_CoreCmdKind_FindSelectedThread: { @@ -2561,17 +2579,17 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: try to resolve name as a symbol U64 voff = 0; - DF_Entity *voff_binary = &df_g_nil_entity; + DI_Key voff_dbgi_key = {0}; if(name_resolved == 0) { - DF_EntityList binaries = df_push_active_binary_list(scratch.arena); - for(DF_EntityNode *n = binaries.first; n != 0; n = n->next) + DI_KeyList keys = df_push_active_dbgi_key_list(scratch.arena); + for(DI_KeyNode *n = keys.first; n != 0; n = n->next) { - U64 binary_voff = df_voff_from_binary_symbol_name(n->entity, name); + U64 binary_voff = df_voff_from_dbgi_key_symbol_name(&n->v, name); if(binary_voff != 0) { voff = binary_voff; - voff_binary = n->entity; + voff_dbgi_key = n->v; name_resolved = 1; break; } @@ -2680,19 +2698,25 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // rjf: name resolved to voff * dbg info if(name_resolved != 0 && voff != 0) { - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(voff_binary, voff); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&voff_dbgi_key, voff); DF_CmdParams p = params; { p.file_path = df_full_path_from_entity(scratch.arena, dasm2src_info.file); p.text_point = dasm2src_info.pt; df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); df_cmd_params_mark_slot(&p, DF_CmdParamSlot_TextPoint); - if(!df_entity_is_nil(voff_binary)) + if(voff_dbgi_key.path.size != 0) { - p.entity = df_handle_from_entity(voff_binary); - p.voff = dasm2src_info.voff_range.min; - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_VirtualOff); + DF_EntityList modules = df_modules_from_dbgi_key(scratch.arena, &voff_dbgi_key); + DF_Entity *module = df_first_entity_from_list(&modules); + DF_Entity *process = df_entity_ancestor_from_kind(module, DF_EntityKind_Process); + if(!df_entity_is_nil(process)) + { + p.entity = df_handle_from_entity(process); + p.vaddr = module->vaddr_rng.min + dasm2src_info.voff_range.min; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_VirtualAddr); + } } } df_cmd_list_push(arena, cmds, &p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_FindCodeLocation)); @@ -2911,7 +2935,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) { for(DF_TextLineSrc2DasmInfoNode *n = src2dasm.v[src2dasm_idx].first; n != 0; n = n->next) { - DF_EntityList modules = df_modules_from_binary_file(scratch.arena, n->v.binary); + DF_EntityList modules = df_modules_from_dbgi_key(scratch.arena, &n->v.dbgi_key); DF_Entity *module = df_module_from_thread_candidates(thread, &modules); vaddr = df_vaddr_from_voff(module, n->v.voff_range.min); goto end_lookup; @@ -3299,7 +3323,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) // Rng2F32 window_rect = os_client_rect_from_window(ws->os); Vec2F32 window_rect_dim = dim_2f32(window_rect); - Rng2F32 top_bar_rect = r2f32p(window_rect.x0, window_rect.y0, window_rect.x0+window_rect_dim.x, window_rect.y0+ui_top_pref_height().value); + Rng2F32 top_bar_rect = r2f32p(window_rect.x0, window_rect.y0, window_rect.x0+window_rect_dim.x+1, window_rect.y0+ui_top_pref_height().value); Rng2F32 bottom_bar_rect = r2f32p(window_rect.x0, window_rect_dim.y - ui_top_pref_height().value, window_rect.x0+window_rect_dim.x, window_rect.y0+window_rect_dim.y); Rng2F32 content_rect = r2f32p(window_rect.x0, top_bar_rect.y1, window_rect.x0+window_rect_dim.x, bottom_bar_rect.y0); F32 window_edge_px = os_dpi_from_window(ws->os)*0.035f; @@ -3411,26 +3435,10 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) case DF_EntityKind_Module: { - DF_Entity *bin_file = df_binary_file_from_module(entity); - if(ui_clicked(df_icon_buttonf(DF_IconKind_Module, 0, "Inspect Binary File Memory"))) - { - DF_CmdParams params = df_cmd_params_from_panel(ws, panel); - params.entity = df_handle_from_entity(bin_file); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); - ui_ctx_menu_close(); - } - if(ui_clicked(df_icon_buttonf(DF_IconKind_Module, 0, "View Binary File Disassembly"))) - { - DF_CmdParams params = df_cmd_params_from_panel(ws, panel); - params.entity = df_handle_from_entity(bin_file); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_Entity); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PendingEntity)); - ui_ctx_menu_close(); - } }break; case DF_EntityKind_Process: { +#if 0 if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Process Log"))) { DF_Entity *log = df_log_from_entity(entity); @@ -3440,9 +3448,11 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Code)); ui_ctx_menu_close(); } +#endif }break; case DF_EntityKind_Thread: { +#if 0 if(ui_clicked(df_icon_buttonf(DF_IconKind_FileOutline, 0, "Open Thread Log"))) { DF_Entity *log = df_log_from_entity(entity); @@ -3452,6 +3462,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Code)); ui_ctx_menu_close(); } +#endif }break; } } @@ -3924,13 +3935,13 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(entity); String8List lines = {0}; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next) + for(U64 frame_idx = 0; frame_idx < unwind.frames.count; frame_idx += 1) { - U64 rip_vaddr = frame->rip; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[frame_idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - String8 symbol = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + String8 symbol = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); if(symbol.size != 0) { str8_list_pushf(scratch.arena, &lines, "0x%I64x: %S", rip_vaddr, symbol); @@ -4255,7 +4266,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); //- rjf: gather lister items DF_AutoCompListerItemChunkList item_list = {0}; @@ -4263,7 +4274,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) //- rjf: gather locals if(ws->autocomp_lister_params.flags & DF_AutoCompListerFlag_Locals) { - EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_binary_voff(binary, thread_rip_voff); + EVAL_String2NumMap *locals_map = df_query_cached_locals_map_from_dbgi_key_voff(&dbgi_key, thread_rip_voff); for(EVAL_String2NumMapNode *n = locals_map->first; n != 0; n = n->order_next) { DF_AutoCompListerItem item = {0}; @@ -5306,7 +5317,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) } os_window_push_custom_title_bar_client_area(ws->os, min_sig.box->rect); os_window_push_custom_title_bar_client_area(ws->os, max_sig.box->rect); - os_window_push_custom_title_bar_client_area(ws->os, cls_sig.box->rect); + os_window_push_custom_title_bar_client_area(ws->os, pad_2f32(cls_sig.box->rect, 2.f)); } } } @@ -5716,7 +5727,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) UI_FontSize(df_font_size_from_slot(ws, DF_FontSlot_Main)) { Temp scratch = scratch_begin(&arena, 1); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_CtrlCtx ctrl_ctx = ws->hover_eval_ctrl_ctx; DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -5983,7 +5994,7 @@ df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdList *cmds) } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); } } @@ -8311,7 +8322,7 @@ df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags } internal DF_EvalVizWindowedRowList -df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks) +df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -8697,12 +8708,12 @@ df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scop for(U64 idx = visible_idx_range.min; idx < visible_idx_range.max; idx += 1) { // rjf: unpack info about this row - String8 name = dbgi_fuzzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, block->dbgi_target, block->backing_search_items.v[idx].idx); + String8 name = fzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, block->fzy_target, block->fzy_backing_items.v[idx].idx); // rjf: get keys for this row DF_ExpandKey parent_key = block->parent_key; DF_ExpandKey key = block->key; - key.child_num = block->backing_search_items.v[idx].idx; + key.child_num = block->fzy_backing_items.v[idx].idx; // rjf: get eval for this row DF_Eval eval = df_eval_from_string(arena, scope, ctrl_ctx, parse_ctx, macro_map, name); @@ -9547,6 +9558,13 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, Temp scratch = scratch_begin(&arena, 1); DF_Entity *thread = df_entity_from_ctrl_handle(event->machine_id, event->entity); String8 thread_display_string = df_display_string_from_entity(scratch.arena, thread); + String8 process_thread_string = thread_display_string; + DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); + if(process->kind == DF_EntityKind_Process) + { + String8 process_display_string = df_display_string_from_entity(scratch.arena, process); + process_thread_string = push_str8f(scratch.arena, "%S: %S", process_display_string, thread_display_string); + } switch(event->kind) { default: @@ -9558,7 +9576,7 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, { if(!df_entity_is_nil(thread)) { - explanation = push_str8f(arena, "%S completed step", thread_display_string); + explanation = push_str8f(arena, "%S completed step", process_thread_string); } else { @@ -9570,7 +9588,7 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, if(!df_entity_is_nil(thread)) { icon = DF_IconKind_CircleFilled; - explanation = push_str8f(arena, "%S hit a breakpoint", thread_display_string); + explanation = push_str8f(arena, "%S hit a breakpoint", process_thread_string); } }break; case CTRL_EventCause_InterruptedByException: @@ -9583,30 +9601,30 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, default: { String8 exception_code_string = df_string_from_exception_code(event->exception_code); - explanation = push_str8f(arena, "Exception thrown by %S - 0x%x%s%S", thread_display_string, event->exception_code, exception_code_string.size > 0 ? ": " : "", exception_code_string); + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x%s%S", process_thread_string, event->exception_code, exception_code_string.size > 0 ? ": " : "", exception_code_string); }break; case CTRL_ExceptionKind_CppThrow: { - explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: C++ exception", thread_display_string, event->exception_code); + explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: C++ exception", process_thread_string, event->exception_code); }break; case CTRL_ExceptionKind_MemoryRead: { explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation reading 0x%I64x", - thread_display_string, + process_thread_string, event->exception_code, event->vaddr_rng.min); }break; case CTRL_ExceptionKind_MemoryWrite: { explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation writing 0x%I64x", - thread_display_string, + process_thread_string, event->exception_code, event->vaddr_rng.min); }break; case CTRL_ExceptionKind_MemoryExecute: { explanation = push_str8f(arena, "Exception thrown by %S - 0x%x: Access violation executing 0x%I64x", - thread_display_string, + process_thread_string, event->exception_code, event->vaddr_rng.min); }break; @@ -9621,7 +9639,7 @@ df_stop_explanation_string_icon_from_ctrl_event(Arena *arena, CTRL_Event *event, case CTRL_EventCause_InterruptedByTrap: { icon = DF_IconKind_WarningBig; - explanation = push_str8f(arena, "%S interrupted by trap - 0x%x", thread_display_string, event->exception_code); + explanation = push_str8f(arena, "%S interrupted by trap - 0x%x", process_thread_string, event->exception_code); }break; case CTRL_EventCause_InterruptedByHalt: { @@ -9938,13 +9956,13 @@ df_entity_tooltips(DF_Entity *entity) ui_spacer(ui_em(1.5f, 1.f)); DF_Entity *process = df_entity_ancestor_from_kind(entity, DF_EntityKind_Process); CTRL_Unwind unwind = df_query_cached_unwind_from_thread(entity); - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next) + for(U64 idx = 0; idx < unwind.frames.count; idx += 1) { - U64 rip_vaddr = frame->rip; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, unwind.frames.v[idx].regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - String8 symbol = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + String8 symbol = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); UI_PrefWidth(ui_children_sum(1)) UI_Row { UI_Font(df_font_from_slot(DF_FontSlot_Code)) UI_PrefWidth(ui_em(18.f, 1.f)) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) ui_labelf("0x%I64x", rip_vaddr); @@ -10059,13 +10077,12 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam ui_set_next_background_color(bg_color); } ui_set_next_hover_cursor(OS_Cursor_HandPoint); - UI_Key key = ui_key_from_stringf(ui_top_parent()->key, "entity_ref_button_%p", entity); - UI_Box *box = ui_build_box_from_key(UI_BoxFlag_Clickable| - UI_BoxFlag_DrawBorder| - UI_BoxFlag_DrawBackground| - UI_BoxFlag_DrawHotEffects| - UI_BoxFlag_DrawActiveEffects, - key); + UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| + UI_BoxFlag_DrawBorder| + UI_BoxFlag_DrawBackground| + UI_BoxFlag_DrawHotEffects| + UI_BoxFlag_DrawActiveEffects, + "entity_ref_button_%p", entity); //- rjf: build contents UI_Parent(box) UI_PrefWidth(ui_text_dim(10, 0)) @@ -10133,13 +10150,14 @@ df_entity_desc_button(DF_Window *ws, DF_Entity *entity, FuzzyMatchRangeList *nam U64 idx = 0; U64 limit = 3; ui_spacer(ui_em(1.f, 1.f)); - for(CTRL_UnwindFrame *f = unwind.last; f != 0 && idx < limit; f = f->prev) + for(U64 num = unwind.frames.count; num > 0; num -= 1) { - U64 rip_vaddr = f->rip; + CTRL_UnwindFrame *f = &unwind.frames.v[num-1]; + U64 rip_vaddr = regs_rip_from_arch_block(entity->arch, f->regs); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 procedure_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + String8 procedure_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); if(procedure_name.size != 0) { FuzzyMatchRangeList fuzzy_matches = {0}; @@ -10582,7 +10600,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 thread_rip_voff = df_voff_from_vaddr(module, thread_rip_vaddr); // rjf: thread info => color @@ -10649,7 +10667,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ n != 0; n = n->next) { - if(n->v.binary == binary) + if(di_key_match(&n->v.dbgi_key, &dbgi_key)) { line_info = &n->v; break; @@ -10964,7 +10982,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // UI_Focus(UI_FocusKind_Off) { - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); U64 line_idx = 0; for(S64 line_num = params->line_num_range.min; line_num < params->line_num_range.max; @@ -11029,7 +11047,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } } } - dbgi_scope_close(scope); + di_scope_close(scope); } ////////////////////////////// @@ -11257,11 +11275,11 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ if(params->line_src2dasm[line_slice_idx].first != 0 && params->line_src2dasm[line_slice_idx].first->v.remap_line == mouse_pt.line) { - df_set_hovered_line_info(params->line_src2dasm[line_slice_idx].first->v.binary, params->line_src2dasm[line_slice_idx].first->v.voff_range.min); + df_set_hovered_line_info(¶ms->line_src2dasm[line_slice_idx].first->v.dbgi_key, params->line_src2dasm[line_slice_idx].first->v.voff_range.min); } if(params->line_dasm2src[line_slice_idx].first != 0) { - df_set_hovered_line_info(params->line_dasm2src[line_slice_idx].first->v.binary, params->line_dasm2src[line_slice_idx].first->v.voff_range.min); + df_set_hovered_line_info(¶ms->line_dasm2src[line_slice_idx].first->v.dbgi_key, params->line_dasm2src[line_slice_idx].first->v.voff_range.min); } } @@ -11399,7 +11417,6 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } if(dasm2src_info != 0) { - DF_Entity *binary = dasm2src_info->binary; has_line_info = 1; line_info_line_num = dasm2src_info->pt.line; line_info_t = selected_thread_module->alive_t; @@ -11426,7 +11443,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // UI_Parent(text_container_box) ProfScope("build line text") UI_Focus(UI_FocusKind_Off) { - DF_Entity *hovered_line_binary = df_get_hovered_line_info_binary(); + DI_Key hovered_line_dbgi_key = df_get_hovered_line_info_dbgi_key(); U64 hovered_line_voff = df_get_hovered_line_info_voff(); ui_set_next_pref_height(ui_px(params->line_height_px*(dim_1s64(params->line_num_range)+1), 1.f)); UI_WidthFill @@ -11501,12 +11518,12 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ if(token->kind == TXT_TokenKind_Identifier || token->kind == TXT_TokenKind_Keyword) { B32 mapped_special = 0; - for(DF_EntityNode *n = params->relevant_binaries.first; n != 0; n = n->next) + for(DI_KeyNode *n = params->relevant_dbgi_keys.first; n != 0; n = n->next) { - DF_Entity *binary = n->entity; + DI_Key dbgi_key = n->v; if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { - U64 voff = df_voff_from_binary_symbol_name(binary, token_string); + U64 voff = df_voff_from_dbgi_key_symbol_name(&dbgi_key, token_string); if(voff != 0) { mapped_special = 1; @@ -11516,7 +11533,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ } if(!mapped_special && token->kind == TXT_TokenKind_Identifier) { - U64 type_num = df_type_num_from_binary_name(binary, token_string); + U64 type_num = df_type_num_from_dbgi_key_name(&dbgi_key, token_string); if(type_num != 0) { mapped_special = 1; @@ -11708,7 +11725,7 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ for(DF_TextLineSrc2DasmInfoNode *n = src2dasm_list->first; n != 0; n = n->next) { if(n->v.remap_line == line_num && - n->v.binary == hovered_line_binary && + di_key_match(&n->v.dbgi_key, &hovered_line_dbgi_key) && n->v.voff_range.min <= hovered_line_voff && hovered_line_voff < n->v.voff_range.max) { matches = 1; @@ -11721,8 +11738,8 @@ df_code_slice(DF_Window *ws, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, DF_ // rjf: check dasm2src if(dasm2src_list->first != 0) { - DF_Entity *binary = dasm2src_list->first->v.binary; - if(binary == hovered_line_binary) + DI_Key dbgi_key = dasm2src_list->first->v.dbgi_key; + if(di_key_match(&dbgi_key, &dasm2src_list->first->v.dbgi_key)) { for(DF_TextLineDasm2SrcInfoNode *n = dasm2src_list->first; n != 0; n = n->next) { @@ -12820,6 +12837,7 @@ df_gfx_init(OS_WindowRepaintFunctionType *window_repaint_entry_point, DF_StateDe df_gfx_state->repaint_hook = window_repaint_entry_point; df_gfx_state->cfg_main_font_path_arena = arena_alloc(); df_gfx_state->cfg_code_font_path_arena = arena_alloc(); + df_gfx_state->hover_line_arena = arena_alloc(); df_clear_bindings(); // rjf: register gfx layer views @@ -13829,7 +13847,7 @@ df_gfx_end_frame(void) //- rjf: clear hover line info if(df_gfx_state->hover_line_set_this_frame == 0) { - df_gfx_state->hover_line_binary = df_handle_zero(); + MemoryZeroStruct(&df_gfx_state->hover_line_dbgi_key); df_gfx_state->hover_line_voff = 0; } diff --git a/src/df/gfx/df_gfx.h b/src/df/gfx/df_gfx.h index a7c1b964..60e0f83f 100644 --- a/src/df/gfx/df_gfx.h +++ b/src/df/gfx/df_gfx.h @@ -300,11 +300,11 @@ enum #define DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(name) df_gfx_view_rule_line_stringize__##name #define DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_DEF(name) internal DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_SIG(DF_GFX_VIEW_RULE_LINE_STRINGIZE_FUNCTION_NAME(name)) -#define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(name) void name(DF_ExpandKey key, DF_Eval eval, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg) +#define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(name) void name(DF_ExpandKey key, DF_Eval eval, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg) #define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(name) df_gfx_view_rule_row_ui__##name #define DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_ROW_UI_FUNCTION_NAME(name)) -#define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(name) void name(struct DF_Window *ws, DF_ExpandKey key, DF_Eval eval, String8 string, DBGI_Scope *dbgi_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg, Vec2F32 dim) +#define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(name) void name(struct DF_Window *ws, DF_ExpandKey key, DF_Eval eval, String8 string, DI_Scope *di_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, struct DF_CfgNode *cfg, Vec2F32 dim) #define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name) df_gfx_view_rule_block_ui__##name #define DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(name) DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_SIG(DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_NAME(name)) @@ -405,7 +405,7 @@ struct DF_CodeSliceParams DF_EntityList *line_pins; DF_TextLineDasm2SrcInfoList *line_dasm2src; DF_TextLineSrc2DasmInfoList *line_src2dasm; - DF_EntityList relevant_binaries; + DI_KeyList relevant_dbgi_keys; // rjf: visual parameters F_Tag font; @@ -513,6 +513,7 @@ struct DF_Window UI_State *ui; F32 code_font_size_delta; F32 main_font_size_delta; + B32 window_temporarily_focused_ipc; // rjf: view state delta history DF_StateDeltaHistory *view_state_hist; @@ -714,7 +715,8 @@ struct DF_GfxState DF_DragDropState drag_drop_state; // rjf: hover line info correllation state - DF_Handle hover_line_binary; + Arena *hover_line_arena; + DI_Key hover_line_dbgi_key; U64 hover_line_voff; B32 hover_line_set_this_frame; @@ -871,8 +873,8 @@ internal B32 df_drag_drop(DF_DragDropPayload *out_payload); internal void df_drag_kill(void); internal void df_queue_drag_drop(void); -internal void df_set_hovered_line_info(DF_Entity *binary, U64 voff); -internal DF_Entity *df_get_hovered_line_info_binary(void); +internal void df_set_hovered_line_info(DI_Key *dbgi_key, U64 voff); +internal DI_Key df_get_hovered_line_info_dbgi_key(void); internal U64 df_get_hovered_line_info_voff(void); //////////////////////////////// @@ -930,7 +932,7 @@ internal void df_window_update_and_render(Arena *arena, DF_Window *ws, DF_CmdLis internal String8 df_eval_escaped_from_raw_string(Arena *arena, String8 raw); internal String8List df_single_line_eval_value_strings_from_eval(Arena *arena, DF_EvalVizStringFlags flags, TG_Graph *graph, RDI_Parsed *rdi, DF_CtrlCtx *ctrl_ctx, U32 default_radix, F_Tag font, F32 font_size, F32 max_size, S32 depth, DF_Eval eval, TG_Member *opt_member, DF_CfgTable *cfg_table); -internal DF_EvalVizWindowedRowList df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks); +internal DF_EvalVizWindowedRowList df_eval_viz_windowed_row_list_from_viz_block_list(Arena *arena, DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_EvalView *eval_view, U32 default_radix, F_Tag font, F32 font_size, Rng1S64 visible_range, DF_EvalVizBlockList *blocks); //////////////////////////////// //~ rjf: Hover Eval diff --git a/src/df/gfx/df_view_rules.c b/src/df/gfx/df_view_rules.c index 7cd81c32..53251592 100644 --- a/src/df/gfx/df_view_rules.c +++ b/src/df/gfx/df_view_rules.c @@ -23,7 +23,7 @@ DF_CORE_VIEW_RULE_EVAL_RESOLUTION_FUNCTION_DEF(array) str8_list_push(scratch.arena, &array_size_expr_strs, child->string); } String8 array_size_expr = str8_list_join(scratch.arena, &array_size_expr_strs, 0); - DF_Eval array_size_eval = df_eval_from_string(arena, dbgi_scope, ctrl_ctx, parse_ctx, macro_map, array_size_expr); + DF_Eval array_size_eval = df_eval_from_string(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, array_size_expr); DF_Eval array_size_eval_value = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, array_size_eval); eval_error_list_concat_in_place(&eval.errors, &array_size_eval.errors); array_size = array_size_eval_value.imm_u64; @@ -1036,7 +1036,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(rgba) //~ rjf: "text" internal DF_TxtTopologyInfo -df_vr_txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_txt_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_TxtTopologyInfo result = zero_struct; @@ -1094,7 +1094,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(text) // DF_Entity *thread = df_entity_from_handle(ctrl_ctx->thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - DF_TxtTopologyInfo top = df_vr_txt_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_TxtTopologyInfo top = df_vr_txt_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr + (top.size_cap ? top.size_cap : 2048)); @@ -1177,7 +1177,7 @@ DF_VIEW_UI_FUNCTION_DEF(text) //~ rjf: "disasm" internal DF_DisasmTopologyInfo -df_vr_disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_disasm_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_DisasmTopologyInfo result = zero_struct; @@ -1236,7 +1236,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm) state->last_open_frame_idx = df_frame_index(); { //- rjf: unpack params - DF_DisasmTopologyInfo top = df_vr_disasm_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_DisasmTopologyInfo top = df_vr_disasm_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); //- rjf: resolve to address value & range DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); @@ -1259,7 +1259,6 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(disasm) dasm_params.style_flags = DASM_StyleFlag_Addresses; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = 0; - dasm_params.exe_path = str8_zero(); } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &data_hash); String8 dasm_text_data = {0}; @@ -1388,7 +1387,7 @@ df_bitmap_view_state__canvas_from_screen_rect(DF_BitmapViewState *bvs, Rng2F32 r } internal DF_BitmapTopologyInfo -df_vr_bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_bitmap_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_BitmapTopologyInfo info = {0}; @@ -1513,7 +1512,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) // DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx->type_graph, parse_ctx->rdi, ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; - DF_BitmapTopologyInfo topology_info = df_vr_bitmap_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_BitmapTopologyInfo topology_info = df_vr_bitmap_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); U64 expected_size = topology_info.width*topology_info.height*r_tex2d_format_bytes_per_pixel_table[topology_info.fmt]; Rng1U64 vaddr_range = r1u64(base_vaddr, base_vaddr+expected_size); @@ -1568,7 +1567,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(bitmap) DF_VIEW_SETUP_FUNCTION_DEF(bitmap) { DF_BitmapViewState *bvs = df_view_user_state(view, DF_BitmapViewState); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); DF_CfgNode *view_center_cfg = df_cfg_node_child_from_string(cfg_root, str8_lit("view_center"), StringMatchFlag_CaseInsensitive); DF_CfgNode *zoom_cfg = df_cfg_node_child_from_string(cfg_root, str8_lit("zoom"), StringMatchFlag_CaseInsensitive); DF_CfgNode *bitmap_cfg = df_cfg_node_child_from_string(cfg_root, str8_lit("bitmap"), StringMatchFlag_CaseInsensitive); @@ -1576,16 +1575,16 @@ DF_VIEW_SETUP_FUNCTION_DEF(bitmap) DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, process, thread_unwind_rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, thread_unwind_rip_vaddr); bvs->view_center_pos.x = (F32)f64_from_str8(bitmap_cfg->first->string); bvs->view_center_pos.y = (F32)f64_from_str8(bitmap_cfg->first->next->string); bvs->zoom = (F32)f64_from_str8(zoom_cfg->first->string); - bvs->top = df_vr_bitmap_topology_info_from_cfg(dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, bitmap_cfg); + bvs->top = df_vr_bitmap_topology_info_from_cfg(di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, bitmap_cfg); if(bvs->zoom == 0) { bvs->zoom = 1.f; } - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); } DF_VIEW_STRING_FROM_STATE_FUNCTION_DEF(bitmap) @@ -1636,7 +1635,7 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) { DF_BitmapViewState *bvs = df_view_user_state(view, DF_BitmapViewState); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); HS_Scope *hs_scope = hs_scope_open(); TEX_Scope *tex_scope = tex_scope_open(); @@ -1647,13 +1646,13 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, process, thread_unwind_rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, thread_unwind_rip_vaddr); ////////////////////////////// //- rjf: evaluate expression // String8 expr = str8(view->query_buffer, view->query_string_size); - DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); DF_Eval value_eval = df_value_mode_eval_from_eval(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, eval); U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; U64 expected_size = bvs->top.width*bvs->top.height*r_tex2d_format_bytes_per_pixel_table[bvs->top.fmt]; @@ -1731,7 +1730,7 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) hs_scope_close(hs_scope); tex_scope_close(tex_scope); - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); scratch_end(scratch); } @@ -1739,7 +1738,7 @@ DF_VIEW_UI_FUNCTION_DEF(bitmap) //~ rjf: "geo" internal DF_GeoTopologyInfo -df_vr_geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) +df_vr_geo_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg) { Temp scratch = scratch_begin(0, 0); DF_GeoTopologyInfo result = {0}; @@ -1860,7 +1859,7 @@ DF_GFX_VIEW_RULE_BLOCK_UI_FUNCTION_DEF(geo) U64 base_vaddr = value_eval.imm_u64 ? value_eval.imm_u64 : value_eval.offset; //- rjf: extract extra geo topology info from view rule - DF_GeoTopologyInfo top = df_vr_geo_topology_info_from_cfg(dbgi_scope, ctrl_ctx, parse_ctx, macro_map, cfg); + DF_GeoTopologyInfo top = df_vr_geo_topology_info_from_cfg(di_scope, ctrl_ctx, parse_ctx, macro_map, cfg); Rng1U64 index_buffer_vaddr_range = r1u64(base_vaddr, base_vaddr+top.index_count*sizeof(U32)); Rng1U64 vertex_buffer_vaddr_range = top.vertices_vaddr_range; diff --git a/src/df/gfx/df_view_rules.h b/src/df/gfx/df_view_rules.h index d69435ca..9d895ed1 100644 --- a/src/df/gfx/df_view_rules.h +++ b/src/df/gfx/df_view_rules.h @@ -38,7 +38,7 @@ struct DF_VR_TextState F32 loaded_t; }; -internal DF_TxtTopologyInfo df_vr_txt_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_TxtTopologyInfo df_vr_txt_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); //////////////////////////////// //~ rjf: "disasm" @@ -61,7 +61,7 @@ struct DF_VR_DisasmState F32 loaded_t; }; -internal DF_DisasmTopologyInfo df_vr_disasm_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_DisasmTopologyInfo df_vr_disasm_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); //////////////////////////////// //~ rjf: "bitmap" @@ -104,7 +104,7 @@ internal Vec2F32 df_bitmap_view_state__screen_from_canvas_pos(DF_BitmapViewState internal Rng2F32 df_bitmap_view_state__screen_from_canvas_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 cvs); internal Vec2F32 df_bitmap_view_state__canvas_from_screen_pos(DF_BitmapViewState *bvs, Rng2F32 rect, Vec2F32 scr); internal Rng2F32 df_bitmap_view_state__canvas_from_screen_rect(DF_BitmapViewState *bvs, Rng2F32 rect, Rng2F32 scr); -internal DF_BitmapTopologyInfo df_vr_bitmap_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_BitmapTopologyInfo df_vr_bitmap_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); //////////////////////////////// //~ rjf: "geo" @@ -139,6 +139,6 @@ struct DF_VR_GeoBoxDrawData F32 loaded_t; }; -internal DF_GeoTopologyInfo df_vr_geo_topology_info_from_cfg(DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); +internal DF_GeoTopologyInfo df_vr_geo_topology_info_from_cfg(DI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_CfgNode *cfg); #endif // DF_VIEW_RULES_H diff --git a/src/df/gfx/df_views.c b/src/df/gfx/df_views.c index 59fee683..4483019d 100644 --- a/src/df/gfx/df_views.c +++ b/src/df/gfx/df_views.c @@ -543,7 +543,7 @@ df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint p //- rjf: windowed watch tree visualization (both single-line and multi-line) internal DF_EvalVizBlockList -df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews) +df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *di_scope, FZY_Scope *fzy_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews) { ProfBeginFunction(); Temp scratch = scratch_begin(&arena, 1); @@ -551,7 +551,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF DF_EvalViewKey eval_view_key = df_eval_view_key_from_eval_watch_view(ews); DF_EvalView *eval_view = df_eval_view_from_key(eval_view_key); String8 filter = str8(view->query_buffer, view->query_string_size); - DBGI_FuzzySearchTarget dbgi_target = DBGI_FuzzySearchTarget_UDTs; + FZY_Target fzy_target = FZY_Target_UDTs; switch(ews->fill_kind) { //////////////////////////// @@ -568,7 +568,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF { DF_ExpandKey parent_key = df_parent_expand_key_from_eval_root(root); DF_ExpandKey key = df_expand_key_from_eval_root(root); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -594,7 +594,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF { DF_ExpandKey parent_key = df_expand_key_make(5381, 0); DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -606,7 +606,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF { DF_ExpandKey parent_key = df_expand_key_make(5381, 0); DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -626,7 +626,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF { DF_ExpandKey parent_key = df_expand_key_make(5381, 0); DF_ExpandKey key = df_expand_key_make(df_hash_from_expand_key(parent_key), num); - DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); + DF_EvalVizBlockList root_blocks = df_eval_viz_block_list_from_eval_view_expr_keys(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, eval_view, root_expr_string, parent_key, key); df_eval_viz_block_list_concat__in_place(&blocks, &root_blocks); } } @@ -635,10 +635,10 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //////////////////////////// //- rjf: debug info table fill -> build split debug info table blocks // - case DF_WatchViewFillKind_Globals: dbgi_target = DBGI_FuzzySearchTarget_GlobalVariables; goto dbgi_table; - case DF_WatchViewFillKind_ThreadLocals: dbgi_target = DBGI_FuzzySearchTarget_ThreadVariables; goto dbgi_table; - case DF_WatchViewFillKind_Types: dbgi_target = DBGI_FuzzySearchTarget_UDTs; goto dbgi_table; - case DF_WatchViewFillKind_Procedures: dbgi_target = DBGI_FuzzySearchTarget_Procedures; goto dbgi_table; + case DF_WatchViewFillKind_Globals: fzy_target = FZY_Target_GlobalVariables; goto dbgi_table; + case DF_WatchViewFillKind_ThreadLocals: fzy_target = FZY_Target_ThreadVariables; goto dbgi_table; + case DF_WatchViewFillKind_Types: fzy_target = FZY_Target_UDTs; goto dbgi_table; + case DF_WatchViewFillKind_Procedures: fzy_target = FZY_Target_Procedures; goto dbgi_table; dbgi_table:; { //- rjf: unpack context @@ -646,10 +646,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); U64 thread_rip_unwind_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx->unwind_count); DF_Entity *module = df_module_from_process_vaddr(process, thread_rip_unwind_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 exe_path = df_full_path_from_entity(scratch.arena, binary); - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, os_now_microseconds()+100); - RDI_Parsed *rdi = &dbgi->rdi; + DI_Key dbgi_key = df_dbgi_key_from_module(module); //- rjf: calculate top-level keys, expand root-level, grab root expansion node DF_ExpandKey parent_key = df_expand_key_make(5381, 0); @@ -660,7 +657,12 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF //- rjf: query all filtered items from dbgi searching system U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; B32 items_stale = 0; - DBGI_FuzzySearchItemArray items = dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, filter, dbgi_target, os_now_microseconds()+100, &items_stale); + FZY_Params params = {fzy_target}; + { + params.dbgi_keys.count = 1; + params.dbgi_keys.v = &dbgi_key; + } + FZY_ItemArray items = fzy_items_from_key_params_query(fzy_scope, fuzzy_search_key, ¶ms, filter, os_now_microseconds()+100, &items_stale); if(items_stale) { df_gfx_request_frame(); @@ -691,7 +693,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF U64 idx = 0; for(DF_ExpandNode *child = root_node->first; child != 0; child = child->next) { - U64 item_num = dbgi_fuzzy_item_num_from_array_element_idx__linear_search(&items, child->key.child_num); + U64 item_num = fzy_item_num_from_array_element_idx__linear_search(&items, child->key.child_num); if(item_num != 0) { sub_expand_keys[idx] = child->key; @@ -731,8 +733,8 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF DF_EvalVizBlock *last_vb = df_eval_viz_block_begin(arena, DF_EvalVizBlockKind_DebugInfoTable, parent_key, root_key, 0); { last_vb->visual_idx_range = last_vb->semantic_idx_range = r1u64(0, items.count); - last_vb->dbgi_target = dbgi_target; - last_vb->backing_search_items = items; + last_vb->fzy_target = fzy_target; + last_vb->fzy_backing_items = items; } for(U64 sub_expand_idx = 0; sub_expand_idx < sub_expand_keys_count; sub_expand_idx += 1) { @@ -740,7 +742,7 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF last_vb = df_eval_viz_block_split_and_continue(arena, &blocks, last_vb, sub_expand_item_idxs[sub_expand_idx]); // rjf: grab name for the expanded row - String8 name = dbgi_fuzzy_item_string_from_rdi_target_element_idx(&dbgi->rdi, dbgi_target, sub_expand_keys[sub_expand_idx].child_num); + String8 name = fzy_item_string_from_rdi_target_element_idx(parse_ctx->rdi, fzy_target, sub_expand_keys[sub_expand_idx].child_num); // rjf: recurse for sub-expansion { @@ -752,8 +754,8 @@ df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF df_cfg_table_push_unparsed_string(arena, &child_cfg, view_rule_string, DF_CfgSrc_User); } } - DF_Eval eval = df_eval_from_string(arena, scope, ctrl_ctx, parse_ctx, macro_map, name); - df_append_viz_blocks_for_parent__rec(arena, scope, eval_view, ctrl_ctx, parse_ctx, macro_map, parent_key, sub_expand_keys[sub_expand_idx], name, eval, 0, &child_cfg, 0, &blocks); + DF_Eval eval = df_eval_from_string(arena, di_scope, ctrl_ctx, parse_ctx, macro_map, name); + df_append_viz_blocks_for_parent__rec(arena, di_scope, eval_view, ctrl_ctx, parse_ctx, macro_map, parent_key, sub_expand_keys[sub_expand_idx], name, eval, 0, &child_cfg, 0, &blocks); } } df_eval_viz_block_end(&blocks, last_vb); @@ -817,7 +819,8 @@ internal void df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewState *ewv, B32 modifiable, U32 default_radix, Rng2F32 rect) { ProfBeginFunction(); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); + FZY_Scope *fzy_scope = fzy_scope_open(); Temp scratch = scratch_begin(0, 0); ////////////////////////////// @@ -837,7 +840,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS ////////////////////////////// //- rjf: process * thread info -> parse_ctx // - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, process, thread_ip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, thread_ip_vaddr); ////////////////////////////// //- rjf: determine autocompletion string @@ -888,19 +891,12 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); Architecture arch = df_architecture_from_entity(thread); U64 reg_size = regs_block_size_from_architecture(arch); - U64 thread_unwind_ip_vaddr = 0; void *thread_unwind_regs_block = push_array(scratch.arena, U8, reg_size); + U64 thread_unwind_ip_vaddr = 0; + if(unwind.frames.count != 0) { - U64 idx = 0; - for(CTRL_UnwindFrame *f = unwind.first; f != 0; f = f->next, idx += 1) - { - if(idx == unwind_count) - { - thread_unwind_ip_vaddr = f->rip; - thread_unwind_regs_block = f->regs; - break; - } - } + thread_unwind_regs_block = unwind.frames.v[unwind_count%unwind.frames.count].regs; + thread_unwind_ip_vaddr = regs_rip_from_arch_block(arch, thread_unwind_regs_block); } //- rjf: lex & parse @@ -919,7 +915,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS // if(state_dirty) { - blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, view, ewv); + blocks = df_eval_viz_block_list_from_watch_view_state(scratch.arena, di_scope, fzy_scope, &ctrl_ctx, &parse_ctx, ¯o_map, view, ewv); } ////////////////////////// @@ -1057,7 +1053,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS ewv->text_edit_state_slots_count = u64_up_to_pow2(selection_dim.y+1); ewv->text_edit_state_slots_count = Max(ewv->text_edit_state_slots_count, 64); ewv->text_edit_state_slots = push_array(ewv->text_edit_arena, DF_WatchViewTextEditState*, ewv->text_edit_state_slots_count); - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); DF_EvalVizRow *row = rows.first; @@ -1089,7 +1085,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS if(!ewv->text_editing && evt->slot == UI_EventActionSlot_Accept && selection_tbl.min.x <= 0) { taken = 1; - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); DF_EvalVizRow *row = rows.first; @@ -1100,6 +1096,25 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS B32 is_expanded = df_expand_key_is_set(&eval_view->expand_tree_table, row->key); df_expand_set_expansion(eval_view->arena, &eval_view->expand_tree_table, row->parent_key, row->key, !is_expanded); } + if(row->flags & DF_EvalVizRowFlag_Canvas) + { + DF_CfgNode *cfg = df_cfg_tree_copy(scratch.arena, row->expand_ui_rule_node); + DF_CfgNode *cfg_root = push_array(scratch.arena, DF_CfgNode, 1); + cfg_root->first = cfg_root->last = cfg; + cfg_root->next = cfg_root->parent = &df_g_nil_cfg_node; + if(cfg != &df_g_nil_cfg_node) + { + cfg->parent = cfg_root; + } + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.string = row->edit_expr; + p.view_spec = df_tab_view_spec_from_gfx_view_rule_spec(row->expand_ui_rule_spec); + p.cfg_node = cfg_root; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_ViewSpec); + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_CfgNode); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_OpenTab)); + } } } @@ -1188,13 +1203,13 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS case DF_WatchViewColumnKind_Value: if(editing_complete && evt->slot != UI_EventActionSlot_Cancel) { - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, y-1), ui_scroll_list_row_from_item(&row_blocks, y-1)+1), &blocks); B32 success = 0; if(rows.first != 0) { - DF_Eval write_eval = df_eval_from_string(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, new_string); + DF_Eval write_eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, new_string); success = df_commit_eval_value(parse_ctx.type_graph, parse_ctx.rdi, &ctrl_ctx, rows.first->eval, write_eval); } if(!success) @@ -1230,7 +1245,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS { taken = 1; String8List strs = {0}; - DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), + DF_EvalVizWindowedRowList rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(ui_scroll_list_row_from_item(&row_blocks, selection_tbl.min.y-1), ui_scroll_list_row_from_item(&row_blocks, selection_tbl.max.y-1)+1), &blocks); DF_EvalVizRow *row = rows.first; @@ -1566,7 +1581,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS //- rjf: viz blocks -> rows DF_EvalVizWindowedRowList rows = {0}; { - rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(visible_row_rng.min-1, visible_row_rng.max), &blocks); + rows = df_eval_viz_windowed_row_list_from_viz_block_list(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, eval_view, default_radix, code_font, ui_top_font_size(), r1s64(visible_row_rng.min-1, visible_row_rng.max), &blocks); } //- rjf: build table @@ -1631,7 +1646,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS { Vec2F32 canvas_dim = v2f32(scroll_list_params.dim_px.x - ui_top_font_size()*1.5f, (row->skipped_size_in_rows+row->size_in_rows+row->chopped_size_in_rows)*scroll_list_params.row_height_px); - row->expand_ui_rule_spec->info.block_ui(ws, row->key, row->eval, row->edit_expr, scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->expand_ui_rule_node, canvas_dim); + row->expand_ui_rule_spec->info.block_ui(ws, row->key, row->eval, row->edit_expr, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->expand_ui_rule_node, canvas_dim); } } } @@ -1906,7 +1921,7 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clip|UI_BoxFlag_Clickable, "###val_%I64x", row_hash); UI_Parent(box) { - row->value_ui_rule_spec->info.row_ui(row->key, row->eval, scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->value_ui_rule_node); + row->value_ui_rule_spec->info.row_ui(row->key, row->eval, di_scope, &ctrl_ctx, &parse_ctx, ¯o_map, row->value_ui_rule_node); } sig = ui_signal_from_box(box); } @@ -2042,7 +2057,8 @@ df_watch_view_build(DF_Window *ws, DF_Panel *panel, DF_View *view, DF_WatchViewS } scratch_end(scratch); - dbgi_scope_close(scope); + fzy_scope_close(fzy_scope); + di_scope_close(di_scope); ProfEnd(); } @@ -3235,17 +3251,26 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); + FZY_Scope *fzy_scope = fzy_scope_open(); F32 row_height_px = floor_f32(ui_top_font_size()*2.5f); - DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); - DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); - DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - U64 thread_unwind_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); - DF_Entity *module = df_module_from_process_vaddr(process, thread_unwind_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - String8 exe_path = df_full_path_from_entity(scratch.arena, binary); String8 query = str8(view->query_buffer, view->query_string_size); - TG_Graph *graph = tg_graph_begin(bit_size_from_arch(df_architecture_from_entity(thread))/8, 256); + DI_KeyList dbgi_keys_list = df_push_active_dbgi_key_list(scratch.arena); + DI_KeyArray dbgi_keys = di_key_array_from_list(scratch.arena, &dbgi_keys_list); + FZY_Params params = {FZY_Target_Procedures, dbgi_keys}; + U64 endt_us = os_now_microseconds()+200; + + //- rjf: grab rdis, make type graphs for each + U64 rdis_count = dbgi_keys.count; + RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); + TG_Graph **graphs = push_array(scratch.arena, TG_Graph *, rdis_count); + { + for(U64 idx = 0; idx < rdis_count; idx += 1) + { + rdis[idx] = di_rdi_from_key(di_scope, &dbgi_keys.v[idx], endt_us); + graphs[idx] = tg_graph_begin(rdi_addr_size_from_arch(rdis[idx]->top_level_info->architecture), 256); + } + } //- rjf: grab state typedef struct DF_SymbolListerViewState DF_SymbolListerViewState; @@ -3257,10 +3282,8 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: query -> raddbg, filtered items U128 fuzzy_search_key = {(U64)view, df_hash_from_string(str8_struct(&view))}; - DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, os_now_microseconds()+100); - RDI_Parsed *rdi = &dbgi->rdi; B32 items_stale = 0; - DBGI_FuzzySearchItemArray items = dbgi_fuzzy_search_items_from_key_exe_query(scope, fuzzy_search_key, exe_path, query, DBGI_FuzzySearchTarget_Procedures, os_now_microseconds()+100, &items_stale); + FZY_ItemArray items = fzy_items_from_key_params_query(fzy_scope, fuzzy_search_key, ¶ms, query, endt_us, &items_stale); if(items_stale) { df_gfx_request_frame(); @@ -3269,16 +3292,27 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) //- rjf: submit best match when hitting enter w/ no selection if(slv->cursor.y == 0 && items.count != 0 && ui_slot_press(UI_EventActionSlot_Accept)) { - RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, items.v[0].idx); - U64 name_size = 0; - U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); - String8 name = str8(name_base, name_size); - if(name.size != 0) + FZY_Item *item = &items.v[0]; + U64 base_idx = 0; + for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1) { - DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); - p.string = name; - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); - df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CompleteQuery)); + RDI_Parsed *rdi = rdis[rdi_idx]; + if(base_idx <= item->idx && item->idx < base_idx + rdi->procedures_count) + { + RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx-base_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); + String8 name = str8(name_base, name_size); + if(name.size != 0) + { + DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); + p.string = name; + df_cmd_params_mark_slot(&p, DF_CmdParamSlot_String); + df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_CompleteQuery)); + } + break; + } + base_idx += rdi->procedures_count; } } @@ -3311,13 +3345,36 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) idx += 1) UI_Focus((slv->cursor.y == idx+1) ? UI_FocusKind_On : UI_FocusKind_Off) { - DBGI_FuzzySearchItem *item = &items.v[idx]; - RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx); + FZY_Item *item = &items.v[idx]; + + //- rjf: determine dbgi/rdi to which this item belongs + DI_Key dbgi_key = {0}; + RDI_Parsed *rdi = &di_rdi_parsed_nil; + TG_Graph *graph = 0; + U64 base_idx = 0; + { + for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1) + { + if(base_idx <= item->idx && item->idx < base_idx + rdis[rdi_idx]->procedures_count) + { + dbgi_key = dbgi_keys.v[rdi_idx]; + rdi = rdis[rdi_idx]; + graph = graphs[rdi_idx]; + break; + } + base_idx += rdis[rdi_idx]->procedures_count; + } + } + + //- rjf: unpack this item's info + RDI_Procedure *procedure = rdi_element_from_idx(rdi, procedures, item->idx-base_idx); U64 name_size = 0; U8 *name_base = rdi_string_from_idx(rdi, procedure->name_string_idx, &name_size); String8 name = str8(name_base, name_size); RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, procedure->type_idx); TG_Key type_key = tg_key_ext(tg_kind_from_rdi_type_kind(type_node->kind), procedure->type_idx); + + //- rjf: build item button ui_set_next_hover_cursor(OS_Cursor_HandPoint); UI_Box *box = ui_build_box_from_stringf(UI_BoxFlag_Clickable| UI_BoxFlag_DrawBackground| @@ -3330,12 +3387,14 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) { UI_Box *box = df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeFunction), name); ui_box_equip_fuzzy_match_ranges(box, &item->match_ranges); - if(!tg_key_match(tg_key_zero(), type_key)) + if(!tg_key_match(tg_key_zero(), type_key) && graph != 0) { String8 type_string = tg_string_from_key(scratch.arena, graph, rdi, type_key); df_code_label(0.5f, 0, df_rgba_from_theme_color(DF_ThemeColor_WeakText), type_string); } } + + //- rjf: interact UI_Signal sig = ui_signal_from_box(box); if(ui_clicked(sig)) { @@ -3346,8 +3405,8 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } if(ui_hovering(sig)) UI_Tooltip { - U64 binary_voff = df_voff_from_binary_symbol_name(binary, name); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, binary_voff); + U64 binary_voff = df_voff_from_dbgi_key_symbol_name(&dbgi_key, name); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, binary_voff); String8 file_path = df_full_path_from_entity(scratch.arena, dasm2src_info.file); S64 line_num = dasm2src_info.pt.line; df_code_label(1.f, 0, df_rgba_from_theme_color(DF_ThemeColor_CodeFunction), name); @@ -3367,7 +3426,8 @@ DF_VIEW_UI_FUNCTION_DEF(SymbolLister) } } - dbgi_scope_close(scope); + fzy_scope_close(fzy_scope); + di_scope_close(di_scope); scratch_end(scratch); ProfEnd(); } @@ -4527,7 +4587,6 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); String8 query = str8(view->query_buffer, view->query_string_size); DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_view(ws, view); @@ -4742,8 +4801,8 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) U64 rip_vaddr = df_query_cached_rip_from_thread(entity); DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + DF_TextLineDasm2SrcInfo line_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, rip_voff); if(!df_entity_is_nil(line_info.file)) { UI_PrefWidth(ui_children_sum(0)) df_entity_src_loc_button(ws, line_info.file, line_info.pt); @@ -4760,7 +4819,6 @@ DF_VIEW_UI_FUNCTION_DEF(Scheduler) sv->selected_column = cursor.x; sv->selected_entity = (1 <= cursor.y && cursor.y <= items.count) ? df_handle_from_entity(items.v[cursor.y-1].entity) : df_handle_zero(); - dbgi_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -4815,8 +4873,8 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) scroll_list_params.flags = UI_ScrollListFlag_All; scroll_list_params.row_height_px = floor_f32(ui_top_font_size()*2.5f); scroll_list_params.dim_px = dim_2f32(rect); - scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, unwind.count)); - scroll_list_params.item_range = r1s64(0, unwind.count+1); + scroll_list_params.cursor_range = r2s64(v2s64(0, 0), v2s64(3, unwind.frames.count)); + scroll_list_params.item_range = r1s64(0, unwind.frames.count+1); scroll_list_params.cursor_min_is_empty_selection[Axis2_Y] = 1; } UI_ScrollListSignal scroll_list_sig = {0}; @@ -4849,20 +4907,20 @@ DF_VIEW_UI_FUNCTION_DEF(CallStack) } //- rjf: frame rows - U64 frame_idx = 0; - for(CTRL_UnwindFrame *frame = unwind.first; frame != 0; frame = frame->next, frame_idx += 1) + for(S64 row_num = visible_row_range.min; row_num <= visible_row_range.max && row_num <= unwind.frames.count; row_num += 1) { - // rjf: out of range -> skip (TODO(rjf): this should be an array...) - if(frame_idx+1 < visible_row_range.min || visible_row_range.max < frame_idx+1) + if(row_num == 0) { continue; } + U64 frame_idx = row_num-1; + CTRL_UnwindFrame *frame = &unwind.frames.v[frame_idx]; // rjf: determine selection - B32 row_selected = cs->cursor.y == ((S64)frame_idx+1); + B32 row_selected = (cs->cursor.y == row_num); // rjf: regs => rip - U64 rip_vaddr = frame->rip; + U64 rip_vaddr = regs_rip_from_arch_block(thread->arch, frame->regs); // rjf: rip_vaddr => module DF_Entity *module = df_module_from_process_vaddr(process, rip_vaddr); @@ -5036,7 +5094,7 @@ DF_VIEW_CMD_FUNCTION_DEF(Modules) { String8 exe_path = module->name; String8 dbg_path = pick_string; - dbgi_force_exe_path_dbg_path(exe_path, dbg_path); + // TODO(rjf) } scratch_end(scratch); }break; @@ -5048,7 +5106,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); String8 query = str8(view->query_buffer, view->query_string_size); //- rjf: get state @@ -5215,16 +5273,17 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) B32 brw_is_selected = (row_is_selected && cursor.x == 3); // rjf: unpack module info - DF_Entity *binary = df_binary_file_from_module(entity); - DBGI_Parse *dbgi = df_dbgi_parse_from_binary_file(scope, binary); - B32 dbgi_is_valid = (dbgi->dbg_props.modified != 0); + DI_Key dbgi_key = df_dbgi_key_from_module(entity); + String8 dbgi_path = dbgi_key.path; + RDI_Parsed *rdi = di_rdi_from_key(scope, &dbgi_key, 0); + B32 dbgi_is_valid = (rdi != &di_rdi_parsed_nil); // rjf: begin editing if(txt_is_selected && edit_begin) { mv->txt_editing = 1; - mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi->dbg_path.size); - MemoryCopy(mv->txt_buffer, dbgi->dbg_path.str, mv->txt_size); + mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi_path.size); + MemoryCopy(mv->txt_buffer, dbgi_path.str, mv->txt_size); mv->txt_cursor = txt_pt(1, 1+mv->txt_size); mv->txt_mark = txt_pt(1, 1); } @@ -5236,7 +5295,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) UI_WidthFill { UI_TextColor(!dbgi_is_valid ? df_rgba_from_theme_color(DF_ThemeColor_FailureBackground) : ui_top_text_color()) - sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &mv->txt_cursor, &mv->txt_mark, mv->txt_buffer, sizeof(mv->txt_buffer), &mv->txt_size, 0, dbgi->dbg_path, "###dbg_path_%p", entity); + sig = df_line_editf(DF_LineEditFlag_NoBackground, 0, 0, &mv->txt_cursor, &mv->txt_mark, mv->txt_buffer, sizeof(mv->txt_buffer), &mv->txt_size, 0, dbgi_path, "###dbg_path_%p", entity); edit_commit = (edit_commit || ui_committed(sig)); } @@ -5254,8 +5313,8 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { ui_kill_action(); mv->txt_editing = 1; - mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi->dbg_path.size); - MemoryCopy(mv->txt_buffer, dbgi->dbg_path.str, mv->txt_size); + mv->txt_size = Min(sizeof(mv->txt_buffer), dbgi_path.size); + MemoryCopy(mv->txt_buffer, dbgi_path.str, mv->txt_size); mv->txt_cursor = txt_pt(1, 1+mv->txt_size); mv->txt_mark = txt_pt(1, 1); } @@ -5294,7 +5353,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) { String8 exe_path = commit_module->name; String8 dbg_path = str8(mv->txt_buffer, mv->txt_size); - dbgi_force_exe_path_dbg_path(exe_path, dbg_path); + // TODO(rjf) } if(edit_submit) { @@ -5312,7 +5371,7 @@ DF_VIEW_UI_FUNCTION_DEF(Modules) mv->selected_column = cursor.x; mv->selected_entity = (1 <= cursor.y && cursor.y <= items.count) ? df_handle_from_entity(items.v[cursor.y-1].entity) : df_handle_zero(); - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -5356,24 +5415,6 @@ DF_VIEW_CMD_FUNCTION_DEF(PendingEntity) { default:break; - // rjf: pick file - case DF_CoreCmdKind_PickFile: - { - DF_Entity *missing_file = df_entity_from_handle(pves->pick_file_override_target); - String8 pick_string = cmd->params.file_path; - if(!df_entity_is_nil(missing_file) && pick_string.size != 0) - { - DF_Entity *replacement = df_entity_from_path(pick_string, DF_EntityFromPathFlag_OpenAsNeeded|DF_EntityFromPathFlag_OpenMissing); - view->entity = df_handle_from_entity(replacement); - DF_CmdParams p = df_cmd_params_from_view(ws, panel, view); - p.entity = df_handle_from_entity(missing_file); - p.file_path = pick_string; - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_Entity); - df_cmd_params_mark_slot(&p, DF_CmdParamSlot_FilePath); - df_push_cmd__root(&p, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_SetFileReplacementPath)); - } - }break; - // rjf: gather deferred commands to redispatch when entity is ready case DF_CoreCmdKind_GoToLine: case DF_CoreCmdKind_GoToAddress: @@ -5442,52 +5483,8 @@ DF_VIEW_CMD_FUNCTION_DEF(PendingEntity) DF_VIEW_UI_FUNCTION_DEF(PendingEntity) { - // rjf: grab state - DF_PendingEntityViewState *pves = df_view_user_state(view, DF_PendingEntityViewState); - DF_Entity *entity = df_entity_from_handle(view->entity); - - // rjf: entity is missing -> notify user - if(entity->flags & DF_EntityFlag_IsMissing) - { - UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_pct(1, 0)) - { - Temp scratch = scratch_begin(0, 0); - String8 full_path = df_full_path_from_entity(scratch.arena, entity); - UI_PrefWidth(ui_children_sum(1)) UI_PrefHeight(ui_em(3, 1)) - UI_Row UI_Padding(ui_pct(1, 0)) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_FailureBackground)) - { - UI_Font(ui_icon_font()) ui_label(df_g_icon_kind_text_table[DF_IconKind_WarningBig]); - ui_labelf("Could not find \"%S\".", full_path); - } - UI_PrefHeight(ui_em(3, 1)) - UI_Row UI_Padding(ui_pct(1, 0)) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_ActionText)) - UI_BackgroundColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBackground)) - UI_BorderColor(df_rgba_from_theme_color(DF_ThemeColor_ActionBorder)) - UI_CornerRadius(ui_top_font_size()/3) - UI_PrefWidth(ui_text_dim(10, 1)) - UI_Focus(UI_FocusKind_On) - if(ui_clicked(ui_buttonf("Find alternative..."))) - { - DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); - params.cmd_spec = df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_PickFile); - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_CmdSpec); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_RunCommand)); - pves->pick_file_override_target = df_handle_from_entity(entity); - } - scratch_end(scratch); - } - } - - // rjf: entity is still loading -> loading animation - else - { - view->loading_t = view->loading_t_target = 1.f; - df_gfx_request_frame(); - } + view->loading_t = view->loading_t_target = 1.f; + df_gfx_request_frame(); } //////////////////////////////// @@ -5608,8 +5605,8 @@ DF_VIEW_CMD_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *binary = src2dasm_list->first->v.binary; - DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DI_Key dbgi_key = src2dasm_list->first->v.dbgi_key; + DF_EntityList possible_modules = df_modules_from_dbgi_key(scratch.arena, &dbgi_key); DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); U64 thread_dst_voff = voff_rng.min; if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) @@ -5734,7 +5731,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); HS_Scope *hs_scope = hs_scope_open(); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); @@ -5761,7 +5758,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) U64 unwind_count = ctrl_ctx.unwind_count; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, unwind_count); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, process, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, process, rip_vaddr); ////////////////////////////// //- rjf: unpack file/text entity info @@ -5911,8 +5908,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) U64 last_inst_on_unwound_rip_vaddr = rip_vaddr - !!unwind_count; DF_Entity *module = df_module_from_process_vaddr(process, last_inst_on_unwound_rip_vaddr); U64 rip_voff = df_voff_from_vaddr(module, last_inst_on_unwound_rip_vaddr); - DF_Entity *binary = df_binary_file_from_module(module); - DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_binary_voff(binary, rip_voff); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + DF_TextLineDasm2SrcInfo dasm2src_info = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, rip_voff); if(dasm2src_info.file == entity && visible_line_num_range.min <= dasm2src_info.pt.line && dasm2src_info.pt.line <= visible_line_num_range.max) { U64 slice_line_idx = dasm2src_info.pt.line-visible_line_num_range.min; @@ -5943,14 +5940,14 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { MemoryCopy(code_slice_params.line_src2dasm, src2dasm.v, sizeof(DF_TextLineSrc2DasmInfoList)*src2dasm.count); } - code_slice_params.relevant_binaries = src2dasm.binaries; + code_slice_params.relevant_dbgi_keys = src2dasm.dbgi_keys; } } ////////////////////////////// //- rjf: build missing & override interface // - if(entity_is_missing) + if(entity_is_missing && !text_info_is_ready) { UI_WidthFill UI_HeightFill UI_Column UI_Padding(ui_pct(1, 0)) { @@ -6187,7 +6184,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) String8 expr = txt_string_from_info_data_txt_rng(&text_info, data, expr_rng); if(expr.size != 0) { - DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); if(eval.mode != EVAL_EvalMode_NULL) { df_set_hover_eval(ws, sig.mouse_expr_baseline_pos, ctrl_ctx, entity, sig.mouse_pt, 0, expr); @@ -6259,8 +6256,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *binary = src2dasm_list->first->v.binary; - DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DI_Key dbgi_key = src2dasm_list->first->v.dbgi_key; + DF_EntityList possible_modules = df_modules_from_dbgi_key(scratch.arena, &dbgi_key); DF_Entity *thread_dst_module = df_module_from_thread_candidates(dropped_entity, &possible_modules); U64 thread_dst_voff = voff_rng.min; if(!df_entity_is_nil(thread_dst_module) && thread_dst_voff != 0) @@ -6316,8 +6313,8 @@ DF_VIEW_UI_FUNCTION_DEF(Code) if(src2dasm_list->first != 0) { Rng1U64 voff_rng = src2dasm_list->first->v.voff_range; - DF_Entity *binary = src2dasm_list->first->v.binary; - DF_EntityList possible_modules = df_modules_from_binary_file(scratch.arena, binary); + DI_Key dbgi_key = src2dasm_list->first->v.dbgi_key; + DF_EntityList possible_modules = df_modules_from_dbgi_key(scratch.arena, &dbgi_key); DF_Entity *thread = df_entity_from_handle(ctrl_ctx.thread); DF_Entity *thread_dst_module = df_module_from_thread_candidates(thread, &possible_modules); DF_Entity *process = df_entity_ancestor_from_kind(thread, DF_EntityKind_Process); @@ -6475,20 +6472,19 @@ DF_VIEW_UI_FUNCTION_DEF(Code) //- rjf: determine up-to-dateness of source file // B32 file_is_out_of_date = 0; - String8 out_of_date_binary_name = {0}; - for(DF_EntityNode *n = code_slice_params.relevant_binaries.first; n != 0; n = n->next) + String8 out_of_date_dbgi_name = {0}; + for(DI_KeyNode *n = code_slice_params.relevant_dbgi_keys.first; n != 0; n = n->next) { - DF_Entity *binary = n->entity; - if(!df_entity_is_nil(binary)) + DI_Key key = n->v; + if(key.path.size != 0) { String8 full_path = df_full_path_from_entity(scratch.arena, entity); TXTI_Handle handle = txti_handle_from_path(full_path); TXTI_BufferInfo info = txti_buffer_info_from_handle(scratch.arena, handle); - DBGI_Parse *parse = df_dbgi_parse_from_binary_file(dbgi_scope, binary); - if(parse->exe_props.modified < info.timestamp) + if(key.min_timestamp < info.timestamp) { file_is_out_of_date = 1; - out_of_date_binary_name = binary->name; + out_of_date_dbgi_name = str8_skip_last_slash(key.path); break; } } @@ -6526,9 +6522,9 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { UI_PrefWidth(ui_children_sum(1)) UI_Row UI_PrefWidth(ui_text_dim(1, 1)) { - ui_labelf("This file has changed since ", out_of_date_binary_name); - UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight0)) ui_label(out_of_date_binary_name); - ui_labelf(" was built."); + ui_labelf("This file has changed since ", out_of_date_dbgi_name); + UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_Highlight0)) ui_label(out_of_date_dbgi_name); + ui_labelf(" was produced."); } } } @@ -6536,7 +6532,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) { ui_label(full_path); ui_spacer(ui_em(1.5f, 1)); - ui_labelf("Row: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); + ui_labelf("Line: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); ui_spacer(ui_pct(1, 0)); ui_labelf("(read only)"); ui_labelf("%s", @@ -6548,7 +6544,7 @@ DF_VIEW_UI_FUNCTION_DEF(Code) } txt_scope_close(txt_scope); - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); hs_scope_close(hs_scope); scratch_end(scratch); ProfEnd(); @@ -6590,8 +6586,8 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) DF_Entity *process = df_entity_from_handle(dv->process); Architecture arch = df_architecture_from_entity(process); U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); - DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); - DF_Entity *dasm_binary = df_binary_file_from_module(dasm_module); + DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); + DI_Key dasm_dbgi_key = df_dbgi_key_from_module(dasm_module); Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); U128 dasm_data_hash = {0}; @@ -6602,7 +6598,7 @@ DF_VIEW_CMD_FUNCTION_DEF(Disassembly) dasm_params.style_flags = dv->style_flags; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = dasm_module->vaddr_rng.min; - dasm_params.exe_path = df_full_path_from_entity(scratch.arena, dasm_binary); + dasm_params.dbgi_key = dasm_dbgi_key; } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &dasm_data_hash); U128 dasm_text_hash = {0}; @@ -6801,7 +6797,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) HS_Scope *hs_scope = hs_scope_open(); DASM_Scope *dasm_scope = dasm_scope_open(); TXT_Scope *txt_scope = txt_scope_open(); - DBGI_Scope *dbgi_scope = dbgi_scope_open(); + DI_Scope *di_scope = di_scope_open(); DF_DisasmViewState *dv = df_view_user_state(view, DF_DisasmViewState); ////////////////////////////// @@ -6826,7 +6822,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_Entity *selected_process = df_entity_ancestor_from_kind(selected_thread, DF_EntityKind_Process); U64 unwind_count = ctrl_ctx.unwind_count; U64 rip_vaddr = df_query_cached_rip_from_thread_unwind(selected_thread, unwind_count); - EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(dbgi_scope, selected_process, rip_vaddr); + EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(di_scope, selected_process, rip_vaddr); ////////////////////////////// //- rjf: no disasm process open? -> snap to selected thread @@ -6843,10 +6839,10 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) // DF_Entity *process = df_entity_from_handle(dv->process); Architecture arch = df_architecture_from_entity(process); - U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(64)); + U64 dasm_base_vaddr = AlignDownPow2(dv->base_vaddr, KB(16)); DF_Entity *dasm_module = df_module_from_process_vaddr(process, dasm_base_vaddr); - DF_Entity *dasm_binary = df_binary_file_from_module(dasm_module); - Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(64)); + DI_Key dasm_dbgi_key = df_dbgi_key_from_module(dasm_module); + Rng1U64 dasm_vaddr_range = r1u64(dasm_base_vaddr, dasm_base_vaddr+KB(16)); U128 dasm_key = ctrl_hash_store_key_from_process_vaddr_range(process->ctrl_machine_id, process->ctrl_handle, dasm_vaddr_range, 0); U128 dasm_data_hash = {0}; DASM_Params dasm_params = {0}; @@ -6856,7 +6852,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) dasm_params.style_flags = dv->style_flags; dasm_params.syntax = DASM_Syntax_Intel; dasm_params.base_vaddr = dasm_module->vaddr_rng.min; - dasm_params.exe_path = df_full_path_from_entity(scratch.arena, dasm_binary); + dasm_params.dbgi_key = dasm_dbgi_key; } DASM_Info dasm_info = dasm_info_from_key_params(dasm_scope, dasm_key, &dasm_params, &dasm_data_hash); U128 dasm_text_hash = {0}; @@ -6869,7 +6865,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) //- rjf: unpack module info for this region // DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); ////////////////////////////// //- rjf: is loading -> equip view with loading information @@ -6958,7 +6954,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { code_slice_params.margin_float_off_px = 0; } - df_entity_list_push(scratch.arena, &code_slice_params.relevant_binaries, binary); + di_key_list_push(scratch.arena, &code_slice_params.relevant_dbgi_keys, &dbgi_key); // rjf: fill text info { @@ -7040,7 +7036,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) // rjf: fill dasm -> src info { DF_Entity *module = df_module_from_process_vaddr(process, dasm_vaddr_range.min); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); for(S64 line_num = visible_line_num_range.min; line_num < visible_line_num_range.max; line_num += 1) { U64 vaddr = dasm_vaddr_range.min + dasm_inst_array_code_off_from_idx(&dasm_info.insts, line_num-1); @@ -7049,7 +7045,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) DF_TextLineDasm2SrcInfoNode *dasm2src_n = push_array(scratch.arena, DF_TextLineDasm2SrcInfoNode, 1); SLLQueuePush(code_slice_params.line_dasm2src[slice_idx].first, code_slice_params.line_dasm2src[slice_idx].last, dasm2src_n); code_slice_params.line_dasm2src[slice_idx].count += 1; - dasm2src_n->v = df_text_line_dasm2src_info_from_binary_voff(binary, voff); + dasm2src_n->v = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, voff); } } } @@ -7119,7 +7115,7 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) String8 expr = str8_substr(code_slice_params.line_text[line_idx], r1u64(sig.mouse_expr_rng.min.column-1, sig.mouse_expr_rng.max.column-1)); if(expr.size != 0) { - DF_Eval eval = df_eval_from_string(scratch.arena, dbgi_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); + DF_Eval eval = df_eval_from_string(scratch.arena, di_scope, &ctrl_ctx, &parse_ctx, &eval_string2expr_map_nil, expr); if(eval.mode != EVAL_EvalMode_NULL) { U64 off = dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.mouse_expr_rng.min.line-1); @@ -7219,9 +7215,9 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) { U64 vaddr = dasm_vaddr_range.min+dasm_inst_array_code_off_from_idx(&dasm_info.insts, sig.goto_src_line_num-1); DF_Entity *module = df_module_from_process_vaddr(process, vaddr); - DF_Entity *binary = df_binary_file_from_module(module); + DI_Key dbgi_key = df_dbgi_key_from_module(module); U64 voff = df_voff_from_vaddr(module, vaddr); - DF_TextLineDasm2SrcInfo dasm2src = df_text_line_dasm2src_info_from_binary_voff(binary, voff); + DF_TextLineDasm2SrcInfo dasm2src = df_text_line_dasm2src_info_from_dbgi_key_voff(&dbgi_key, voff); String8 file_path = df_full_path_from_entity(scratch.arena, dasm2src.file); DF_CmdParams params = df_cmd_params_from_view(ws, panel, view); params.text_point = dasm2src.pt; @@ -7388,14 +7384,14 @@ DF_VIEW_UI_FUNCTION_DEF(Disassembly) U64 cursor_vaddr = (1 <= dv->cursor.line && dv->cursor.line <= dasm_info.insts.count) ? (dasm_vaddr_range.min+dasm_info.insts.v[dv->cursor.line-1].code_off) : 0; ui_labelf("%S", path_normalized_from_string(scratch.arena, module->name)); ui_spacer(ui_em(1.5f, 1)); - ui_labelf("Address: 0x%I64x, Row: %I64d, Col: %I64d", cursor_vaddr, dv->cursor.line, dv->cursor.column); + ui_labelf("Address: 0x%I64x, Line: %I64d, Col: %I64d", cursor_vaddr, dv->cursor.line, dv->cursor.column); ui_spacer(ui_pct(1, 0)); ui_labelf("(read only)"); ui_labelf("bin"); } } - dbgi_scope_close(dbgi_scope); + di_scope_close(di_scope); txt_scope_close(txt_scope); dasm_scope_close(dasm_scope); hs_scope_close(hs_scope); @@ -7667,7 +7663,7 @@ DF_VIEW_UI_FUNCTION_DEF(Output) { ProfBeginFunction(); Temp scratch = scratch_begin(0, 0); - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); DF_CodeViewState *tv = df_view_user_state(view, DF_CodeViewState); ////////////////////////////// @@ -8182,13 +8178,13 @@ DF_VIEW_UI_FUNCTION_DEF(Output) UI_TextColor(df_rgba_from_theme_color(DF_ThemeColor_WeakText)) UI_Font(code_font) { - ui_labelf("Row: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); + ui_labelf("Line: %I64d, Col: %I64d", tv->cursor.line, tv->cursor.column); ui_spacer(ui_pct(1, 0)); ui_labelf("(read only)"); } } - dbgi_scope_close(scope); + di_scope_close(scope); scratch_end(scratch); ProfEnd(); } @@ -8547,21 +8543,23 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) CTRL_Unwind unwind = df_query_cached_unwind_from_thread(thread); //- rjf: fill unwind frame annotations - if(unwind.first != 0) + if(unwind.frames.count != 0) { - U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, unwind.first->regs); - for(CTRL_UnwindFrame *f = unwind.first->next; f != 0; f = f->next) + U64 last_stack_top = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs); + for(U64 idx = 1; idx < unwind.frames.count; idx += 1) { + CTRL_UnwindFrame *f = &unwind.frames.v[idx]; U64 f_stack_top = regs_rsp_from_arch_block(thread->arch, f->regs); Rng1U64 frame_vaddr_range = r1u64(last_stack_top, f_stack_top); Rng1U64 frame_vaddr_range_in_viz = intersect_1u64(frame_vaddr_range, viz_range_bytes); last_stack_top = f_stack_top; if(dim_1u64(frame_vaddr_range_in_viz) != 0) { - DF_Entity *module = df_module_from_process_vaddr(process, f->rip); - DF_Entity *binary = df_binary_file_from_module(module); - U64 rip_voff = df_voff_from_vaddr(module, f->rip); - String8 symbol_name = df_symbol_name_from_binary_voff(scratch.arena, binary, rip_voff); + U64 f_rip = regs_rip_from_arch_block(thread->arch, f->regs); + DF_Entity *module = df_module_from_process_vaddr(process, f_rip); + DI_Key dbgi_key = df_dbgi_key_from_module(module); + U64 rip_voff = df_voff_from_vaddr(module, f_rip); + String8 symbol_name = df_symbol_name_from_dbgi_key_voff(scratch.arena, &dbgi_key, rip_voff); Annotation *annotation = push_array(scratch.arena, Annotation, 1); annotation->name_string = symbol_name.size != 0 ? symbol_name : str8_lit("[external code]"); annotation->kind_string = str8_lit("Call Stack Frame"); @@ -8577,10 +8575,10 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) } //- rjf: fill selected thread stack range annotation - if(unwind.first != 0) + if(unwind.frames.count > 0) { U64 stack_base_vaddr = thread->stack_base; - U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, unwind.first->regs); + U64 stack_top_vaddr = regs_rsp_from_arch_block(thread->arch, unwind.frames.v[0].regs); Rng1U64 stack_vaddr_range = r1u64(stack_base_vaddr, stack_top_vaddr); Rng1U64 stack_vaddr_range_in_viz = intersect_1u64(stack_vaddr_range, viz_range_bytes); if(dim_1u64(stack_vaddr_range_in_viz) != 0) @@ -8611,7 +8609,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) df_rgba_from_theme_color(DF_ThemeColor_Thread6), df_rgba_from_theme_color(DF_ThemeColor_Thread7), }; - DBGI_Scope *scope = dbgi_scope_open(); + DI_Scope *scope = di_scope_open(); U64 thread_rip_vaddr = df_query_cached_rip_from_thread_unwind(thread, ctrl_ctx.unwind_count); EVAL_ParseCtx parse_ctx = df_eval_parse_ctx_from_process_vaddr(scope, process, thread_rip_vaddr); RDI_Parsed *rdi = parse_ctx.rdi; @@ -8642,7 +8640,7 @@ DF_VIEW_UI_FUNCTION_DEF(Memory) } } } - dbgi_scope_close(scope); + di_scope_close(scope); } } diff --git a/src/df/gfx/df_views.h b/src/df/gfx/df_views.h index 7f450c41..80af1789 100644 --- a/src/df/gfx/df_views.h +++ b/src/df/gfx/df_views.h @@ -101,7 +101,6 @@ struct DF_PendingEntityViewState { Arena *deferred_cmd_arena; DF_CmdList deferred_cmds; - DF_Handle pick_file_override_target; Arena *complete_cfg_arena; DF_CfgNode *complete_cfg_root; }; @@ -496,7 +495,7 @@ internal String8 df_string_from_eval_viz_row_column_kind(Arena *arena, DF_EvalVi internal DF_WatchViewTextEditState *df_watch_view_text_edit_state_from_pt(DF_WatchViewState *wv, DF_WatchViewPoint pt); //- rjf: windowed watch tree visualization -internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DBGI_Scope *scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews); +internal DF_EvalVizBlockList df_eval_viz_block_list_from_watch_view_state(Arena *arena, DI_Scope *di_scope, FZY_Scope *fzy_scope, DF_CtrlCtx *ctrl_ctx, EVAL_ParseCtx *parse_ctx, EVAL_String2ExprMap *macro_map, DF_View *view, DF_WatchViewState *ews); //- rjf: eval/watch views main hooks internal void df_watch_view_init(DF_WatchViewState *ewv, DF_View *view, DF_WatchViewFillKind fill_kind); diff --git a/src/fuzzy_search/fuzzy_search.c b/src/fuzzy_search/fuzzy_search.c new file mode 100644 index 00000000..24cc8b13 --- /dev/null +++ b/src/fuzzy_search/fuzzy_search.c @@ -0,0 +1,562 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 +fzy_hash_from_string(U64 seed, String8 string) +{ + U64 result = seed; + for(U64 i = 0; i < string.size; i += 1) + { + result = ((result << 5) + result) + string.str[i]; + } + return result; +} + +internal U64 +fzy_hash_from_params(FZY_Params *params) +{ + U64 hash = 5381; + hash = fzy_hash_from_string(hash, str8_struct(¶ms->target)); + for(U64 idx = 0; idx < params->dbgi_keys.count; idx += 1) + { + hash = fzy_hash_from_string(hash, str8_struct(¶ms->dbgi_keys.v[idx].min_timestamp)); + hash = fzy_hash_from_string(hash, params->dbgi_keys.v[idx].path); + } + return hash; +} + +internal U64 +fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx) +{ + U64 fuzzy_item_num = 0; + for(U64 idx = 0; idx < array->count; idx += 1) + { + if(array->v[idx].idx == element_idx) + { + fuzzy_item_num = idx+1; + break; + } + } + return fuzzy_item_num; +} + +internal String8 +fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, U64 element_idx) +{ + String8 result = {0}; + switch(target) + { + // NOTE(rjf): no default - warn if we miss a case + case FZY_Target_Procedures: + { + RDI_Procedure *proc = rdi_element_from_idx(rdi, procedures, element_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, proc->name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_GlobalVariables: + { + RDI_GlobalVariable *gvar = rdi_element_from_idx(rdi, global_variables, element_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, gvar->name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_ThreadVariables: + { + RDI_ThreadVariable *tvar = rdi_element_from_idx(rdi, thread_variables, element_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, tvar->name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_UDTs: + { + RDI_UDT *udt = rdi_element_from_idx(rdi, udts, element_idx); + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, type_node->user_defined.name_string_idx, &name_size); + result = str8(name_base, name_size); + }break; + case FZY_Target_COUNT:{}break; + } + return result; +} + +internal FZY_Params +fzy_params_copy(Arena *arena, FZY_Params *src) +{ + FZY_Params dst = zero_struct; + MemoryCopyStruct(&dst, src); + dst.dbgi_keys.v = push_array(arena, DI_Key, dst.dbgi_keys.count); + MemoryCopy(dst.dbgi_keys.v, src->dbgi_keys.v, sizeof(DI_Key)*src->dbgi_keys.count); + for(U64 idx = 0; idx < dst.dbgi_keys.count; idx += 1) + { + dst.dbgi_keys.v[idx].path = push_str8_copy(arena, dst.dbgi_keys.v[idx].path); + } + return dst; +} + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void +fzy_init(void) +{ + Arena *arena = arena_alloc(); + fzy_shared = push_array(arena, FZY_Shared, 1); + fzy_shared->arena = arena; + fzy_shared->slots_count = 256; + fzy_shared->stripes_count = os_logical_core_count(); + fzy_shared->slots = push_array(arena, FZY_Slot, fzy_shared->slots_count); + fzy_shared->stripes = push_array(arena, FZY_Stripe, fzy_shared->stripes_count); + for(U64 idx = 0; idx < fzy_shared->stripes_count; idx += 1) + { + fzy_shared->stripes[idx].arena = arena_alloc(); + fzy_shared->stripes[idx].rw_mutex = os_rw_mutex_alloc(); + fzy_shared->stripes[idx].cv = os_condition_variable_alloc(); + } + fzy_shared->thread_count = Min(os_logical_core_count(), 2); + fzy_shared->threads = push_array(arena, FZY_Thread, fzy_shared->thread_count); + for(U64 idx = 0; idx < fzy_shared->thread_count; idx += 1) + { + fzy_shared->threads[idx].u2f_ring_mutex = os_mutex_alloc(); + fzy_shared->threads[idx].u2f_ring_cv = os_condition_variable_alloc(); + fzy_shared->threads[idx].u2f_ring_size = KB(64); + fzy_shared->threads[idx].u2f_ring_base = push_array_no_zero(arena, U8, fzy_shared->threads[idx].u2f_ring_size); + fzy_shared->threads[idx].thread = os_launch_thread(fzy_search_thread__entry_point, (void *)idx, 0); + } +} + +//////////////////////////////// +//~ rjf: Scope Functions + +internal FZY_Scope * +fzy_scope_open(void) +{ + if(fzy_tctx == 0) + { + Arena *arena = arena_alloc(); + fzy_tctx = push_array(arena, FZY_TCTX, 1); + fzy_tctx->arena = arena; + } + FZY_Scope *scope = fzy_tctx->free_scope; + if(scope != 0) + { + SLLStackPop(fzy_tctx->free_scope); + } + else + { + scope = push_array_no_zero(fzy_tctx->arena, FZY_Scope, 1); + } + MemoryZeroStruct(scope); + return scope; +} + +internal void +fzy_scope_close(FZY_Scope *scope) +{ + for(FZY_Touch *t = scope->first_touch, *next = 0; t != 0; t = next) + { + next = t->next; + SLLStackPush(fzy_tctx->free_touch, t); + if(t->node != 0) + { + ins_atomic_u64_dec_eval(&t->node->touch_count); + } + } + SLLStackPush(fzy_tctx->free_scope, scope); +} + +internal void +fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node) +{ + if(node != 0) + { + ins_atomic_u64_inc_eval(&node->touch_count); + } + FZY_Touch *touch = fzy_tctx->free_touch; + if(touch != 0) + { + SLLStackPop(fzy_tctx->free_touch); + } + else + { + touch = push_array_no_zero(fzy_tctx->arena, FZY_Touch, 1); + } + MemoryZeroStruct(touch); + SLLQueuePush(scope->first_touch, scope->last_touch, touch); + touch->node = node; +} + +//////////////////////////////// +//~ rjf: Cache Lookup Functions + +internal FZY_ItemArray +fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out) +{ + Temp scratch = scratch_begin(0, 0); + FZY_ItemArray items = {0}; + + //- rjf: hash parameters + U64 params_hash = fzy_hash_from_params(params); + + //- rjf: unpack key + U64 slot_idx = key.u64[1]%fzy_shared->slots_count; + U64 stripe_idx = slot_idx%fzy_shared->stripes_count; + FZY_Slot *slot = &fzy_shared->slots[slot_idx]; + FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx]; + + //- rjf: query and/or request + OS_MutexScopeR(stripe->rw_mutex) for(;;) + { + // rjf: map key -> node + FZY_Node *node = 0; + for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + node = n; + break; + } + } + + // rjf: no node? -> allocate + if(node == 0) OS_MutexScopeRWPromote(stripe->rw_mutex) + { + node = push_array(stripe->arena, FZY_Node, 1); + SLLQueuePush(slot->first, slot->last, node); + node->key = key; + for(U64 idx = 0; idx < ArrayCount(node->buckets); idx += 1) + { + node->buckets[idx].arena = arena_alloc(); + } + } + + // rjf: try to grab last valid results for this key/query; determine if stale + B32 stale = 1; + if(params_hash == node->buckets[node->gen%ArrayCount(node->buckets)].params_hash && + node->gen != 0) + { + fzy_scope_touch_node__stripe_mutex_r_guarded(scope, node); + items = node->gen_items; + stale = !str8_match(query, node->buckets[node->gen%ArrayCount(node->buckets)].query, 0); + if(stale_out != 0) + { + *stale_out = stale; + } + } + + // rjf: if stale -> request again + if(stale) OS_MutexScopeRWPromote(stripe->rw_mutex) + { + if(node->gen <= node->submit_gen && node->submit_gen < node->gen + ArrayCount(node->buckets)-1) + { + node->submit_gen += 1; + arena_clear(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena); + node->buckets[node->submit_gen%ArrayCount(node->buckets)].query = push_str8_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, query); + node->buckets[node->submit_gen%ArrayCount(node->buckets)].params = fzy_params_copy(node->buckets[node->submit_gen%ArrayCount(node->buckets)].arena, params); + node->buckets[node->submit_gen%ArrayCount(node->buckets)].params_hash = params_hash; + } + if((node->submit_gen > node->gen+1 || os_now_microseconds() >= node->last_time_submitted_us+100000) && + fzy_u2s_enqueue_req(key, endt_us)) + { + node->last_time_submitted_us = os_now_microseconds(); + } + } + + // rjf: not stale, or timeout -> break + if(!stale || os_now_microseconds() >= endt_us) + { + break; + } + + // rjf: no results, but have time to wait -> wait + os_condition_variable_wait_rw_r(stripe->cv, stripe->rw_mutex, endt_us); + } + + scratch_end(scratch); + return items; +} + +//////////////////////////////// +//~ rjf: Searcher Threads + +internal B32 +fzy_u2s_enqueue_req(U128 key, U64 endt_us) +{ + B32 sent = 0; + FZY_Thread *thread = &fzy_shared->threads[key.u64[1]%fzy_shared->thread_count]; + OS_MutexScope(thread->u2f_ring_mutex) for(;;) + { + U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; + U64 available_size = thread->u2f_ring_size - unconsumed_size; + if(available_size >= sizeof(U128)) + { + sent = 1; + thread->u2f_ring_write_pos += ring_write_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_write_pos, &key); + break; + } + os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, endt_us); + } + if(sent) + { + os_condition_variable_broadcast(thread->u2f_ring_cv); + } + return sent; +} + +internal void +fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out) +{ + OS_MutexScope(thread->u2f_ring_mutex) for(;;) + { + U64 unconsumed_size = thread->u2f_ring_write_pos - thread->u2f_ring_read_pos; + if(unconsumed_size >= sizeof(U128)) + { + thread->u2f_ring_read_pos += ring_read_struct(thread->u2f_ring_base, thread->u2f_ring_size, thread->u2f_ring_read_pos, key_out); + break; + } + os_condition_variable_wait(thread->u2f_ring_cv, thread->u2f_ring_mutex, max_U64); + } + os_condition_variable_broadcast(thread->u2f_ring_cv); +} + +internal int +fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b) +{ + int result = 0; + if(a->match_ranges.count > b->match_ranges.count) + { + result = -1; + } + else if(a->match_ranges.count < b->match_ranges.count) + { + result = +1; + } + else if(a->missed_size < b->missed_size) + { + result = -1; + } + else if(a->missed_size > b->missed_size) + { + result = +1; + } + return result; +} + +internal void +fzy_search_thread__entry_point(void *p) +{ + ThreadNameF("[fzy] searcher #%I64u", (U64)p); + FZY_Thread *thread = &fzy_shared->threads[(U64)p]; + for(;;) + { + Temp scratch = scratch_begin(0, 0); + DI_Scope *di_scope = di_scope_open(); + + //////////////////////////// + //- rjf: dequeue next request + // + U128 key = {0}; + fzy_u2s_dequeue_req(scratch.arena, thread, &key); + U64 slot_idx = key.u64[1]%fzy_shared->slots_count; + U64 stripe_idx = slot_idx%fzy_shared->stripes_count; + FZY_Slot *slot = &fzy_shared->slots[slot_idx]; + FZY_Stripe *stripe = &fzy_shared->stripes[stripe_idx]; + + //////////////////////////// + //- rjf: grab next exe_path/query for this key + // + B32 task_is_good = 0; + Arena *task_arena = 0; + String8 query = {0}; + FZY_Params params = {FZY_Target_Procedures}; + U64 initial_submit_gen = 0; + OS_MutexScopeW(stripe->rw_mutex) + { + for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + FZY_Bucket *bucket = &n->buckets[n->submit_gen%ArrayCount(n->buckets)]; + task_is_good = 1; + initial_submit_gen = n->submit_gen; + task_arena = bucket->arena; + query = bucket->query; + params = bucket->params; + break; + } + } + } + + //////////////////////////// + //- rjf: params -> look up all rdis + // + U64 rdis_count = params.dbgi_keys.count; + RDI_Parsed **rdis = push_array(scratch.arena, RDI_Parsed *, rdis_count); + if(task_is_good) + { + for(U64 idx = 0; idx < rdis_count; idx += 1) + { + rdis[idx] = di_rdi_from_key(di_scope, ¶ms.dbgi_keys.v[idx], max_U64); + } + } + + //////////////////////////// + //- rjf: search target -> info about search space + // + U64 table_ptr_off = 0; + U64 table_count_off = 0; + U64 element_name_idx_off = 0; + U64 element_size = 0; + if(task_is_good) + { + switch(params.target) + { + // NOTE(rjf): no default! + case FZY_Target_COUNT:{}break; + case FZY_Target_Procedures: + { + table_ptr_off = OffsetOf(RDI_Parsed, procedures); + table_count_off = OffsetOf(RDI_Parsed, procedures_count); + element_name_idx_off = OffsetOf(RDI_Procedure, name_string_idx); + element_size = sizeof(RDI_Procedure); + }break; + case FZY_Target_GlobalVariables: + { + table_ptr_off = OffsetOf(RDI_Parsed, global_variables); + table_count_off = OffsetOf(RDI_Parsed, global_variables_count); + element_name_idx_off = OffsetOf(RDI_GlobalVariable, name_string_idx); + element_size = sizeof(RDI_GlobalVariable); + }break; + case FZY_Target_ThreadVariables: + { + table_ptr_off = OffsetOf(RDI_Parsed, thread_variables); + table_count_off = OffsetOf(RDI_Parsed, thread_variables_count); + element_name_idx_off = OffsetOf(RDI_ThreadVariable, name_string_idx); + element_size = sizeof(RDI_ThreadVariable); + }break; + case FZY_Target_UDTs: + { + table_ptr_off = OffsetOf(RDI_Parsed, udts); + table_count_off = OffsetOf(RDI_Parsed, udts_count); + element_size = sizeof(RDI_UDT); + }break; + } + } + + //////////////////////////// + //- rjf: rdis * query * params -> item list + // + FZY_ItemChunkList items_list = {0}; + if(task_is_good) + { + U64 base_idx = 0; + for(U64 rdi_idx = 0; rdi_idx < rdis_count; rdi_idx += 1) + { + RDI_Parsed *rdi = rdis[rdi_idx]; + void *table_base = (U8*)rdi + table_ptr_off; + U64 element_count = *MemberFromOffset(U64 *, rdi, table_count_off); + for(U64 idx = 1; task_is_good && idx < element_count; idx += 1) + { + void *element = (U8 *)(*(void **)table_base) + element_size*idx; + U32 *name_idx_ptr = (U32 *)((U8 *)element + element_name_idx_off); + if(params.target == FZY_Target_UDTs) + { + RDI_UDT *udt = (RDI_UDT *)element; + RDI_TypeNode *type_node = rdi_element_from_idx(rdi, type_nodes, udt->self_type_idx); + name_idx_ptr = &type_node->user_defined.name_string_idx; + } + U32 name_idx = *name_idx_ptr; + U64 name_size = 0; + U8 *name_base = rdi_string_from_idx(rdi, name_idx, &name_size); + String8 name = str8(name_base, name_size); + if(name.size == 0) { continue; } + FuzzyMatchRangeList matches = fuzzy_match_find(task_arena, query, name); + if(matches.count == matches.needle_part_count) + { + FZY_ItemChunk *chunk = items_list.last; + if(chunk == 0 || chunk->count >= chunk->cap) + { + chunk = push_array(scratch.arena, FZY_ItemChunk, 1); + chunk->cap = 1024; + chunk->count = 0; + chunk->v = push_array_no_zero(scratch.arena, FZY_Item, chunk->cap); + SLLQueuePush(items_list.first, items_list.last, chunk); + items_list.chunk_count += 1; + } + chunk->v[chunk->count].idx = base_idx + idx; + chunk->v[chunk->count].match_ranges = matches; + chunk->v[chunk->count].missed_size = (name_size > matches.total_dim) ? (name_size-matches.total_dim) : 0; + chunk->count += 1; + items_list.total_count += 1; + } + if(idx%100 == 99) OS_MutexScopeR(stripe->rw_mutex) + { + for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key) && n->submit_gen > initial_submit_gen) + { + task_is_good = 0; + break; + } + } + } + } + base_idx += element_count; + } + } + + //- rjf: item list -> item array + FZY_ItemArray items = {0}; + if(task_is_good) + { + items.count = items_list.total_count; + items.v = push_array_no_zero(task_arena, FZY_Item, items.count); + U64 idx = 0; + for(FZY_ItemChunk *chunk = items_list.first; chunk != 0; chunk = chunk->next) + { + MemoryCopy(items.v+idx, chunk->v, sizeof(FZY_Item)*chunk->count); + idx += chunk->count; + } + } + + //- rjf: sort item array + if(items.count != 0 && query.size != 0) + { + qsort(items.v, items.count, sizeof(FZY_Item), (int (*)(const void *, const void *))fzy_qsort_compare_items); + } + + //- rjf: commit to cache - busyloop on scope touches + if(task_is_good) + { + for(B32 done = 0; !done;) + { + B32 found = 0; + OS_MutexScopeW(stripe->rw_mutex) for(FZY_Node *n = slot->first; n != 0; n = n->next) + { + if(u128_match(n->key, key)) + { + if(n->touch_count == 0) + { + n->gen = initial_submit_gen; + n->gen_items = items; + done = 1; + } + found = 1; + break; + } + } + if(!found) + { + break; + } + } + } + + di_scope_close(di_scope); + scratch_end(scratch); + } +} diff --git a/src/fuzzy_search/fuzzy_search.h b/src/fuzzy_search/fuzzy_search.h new file mode 100644 index 00000000..5608c902 --- /dev/null +++ b/src/fuzzy_search/fuzzy_search.h @@ -0,0 +1,202 @@ +// Copyright (c) 2024 Epic Games Tools +// Licensed under the MIT license (https://opensource.org/license/mit/) + +#ifndef FUZZY_SEARCH_H +#define FUZZY_SEARCH_H + +//////////////////////////////// +//~ rjf: Result Types + +typedef struct FZY_Item FZY_Item; +struct FZY_Item +{ + U64 idx; // indexes into whole space of parameter tables. [rdis[0] element count) [rdis[1] element count) ... [rdis[n] element count) + U64 missed_size; + FuzzyMatchRangeList match_ranges; +}; + +typedef struct FZY_ItemChunk FZY_ItemChunk; +struct FZY_ItemChunk +{ + FZY_ItemChunk *next; + FZY_Item *v; + U64 count; + U64 cap; +}; + +typedef struct FZY_ItemChunkList FZY_ItemChunkList; +struct FZY_ItemChunkList +{ + FZY_ItemChunk *first; + FZY_ItemChunk *last; + U64 chunk_count; + U64 total_count; +}; + +typedef struct FZY_ItemArray FZY_ItemArray; +struct FZY_ItemArray +{ + FZY_Item *v; + U64 count; +}; + +//////////////////////////////// +//~ rjf: Search Parameter Types + +typedef enum FZY_Target +{ + FZY_Target_Procedures, + FZY_Target_GlobalVariables, + FZY_Target_ThreadVariables, + FZY_Target_UDTs, + FZY_Target_COUNT +} +FZY_Target; + +typedef struct FZY_Params FZY_Params; +struct FZY_Params +{ + FZY_Target target; + DI_KeyArray dbgi_keys; +}; + +//////////////////////////////// +//~ rjf: Cache Types + +typedef struct FZY_Bucket FZY_Bucket; +struct FZY_Bucket +{ + Arena *arena; + String8 query; + FZY_Params params; + U64 params_hash; +}; + +typedef struct FZY_Node FZY_Node; +struct FZY_Node +{ + FZY_Node *next; + U128 key; + U64 touch_count; + U64 last_time_submitted_us; + FZY_Bucket buckets[3]; + U64 gen; + U64 submit_gen; + FZY_ItemArray gen_items; +}; + +typedef struct FZY_Slot FZY_Slot; +struct FZY_Slot +{ + FZY_Node *first; + FZY_Node *last; +}; + +typedef struct FZY_Stripe FZY_Stripe; +struct FZY_Stripe +{ + Arena *arena; + OS_Handle rw_mutex; + OS_Handle cv; +}; + +//////////////////////////////// +//~ rjf: Scoped Access Types + +typedef struct FZY_Touch FZY_Touch; +struct FZY_Touch +{ + FZY_Touch *next; + FZY_Node *node; +}; + +typedef struct FZY_Scope FZY_Scope; +struct FZY_Scope +{ + FZY_Scope *next; + FZY_Touch *first_touch; + FZY_Touch *last_touch; +}; + +typedef struct FZY_TCTX FZY_TCTX; +struct FZY_TCTX +{ + Arena *arena; + FZY_Scope *free_scope; + FZY_Touch *free_touch; +}; + +//////////////////////////////// +//~ rjf: Shared State Types + +typedef struct FZY_Thread FZY_Thread; +struct FZY_Thread +{ + OS_Handle thread; + OS_Handle u2f_ring_mutex; + OS_Handle u2f_ring_cv; + U64 u2f_ring_size; + U8 *u2f_ring_base; + U64 u2f_ring_write_pos; + U64 u2f_ring_read_pos; +}; + +typedef struct FZY_Shared FZY_Shared; +struct FZY_Shared +{ + Arena *arena; + + // rjf: search artifact cache table + U64 slots_count; + U64 stripes_count; + FZY_Slot *slots; + FZY_Stripe *stripes; + + // rjf: threads + U64 thread_count; + FZY_Thread *threads; +}; + +//////////////////////////////// +//~ rjf: Globals + +global FZY_Shared *fzy_shared = 0; +thread_static FZY_TCTX *fzy_tctx = 0; + +//////////////////////////////// +//~ rjf: Helpers + +internal U64 fzy_hash_from_string(U64 seed, String8 string); +internal U64 fzy_hash_from_params(FZY_Params *params); +internal U64 fzy_item_num_from_array_element_idx__linear_search(FZY_ItemArray *array, U64 element_idx); +internal String8 fzy_item_string_from_rdi_target_element_idx(RDI_Parsed *rdi, FZY_Target target, U64 element_idx); +internal FZY_Params fzy_params_copy(Arena *arena, FZY_Params *src); + +//////////////////////////////// +//~ rjf: Main Layer Initialization + +internal void fzy_init(void); + +//////////////////////////////// +//~ rjf: Scope Functions + +internal FZY_Scope *fzy_scope_open(void); +internal void fzy_scope_close(FZY_Scope *scope); +internal void fzy_scope_touch_node__stripe_mutex_r_guarded(FZY_Scope *scope, FZY_Node *node); + +//////////////////////////////// +//~ rjf: Cache Lookup Functions + +internal FZY_ItemArray fzy_items_from_key_params_query(FZY_Scope *scope, U128 key, FZY_Params *params, String8 query, U64 endt_us, B32 *stale_out); + +//////////////////////////////// +//~ rjf: Searcher Threads + +internal B32 fzy_u2s_enqueue_req(U128 key, U64 endt_us); +internal void fzy_u2s_dequeue_req(Arena *arena, FZY_Thread *thread, U128 *key_out); + +internal int fzy_qsort_compare_items(FZY_Item *a, FZY_Item *b); + +internal void fzy_search_thread__entry_point(void *p); + +#endif // FUZZY_SEARCH_H diff --git a/src/lib_raddbgi_format/raddbgi_format.c b/src/lib_rdi_format/rdi_format.c similarity index 100% rename from src/lib_raddbgi_format/raddbgi_format.c rename to src/lib_rdi_format/rdi_format.c diff --git a/src/lib_raddbgi_format/raddbgi_format.h b/src/lib_rdi_format/rdi_format.h similarity index 99% rename from src/lib_raddbgi_format/raddbgi_format.h rename to src/lib_rdi_format/rdi_format.h index f0bc7b75..23fd54d0 100644 --- a/src/lib_raddbgi_format/raddbgi_format.h +++ b/src/lib_rdi_format/rdi_format.h @@ -4,11 +4,11 @@ //////////////////////////////////////////////////////////////// // RAD Debug Info, (R)AD(D)BG(I) Format Library // -// Defines standard RADDBGI debug information format types and +// Defines standard RDI debug information format types and // functions. -#ifndef RADDBGI_FORMAT_H -#define RADDBGI_FORMAT_H +#ifndef RDI_FORMAT_H +#define RDI_FORMAT_H //////////////////////////////////////////////////////////////// // Overridable procedure decoration @@ -924,4 +924,4 @@ RDI_PROC RDI_EvalConversionKind rdi_eval_conversion_rule(RDI_EvalTypeGroup in, R RDI_PROC RDI_U8* rdi_eval_conversion_message(RDI_EvalConversionKind conversion_kind, RDI_U64 *lennout); RDI_PROC RDI_S32 rdi_eval_opcode_type_compatible(RDI_EvalOp op, RDI_EvalTypeGroup group); -#endif // RADDBGI_FORMAT_H +#endif // RDI_FORMAT_H diff --git a/src/lib_raddbgi_format/raddbgi_format_parse.c b/src/lib_rdi_format/rdi_format_parse.c similarity index 100% rename from src/lib_raddbgi_format/raddbgi_format_parse.c rename to src/lib_rdi_format/rdi_format_parse.c diff --git a/src/lib_raddbgi_format/raddbgi_format_parse.h b/src/lib_rdi_format/rdi_format_parse.h similarity index 100% rename from src/lib_raddbgi_format/raddbgi_format_parse.h rename to src/lib_rdi_format/rdi_format_parse.h diff --git a/src/lib_raddbgi_make/raddbgi_make.c b/src/lib_rdi_make/rdi_make.c similarity index 100% rename from src/lib_raddbgi_make/raddbgi_make.c rename to src/lib_rdi_make/rdi_make.c diff --git a/src/lib_raddbgi_make/raddbgi_make.h b/src/lib_rdi_make/rdi_make.h similarity index 99% rename from src/lib_raddbgi_make/raddbgi_make.h rename to src/lib_rdi_make/rdi_make.h index 6c773aa4..3a497e43 100644 --- a/src/lib_raddbgi_make/raddbgi_make.h +++ b/src/lib_rdi_make/rdi_make.h @@ -5,14 +5,14 @@ // RAD Debug Info Make, (R)AD(D)BG(I) (M)ake Library // // Library for building loose data structures which contain -// RADDBGI debug information, and baking that down into the -// proper flattened RADDBGI format. +// RDI debug information, and baking that down into the +// proper flattened RDI format. // // Requires prior inclusion of the RAD Debug Info, (R)AD(D)BG(I) -// Format Library, in raddbgi_format.h. +// Format Library, in rdi_format.h. -#ifndef RADDBGI_MAKE_H -#define RADDBGI_MAKE_H +#ifndef RDI_MAKE_H +#define RDI_MAKE_H //////////////////////////////// //~ rjf: Overrideable Memory Operations @@ -1252,4 +1252,4 @@ RDI_PROC RDIM_BakeSectionList rdim_bake_idx_run_section_list_from_idx_run_map(RD RDI_PROC RDIM_String8List rdim_serialized_strings_from_params_bake_section_list(RDIM_Arena *arena, RDIM_BakeParams *params, RDIM_BakeSectionList *sections); -#endif // RADDBGI_MAKE_H +#endif // RDI_MAKE_H diff --git a/src/mule/mule_module.cpp b/src/mule/mule_module.cpp index 6fd7170f..c7dcec7e 100644 --- a/src/mule/mule_module.cpp +++ b/src/mule/mule_module.cpp @@ -39,4 +39,5 @@ dll_type_eval_tests(void) Basics basics2 = {4, 5, 6, 7}; int x = 0; (void)x; + *(int *)0 = 0; } diff --git a/src/mule/mule_peb_trample.c b/src/mule/mule_peb_trample.c new file mode 100644 index 00000000..a0aaa2c9 --- /dev/null +++ b/src/mule/mule_peb_trample.c @@ -0,0 +1,61 @@ +#include +#include +#include "mule_peb_trample_reload.c" + +static void +HideModuleFromWindowsReload(HMODULE ModuleToFlush) +{ + /* NOTE(casey): Normally you cannot "reload" an executable module with the same name, + because Windows checks a linked list of loaded modules and assumes that if + it's already loaded, it doesn't need to reload it, even though it may have to because + it has changed on disk. + + This solution to that problem comes from some excellent spelunking by Martins Mozeiko, + who figured out that you could overwrite the filenames Windows stores in your process's + loaded module table, thus thwarting the Windows filename check against loaded modules, + allowing you to reload an existing module that has changed without requiring it to + have a different filename! + */ + + PEB *Peb = (PEB *)__readgsqword(offsetof(TEB, ProcessEnvironmentBlock)); + LIST_ENTRY *Head = &Peb->Ldr->InMemoryOrderModuleList; + for(LIST_ENTRY *Entry = Head->Flink; + Entry != Head; + Entry = Entry->Flink) + { + LDR_DATA_TABLE_ENTRY *Mod = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + if(Mod->DllBase == ModuleToFlush) + { + ZeroMemory(Mod->FullDllName.Buffer, Mod->FullDllName.Length); + Mod->DllBase = 0; + break; + } + } +} + +int main(int argument_count, char **arguments) +{ + char *exe_name = arguments[0]; + HANDLE last_module = GetModuleHandle(0); + int (*loop_iteration_function)(int it) = (int (*)(int))GetProcAddress(last_module, "loop_iteration"); + FILETIME last_filetime = {0}; + int should_exit = 0; + for(int it = 0; !should_exit; it += 1) + { + int result = loop_iteration_function(it); + printf("%i\n", result); + Sleep(50); + FILETIME current_filetime = {0}; + HANDLE current_exe_file = CreateFile(exe_name, 0, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + GetFileTime(current_exe_file, 0, 0, ¤t_filetime); + CloseHandle(current_exe_file); + if(it != 0 && CompareFileTime(&last_filetime, ¤t_filetime) < 0) + { + HideModuleFromWindowsReload(last_module); + last_module = LoadLibrary(arguments[0]); + loop_iteration_function = (int (*)(int))GetProcAddress(last_module, "loop_iteration"); + } + last_filetime = current_filetime; + } + return 0; +} diff --git a/src/mule/mule_peb_trample_reload.c b/src/mule/mule_peb_trample_reload.c new file mode 100644 index 00000000..f505a882 --- /dev/null +++ b/src/mule/mule_peb_trample_reload.c @@ -0,0 +1,13 @@ +__declspec(dllexport) int +loop_iteration(int it) +{ + return 111; +#if 0 + int sum = 0; + for(int i = 0; i < 1000; i += 1) + { + sum += it*i; + } + return sum; +#endif +} diff --git a/src/os/core/linux/os_core_linux.c b/src/os/core/linux/os_core_linux.c index f8b07e81..8a6db843 100644 --- a/src/os/core/linux/os_core_linux.c +++ b/src/os/core/linux/os_core_linux.c @@ -1607,7 +1607,7 @@ os_semaphore_close(OS_Handle semaphore) } internal B32 -os_semaphore_take(OS_Handle semaphore) +os_semaphore_take(OS_Handle semaphore, U64 endt_us) { NotImplemented; return 0; diff --git a/src/os/gfx/win32/os_gfx_win32.c b/src/os/gfx/win32/os_gfx_win32.c index e94e07df..f10e93ac 100644 --- a/src/os/gfx/win32/os_gfx_win32.c +++ b/src/os/gfx/win32/os_gfx_win32.c @@ -771,12 +771,6 @@ w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) result = HTCAPTION; } - // rjf: title bar client area - if(is_over_title_bar_client_area) - { - result = HTCLIENT; - } - // rjf: normal edges if(is_over_left) { result = HTLEFT; } if(is_over_right) { result = HTRIGHT; } @@ -788,6 +782,12 @@ w32_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if(is_over_left && is_over_bottom) { result = HTBOTTOMLEFT; } if(is_over_right && is_over_top) { result = HTTOPRIGHT; } if(is_over_right && is_over_bottom) { result = HTBOTTOMRIGHT; } + + // rjf: title bar client area + if(is_over_title_bar_client_area) + { + result = HTCLIENT; + } } } }break; diff --git a/src/pe/pe.c b/src/pe/pe.c index f2b243f9..9291d179 100644 --- a/src/pe/pe.c +++ b/src/pe/pe.c @@ -69,11 +69,10 @@ pe_bin_info_from_data(Arena *arena, String8 data) } // rjf: read pe magic - U32 coff_off = dos_header.coff_file_offset; U32 pe_magic = 0; if(valid) { - str8_deserial_read_struct(data, coff_off, &pe_magic); + str8_deserial_read_struct(data, dos_header.coff_file_offset, &pe_magic); } // rjf: bad pe magic -> abort @@ -83,7 +82,7 @@ pe_bin_info_from_data(Arena *arena, String8 data) } // rjf: read coff header - U32 coff_header_off = coff_off + sizeof(pe_magic); + U32 coff_header_off = dos_header.coff_file_offset + sizeof(pe_magic); COFF_Header coff_header = {0}; if(valid) { diff --git a/src/raddbg/raddbg.c b/src/raddbg/raddbg.c index c0af86cc..2b636d6a 100644 --- a/src/raddbg/raddbg.c +++ b/src/raddbg/raddbg.c @@ -393,7 +393,7 @@ update_and_render(OS_Handle repaint_window_handle, void *user_data) ProfEnd(); } -internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook) +internal CTRL_WAKEUP_FUNCTION_DEF(wakeup_hook_ctrl) { os_send_wakeup_event(); } diff --git a/src/raddbg/raddbg.h b/src/raddbg/raddbg.h index 1e7a1ce1..927e2393 100644 --- a/src/raddbg/raddbg.h +++ b/src/raddbg/raddbg.h @@ -37,13 +37,8 @@ //////////////////////////////// //~ rjf: Hot, High Priority Tasks (Complete Unusability, Crashes, Fire-Worthy) // -// [ ] robustify dbgi layer to renames (cache should not be based only on -// path - must invalidate naturally when new filetime occurs) -// -// [ ] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly // [ ] PDB files distributed with the build are not found by DbgHelp!!! // [ ] Jai compiler debugging crash -// [ ] raddbgi file regeneration too strict // // [ ] Jump table thunks, on code w/o /INCREMENTAL:NO // @@ -52,15 +47,10 @@ // since that's not normally how Windows fonts work. //////////////////////////////// -//~ rjf: Demon/Cleanup Pass Tasks +//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // -// [ ] TLS eval -> in-process-memory EXE info -// [ ] unwinding -> in-process-memory EXE info // [ ] "root" concept in hash store, which buckets keys & allows usage code to // jettison a collection of keys in retained mode fashion - -//////////////////////////////// -//~ rjf: Hot, Medium Priority Tasks (Low-Hanging-Fruit Features, UI Jank, Cleanup) // // [ ] Jeff Notes // [ ] highlighted text & ctrl+f -> auto-fill search query @@ -379,6 +369,13 @@ // function was displayed in the window by default next to the thread. // [x] ** It would be nice if thread listings displayed the name of the // thread, instead of just the ID. +// [x] TLS eval -> in-process-memory EXE info +// [x] unwinding -> in-process-memory EXE info +// [x] new fuzzy searching layer +// [x] robustify dbgi layer to renames (cache should not be based only on +// path - must invalidate naturally when new filetime occurs) +// [x] rdi file regeneration too strict +// [x] raddbg jai.exe my_file.jai -- foobar -> raddbg consumes `--` incorrectly #ifndef RADDBG_H #define RADDBG_H @@ -404,12 +401,23 @@ struct IPCInfo //////////////////////////////// //~ rjf: Globals -#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(16) +//- rjf: IPC resources +#define IPC_SHARED_MEMORY_BUFFER_SIZE MB(4) StaticAssert(IPC_SHARED_MEMORY_BUFFER_SIZE > sizeof(IPCInfo), ipc_buffer_size_requirement); -read_only global String8 ipc_shared_memory_name = str8_lit_comp("_raddbg_ipc_shared_memory_"); -read_only global String8 ipc_semaphore_name = str8_lit_comp("_raddbg_ipc_semaphore_"); +global OS_Handle ipc_signal_semaphore = {0}; +global OS_Handle ipc_lock_semaphore = {0}; +global U8 *ipc_shared_memory_base = 0; +global U8 ipc_s2m_ring_buffer[MB(4)] = {0}; +global U64 ipc_s2m_ring_write_pos = 0; +global U64 ipc_s2m_ring_read_pos = 0; +global OS_Handle ipc_s2m_ring_mutex = {0}; +global OS_Handle ipc_s2m_ring_cv = {0}; + +//- rjf: frame time history global U64 frame_time_us_history[64] = {0}; global U64 frame_time_us_history_idx = 0; + +//- rjf: main thread log global Log *main_thread_log = 0; global String8 main_thread_log_path = {0}; diff --git a/src/raddbg/raddbg_main.cpp b/src/raddbg/raddbg_main.cpp index cd62a0f2..7f28f917 100644 --- a/src/raddbg/raddbg_main.cpp +++ b/src/raddbg/raddbg_main.cpp @@ -11,14 +11,21 @@ #define BUILD_TITLE "The RAD Debugger" #define OS_FEATURE_GRAPHICAL 1 +#define R_INIT_MANUAL 1 +#define TEX_INIT_MANUAL 1 +#define GEO_INIT_MANUAL 1 +#define F_INIT_MANUAL 1 +#define DF_INIT_MANUAL 1 +#define DF_GFX_INIT_MANUAL 1 + //////////////////////////////// //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format_parse.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" @@ -27,12 +34,11 @@ #include "os/os_inc.h" #include "task_system/task_system.h" #include "ico/ico.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "mdesk/mdesk.h" #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" #include "text_cache/text_cache.h" -#include "dasm_cache/dasm_cache.h" #include "path/path.h" #include "txti/txti.h" #include "coff/coff.h" @@ -42,14 +48,15 @@ #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb/raddbgi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb.h" #include "regs/regs.h" -#include "regs/raddbgi/regs_raddbgi.h" +#include "regs/rdi/regs_rdi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" +#include "dasm_cache/dasm_cache.h" +#include "fuzzy_search/fuzzy_search.h" #include "demon/demon_inc.h" #include "eval/eval_inc.h" -#include "unwind/unwind.h" #include "ctrl/ctrl_inc.h" #include "font_provider/font_provider_inc.h" #include "render/render_inc.h" @@ -66,12 +73,11 @@ #include "os/os_inc.c" #include "task_system/task_system.c" #include "ico/ico.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "mdesk/mdesk.c" #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" #include "text_cache/text_cache.c" -#include "dasm_cache/dasm_cache.c" #include "path/path.c" #include "txti/txti.c" #include "coff/coff.c" @@ -81,14 +87,15 @@ #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb/raddbgi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb.c" #include "regs/regs.c" -#include "regs/raddbgi/regs_raddbgi.c" +#include "regs/rdi/regs_rdi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" +#include "dasm_cache/dasm_cache.c" +#include "fuzzy_search/fuzzy_search.c" #include "demon/demon_inc.c" #include "eval/eval_inc.c" -#include "unwind/unwind.c" #include "ctrl/ctrl_inc.c" #include "font_provider/font_provider_inc.c" #include "render/render_inc.c" @@ -100,6 +107,42 @@ #include "df/df_inc.c" #include "raddbg.c" +//////////////////////////////// +//~ rjf: IPC Signaler Thread + +internal void +ipc_signaler_thread__entry_point(void *p) +{ + for(;;) + { + if(os_semaphore_take(ipc_signal_semaphore, max_U64)) + { + if(os_semaphore_take(ipc_lock_semaphore, max_U64)) + { + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + String8 msg = str8((U8 *)(ipc_info+1), ipc_info->msg_size); + msg.size = Min(msg.size, IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo)); + OS_MutexScope(ipc_s2m_ring_mutex) for(;;) + { + U64 unconsumed_size = ipc_s2m_ring_write_pos - ipc_s2m_ring_read_pos; + U64 available_size = (sizeof(ipc_s2m_ring_buffer) - unconsumed_size); + if(available_size >= sizeof(U64)+sizeof(msg.size)) + { + ipc_s2m_ring_write_pos += ring_write_struct(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_write_pos, &msg.size); + ipc_s2m_ring_write_pos += ring_write(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_write_pos, msg.str, msg.size); + break; + } + os_condition_variable_wait(ipc_s2m_ring_cv, ipc_s2m_ring_mutex, max_U64); + } + os_condition_variable_broadcast(ipc_s2m_ring_cv); + os_send_wakeup_event(); + ipc_info->msg_size = 0; + os_semaphore_drop(ipc_lock_semaphore); + } + } + } +} + //////////////////////////////// //~ rjf: Entry Point @@ -178,7 +221,7 @@ entry_point(CmdLine *cmd_line) } //- rjf: set up layers - ctrl_set_wakeup_hook(wakeup_hook); + ctrl_set_wakeup_hook(wakeup_hook_ctrl); //- rjf: dispatch to top-level codepath based on execution mode switch(exec_mode) @@ -187,12 +230,16 @@ entry_point(CmdLine *cmd_line) default: case ExecMode_Normal: { - //- rjf: set up shared memory for ipc - OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); - void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); - OS_Handle ipc_semaphore = os_semaphore_alloc(1, 1, ipc_semaphore_name); - IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; - ipc_info->msg_size = 0; + //- rjf: manual layer initialization + { + r_init(cmd_line); + tex_init(); + geo_init(); + f_init(); + DF_StateDeltaHistory *hist = df_state_delta_history_alloc(); + df_core_init(cmd_line, hist); + df_gfx_init(update_and_render, df_state_delta_history()); + } //- rjf: setup initial target from command line args { @@ -247,56 +294,97 @@ entry_point(CmdLine *cmd_line) } } + //- rjf: set up shared resources for ipc to this instance; launch IPC signaler thread + { + Temp scratch = scratch_begin(0, 0); + U32 instance_pid = os_get_pid(); + String8 ipc_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_shared_memory_%i_", instance_pid); + String8 ipc_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_signal_semaphore_%i_", instance_pid); + String8 ipc_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_lock_semaphore_%i_", instance_pid); + OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); + ipc_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); + ipc_signal_semaphore = os_semaphore_alloc(0, 1, ipc_signal_semaphore_name); + ipc_lock_semaphore = os_semaphore_alloc(1, 1, ipc_lock_semaphore_name); + ipc_s2m_ring_mutex = os_mutex_alloc(); + ipc_s2m_ring_cv = os_condition_variable_alloc(); + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + MemoryZeroStruct(ipc_info); + os_launch_thread(ipc_signaler_thread__entry_point, 0, 0); + scratch_end(scratch); + } + //- rjf: main application loop { for(;;) { - //- rjf: get IPC messages & dispatch ui commands from them + //- rjf: consume IPC messages, dispatch UI commands { - if(os_semaphore_take(ipc_semaphore, max_U64)) + Temp scratch = scratch_begin(0, 0); + B32 consumed = 0; + String8 msg = {0}; + OS_MutexScope(ipc_s2m_ring_mutex) { - if(ipc_info->msg_size != 0) + U64 unconsumed_size = ipc_s2m_ring_write_pos - ipc_s2m_ring_read_pos; + if(unconsumed_size >= sizeof(U64)) { - U8 *buffer = (U8 *)(ipc_info+1); - U64 msg_size = ipc_info->msg_size; - String8 cmd_string = str8(buffer, msg_size); - ipc_info->msg_size = 0; - DF_Window *dst_window = df_gfx_state->first_window; - for(DF_Window *window = dst_window; window != 0; window = window->next) + consumed = 1; + ipc_s2m_ring_read_pos += ring_read_struct(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_read_pos, &msg.size); + msg.size = Min(msg.size, unconsumed_size); + msg.str = push_array(scratch.arena, U8, msg.size); + ipc_s2m_ring_read_pos += ring_read(ipc_s2m_ring_buffer, sizeof(ipc_s2m_ring_buffer), ipc_s2m_ring_read_pos, msg.str, msg.size); + } + } + if(consumed) + { + os_condition_variable_broadcast(ipc_s2m_ring_cv); + } + if(msg.size != 0) + { + log_infof("IPC message received: \"%S\"", msg); + DF_Window *dst_window = df_gfx_state->first_window; + for(DF_Window *window = dst_window; window != 0; window = window->next) + { + if(os_window_is_focused(window->os)) { - if(os_window_is_focused(window->os)) - { - dst_window = window; - break; - } - } - if(dst_window != 0) - { - Temp scratch = scratch_begin(0, 0); - String8 cmd_spec_string = df_cmd_name_part_from_string(cmd_string); - DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(cmd_spec_string); - if(!df_cmd_spec_is_nil(cmd_spec)) - { - DF_CmdParams params = df_cmd_params_from_gfx(); - DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(dst_window); - String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, cmd_spec, df_cmd_arg_part_from_string(cmd_string)); - if(error.size == 0) - { - df_push_cmd__root(¶ms, cmd_spec); - } - else - { - DF_CmdParams params = df_cmd_params_from_window(dst_window); - params.string = error; - df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); - df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); - } - } - scratch_end(scratch); + dst_window = window; + break; + } + } + if(dst_window != 0) + { + dst_window->window_temporarily_focused_ipc = 1; + String8 cmd_spec_string = df_cmd_name_part_from_string(msg); + DF_CmdSpec *cmd_spec = df_cmd_spec_from_string(cmd_spec_string); + if(!df_cmd_spec_is_nil(cmd_spec)) + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + DF_CtrlCtx ctrl_ctx = df_ctrl_ctx_from_window(dst_window); + String8 error = df_cmd_params_apply_spec_query(scratch.arena, &ctrl_ctx, ¶ms, cmd_spec, df_cmd_arg_part_from_string(msg)); + if(error.size == 0) + { + df_push_cmd__root(¶ms, cmd_spec); + df_gfx_request_frame(); + } + else + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + params.string = error; + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + df_gfx_request_frame(); + } + } + else + { + DF_CmdParams params = df_cmd_params_from_window(dst_window); + params.string = push_str8f(scratch.arena, "\"%S\" is not a command.", cmd_spec_string); + df_cmd_params_mark_slot(¶ms, DF_CmdParamSlot_String); + df_push_cmd__root(¶ms, df_cmd_spec_from_core_cmd_kind(DF_CoreCmdKind_Error)); + df_gfx_request_frame(); } } - os_semaphore_drop(ipc_semaphore); } + scratch_end(scratch); } //- rjf: update & render frame @@ -344,25 +432,61 @@ entry_point(CmdLine *cmd_line) { Temp scratch = scratch_begin(0, 0); - //- rjf: grab ipc shared memory - OS_Handle ipc_shared_memory = os_shared_memory_open(ipc_shared_memory_name); - void *ipc_shared_memory_base = os_shared_memory_view_open(ipc_shared_memory, r1u64(0, MB(16))); - if(ipc_shared_memory_base != 0) + //- rjf: grab explicit PID argument + U32 dst_pid = 0; + if(cmd_line_has_argument(cmd_line, str8_lit("pid"))) { - OS_Handle ipc_semaphore = os_semaphore_open(ipc_semaphore_name); - IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; - if(os_semaphore_take(ipc_semaphore, os_now_microseconds() + Million(6))) + String8 dst_pid_string = cmd_line_string(cmd_line, str8_lit("pid")); + U64 dst_pid_u64 = 0; + if(dst_pid_string.size != 0 && + try_u64_from_str8_c_rules(dst_pid_string, &dst_pid_u64)) { - U8 *buffer = (U8 *)(ipc_info+1); - U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); - StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; - String8 msg = str8_list_join(scratch.arena, &cmd_line->inputs, &join); - ipc_info->msg_size = Min(buffer_max, msg.size); - MemoryCopy(buffer, msg.str, ipc_info->msg_size); - os_semaphore_drop(ipc_semaphore); + dst_pid = (U32)dst_pid_u64; } } + //- rjf: no explicit PID? -> find PID to send message to, by looking for other raddbg instances + if(dst_pid == 0) + { + U32 this_pid = os_get_pid(); + DMN_ProcessIter it = {0}; + dmn_process_iter_begin(&it); + for(DMN_ProcessInfo info = {0}; dmn_process_iter_next(scratch.arena, &it, &info);) + { + if(str8_match(str8_skip_last_slash(str8_chop_last_dot(cmd_line->exe_name)), str8_skip_last_slash(str8_chop_last_dot(info.name)), StringMatchFlag_CaseInsensitive) && + this_pid != info.pid) + { + dst_pid = info.pid; + break; + } + } + dmn_process_iter_end(&it); + } + + //- rjf: grab destination instance's shared memory resources + String8 ipc_shared_memory_name = push_str8f(scratch.arena, "_raddbg_ipc_shared_memory_%i_", dst_pid); + String8 ipc_signal_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_signal_semaphore_%i_", dst_pid); + String8 ipc_lock_semaphore_name = push_str8f(scratch.arena, "_raddbg_ipc_lock_semaphore_%i_", dst_pid); + OS_Handle ipc_shared_memory = os_shared_memory_alloc(IPC_SHARED_MEMORY_BUFFER_SIZE, ipc_shared_memory_name); + ipc_shared_memory_base = (U8 *)os_shared_memory_view_open(ipc_shared_memory, r1u64(0, IPC_SHARED_MEMORY_BUFFER_SIZE)); + ipc_signal_semaphore = os_semaphore_alloc(0, 1, ipc_signal_semaphore_name); + ipc_lock_semaphore = os_semaphore_alloc(1, 1, ipc_lock_semaphore_name); + + //- rjf: got resources -> write message + if(ipc_shared_memory_base != 0 && + os_semaphore_take(ipc_lock_semaphore, max_U64)) + { + IPCInfo *ipc_info = (IPCInfo *)ipc_shared_memory_base; + U8 *buffer = (U8 *)(ipc_info+1); + U64 buffer_max = IPC_SHARED_MEMORY_BUFFER_SIZE - sizeof(IPCInfo); + StringJoin join = {str8_lit(""), str8_lit(" "), str8_lit("")}; + String8 msg = str8_list_join(scratch.arena, &cmd_line->inputs, &join); + ipc_info->msg_size = Min(buffer_max, msg.size); + MemoryCopy(buffer, msg.str, ipc_info->msg_size); + os_semaphore_drop(ipc_signal_semaphore); + os_semaphore_drop(ipc_lock_semaphore); + } + scratch_end(scratch); }break; diff --git a/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c similarity index 95% rename from src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c rename to src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c index 1576b8c0..134c7048 100644 --- a/src/raddbgi_breakpad_from_pdb/raddbgi_breakpad_from_pdb_main.c +++ b/src/rdi_breakpad_from_pdb/rdi_breakpad_from_pdb_main.c @@ -5,17 +5,17 @@ #define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_PATCH 10 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" -#define BUILD_TITLE "raddbgi_breakpad_from_pdb" +#define BUILD_TITLE "rdi_breakpad_from_pdb" #define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" @@ -24,27 +24,27 @@ #include "base/base_inc.h" #include "os/os_inc.h" #include "task_system/task_system.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "coff/coff.h" #include "codeview/codeview.h" #include "codeview/codeview_stringize.h" #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb/raddbgi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" #include "task_system/task_system.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "coff/coff.c" #include "codeview/codeview.c" #include "codeview/codeview_stringize.c" #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb/raddbgi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb.c" //////////////////////////////// //~ rjf: Baking Tasks @@ -209,7 +209,7 @@ entry_point(CmdLine *cmdline) //- rjf: display help if(do_help || user2convert->errors.node_count != 0) { - fprintf(stderr, "--- raddbgi_breakpad_from_pdb -------------------------------------------------\n\n"); + fprintf(stderr, "--- rdi_breakpad_from_pdb -----------------------------------------------------\n\n"); fprintf(stderr, "This utility converts debug information from PDBs into the textual Breakpad\n"); fprintf(stderr, "symbol information format, used for various external utilities, using the RAD\n"); diff --git a/src/raddbgi_dump/raddbgi_dump.c b/src/rdi_dump/rdi_dump.c similarity index 99% rename from src/raddbgi_dump/raddbgi_dump.c rename to src/rdi_dump/rdi_dump.c index 019be63b..92f96225 100644 --- a/src/raddbgi_dump/raddbgi_dump.c +++ b/src/rdi_dump/rdi_dump.c @@ -2,7 +2,7 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) //////////////////////////////// -//~ rjf: RADDBGI Enum -> String Functions +//~ rjf: RDI Enum -> String Functions internal String8 rdi_string_from_data_section_tag(RDI_DataSectionTag tag){ @@ -79,7 +79,7 @@ rdi_string_from_local_kind(RDI_LocalKind local_kind){ } //////////////////////////////// -//~ rjf: RADDBGI Flags -> String Functions +//~ rjf: RDI Flags -> String Functions internal void rdi_stringize_binary_section_flags(Arena *arena, String8List *out, diff --git a/src/raddbgi_dump/raddbgi_dump.h b/src/rdi_dump/rdi_dump.h similarity index 94% rename from src/raddbgi_dump/raddbgi_dump.h rename to src/rdi_dump/rdi_dump.h index add5f987..473093d9 100644 --- a/src/raddbgi_dump/raddbgi_dump.h +++ b/src/rdi_dump/rdi_dump.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_DUMP_H -#define RADDBGI_DUMP_H +#ifndef RDI_DUMP_H +#define RDI_DUMP_H //////////////////////////////// //~ rjf: RADDBG Stringize Helper Types @@ -39,7 +39,7 @@ struct RDI_ScopeBundle }; //////////////////////////////// -//~ rjf: RADDBGI Enum -> String Functions +//~ rjf: RDI Enum -> String Functions internal String8 rdi_string_from_data_section_tag(RDI_DataSectionTag tag); internal String8 rdi_string_from_arch(RDI_Arch arch); @@ -49,7 +49,7 @@ internal String8 rdi_string_from_member_kind(RDI_MemberKind member_kind); internal String8 rdi_string_from_local_kind(RDI_LocalKind local_kind); //////////////////////////////// -//~ rjf: RADDBGI Flags -> String Functions +//~ rjf: RDI Flags -> String Functions internal void rdi_stringize_binary_section_flags(Arena *arena, String8List *out, RDI_BinarySectionFlags flags); internal void rdi_stringize_type_modifier_flags(Arena *arena, String8List *out, RDI_TypeModifierFlags flags); @@ -57,7 +57,7 @@ internal void rdi_stringize_user_defined_type_flags(Arena *arena, String8List *o internal void rdi_stringize_link_flags(Arena *arena, String8List *out, RDI_LinkFlags flags); //////////////////////////////// -//~ rjf: RADDBG Compound Stringize Functions +//~ rjf: RDI Compound Stringize Functions internal void rdi_stringize_data_sections(Arena *arena, String8List *out, RDI_Parsed *parsed, U32 indent_level); internal void rdi_stringize_top_level_info(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_TopLevelInfo *tli, U32 indent_level); @@ -72,4 +72,4 @@ internal void rdi_stringize_thread_variable(Arena *arena, String8List *out, RDI_ internal void rdi_stringize_procedure(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_Procedure *proc, U32 indent_level); internal void rdi_stringize_scope(Arena *arena, String8List *out, RDI_Parsed *parsed, RDI_ScopeBundle *bundle, RDI_Scope *scope, U32 indent_level); -#endif // RADDBGI_DUMP_H +#endif // RDI_DUMP_H diff --git a/src/raddbgi_dump/raddbgi_dump_main.c b/src/rdi_dump/rdi_dump_main.c similarity index 70% rename from src/raddbgi_dump/raddbgi_dump_main.c rename to src/rdi_dump/rdi_dump_main.c index 2fea4fb5..315850e9 100644 --- a/src/raddbgi_dump/raddbgi_dump_main.c +++ b/src/rdi_dump/rdi_dump_main.c @@ -8,27 +8,33 @@ #define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_PATCH 10 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" -#define BUILD_TITLE "raddbgi_dump" +#define BUILD_TITLE "rdi_dump" #define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.c" +#include "third_party/rad_lzb_simple/rad_lzb_simple.h" +#include "third_party/rad_lzb_simple/rad_lzb_simple.c" //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" -#include "raddbgi_dump.h" +#include "path/path.h" +#include "dbgi/dbgi.h" +#include "rdi_dump.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" -#include "raddbgi_dump.c" +#include "path/path.c" +#include "dbgi/dbgi.c" +#include "rdi_dump.c" //////////////////////////////// //~ rjf: Entry Point @@ -40,6 +46,7 @@ entry_point(CmdLine *cmd_line) //- rjf: set up // Arena *arena = arena_alloc(); + DI_Scope *di_scope = di_scope_open(); String8List errors = {0}; ////////////////////////////// @@ -70,11 +77,8 @@ entry_point(CmdLine *cmd_line) String8 input_data = {0}; DumpFlags dump_flags = (U32)0xffffffff; { - // rjf: extract input file path & load data + // rjf: extract input file path input_name = str8_list_first(&cmd_line->inputs); - if(input_name.size > 0) { input_data = os_data_from_file_path(arena, input_name); } - else {str8_list_pushf(arena, &errors, "error (input): No input RADDBGI file specified.");} - if(input_name.size != 0 && input_data.size == 0) { str8_list_pushf(arena, &errors, "error (input): No input RADDBGI file successfully loaded; either the path or file contents are invalid."); } // rjf: extract dump options { @@ -107,17 +111,22 @@ entry_point(CmdLine *cmd_line) } ////////////////////////////// - //- rjf: parse raddbg from input data + //- rjf: obtain rdi parse // - RDI_ParseStatus parse_status = RDI_ParseStatus_Good; - RDI_Parsed raddbg_ = {0}; - RDI_Parsed *raddbg = &raddbg_; + RDI_Parsed *rdi = &di_rdi_parsed_nil; + if(input_name.size == 0) { - parse_status = rdi_parse(input_data.str, input_data.size, &raddbg_); - if(parse_status != RDI_ParseStatus_Good) - { - str8_list_pushf(arena, &errors, "error (parse): RADDBGI file wasn't parsed successfully. (0x%x)", parse_status); - } + str8_list_pushf(arena, &errors, "error (input): No input RDI file specified."); + } + else + { + DI_Key key = {input_name}; + di_open(&key); + rdi = di_rdi_from_key(di_scope, &key, max_U64); + } + if(rdi == &di_rdi_parsed_nil) + { + str8_list_pushf(arena, &errors, "error (input): No input RDI file successfully loaded; either the path or file contents are invalid."); } ////////////////////////////// @@ -133,13 +142,13 @@ entry_point(CmdLine *cmd_line) //- rjf: build dump strings // String8List dump = {0}; - if(parse_status == RDI_ParseStatus_Good) + if(rdi != &di_rdi_parsed_nil) { //- rjf: DATA SECTIONS if(dump_flags & DumpFlag_DataSections) { str8_list_pushf(arena, &dump, "# DATA SECTIONS:\n"); - rdi_stringize_data_sections(arena, &dump, raddbg, 1); + rdi_stringize_data_sections(arena, &dump, rdi, 1); str8_list_push(arena, &dump, str8_lit("\n")); } @@ -147,7 +156,7 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_TopLevelInfo) { str8_list_pushf(arena, &dump, "# TOP LEVEL INFO:\n"); - rdi_stringize_top_level_info(arena, &dump, raddbg, raddbg->top_level_info, 1); + rdi_stringize_top_level_info(arena, &dump, rdi, rdi->top_level_info, 1); str8_list_push(arena, &dump, str8_lit("\n")); } @@ -155,11 +164,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_BinarySections) { str8_list_pushf(arena, &dump, "# BINARY SECTIONS:\n"); - RDI_BinarySection *ptr = raddbg->binary_sections; - for(U32 i = 0; i < raddbg->binary_sections_count; i += 1, ptr += 1) + RDI_BinarySection *ptr = rdi->binary_sections; + for(U32 i = 0; i < rdi->binary_sections_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " section[%u]:\n", i); - rdi_stringize_binary_section(arena, &dump, raddbg, ptr, 2); + rdi_stringize_binary_section(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -170,16 +179,16 @@ entry_point(CmdLine *cmd_line) { RDI_FilePathBundle file_path_bundle = {0}; { - file_path_bundle.file_paths = raddbg->file_paths; - file_path_bundle.file_path_count = raddbg->file_paths_count; + file_path_bundle.file_paths = rdi->file_paths; + file_path_bundle.file_path_count = rdi->file_paths_count; } str8_list_pushf(arena, &dump, "# FILE PATHS\n"); - RDI_FilePathNode *ptr = raddbg->file_paths; - for(U32 i = 0; i < raddbg->file_paths_count; i += 1, ptr += 1) + RDI_FilePathNode *ptr = rdi->file_paths; + for(U32 i = 0; i < rdi->file_paths_count; i += 1, ptr += 1) { if(ptr->parent_path_node == 0) { - rdi_stringize_file_path(arena, &dump, raddbg, &file_path_bundle, ptr, 1); + rdi_stringize_file_path(arena, &dump, rdi, &file_path_bundle, ptr, 1); } } str8_list_push(arena, &dump, str8_lit("\n")); @@ -189,11 +198,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_SourceFiles) { str8_list_pushf(arena, &dump, "# SOURCE FILES\n"); - RDI_SourceFile *ptr = raddbg->source_files; - for(U32 i = 0; i < raddbg->source_files_count; i += 1, ptr += 1) + RDI_SourceFile *ptr = rdi->source_files; + for(U32 i = 0; i < rdi->source_files_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " source_file[%u]:\n", i); - rdi_stringize_source_file(arena, &dump, raddbg, ptr, 2); + rdi_stringize_source_file(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -203,11 +212,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_Units) { str8_list_pushf(arena, &dump, "# UNITS\n"); - RDI_Unit *ptr = raddbg->units; - for (U32 i = 0; i < raddbg->units_count; i += 1, ptr += 1) + RDI_Unit *ptr = rdi->units; + for (U32 i = 0; i < rdi->units_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " unit[%u]:\n", i); - rdi_stringize_unit(arena, &dump, raddbg, ptr, 2); + rdi_stringize_unit(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -217,8 +226,8 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_UnitVMap) { str8_list_pushf(arena, &dump, "# UNIT VMAP\n"); - RDI_VMapEntry *ptr = raddbg->unit_vmap; - for(U32 i = 0; i < raddbg->unit_vmap_count; i += 1, ptr += 1) + RDI_VMapEntry *ptr = rdi->unit_vmap; + for(U32 i = 0; i < rdi->unit_vmap_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); } @@ -229,11 +238,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_TypeNodes) { str8_list_pushf(arena, &dump, "# TYPE NODES:\n"); - RDI_TypeNode *ptr = raddbg->type_nodes; - for(U32 i = 0; i < raddbg->type_nodes_count; i += 1, ptr += 1) + RDI_TypeNode *ptr = rdi->type_nodes; + for(U32 i = 0; i < rdi->type_nodes_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " type[%u]:\n", i); - rdi_stringize_type_node(arena, &dump, raddbg, ptr, 2); + rdi_stringize_type_node(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -244,17 +253,17 @@ entry_point(CmdLine *cmd_line) { RDI_UDTMemberBundle member_bundle = {0}; { - member_bundle.members = raddbg->members; - member_bundle.enum_members = raddbg->enum_members; - member_bundle.member_count = raddbg->members_count; - member_bundle.enum_member_count = raddbg->enum_members_count; + member_bundle.members = rdi->members; + member_bundle.enum_members = rdi->enum_members; + member_bundle.member_count = rdi->members_count; + member_bundle.enum_member_count = rdi->enum_members_count; } str8_list_pushf(arena, &dump, "# UDTS:\n"); - RDI_UDT *ptr = raddbg->udts; - for(U32 i = 0; i < raddbg->udts_count; i += 1, ptr += 1) + RDI_UDT *ptr = rdi->udts; + for(U32 i = 0; i < rdi->udts_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " udt[%u]:\n", i); - rdi_stringize_udt(arena, &dump, raddbg, &member_bundle, ptr, 2); + rdi_stringize_udt(arena, &dump, rdi, &member_bundle, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -264,11 +273,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_GlobalVariables) { str8_list_pushf(arena, &dump, "# GLOBAL VARIABLES:\n"); - RDI_GlobalVariable *ptr = raddbg->global_variables; - for(U32 i = 0; i < raddbg->global_variables_count; i += 1, ptr += 1) + RDI_GlobalVariable *ptr = rdi->global_variables; + for(U32 i = 0; i < rdi->global_variables_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " global_variable[%u]:\n", i); - rdi_stringize_global_variable(arena, &dump, raddbg, ptr, 2); + rdi_stringize_global_variable(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -278,8 +287,8 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_GlobalVMap) { str8_list_pushf(arena, &dump, "# GLOBAL VMAP:\n"); - RDI_VMapEntry *ptr = raddbg->global_vmap; - for(U32 i = 0; i < raddbg->global_vmap_count; i += 1, ptr += 1) + RDI_VMapEntry *ptr = rdi->global_vmap; + for(U32 i = 0; i < rdi->global_vmap_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); } @@ -290,11 +299,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_ThreadVariables) { str8_list_pushf(arena, &dump, "# THREAD VARIABLES:\n"); - RDI_ThreadVariable *ptr = raddbg->thread_variables; - for(U32 i = 0; i < raddbg->thread_variables_count; i += 1, ptr += 1) + RDI_ThreadVariable *ptr = rdi->thread_variables; + for(U32 i = 0; i < rdi->thread_variables_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " thread_variable[%u]:\n", i); - rdi_stringize_thread_variable(arena, &dump, raddbg, ptr, 2); + rdi_stringize_thread_variable(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -304,11 +313,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_Procedures) { str8_list_pushf(arena, &dump, "# PROCEDURES:\n"); - RDI_Procedure *ptr = raddbg->procedures; - for(U32 i = 0; i < raddbg->procedures_count; i += 1, ptr += 1) + RDI_Procedure *ptr = rdi->procedures; + for(U32 i = 0; i < rdi->procedures_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " procedure[%u]:\n", i); - rdi_stringize_procedure(arena, &dump, raddbg, ptr, 2); + rdi_stringize_procedure(arena, &dump, rdi, ptr, 2); str8_list_push(arena, &dump, str8_lit("\n")); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -319,24 +328,24 @@ entry_point(CmdLine *cmd_line) { RDI_ScopeBundle scope_bundle = {0}; { - scope_bundle.scopes = raddbg->scopes; - scope_bundle.scope_count = raddbg->scopes_count; - scope_bundle.scope_voffs = raddbg->scope_voffs; - scope_bundle.scope_voff_count = raddbg->scope_voffs_count; - scope_bundle.locals = raddbg->locals; - scope_bundle.local_count = raddbg->locals_count; - scope_bundle.location_blocks = raddbg->location_blocks; - scope_bundle.location_block_count = raddbg->location_blocks_count; - scope_bundle.location_data = raddbg->location_data; - scope_bundle.location_data_size = raddbg->location_data_size; + scope_bundle.scopes = rdi->scopes; + scope_bundle.scope_count = rdi->scopes_count; + scope_bundle.scope_voffs = rdi->scope_voffs; + scope_bundle.scope_voff_count = rdi->scope_voffs_count; + scope_bundle.locals = rdi->locals; + scope_bundle.local_count = rdi->locals_count; + scope_bundle.location_blocks = rdi->location_blocks; + scope_bundle.location_block_count = rdi->location_blocks_count; + scope_bundle.location_data = rdi->location_data; + scope_bundle.location_data_size = rdi->location_data_size; } str8_list_pushf(arena, &dump, "# SCOPES:\n"); - RDI_Scope *ptr = raddbg->scopes; - for(U32 i = 0; i < raddbg->scopes_count; i += 1, ptr += 1) + RDI_Scope *ptr = rdi->scopes; + for(U32 i = 0; i < rdi->scopes_count; i += 1, ptr += 1) { if(ptr->parent_scope_idx == 0) { - rdi_stringize_scope(arena, &dump, raddbg, &scope_bundle, ptr, 1); + rdi_stringize_scope(arena, &dump, rdi, &scope_bundle, ptr, 1); str8_list_push(arena, &dump, str8_lit("\n")); } } @@ -347,8 +356,8 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_ScopeVMap) { str8_list_pushf(arena, &dump, "# SCOPE VMAP:\n"); - RDI_VMapEntry *ptr = raddbg->scope_vmap; - for(U32 i = 0; i < raddbg->scope_vmap_count; i += 1, ptr += 1) + RDI_VMapEntry *ptr = rdi->scope_vmap; + for(U32 i = 0; i < rdi->scope_vmap_count; i += 1, ptr += 1) { str8_list_pushf(arena, &dump, " 0x%08x: %llu\n", ptr->voff, ptr->idx); } @@ -359,11 +368,11 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_NameMaps) { str8_list_pushf(arena, &dump, "# NAME MAP:\n"); - RDI_NameMap *ptr = raddbg->name_maps; - for(U32 i = 0; i < raddbg->name_maps_count; i += 1, ptr += 1) + RDI_NameMap *ptr = rdi->name_maps; + for(U32 i = 0; i < rdi->name_maps_count; i += 1, ptr += 1) { RDI_ParsedNameMap name_map = {0}; - rdi_name_map_parse(raddbg, ptr, &name_map); + rdi_name_map_parse(rdi, ptr, &name_map); str8_list_pushf(arena, &dump, " name_map[%u]:\n", i); RDI_NameMapBucket *bucket = name_map.buckets; for(U32 j = 0; j < name_map.bucket_count; j += 1, bucket += 1) @@ -376,7 +385,7 @@ entry_point(CmdLine *cmd_line) for(;node < node_opl; node += 1) { String8 string = {0}; - string.str = rdi_string_from_idx(raddbg, node->string_idx, &string.size); + string.str = rdi_string_from_idx(rdi, node->string_idx, &string.size); str8_list_pushf(arena, &dump, " match \"%.*s\": ", str8_varg(string)); if(node->match_count == 1) { @@ -386,7 +395,7 @@ entry_point(CmdLine *cmd_line) { RDI_U32 idx_count = 0; RDI_U32 *idx_run = - rdi_idx_run_from_first_count(raddbg, node->match_idx_or_idx_run_first, + rdi_idx_run_from_first_count(rdi, node->match_idx_or_idx_run_first, node->match_count, &idx_count); if(idx_count > 0) { @@ -411,10 +420,10 @@ entry_point(CmdLine *cmd_line) if(dump_flags & DumpFlag_Strings) { str8_list_pushf(arena, &dump, "# STRINGS:\n"); - for(U64 string_idx = 0; string_idx < raddbg->string_count; string_idx += 1) + for(U64 string_idx = 0; string_idx < rdi->string_count; string_idx += 1) { String8 string = {0}; - string.str = rdi_string_from_idx(raddbg, string_idx, &string.size); + string.str = rdi_string_from_idx(rdi, string_idx, &string.size); str8_list_pushf(arena, &dump, " string[%I64u]: \"%S\"\n", string_idx, string); } str8_list_push(arena, &dump, str8_lit("\n")); @@ -428,4 +437,6 @@ entry_point(CmdLine *cmd_line) { fwrite(n->string.str, 1, n->string.size, stdout); } + + di_scope_close(di_scope); } diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf.c b/src/rdi_from_dwarf/rdi_dwarf.c similarity index 100% rename from src/raddbgi_from_dwarf/raddbgi_dwarf.c rename to src/rdi_from_dwarf/rdi_dwarf.c diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf.h b/src/rdi_from_dwarf/rdi_dwarf.h similarity index 99% rename from src/raddbgi_from_dwarf/raddbgi_dwarf.h rename to src/rdi_from_dwarf/rdi_dwarf.h index 186f0486..273ae521 100644 --- a/src/raddbgi_from_dwarf/raddbgi_dwarf.h +++ b/src/rdi_from_dwarf/rdi_dwarf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_DWARF_H -#define RADDBGI_DWARF_H +#ifndef RDI_DWARF_H +#define RDI_DWARF_H // https://dwarfstd.org/doc/DWARF4.pdf // https://dwarfstd.org/doc/DWARF5.pdf @@ -1489,5 +1489,5 @@ static String8 dwarf_string_from_line_ext_op(DWARF_LineExtOp op); static String8 dwarf_string_from_line_entry_format(DWARF_LineEntryFormat format); static String8 dwarf_string_from_section_code(DWARF_SectionCode sec_code); -#endif //RADDBGI_DWARF_H +#endif //RDI_DWARF_H diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.c b/src/rdi_from_dwarf/rdi_dwarf_stringize.c similarity index 100% rename from src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.c rename to src/rdi_from_dwarf/rdi_dwarf_stringize.c diff --git a/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h b/src/rdi_from_dwarf/rdi_dwarf_stringize.h similarity index 87% rename from src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h rename to src/rdi_from_dwarf/rdi_dwarf_stringize.h index d8cd9e87..0fa77da1 100644 --- a/src/raddbgi_from_dwarf/raddbgi_dwarf_stringize.h +++ b/src/rdi_from_dwarf/rdi_dwarf_stringize.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_DWARF_STRINGIZE_H -#define RADDBGI_DWARF_STRINGIZE_H +#ifndef RDI_DWARF_STRINGIZE_H +#define RDI_DWARF_STRINGIZE_H //////////////////////////////// //~ DWARF Stringize Functions @@ -25,4 +25,4 @@ dwarf_stringize_addr(Arena *arena, String8List *out, DWARF_AddrUnit *unit, U32 i -#endif //RADDBGI_DWARF_STRINGIZE_H +#endif //RDI_DWARF_STRINGIZE_H diff --git a/src/raddbgi_from_dwarf/raddbgi_elf.c b/src/rdi_from_dwarf/rdi_elf.c similarity index 100% rename from src/raddbgi_from_dwarf/raddbgi_elf.c rename to src/rdi_from_dwarf/rdi_elf.c diff --git a/src/raddbgi_from_dwarf/raddbgi_elf.h b/src/rdi_from_dwarf/rdi_elf.h similarity index 99% rename from src/raddbgi_from_dwarf/raddbgi_elf.h rename to src/rdi_from_dwarf/rdi_elf.h index 99882ec4..ae0bf781 100644 --- a/src/raddbgi_from_dwarf/raddbgi_elf.h +++ b/src/rdi_from_dwarf/rdi_elf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_ELF_H -#define RADDBGI_ELF_H +#ifndef RDI_ELF_H +#define RDI_ELF_H // https://refspecs.linuxfoundation.org/elf/elf.pdf @@ -514,4 +514,4 @@ static String8 elf_string_from_symbol_binding(ELF_SymbolBinding binding); static String8 elf_string_from_symbol_type(ELF_SymbolType type); static String8 elf_string_from_symbol_visibility(ELF_SymbolVisibility visibility); -#endif //RADDBGI_ELF_H +#endif //RDI_ELF_H diff --git a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.c b/src/rdi_from_dwarf/rdi_from_dwarf.c similarity index 98% rename from src/raddbgi_from_dwarf/raddbgi_from_dwarf.c rename to src/rdi_from_dwarf/rdi_from_dwarf.c index e8607272..6c89740f 100644 --- a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.c +++ b/src/rdi_from_dwarf/rdi_from_dwarf.c @@ -1,27 +1,27 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include "lib_raddbgi_format/raddbgi_format.h" +#include "lib_rdi_format/rdi_format.h" #include "base/base_inc.h" #include "os/os_inc.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" -#include "raddbgi_elf.h" -#include "raddbgi_dwarf.h" +#include "rdi_elf.h" +#include "rdi_dwarf.h" -#include "raddbgi_dwarf_stringize.h" +#include "rdi_dwarf_stringize.h" -#include "raddbgi_from_dwarf.h" +#include "rdi_from_dwarf.h" -#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_rdi_format/rdi_format.c" #include "base/base_inc.c" #include "os/os_inc.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" -#include "raddbgi_elf.c" -#include "raddbgi_dwarf.c" +#include "rdi_elf.c" +#include "rdi_dwarf.c" -#include "raddbgi_dwarf_stringize.c" +#include "rdi_dwarf_stringize.c" // TODO(allen): // [ ] need sample data for .debug_names diff --git a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.h b/src/rdi_from_dwarf/rdi_from_dwarf.h similarity index 91% rename from src/raddbgi_from_dwarf/raddbgi_from_dwarf.h rename to src/rdi_from_dwarf/rdi_from_dwarf.h index 82052c44..bf9689c9 100644 --- a/src/raddbgi_from_dwarf/raddbgi_from_dwarf.h +++ b/src/rdi_from_dwarf/rdi_from_dwarf.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_FROM_DWARF_H -#define RADDBGI_FROM_DWARF_H +#ifndef RDI_FROM_DWARF_H +#define RDI_FROM_DWARF_H //////////////////////////////// //~ Program Parameters Type @@ -47,4 +47,4 @@ static DWARFCONV_Params *dwarf_convert_params_from_cmd_line(Arena *arena, CmdLin -#endif //RADDBGI_FROM_DWARF_H +#endif //RDI_FROM_DWARF_H diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.c b/src/rdi_from_pdb/rdi_from_pdb.c similarity index 99% rename from src/raddbgi_from_pdb/raddbgi_from_pdb.c rename to src/rdi_from_pdb/rdi_from_pdb.c index a85e1105..8ea57171 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.c +++ b/src/rdi_from_pdb/rdi_from_pdb.c @@ -147,7 +147,7 @@ Case("source_path_name_map",NormalSourcePathNameMap)\ } //////////////////////////////// -//~ rjf: COFF <-> RADDBGI Canonical Conversions +//~ rjf: COFF <-> RDI Canonical Conversions internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) @@ -169,7 +169,7 @@ p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags) } //////////////////////////////// -//~ rjf: CodeView <-> RADDBGI Canonical Conversions +//~ rjf: CodeView <-> RDI Canonical Conversions internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch cv_arch) @@ -2935,7 +2935,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: types pass 2: produce per-itype itype chain // // this pass is to ensure that subsequent passes always produce types for - // dependent itypes first - guaranteeing raddbgi's "only reference backward" + // dependent itypes first - guaranteeing rdi's "only reference backward" // rule (which eliminates cycles). each itype slot gets a list of itypes, // starting with the deepest dependency - when types are produced per-itype, // this chain is walked, so that deeper dependencies are built first, and @@ -2974,7 +2974,7 @@ p2r_convert(Arena *arena, P2R_User2Convert *in) //- rjf: types pass 3: construct all types from TPI // // this doesn't gather struct/class/union/enum members, which is done by - // subsequent passes, to build RADDBGI "UDT" information, which is distinct + // subsequent passes, to build RDI "UDT" information, which is distinct // from regular type info. // RDIM_Type **itype_type_ptrs = 0; diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb.h b/src/rdi_from_pdb/rdi_from_pdb.h similarity index 98% rename from src/raddbgi_from_pdb/raddbgi_from_pdb.h rename to src/rdi_from_pdb/rdi_from_pdb.h index 226c0bde..088d4521 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb.h +++ b/src/rdi_from_pdb/rdi_from_pdb.h @@ -1,8 +1,8 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef RADDBGI_FROM_PDB_H -#define RADDBGI_FROM_PDB_H +#ifndef RDI_FROM_PDB_H +#define RDI_FROM_PDB_H //////////////////////////////// //~ rjf: Export Artifact Flags @@ -514,12 +514,12 @@ internal U64 p2r_hash_from_voff(U64 voff); internal P2R_User2Convert *p2r_user2convert_from_cmdln(Arena *arena, CmdLine *cmdline); //////////////////////////////// -//~ rjf: COFF => RADDBGI Canonical Conversions +//~ rjf: COFF => RDI Canonical Conversions internal RDI_BinarySectionFlags p2r_rdi_binary_section_flags_from_coff_section_flags(COFF_SectionFlags flags); //////////////////////////////// -//~ rjf: CodeView => RADDBGI Canonical Conversions +//~ rjf: CodeView => RDI Canonical Conversions internal RDI_Arch p2r_rdi_arch_from_cv_arch(CV_Arch arch); internal RDI_RegisterCode p2r_rdi_reg_code_from_cv_reg_code(RDI_Arch arch, CV_Reg reg_code); @@ -626,4 +626,4 @@ internal P2R_Bake2Serialize *p2r_bake(Arena *arena, P2R_Convert2Bake *in); internal P2R_Bake2Serialize *p2r_compress(Arena *arena, P2R_Bake2Serialize *in); -#endif // RADDBGI_FROM_PDB_H +#endif // RDI_FROM_PDB_H diff --git a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c b/src/rdi_from_pdb/rdi_from_pdb_main.c similarity index 91% rename from src/raddbgi_from_pdb/raddbgi_from_pdb_main.c rename to src/rdi_from_pdb/rdi_from_pdb_main.c index fbf5a91c..75eb0723 100644 --- a/src/raddbgi_from_pdb/raddbgi_from_pdb_main.c +++ b/src/rdi_from_pdb/rdi_from_pdb_main.c @@ -8,15 +8,15 @@ #define BUILD_VERSION_MINOR 9 #define BUILD_VERSION_PATCH 10 #define BUILD_RELEASE_PHASE_STRING_LITERAL "ALPHA" -#define BUILD_TITLE "raddbgi_from_pdb" +#define BUILD_TITLE "rdi_from_pdb" #define BUILD_CONSOLE_INTERFACE 1 //////////////////////////////// //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format.c" #include "third_party/rad_lzb_simple/rad_lzb_simple.h" #include "third_party/rad_lzb_simple/rad_lzb_simple.c" @@ -24,27 +24,27 @@ #include "base/base_inc.h" #include "os/os_inc.h" #include "task_system/task_system.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "coff/coff.h" #include "codeview/codeview.h" #include "codeview/codeview_stringize.h" #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb.h" +#include "rdi_from_pdb.h" //- rjf: [c] #include "base/base_inc.c" #include "os/os_inc.c" #include "task_system/task_system.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "coff/coff.c" #include "codeview/codeview.c" #include "codeview/codeview_stringize.c" #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb.c" +#include "rdi_from_pdb.c" //////////////////////////////// //~ rjf: Entry Point @@ -62,7 +62,7 @@ entry_point(CmdLine *cmdline) //- rjf: display help if(do_help || user2convert->errors.node_count != 0) { - fprintf(stderr, "--- raddbgi_from_pdb ----------------------------------------------------------\n\n"); + fprintf(stderr, "--- rdi_from_pdb --------------------------------------------------------------\n\n"); fprintf(stderr, "This utility converts debug information from PDBs into the RAD Debug Info.\n"); fprintf(stderr, "format. The following arguments are accepted:\n\n"); diff --git a/src/raddbgi_make_local/raddbgi_make_local.c b/src/rdi_make_local/rdi_make_local.c similarity index 72% rename from src/raddbgi_make_local/raddbgi_make_local.c rename to src/rdi_make_local/rdi_make_local.c index 7e476d6c..981c819e 100644 --- a/src/raddbgi_make_local/raddbgi_make_local.c +++ b/src/rdi_make_local/rdi_make_local.c @@ -1,4 +1,4 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include "lib_raddbgi_make/raddbgi_make.c" +#include "lib_rdi_make/rdi_make.c" diff --git a/src/raddbgi_make_local/raddbgi_make_local.h b/src/rdi_make_local/rdi_make_local.h similarity index 97% rename from src/raddbgi_make_local/raddbgi_make_local.h rename to src/rdi_make_local/rdi_make_local.h index d4201e24..873cee30 100644 --- a/src/raddbgi_make_local/raddbgi_make_local.h +++ b/src/rdi_make_local/rdi_make_local.h @@ -45,6 +45,6 @@ #define RDIM_ProfBegin(...) ProfBeginDynamic(__VA_ARGS__) #define RDIM_ProfEnd(...) ProfEnd() -#include "lib_raddbgi_make/raddbgi_make.h" +#include "lib_rdi_make/rdi_make.h" #endif // RDI_CONS_LOCAL_H diff --git a/src/regs/raddbgi/generated/regs_raddbgi.meta.c b/src/regs/rdi/generated/regs_rdi.meta.c similarity index 100% rename from src/regs/raddbgi/generated/regs_raddbgi.meta.c rename to src/regs/rdi/generated/regs_rdi.meta.c diff --git a/src/regs/raddbgi/generated/regs_raddbgi.meta.h b/src/regs/rdi/generated/regs_rdi.meta.h similarity index 65% rename from src/regs/raddbgi/generated/regs_raddbgi.meta.h rename to src/regs/rdi/generated/regs_rdi.meta.h index 4082c723..30461e08 100644 --- a/src/regs/raddbgi/generated/regs_raddbgi.meta.h +++ b/src/regs/rdi/generated/regs_rdi.meta.h @@ -3,10 +3,10 @@ //- GENERATED CODE -#ifndef REGS_RADDBGI_META_H -#define REGS_RADDBGI_META_H +#ifndef REGS_RDI_META_H +#define REGS_RDI_META_H C_LINKAGE_BEGIN C_LINKAGE_END -#endif // REGS_RADDBGI_META_H +#endif // REGS_RDI_META_H diff --git a/src/regs/raddbgi/regs_raddbgi.c b/src/regs/rdi/regs_rdi.c similarity index 67% rename from src/regs/raddbgi/regs_raddbgi.c rename to src/regs/rdi/regs_rdi.c index b72739f4..1e130772 100644 --- a/src/regs/raddbgi/regs_raddbgi.c +++ b/src/regs/rdi/regs_rdi.c @@ -1,4 +1,4 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#include "regs/raddbgi/generated/regs_raddbgi.meta.c" +#include "regs/rdi/generated/regs_rdi.meta.c" diff --git a/src/regs/raddbgi/regs_raddbgi.h b/src/regs/rdi/regs_rdi.h similarity index 81% rename from src/regs/raddbgi/regs_raddbgi.h rename to src/regs/rdi/regs_rdi.h index 4049a5b1..72a52ce6 100644 --- a/src/regs/raddbgi/regs_raddbgi.h +++ b/src/regs/rdi/regs_rdi.h @@ -1,10 +1,10 @@ // Copyright (c) 2024 Epic Games Tools // Licensed under the MIT license (https://opensource.org/license/mit/) -#ifndef REGS_RADDBGI_H -#define REGS_RADDBGI_H +#ifndef REGS_RDI_H +#define REGS_RDI_H internal RDI_RegisterCode regs_rdi_code_from_arch_reg_code(Architecture arch, REGS_RegCode code); internal REGS_RegCode regs_reg_code_from_arch_rdi_code(Architecture arch, RDI_RegisterCode reg); -#endif //REGS_RADDBGI_H +#endif //REGS_RDI_H diff --git a/src/regs/raddbgi/regs_raddbgi.mdesk b/src/regs/rdi/regs_rdi.mdesk similarity index 100% rename from src/regs/raddbgi/regs_raddbgi.mdesk rename to src/regs/rdi/regs_rdi.mdesk diff --git a/src/regs/regs.c b/src/regs/regs.c index 028cd559..6d701480 100644 --- a/src/regs/regs.c +++ b/src/regs/regs.c @@ -13,7 +13,7 @@ internal U64 regs_rip_from_arch_block(Architecture arch, void *block) { U64 result = 0; - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{result = ((REGS_RegBlockX64 *)block)->rip.u64;}break; @@ -26,7 +26,7 @@ internal U64 regs_rsp_from_arch_block(Architecture arch, void *block) { U64 result = 0; - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{result = ((REGS_RegBlockX64 *)block)->rsp.u64;}break; @@ -38,7 +38,7 @@ regs_rsp_from_arch_block(Architecture arch, void *block) internal void regs_arch_block_write_rip(Architecture arch, void *block, U64 rip) { - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{((REGS_RegBlockX64 *)block)->rip.u64 = rip;}break; @@ -49,7 +49,7 @@ regs_arch_block_write_rip(Architecture arch, void *block, U64 rip) internal void regs_arch_block_write_rsp(Architecture arch, void *block, U64 rsp) { - switch(arch) + if(block != 0) switch(arch) { default:{}break; case Architecture_x64:{((REGS_RegBlockX64 *)block)->rsp.u64 = rsp;}break; diff --git a/src/render/d3d11/render_d3d11.cpp b/src/render/d3d11/render_d3d11.cpp index 30205966..eef97d94 100644 --- a/src/render/d3d11/render_d3d11.cpp +++ b/src/render/d3d11/render_d3d11.cpp @@ -496,7 +496,7 @@ r_window_equip(OS_Handle handle) os_graphical_message(1, str8_lit("Fatal Error"), str8_cstring(buffer)); os_exit_process(1); } - + r_d3d11_state->dxgi_factory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); //- rjf: create framebuffer & view @@ -841,18 +841,13 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) Vec2S32 resolution = {(S32)(client_rect.x1 - client_rect.x0), (S32)(client_rect.y1 - client_rect.y0)}; //- rjf: resolution change + B32 resize_done = 0; if(wnd->last_resolution.x != resolution.x || wnd->last_resolution.y != resolution.y) { + resize_done = 1; wnd->last_resolution = resolution; - // rjf: resize swapchain & main framebuffer - wnd->framebuffer_rtv->Release(); - wnd->framebuffer->Release(); - wnd->swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0); - wnd->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&wnd->framebuffer)); - r_d3d11_state->device->CreateRenderTargetView(wnd->framebuffer, 0, &wnd->framebuffer_rtv); - // rjf: release screen-sized render target resources, if there if(wnd->stage_scratch_color_srv){wnd->stage_scratch_color_srv->Release();} if(wnd->stage_scratch_color_rtv){wnd->stage_scratch_color_rtv->Release();} @@ -867,6 +862,13 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) if(wnd->geo3d_depth_dsv) {wnd->geo3d_depth_dsv->Release();} if(wnd->geo3d_depth) {wnd->geo3d_depth->Release();} + // rjf: resize swapchain & main framebuffer + wnd->framebuffer_rtv->Release(); + wnd->framebuffer->Release(); + wnd->swapchain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0); + wnd->swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)(&wnd->framebuffer)); + r_d3d11_state->device->CreateRenderTargetView(wnd->framebuffer, 0, &wnd->framebuffer_rtv); + // rjf: create stage color targets { D3D11_TEXTURE2D_DESC color_desc = {}; @@ -946,6 +948,10 @@ r_window_begin_frame(OS_Handle window, R_Handle window_equip) Vec4F32 clear_color = {0, 0, 0, 0}; d_ctx->ClearRenderTargetView(wnd->framebuffer_rtv, clear_color.v); d_ctx->ClearRenderTargetView(wnd->stage_color_rtv, clear_color.v); + if(resize_done) + { + d_ctx->Flush(); + } } ProfEnd(); } diff --git a/src/scratch/ryan_scratch.c b/src/scratch/ryan_scratch.c index 0d49c41e..1087cf13 100644 --- a/src/scratch/ryan_scratch.c +++ b/src/scratch/ryan_scratch.c @@ -15,16 +15,16 @@ //~ rjf: Includes //- rjf: [lib] -#include "lib_raddbgi_format/raddbgi_format.h" -#include "lib_raddbgi_format/raddbgi_format_parse.h" -#include "lib_raddbgi_format/raddbgi_format.c" -#include "lib_raddbgi_format/raddbgi_format_parse.c" +#include "lib_rdi_format/rdi_format.h" +#include "lib_rdi_format/rdi_format_parse.h" +#include "lib_rdi_format/rdi_format.c" +#include "lib_rdi_format/rdi_format_parse.c" //- rjf: [h] #include "base/base_inc.h" #include "os/os_inc.h" #include "task_system/task_system.h" -#include "raddbgi_make_local/raddbgi_make_local.h" +#include "rdi_make_local/rdi_make_local.h" #include "mdesk/mdesk.h" #include "hash_store/hash_store.h" #include "file_stream/file_stream.h" @@ -38,9 +38,9 @@ #include "msf/msf.h" #include "pdb/pdb.h" #include "pdb/pdb_stringize.h" -#include "raddbgi_from_pdb/raddbgi_from_pdb.h" +#include "rdi_from_pdb/rdi_from_pdb.h" #include "regs/regs.h" -#include "regs/raddbgi/regs_raddbgi.h" +#include "regs/rdi/regs_rdi.h" #include "type_graph/type_graph.h" #include "dbgi/dbgi.h" #include "demon/demon_inc.h" @@ -52,7 +52,7 @@ #include "base/base_inc.c" #include "os/os_inc.c" #include "task_system/task_system.c" -#include "raddbgi_make_local/raddbgi_make_local.c" +#include "rdi_make_local/rdi_make_local.c" #include "mdesk/mdesk.c" #include "hash_store/hash_store.c" #include "file_stream/file_stream.c" @@ -66,9 +66,9 @@ #include "msf/msf.c" #include "pdb/pdb.c" #include "pdb/pdb_stringize.c" -#include "raddbgi_from_pdb/raddbgi_from_pdb.c" +#include "rdi_from_pdb/rdi_from_pdb.c" #include "regs/regs.c" -#include "regs/raddbgi/regs_raddbgi.c" +#include "regs/rdi/regs_rdi.c" #include "type_graph/type_graph.c" #include "dbgi/dbgi.c" #include "demon/demon_inc.c" diff --git a/src/text_cache/text_cache.c b/src/text_cache/text_cache.c index 18e21dc5..11924354 100644 --- a/src/text_cache/text_cache.c +++ b/src/text_cache/text_cache.c @@ -17,6 +17,12 @@ txt_lang_kind_from_extension(String8 extension) str8_match(extension, str8_lit("cxx"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("cc"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("c++"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("ixx"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cxxm"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("c++m"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("ccm"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("cppm"), StringMatchFlag_CaseInsensitive) || + str8_match(extension, str8_lit("mpp"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("C"), 0) || str8_match(extension, str8_lit("hpp"), StringMatchFlag_CaseInsensitive) || str8_match(extension, str8_lit("hxx"), StringMatchFlag_CaseInsensitive) || diff --git a/src/unwind/unwind.c b/src/unwind/unwind.c deleted file mode 100644 index f0d6916e..00000000 --- a/src/unwind/unwind.c +++ /dev/null @@ -1,859 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -//////////////////////////////// -//~ rjf: Memory View Helpers - -internal UNW_MemView -unw_memview_from_data(String8 data, U64 base_vaddr) -{ - UNW_MemView result = {0}; - result.data = data.str; - result.addr_first = base_vaddr; - result.addr_opl = base_vaddr + data.size; - return result; -} - -internal B32 -unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out) -{ - B32 result = 0; - if(memview->addr_first <= addr && addr + size <= memview->addr_opl) - { - MemoryCopy(out, (U8*)memview->data + addr - memview->addr_first, size); - result = 1; - } - return result; -} - -//////////////////////////////// -//~ rjf: PE/X64 Unwind Implementation - -//- rjf: helpers - -internal UNW_Step -unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView*memview, REGS_RegBlockX64 *regs) -{ - UNW_Step result = {0}; - U64 missed_read_addr = 0; - - //- setup parsing context - U64 ip_voff = regs->rip.u64 - base_vaddr; - U64 sec_number = pe_section_num_from_voff(bindata, bin, ip_voff); - COFF_SectionHeader *sec = coff_section_header_from_num(bindata, bin->section_array_off, sec_number); - void* inst_base = pe_ptr_from_section_num(bindata, bin, sec_number); - U64 inst_size = sec->vsize; - - //- setup parsing variables - B32 keep_parsing = 1; - U64 off = ip_voff - sec->voff; - - - //- parsing loop - for(;keep_parsing;) - { - keep_parsing = 0; - - U8 inst_byte = 0; - if(off + sizeof(inst_byte) <= inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); - } - off += 1; - - U8 rex = 0; - if((inst_byte & 0xF0) == 0x40) - { - rex = inst_byte & 0xF; // rex prefix - if(off + sizeof(inst_base) <= inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); - } - off += 1; - } - - switch(inst_byte) - { - // pop - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - { - U64 sp = regs->rsp.u64; - U64 value = 0; - if(!unw_memview_read_struct(memview, sp, &value)) - { - missed_read_addr = sp; - goto error_out; - } - - // modify register - PE_UnwindGprRegX64 gpr_reg = (inst_byte - 0x58) + (rex & 1)*8; - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); - - // not a final instruction - keep_parsing = 1; - - // commit registers - reg->u64 = value; - regs->rsp.u64 = sp + 8; - }break; - - // add $nnnn,%rsp - case 0x81: - { - // skip one byte (we already know what it is in this scenario) - off += 1; - - // read the 4-byte immediate - S32 imm = 0; - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - off += 4; - - // not a final instruction - keep_parsing = 1; - - // update stack pointer - regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); - }break; - - // add $n,%rsp - case 0x83: - { - // skip one byte (we already know what it is in this scenario) - off += 1; - - // read the 1-byte immediate - S8 imm = 0; - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - off += 1; - - // update stack pointer - regs->rsp.u64 = (U64)(regs->rsp.u64 + imm); - keep_parsing = 1; - }break; - - // lea imm8/imm32,$rsp - case 0x8D: - { - // read source register - U8 modrm = 0; - if(off + sizeof(modrm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&modrm, ptr, sizeof(modrm)); - } - PE_UnwindGprRegX64 gpr_reg = (modrm & 7) + (rex & 1)*8; - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, gpr_reg); - U64 reg_value = reg->u64; - - // advance to the immediate - off += 1; - - S32 imm = 0; - // read 1-byte immediate - if((modrm >> 6) == 1) - { - S8 imm8 = 0; - if(off + sizeof(imm8) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm8, ptr, sizeof(imm8)); - } - imm = imm8; - off += 1; - } - - // read 4-byte immediate - else - { - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - off += 4; - } - - regs->rsp.u64 = (U64)(reg_value + imm); - keep_parsing = 1; - }break; - - // ret $nn - case 0xC2: - { - // read new ip - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // read 2-byte immediate & advance stack pointer - U16 imm = 0; - if(off + sizeof(imm) < inst_size) - { - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - U64 new_sp = sp + 8 + imm; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - }break; - - // ret / rep; ret - case 0xF3: - { - Assert(!"Hit me!"); - } - case 0xC3: - { - // read new ip - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - }break; - - // jmp nnnn - case 0xE9: - { - Assert(!"Hit Me"); - // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done - // we don't have any cases to exercise this right now. no guess implementation! - }break; - - // jmp n - case 0xEB: - { - Assert(!"Hit Me"); - // TODO(allen): general idea: read the immediate, move the ip, leave the sp, done - // we don't have any cases to exercise this right now. no guess implementation! - }break; - } - - } - - error_out:; - - if(missed_read_addr != 0) - { - result.dead = 1; - result.missed_read = 1; - result.missed_read_addr = missed_read_addr; - } - - return(result); -} - -internal B32 -unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, U64 voff, PE_IntelPdata *final_pdata) -{ - // NOTE(allen): There are restrictions placed on how an epilog is allowed - // to be formed (https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog?view=msvc-160) - // Here we interpret machine code directly according to the rules - // given there to determine if the code we're looking at looks like an epilog. - - // TODO(allen): Figure out how to verify this. - - //- setup parsing context - U64 sec_number = pe_section_num_from_voff(bindata, bin, voff); - COFF_SectionHeader *sec = coff_section_header_from_num(bindata, bin->section_array_off, sec_number); - void* inst_base = pe_ptr_from_section_num(bindata, bin, sec_number); - U64 inst_size = sec->vsize; - - //- setup parsing variables - B32 is_epilog = 0; - B32 keep_parsing = 1; - U64 off = voff - sec->voff; - - //- check first instruction - { - B32 inst_read_success = 0; - U8 inst[4]; - if (off + sizeof(inst) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst, ptr, sizeof(inst)); - inst_read_success = 1; - } - - if (!inst_read_success){ - keep_parsing = 0; - } - else{ - if ((inst[0] & 0xF8) == 0x48){ - switch (inst[1]){ - // add $nnnn,%rsp - case 0x81: - { - if (inst[0] == 0x48 && inst[2] == 0xC4){ - off += 7; - } - else{ - keep_parsing = 0; - } - }break; - - // add $n,%rsp - case 0x83: - { - if (inst[0] == 0x48 && inst[2] == 0xC4){ - off += 4; - } - else{ - keep_parsing = 0; - } - }break; - - // lea n(reg),%rsp - case 0x8D: - { - if ((inst[0] & 0x06) == 0 && - ((inst[2] >> 3) & 0x07) == 0x04 && - (inst[2] & 0x07) != 0x04){ - U8 imm_size = (inst[2] >> 6); - // 1-byte immediate - if (imm_size == 1){ - off += 4; - } - // 4-byte immediate - else if (imm_size == 2){ - off += 7; - } - else{ - keep_parsing = 0; - } - } - else{ - keep_parsing = 0; - } - }break; - } - } - } - } - - //- parsing loop - if (keep_parsing){ - for (;;){ - // read inst - U8 inst_byte = 0; - if (off + sizeof(inst_byte) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&inst_byte, ptr, sizeof(inst_byte)); - } - else{ - goto loop_break; - } - - // when (... I don't know ...) rely on the next byte - U64 check_off = off; - U8 check_inst_byte = inst_byte; - if ((inst_byte & 0xF0) == 0x40){ - check_off = off + 1; - if (off + sizeof(check_inst_byte) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&check_inst_byte, ptr, sizeof(check_inst_byte)); - } - else{ - goto loop_break; - } - } - - switch (check_inst_byte){ - // pop - case 0x58:case 0x59:case 0x5A:case 0x5B: - case 0x5C:case 0x5D:case 0x5E:case 0x5F: - { - off = check_off + 1; - }break; - - // ret - case 0xC2:case 0xC3: - { - is_epilog = 1; - goto loop_break; - }break; - - // jmp nnnn - case 0xE9: - { - U64 imm_off = check_off + 1; - S32 imm = 0; - if (off + sizeof(imm) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&imm, ptr, sizeof(imm)); - } - else{ - goto loop_break; - } - - U64 next_off = (U64)(imm_off + sizeof(imm) + imm); - if (!(final_pdata->voff_first <= next_off && next_off < final_pdata->voff_one_past_last)){ - goto loop_break; - } - - off = next_off; - // TODO(allen): why isn't this just the end of the epilog? - }break; - - // rep; ret (for amd64 prediction bug) - case 0xF3: - { - U8 next_inst_byte = 0; - if (off + sizeof(next_inst_byte) < inst_size){ - void *ptr = (U8*)inst_base + off; - MemoryCopy(&next_inst_byte, ptr, sizeof(next_inst_byte)); - } - is_epilog = (next_inst_byte == 0xC3); - goto loop_break; - }break; - - default: goto loop_break; - } - } - - loop_break:; - } - - //- fill result - B32 result = is_epilog; - return(result); -} - -internal REGS_Reg64* -unw_pe_x64__gpr_reg(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 unw_reg){ - static REGS_Reg64 dummy = {0}; - REGS_Reg64 *result = &dummy; - switch (unw_reg){ - case PE_UnwindGprRegX64_RAX: result = ®s->rax; break; - case PE_UnwindGprRegX64_RCX: result = ®s->rcx; break; - case PE_UnwindGprRegX64_RDX: result = ®s->rdx; break; - case PE_UnwindGprRegX64_RBX: result = ®s->rbx; break; - case PE_UnwindGprRegX64_RSP: result = ®s->rsp; break; - case PE_UnwindGprRegX64_RBP: result = ®s->rbp; break; - case PE_UnwindGprRegX64_RSI: result = ®s->rsi; break; - case PE_UnwindGprRegX64_RDI: result = ®s->rdi; break; - case PE_UnwindGprRegX64_R8 : result = ®s->r8 ; break; - case PE_UnwindGprRegX64_R9 : result = ®s->r9 ; break; - case PE_UnwindGprRegX64_R10: result = ®s->r10; break; - case PE_UnwindGprRegX64_R11: result = ®s->r11; break; - case PE_UnwindGprRegX64_R12: result = ®s->r12; break; - case PE_UnwindGprRegX64_R13: result = ®s->r13; break; - case PE_UnwindGprRegX64_R14: result = ®s->r14; break; - case PE_UnwindGprRegX64_R15: result = ®s->r15; break; - } - return(result); -} - -//- rjf: unwind step - -internal UNW_Step -unw_unwind_pe_x64(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs) -{ - UNW_Step result = {0}; - U64 missed_read_addr = 0; - - //- grab ip_voff (several places can use this) - U64 ip_voff = regs->rip.u64 - base_vaddr; - - //- get pdata entry from current ip - PE_IntelPdata *initial_pdata = 0; - { - U64 initial_pdata_off = pe_intel_pdata_off_from_voff__binary_search(bindata, bin, ip_voff); - if(initial_pdata_off != 0) - { - initial_pdata = (PE_IntelPdata*)(bindata.str + initial_pdata_off); - } - } - - //- no pdata; unwind by reading stack pointer - if(initial_pdata == 0) - { - // read ip from stack pointer - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - //- got pdata; perform unwinding with exception handling - else - { - // try epilog unwind - B32 did_epilog_unwind = 0; - if(unw_pe_x64__voff_is_in_epilog(bindata, bin, ip_voff, initial_pdata)) - { - result = unw_pe_x64__epilog(bindata, bin, base_vaddr, memview, regs); - did_epilog_unwind = 1; - } - - // try xdata unwind - if(!did_epilog_unwind) - { - B32 did_machframe = 0; - - // get frame reg - REGS_Reg64 *frame_reg = 0; - U64 frame_off = 0; - - { - U64 unwind_info_off = initial_pdata->voff_unwind_info; - PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - - U32 frame_reg_id = PE_UNWIND_INFO_REG_FROM_FRAME(unwind_info->frame); - U64 frame_off_val = PE_UNWIND_INFO_OFF_FROM_FRAME(unwind_info->frame); - - if (frame_reg_id != 0){ - frame_reg = unw_pe_x64__gpr_reg(regs, frame_reg_id); - // TODO(allen): at this point if frame_reg is zero, the exe is corrupted. - } - frame_off = frame_off_val; - } - - PE_IntelPdata *last_pdata = 0; - PE_IntelPdata *pdata = initial_pdata; - for (;pdata != last_pdata;) - { - //- rjf: unpack unwind info & codes - U64 unwind_info_off = pdata->voff_unwind_info; - PE_UnwindInfo *unwind_info = (PE_UnwindInfo*)(pe_ptr_from_voff(bindata, bin, unwind_info_off)); - PE_UnwindCode *unwind_codes = (PE_UnwindCode*)(unwind_info + 1); - - //- rjf: unpack frame base - U64 frame_base = regs->rsp.u64; - if(frame_reg != 0) - { - U64 raw_frame_base = frame_reg->u64; - U64 adjusted_frame_base = raw_frame_base - frame_off*16; - if(adjusted_frame_base < raw_frame_base) - { - frame_base = adjusted_frame_base; - } - else - { - frame_base = 0; - } - } - - //- rjf: bad unwind info -> abort - if(unwind_info == 0) - { - result.dead = 1; - goto error_out; - } - - //- op code interpreter - PE_UnwindCode *code_ptr = unwind_codes; - PE_UnwindCode *code_opl = unwind_codes + unwind_info->codes_num; - for(PE_UnwindCode *next_code_ptr = 0; code_ptr < code_opl; code_ptr = next_code_ptr) - { - // extract op code parts - U32 op_code = PE_UNWIND_OPCODE_FROM_FLAGS(code_ptr->flags); - U32 op_info = PE_UNWIND_INFO_FROM_FLAGS(code_ptr->flags); - - // determine number of op code slots - U32 slot_count = pe_slot_count_from_unwind_op_code(op_code); - if(op_code == PE_UnwindOpCode_ALLOC_LARGE && op_info == 1) - { - slot_count += 1; - } - - // check op code slot count - if (slot_count == 0 || code_ptr + slot_count > code_opl){ - result.dead = 1; - goto end_xdata_unwind; - } - - // set next op code pointer - next_code_ptr = code_ptr + slot_count; - - // interpret this op code - U64 code_voff = pdata->voff_first + code_ptr->off_in_prolog; - if (code_voff <= ip_voff){ - switch (op_code){ - case PE_UnwindOpCode_PUSH_NONVOL: - { - // read value from stack pointer - U64 sp = regs->rsp.u64; - U64 value = 0; - if(!unw_memview_read_struct(memview, sp, &value)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - regs->rsp.u64 = new_sp; - }break; - - case PE_UnwindOpCode_ALLOC_LARGE: - { - // read alloc size - U64 size = 0; - if (op_info == 0){ - size = code_ptr[1].u16*8; - } - else if (op_info == 1){ - size = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - } - else{ - result.dead = 1; - goto end_xdata_unwind; - } - - // advance stack pointer - U64 sp = regs->rsp.u64; - U64 new_sp = sp + size; - - // advance stack pointer - regs->rsp.u64 = new_sp; - }break; - - case PE_UnwindOpCode_ALLOC_SMALL: - { - // advance stack pointer - regs->rsp.u64 += op_info*8 + 8; - }break; - - case PE_UnwindOpCode_SET_FPREG: - { - // put stack pointer back to the frame base - regs->rsp.u64 = frame_base; - }break; - - case PE_UnwindOpCode_SAVE_NONVOL: - { - // read value from frame base - U64 off = code_ptr[1].u16*8; - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case PE_UnwindOpCode_SAVE_NONVOL_FAR: - { - // read value from frame base - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - U64 value = 0; - if (!unw_memview_read_struct(memview, addr, &value)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - REGS_Reg64 *reg = unw_pe_x64__gpr_reg(regs, op_info); - reg->u64 = value; - }break; - - case PE_UnwindOpCode_EPILOG: - { - result.dead = 1; - }break; - - case PE_UnwindOpCode_SPARE_CODE: - { - result.dead = 1; - // Assert(!"Hit me!"); - // TODO(allen): ??? - }break; - - case PE_UnwindOpCode_SAVE_XMM128: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16*16; - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case PE_UnwindOpCode_SAVE_XMM128_FAR: - { - // read new register values - U8 buf[16]; - U64 off = code_ptr[1].u16 + ((U32)code_ptr[2].u16 << 16); - U64 addr = frame_base + off; - if (!unw_memview_read(memview, addr, 16, buf)){ - missed_read_addr = addr; - goto error_out; - } - - // commit to register - void *xmm_reg = (®s->ymm0) + op_info; - MemoryCopy(xmm_reg, buf, sizeof(buf)); - }break; - - case PE_UnwindOpCode_PUSH_MACHFRAME: - { - // NOTE(rjf): this was found by stepping through kernel code after an exception was - // thrown, encountered in the exception_stepping_tests (after the throw) in mule_main - - if(op_info > 1) - { - result.dead = 1; - goto end_xdata_unwind; - } - - // read values - U64 sp_og = regs->rsp.u64; - U64 sp_adj = sp_og; - if(op_info == 1) - { - sp_adj += 8; - } - - U64 ip_value = 0; - if(!unw_memview_read_struct(memview, sp_adj, &ip_value)) - { - missed_read_addr = sp_adj; - goto error_out; - } - - U64 sp_after_ip = sp_adj + 8; - U16 ss_value = 0; - if(!unw_memview_read_struct(memview, sp_after_ip, &ss_value)) - { - missed_read_addr = sp_after_ip; - goto error_out; - } - - U64 sp_after_ss = sp_after_ip + 8; - U64 rflags_value = 0; - if(!unw_memview_read_struct(memview, sp_after_ss, &rflags_value)) - { - missed_read_addr = sp_after_ss; - goto error_out; - } - - U64 sp_after_rflags = sp_after_ss + 8; - U64 sp_value = 0; - if(!unw_memview_read_struct(memview, sp_after_rflags, &sp_value)) - { - missed_read_addr = sp_after_rflags; - goto error_out; - } - - // commit registers - regs->rip.u64 = ip_value; - regs->ss.u16 = ss_value; - regs->rflags.u64 = rflags_value; - regs->rsp.u64 = sp_value; - - // mark machine frame - did_machframe = 1; - }break; - } - } - } - - //- iterate pdata chain - U32 flags = PE_UNWIND_INFO_FLAGS_FROM_HDR(unwind_info->header); - if (!(flags & PE_UnwindInfoFlag_CHAINED)){ - break; - } - - U64 code_count_rounded = AlignPow2(unwind_info->codes_num, sizeof(PE_UnwindCode)); - U64 code_size = code_count_rounded*sizeof(PE_UnwindCode); - U64 chained_pdata_off = unwind_info_off + sizeof(PE_UnwindInfo) + code_size; - - last_pdata = pdata; - pdata = (PE_IntelPdata*)pe_ptr_from_voff(bindata, bin, chained_pdata_off); - } - - if(!did_machframe) - { - U64 sp = regs->rsp.u64; - U64 new_ip = 0; - if(!unw_memview_read_struct(memview, sp, &new_ip)) - { - missed_read_addr = sp; - goto error_out; - } - - // advance stack pointer - U64 new_sp = sp + 8; - - // commit registers - regs->rip.u64 = new_ip; - regs->rsp.u64 = new_sp; - } - - end_xdata_unwind:; - } - } - - error_out:; - - if(missed_read_addr != 0) - { - result.dead = 1; - result.missed_read = 1; - result.missed_read_addr = missed_read_addr; - } - - if(!result.dead) - { - result.stack_pointer = regs->rsp.u64; - } - - return(result); -} diff --git a/src/unwind/unwind.h b/src/unwind/unwind.h deleted file mode 100644 index 310e940c..00000000 --- a/src/unwind/unwind.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) 2024 Epic Games Tools -// Licensed under the MIT license (https://opensource.org/license/mit/) - -#ifndef UNWIND_H -#define UNWIND_H - -//////////////////////////////// -//~ rjf: Memory View Types -// -// Memory views are used to provide a slice (or, in the future, slices) of data -// required to do a proper unwind. This is generally a very small region in an -// address space, generally some things on the stack. But, some formats don't -// restrict this in an organized way, and so theoretically you might have some -// unwind information require arbitrary reads at an unknown address. So this -// "memory view" concept serves as kind of a "stand-in" for "provided memory -// info from the user". This keeps the control flow of this layer simpler, so -// we aren't calling a user-supplied hook to read memory or anything like that. - -typedef struct UNW_MemView UNW_MemView; -struct UNW_MemView -{ - // Upgrade Path: - // 1. A list of ranges like this one - // 2. Binary-searchable list of ranges - // 3. In-line growth strategy for missing pages (hardwired to source of new data) - // 4. Abstracted source of new data - void *data; - U64 addr_first; - U64 addr_opl; -}; - -//////////////////////////////// -//~ rjf: Unwind Step Results - -typedef struct UNW_Step UNW_Step; -struct UNW_Step -{ - B32 dead; - B32 missed_read; - U64 missed_read_addr; - U64 stack_pointer; -}; - -//////////////////////////////// -//~ rjf: Memory View Helpers - -internal UNW_MemView unw_memview_from_data(String8 data, U64 base_vaddr); -internal B32 unw_memview_read(UNW_MemView *memview, U64 addr, U64 size, void *out); -#define unw_memview_read_struct(v,addr,p) unw_memview_read((v), (addr), sizeof(*(p)), (p)) - -//////////////////////////////// -//~ rjf: PE/X64 Unwind Implementation - -//- rjf: helpers -internal UNW_Step unw_pe_x64__epilog(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs_inout); -internal B32 unw_pe_x64__voff_is_in_epilog(String8 bindata, PE_BinInfo *bin, U64 voff, PE_IntelPdata *final_pdata); -internal REGS_Reg64 *unw_pe_x64__gpr_reg(REGS_RegBlockX64 *regs, PE_UnwindGprRegX64 unw_reg); - -//- rjf: unwind step -internal UNW_Step unw_unwind_pe_x64(String8 bindata, PE_BinInfo *bin, U64 base_vaddr, UNW_MemView *memview, REGS_RegBlockX64 *regs_inout); - -#endif // UNWIND_H