From 7707ba1d60bbeaaed21e5a78b4f7c97fe3873418 Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Wed, 1 Oct 2025 15:36:36 -0700 Subject: [PATCH] dwarf debug info option in builds, fix heuristic to try to load debug info from exe itself --- build.bat | 12 +++++++----- src/ctrl/ctrl_core.c | 37 ++++++++++++++++++++++++++++--------- src/dwarf/dwarf_coff.c | 22 +++++++++------------- src/dwarf/dwarf_coff.h | 2 +- src/radbin/radbin.c | 2 +- src/raddbg/raddbg_core.c | 2 +- 6 files changed, 47 insertions(+), 30 deletions(-) diff --git a/build.bat b/build.bat index 81427182..77784200 100644 --- a/build.bat +++ b/build.bat @@ -39,10 +39,12 @@ if "%~1"=="release" if "%~2"=="" echo [default mode, assuming `raddbg` build] && :: --- Unpack Command Line Build Arguments ------------------------------------ set auto_compile_flags= -if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled] -if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled] -if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] -if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend] +if "%telemetry%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_TELEMETRY=1 && echo [telemetry profiling enabled] +if "%spall%"=="1" set auto_compile_flags=%auto_compile_flags% -DPROFILE_SPALL=1 && echo [spall profiling enabled] +if "%asan%"=="1" set auto_compile_flags=%auto_compile_flags% -fsanitize=address && echo [asan enabled] +if "%opengl%"=="1" set auto_compile_flags=%auto_compile_flags% -DR_BACKEND=R_BACKEND_OPENGL && echo [opengl render backend] +if "%dwarf%"=="1" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gdwarf && echo [dwarf debug info] +if "%dwarf%"=="" if "%clang%"=="1" set auto_compile_flags=%auto_compile_flags% -gcodeview if "%pgo%"=="1" ( if "%no_meta%"=="" echo ERROR: PGO build must have no_meta argument || exit /b 1 where llvm-profdata /q || echo llvm-profdata is not in the PATH || exit /b 1 @@ -70,7 +72,7 @@ set cl_release= call cl /O2 /DBUILD_DEBUG=0 %cl_common% %auto_compile_flags% set cl_link= /link /MANIFEST:EMBED /INCREMENTAL:NO /pdbaltpath:%%%%_PDB%%%% /NATVIS:"%~dp0\src\natvis\base.natvis" /noexp /nocoffgrpinfo /opt:ref /opt:icf set cl_out= /out: set cl_linker= -set clang_common= -I..\src\ -I..\local\ -gcodeview -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 +set clang_common= -I..\src\ -I..\local\ -fdiagnostics-absolute-paths -Wall -Wno-unknown-warning-option -Wno-missing-braces -Wno-unused-function -Wno-unused-parameter -Wno-writable-strings -Wno-missing-field-initializers -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -ferror-limit=10000 -mcx16 set clang_debug= call clang -g -O0 -DBUILD_DEBUG=1 %clang_common% %auto_compile_flags% set clang_release= call clang -g -O2 -DBUILD_DEBUG=0 %clang_common% %auto_compile_flags% set clang_link= -fuse-ld=lld -Xlinker /MANIFEST:EMBED -Xlinker /pdbaltpath:%%%%_PDB%%%% -Xlinker /NATVIS:"%~dp0\src\natvis\base.natvis" -Xlinker /opt:ref -Xlinker /opt:icf diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index 1a015a2f..ae3c131b 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -3399,11 +3399,12 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U32 pdb_dbg_time = 0; U32 pdb_dbg_age = 0; Guid pdb_dbg_guid = {0}; - String8 pdb_dbg_path = str8_zero(); + String8 pdb_dbg_path = {0}; U32 rdi_dbg_time = 0; Guid rdi_dbg_guid = {0}; - String8 rdi_dbg_path = str8_zero(); - String8 raddbg_data = str8_zero(); + String8 exe_dbg_path = {0}; + String8 rdi_dbg_path = {0}; + String8 raddbg_data = {0}; Rng1U64 raddbg_section_voff_range = r1u64(0, 0); Rng1U64 raddbg_is_attached_section_voff_range = r1u64(0, 0); ProfScope("unpack relevant PE info") @@ -3453,6 +3454,8 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U32 data_dir_count = 0; if(opt_ext_size > 0) { + Temp scratch = scratch_begin(0, 0); + // rjf: read magic number U16 opt_ext_magic = 0; dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min, &opt_ext_magic); @@ -3523,6 +3526,12 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ } } + // rjf: extract sections + U64 sec_array_off = opt_ext_off_range.max; + U64 sec_count = file_header.section_count; + COFF_SectionHeader *sec = push_array(scratch.arena, COFF_SectionHeader, sec_count); + dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec); + // rjf: grab entry point vaddr entry_point_voff = entry_point; @@ -3589,13 +3598,18 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ } } + // rjf: look for DWARF debug info + { + U64 symbol_array_off = file_header.symbol_table_foff; + U64 symbol_count = file_header.symbol_count; + if(symbol_array_off != 0) + { + exe_dbg_path = path; + } + } + // rjf: extract copy of module's raddbg data { - Temp scratch = scratch_begin(0, 0); - U64 sec_array_off = opt_ext_off_range.max; - U64 sec_count = file_header.section_count; - COFF_SectionHeader *sec = push_array(scratch.arena, COFF_SectionHeader, sec_count); - dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec); for EachIndex(idx, sec_count) { String8 section_name = str8_cstring((char *)sec[idx].name); @@ -3614,7 +3628,6 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ raddbg_data.str = push_array(arena, U8, raddbg_data.size); dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min + raddbg_section_voff_range.min, vaddr_range.min + raddbg_section_voff_range.max), raddbg_data.str); - scratch_end(scratch); } // rjf: if we have a "raddbg is attached" section, mark the first byte as 1, to signify attachment @@ -3623,6 +3636,8 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ U8 new_value = 1; dmn_process_write_struct(process.dmn_handle, vaddr_range.min + raddbg_is_attached_section_voff_range.min, &new_value); } + + scratch_end(scratch); } } @@ -3649,6 +3664,10 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_ str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, rdi_dbg_path); str8_list_push(scratch.arena, &dbg_path_candidates, rdi_dbg_path); } + if(exe_dbg_path.size != 0) + { + str8_list_push(scratch.arena, &dbg_path_candidates, path); + } if(pdb_dbg_path.size != 0) { str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, pdb_dbg_path); diff --git a/src/dwarf/dwarf_coff.c b/src/dwarf/dwarf_coff.c index 9ddbcd89..2c6614f9 100644 --- a/src/dwarf/dwarf_coff.c +++ b/src/dwarf/dwarf_coff.c @@ -2,28 +2,24 @@ // Licensed under the MIT license (https://opensource.org/license/mit/) internal B32 -dw_is_dwarf_present_coff_section_table(String8 raw_image, - String8 string_table, - U64 section_count, - COFF_SectionHeader *section_table) +dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table) { B32 is_dwarf_present = 0; - - for (U64 i = 0; i < section_count; ++i) { - COFF_SectionHeader *header = §ion_table[i]; - String8 name = coff_name_from_section_header(string_table, header); - + for EachIndex(idx, section_count) + { + COFF_SectionHeader *header = §ion_table[idx]; + String8 name = coff_name_from_section_header(string_table, header); DW_SectionKind s = dw_section_kind_from_string(name); - if (s == DW_Section_Null) { + if(s == DW_Section_Null) + { s = dw_section_dwo_kind_from_string(name); } - is_dwarf_present = s != DW_Section_Null; - if (is_dwarf_present) { + if(is_dwarf_present) + { break; } } - return is_dwarf_present; } diff --git a/src/dwarf/dwarf_coff.h b/src/dwarf/dwarf_coff.h index 27f637d6..79cd37c3 100644 --- a/src/dwarf/dwarf_coff.h +++ b/src/dwarf/dwarf_coff.h @@ -4,7 +4,7 @@ #ifndef DWARF_COFF_H #define DWARF_COFF_H -internal B32 dw_is_dwarf_present_coff_section_table(String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table); +internal B32 dw_is_dwarf_present_coff_section_table(String8 string_table, U64 section_count, COFF_SectionHeader *section_table); internal DW_Input dw_input_from_coff_section_table(Arena *arena, String8 raw_image, String8 string_table, U64 section_count, COFF_SectionHeader *section_table); #endif // DWARF_COFF_H diff --git a/src/radbin/radbin.c b/src/radbin/radbin.c index 77d59968..dfa3fec2 100644 --- a/src/radbin/radbin.c +++ b/src/radbin/radbin.c @@ -331,7 +331,7 @@ rb_thread_entry_point(void *p) String8 string_table = str8_substr(file_data, pe_bin_info.string_table_range); U64 section_count = raw_section_table.size / sizeof(COFF_SectionHeader); COFF_SectionHeader *section_table = (COFF_SectionHeader *)raw_section_table.str; - if(dw_is_dwarf_present_coff_section_table(file_data, string_table, section_count, section_table)) + if(dw_is_dwarf_present_coff_section_table(string_table, section_count, section_table)) { file_format_flags |= RB_FileFormatFlag_HasDWARF; } diff --git a/src/raddbg/raddbg_core.c b/src/raddbg/raddbg_core.c index 911a7134..4147365d 100644 --- a/src/raddbg/raddbg_core.c +++ b/src/raddbg/raddbg_core.c @@ -1251,7 +1251,7 @@ rd_target_from_cfg(Arena *arena, RD_Cfg *cfg) target.stdout_path = rd_cfg_child_from_string(cfg, str8_lit("stdout_path"))->first->string; target.stderr_path = rd_cfg_child_from_string(cfg, str8_lit("stderr_path"))->first->string; target.stdin_path = rd_cfg_child_from_string(cfg, str8_lit("stdin_path"))->first->string; - target.debug_subprocesses = (rd_cfg_child_from_string(cfg, str8_lit("debug_subprocesses")) != &rd_nil_cfg); + target.debug_subprocesses = !!e_value_from_string(rd_cfg_child_from_string(cfg, str8_lit("debug_subprocesses"))->first->string).u64; for(RD_Cfg *child = cfg->first; child != &rd_nil_cfg; child = child->next) { if(str8_match(child->string, str8_lit("environment"), 0))