eliminate backend-specific module parsing from debug engine ctrl thread; just pass that info back via the demon event

This commit is contained in:
Ryan Fleury
2026-06-02 12:11:10 -07:00
parent d98d6b56d9
commit 9cc2afc659
20 changed files with 825 additions and 544 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ commands =
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build raddbg debug telemetry", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
// .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "raddbg_stable --ipc kill_all && build radbin", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
.f1 = { .win = "raddbg_stable --ipc kill_all && build torture", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, .f1 = { .win = "build raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
//- rjf: [raddbg wsl] //- rjf: [raddbg wsl]
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, }, // .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
+1 -1
View File
@@ -7,6 +7,7 @@ target:
working_directory: build working_directory: build
arguments: "--user:raddbg_test.user --project:raddbg_test.project" arguments: "--user:raddbg_test.user --project:raddbg_test.project"
debug_subprocesses: 0 debug_subprocesses: 0
enabled: 1
} }
target: target:
{ {
@@ -42,5 +43,4 @@ target:
executable: "build/torture.exe" executable: "build/torture.exe"
working_directory: build working_directory: build
arguments: "rdi_from_pdb/* --gui" arguments: "rdi_from_pdb/* --gui"
enabled: 1
} }
+3 -1
View File
@@ -12,7 +12,9 @@ struct ProcessInfo
String8 binary_file_path; String8 binary_file_path;
String8 binary_path; String8 binary_path;
String8 initial_path; String8 initial_path;
String8 user_program_data_path; String8 user_program_config_data_path;
String8 user_program_cache_data_path;
String8 user_program_logs_data_path;
String8 symbol_cache_path; String8 symbol_cache_path;
String8List module_load_paths; String8List module_load_paths;
String8List environment; String8List environment;
+74 -352
View File
@@ -3754,357 +3754,60 @@ d_ctrl_thread__append_program_defined_bp_traps(Arena *arena, D_Entity *bp, DMN_T
//- rjf: module lifetime open/close work //- rjf: module lifetime open/close work
internal void internal void
d_ctrl_thread__module_open(D_Handle process, D_Handle module, Rng1U64 vaddr_range, String8 path, Rng1U64 elf_phdr_vrange, U64 elf_phdr_entsize) d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DMN_ModuleInfo *module_info)
{ {
Temp scratch = scratch_begin(0,0); Temp scratch = scratch_begin(0,0);
//- rjf: set up per-module info //- rjf: set up per-module info
Arena *arena = arena_alloc(); Arena *arena = arena_alloc();
U64 entry_point_voff = 0; String8 raddbg_data = d_data_from_process_vaddr_range(arena, process, shift_1u64(module_info->raddbg_info_voff_range, base_vaddr), 0);
U32 rdi_dbg_time = 0; U64 pdatas_count = dim_1u64(module_info->pe_intel_pdatas_vaddr_range) / sizeof(PE_IntelPdata);
Guid rdi_dbg_guid = {0}; String8 pdatas_data = d_data_from_process_vaddr_range(arena, process, module_info->pe_intel_pdatas_vaddr_range, 0);
String8 exe_dbg_path = {0}; pdatas_count = Min(pdatas_count, pdatas_data.size / sizeof(PE_IntelPdata));
String8 rdi_dbg_path = {0}; PE_IntelPdata *pdatas = (PE_IntelPdata *)pdatas_data.str;
String8 raddbg_data = {0}; EH_PtrCtx eh_ptr_ctx = {.pc_vaddr = max_U64, .text_vaddr = max_U64, .data_vaddr = max_U64, .func_vaddr = max_U64, .ptr_align = 0};
Rng1U64 raddbg_section_voff_range = {0};
Rng1U64 raddbg_is_attached_section_voff_range = {0};
PE_IntelPdata *pdatas = 0;
U64 pdatas_count = 0;
U32 pdb_dbg_time = 0;
U32 pdb_dbg_age = 0;
Guid pdb_dbg_guid = {0};
String8 pdb_dbg_path = {0};
U64 cfi_rebase = 0;
B32 is_unwind_eh = 0;
EH_FrameHdr eh_frame_hdr = {0}; EH_FrameHdr eh_frame_hdr = {0};
EH_PtrCtx eh_ptr_ctx = { .pc_vaddr = max_U64, .text_vaddr = max_U64, .data_vaddr = max_U64, .func_vaddr = max_U64, .ptr_align = 0 }; B32 is_unwind_eh = 0;
if(module_info->eh_frame_header_vaddr_range.min != 0)
//- read module's signature bytes
U64 module_sig_size = Max(elf_magic_string.size, sizeof(PE_DosMagic));
U8 *module_sig_bytes = push_array(scratch.arena, U8, module_sig_size);
d_process_read(process, rng_1u64(vaddr_range.min, vaddr_range.min + module_sig_size), module_sig_bytes);
//////////////////////////////
//- parse PE module
//
PE_DosMagic dos_magic = *(PE_DosMagic *)module_sig_bytes;
if(dos_magic == PE_DOS_MAGIC)
{ {
ProfScope("unpack relevant PE info") String8 eh_frame_hdr_data = d_data_from_process_vaddr_range(arena, process, module_info->eh_frame_header_vaddr_range, 0);
{ eh_ptr_ctx.pc_vaddr = module_info->eh_frame_header_vaddr_range.min;
B32 is_valid = 1; eh_ptr_ctx.data_vaddr = module_info->eh_frame_header_vaddr_range.min;
eh_frame_hdr = eh_parse_frame_hdr(eh_frame_hdr_data, byte_size_from_arch(module_info->arch), &eh_ptr_ctx);
//- rjf: read DOS header is_unwind_eh = 1;
PE_DosHeader dos_header = {0};
if(is_valid)
{
if(!d_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(!d_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 file_header_off = dos_header.coff_file_offset + sizeof(pe_magic);
COFF_FileHeader file_header = {0};
if(is_valid)
{
if(!d_process_read_struct(process, vaddr_range.min + file_header_off, &file_header))
{
is_valid = 0;
}
}
//- rjf: unpack range of optional extension header
U32 opt_ext_size = file_header.optional_header_size;
Rng1U64 opt_ext_off_range = r1u64(file_header_off + sizeof(COFF_FileHeader),
file_header_off + sizeof(COFF_FileHeader) + opt_ext_size);
//- rjf: read optional header
U64 entry_point = 0;
U32 data_dir_count = 0;
if(opt_ext_size > 0)
{
// rjf: read magic number
U16 opt_ext_magic = 0;
d_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};
d_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &pe_optional);
entry_point = pe_optional.entry_point_va;
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};
d_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min, &pe_optional);
entry_point = pe_optional.entry_point_va;
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: 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);
d_process_read(process, r1u64(vaddr_range.min + sec_array_off, vaddr_range.min + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec);
// rjf: grab pdatas from exceptions section
if(data_dir_count > PE_DataDirectoryIndex_EXCEPTIONS)
{
PE_DataDirectory dir = {0};
d_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);
d_process_read(process, r1u64(vaddr_range.min + pdatas_voff_range.min, vaddr_range.min + pdatas_voff_range.max), pdatas);
}
// rjf: grab entry point vaddr
entry_point_voff = entry_point;
// rjf: grab data about debug info
if(data_dir_count > PE_DataDirectoryIndex_DEBUG)
{
// rjf: read data dir
PE_DataDirectory dir = {0};
d_process_read_struct(process, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DEBUG, &dir);
U64 dbg_dir_count = dir.virt_size / sizeof(PE_DebugDirectory);
for(U64 dbg_dir_idx = 0; dbg_dir_idx < dbg_dir_count; dbg_dir_idx += 1)
{
// rjf: read debug directory
U64 dir_addr = vaddr_range.min + dir.virt_off + dbg_dir_idx * sizeof(PE_DebugDirectory);
PE_DebugDirectory dbg_data = {0};
d_process_read_struct(process, dir_addr, &dbg_data);
// rjf: extract external file info from codeview header
if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW)
{
U32 cv_magic = 0;
d_process_read_struct(process, vaddr_range.min + dbg_data.voff, &cv_magic);
switch(cv_magic)
{
default:break;
case PE_CODEVIEW_PDB20_MAGIC:
{
PE_CvHeaderPDB20 cv;
U64 read_size = d_process_read_struct(process, vaddr_range.min+dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
U64 pdb_dbg_path_vaddr = vaddr_range.min + dbg_data.voff + sizeof(cv);
pdb_dbg_time = cv.time_stamp;
pdb_dbg_age = cv.age;
pdb_dbg_path = d_data_from_process_vaddr_range(arena, process, r1u64(pdb_dbg_path_vaddr, pdb_dbg_path_vaddr+512), 1);
}
}break;
case PE_CODEVIEW_PDB70_MAGIC:
{
PE_CvHeaderPDB70 cv;
U64 read_size = d_process_read_struct(process, vaddr_range.min + dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
U64 pdb_dbg_path_vaddr = vaddr_range.min + dbg_data.voff + sizeof(cv);
pdb_dbg_guid = cv.guid;
pdb_dbg_age = cv.age;
pdb_dbg_path = d_data_from_process_vaddr_range(arena, process, r1u64(pdb_dbg_path_vaddr, pdb_dbg_path_vaddr+512), 1);
}
}break;
case PE_CODEVIEW_RDI_MAGIC:
{
PE_CvHeaderRDI cv;
U64 read_size = d_process_read_struct(process, vaddr_range.min + dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
U64 rdi_dbg_path_vaddr = vaddr_range.min + dbg_data.voff + sizeof(cv);
rdi_dbg_guid = cv.guid;
rdi_dbg_path = d_data_from_process_vaddr_range(arena, process, r1u64(rdi_dbg_path_vaddr, rdi_dbg_path_vaddr+512), 1);
}
}break;
}
}
}
}
// 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
{
for EachIndex(idx, sec_count)
{
String8 section_name = str8_cstring((char *)sec[idx].name);
if(str8_match(section_name, str8_lit(".raddbg"), 0))
{
raddbg_section_voff_range.min = sec[idx].voff;
raddbg_section_voff_range.max = sec[idx].voff + sec[idx].vsize;
}
else if(str8_match(section_name, str8_lit(".rdbgia"), 0))
{
raddbg_is_attached_section_voff_range.min = sec[idx].voff;
raddbg_is_attached_section_voff_range.max = sec[idx].voff + sec[idx].vsize;
}
}
raddbg_data.size = dim_1u64(raddbg_section_voff_range);
raddbg_data.str = push_array(arena, U8, raddbg_data.size);
d_process_read(process, r1u64(vaddr_range.min + raddbg_section_voff_range.min,
vaddr_range.min + raddbg_section_voff_range.max), raddbg_data.str);
}
// rjf: if we have a "raddbg is attached" section, mark the first byte as 1, to signify attachment
if(raddbg_is_attached_section_voff_range.max != raddbg_is_attached_section_voff_range.min)
{
U8 new_value = 1;
d_process_write_struct(process, vaddr_range.min + raddbg_is_attached_section_voff_range.min, &new_value);
}
}
}
}
//////////////////////////////
//- parse ELF module
//
else if(str8_match(str8(module_sig_bytes, elf_magic_string.size), elf_magic_string, 0))
{
U64 e_entry = 0;
ELF_Type e_type = ELF_Type_None;
{
U8 *elf_sig = d_data_from_process_vaddr_range(scratch.arena, process, rng_1u64(vaddr_range.min, vaddr_range.min + sizeof(elf_sig[0]) * ELF_Identifier_Max), 0).str;
if(elf_sig == 0) { goto elf_exit; }
switch(elf_sig[ELF_Identifier_Class])
{
default:
case ELF_Class_None:
case ELF_Class_32:
{}break;
case ELF_Class_64:
{
ELF_Hdr64 *ehdr = (ELF_Hdr64 *)d_data_from_process_vaddr_range(scratch.arena, process, r1u64(vaddr_range.min, vaddr_range.min + sizeof(*ehdr)), 0).str;
if(ehdr == 0) { goto elf_exit; }
e_entry = ehdr->e_entry;
e_type = ehdr->e_type;
}break;
}
}
if(e_type == ELF_Type_Dyn)
{
cfi_rebase = vaddr_range.min;
}
// find and parse .eh_frame_hdr
Rng1U64 eh_frame_hdr_vrange = {0};
String8 eh_frame_hdr_data = {0};
{
void *phdrs_raw = d_data_from_process_vaddr_range(scratch.arena, process, elf_phdr_vrange, 0).str;
if(phdrs_raw == 0) { goto elf_exit; }
if(elf_phdr_entsize == sizeof(ELF_Phdr64))
{
U64 elf_phcount = dim_1u64(elf_phdr_vrange) / elf_phdr_entsize;
ELF_Phdr64 *phdrs64 = phdrs_raw;
for EachIndex(phdr_idx, elf_phcount)
{
ELF_Phdr64 *phdr = phdrs64 + phdr_idx;
if(phdr->p_type == ELF_PType_GnuEHFrame)
{
eh_frame_hdr_vrange = r1u64(cfi_rebase + phdr->p_vaddr, cfi_rebase + phdr->p_vaddr + phdr->p_memsz);
eh_frame_hdr_data = d_data_from_process_vaddr_range(arena, process, eh_frame_hdr_vrange, 0);
is_unwind_eh = 1;
break;
}
}
}
}
// parse .eh_frame_hdr
D_Entity *process_entity = d_entity_from_handle(process);
Arch arch = process_entity->arch;
eh_ptr_ctx.pc_vaddr = eh_frame_hdr_vrange.min;
eh_ptr_ctx.data_vaddr = eh_frame_hdr_vrange.min;
eh_frame_hdr = eh_parse_frame_hdr(eh_frame_hdr_data, byte_size_from_arch(arch), &eh_ptr_ctx);
// set entry point
if (e_entry != 0)
{
entry_point_voff = e_entry - vaddr_range.min;
}
// TODO: is there a way to detect DWARF in runtime ELF?
if(1)
{
exe_dbg_path = path;
}
elf_exit:;
} }
////////////////////////////// //////////////////////////////
//- rjf: pick default initial debug info path //- rjf: pick default initial debug info path
// //
String8 initial_debug_info_path = str8_zero(); String8 initial_debug_info_path = {0};
{ {
String8 exe_folder = str8_chop_last_slash(path); String8List candidates = {0};
String8List dbg_path_candidates = {0};
// // rjf: push module-embedded debug info paths, try both relative-to-exe & absolute
//~ TODO(rjf): @linux_port PLEASE READ RYAN vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv if(module_info->debug_info_path.size != 0)
//
// TODO(rjf): trying "exe_folder/embedded_path" as the first option is only a valid
// heuristic on Windows, because we know that two absolute paths concatted together
// are necessarily invalid. however, on Linux, this is not the case - you could stitch
// two paths together and get a third path that is completely valid. so, in that case,
// we will need to infer if the path is relative, and then use either the embedded
// path as-is, or the exe-relative-path accordingly, depending on that.
//
if(rdi_dbg_path.size != 0)
{ {
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, rdi_dbg_path); PathStyle path_style = path_style_from_str8(module_info->debug_info_path);
str8_list_push(scratch.arena, &dbg_path_candidates, rdi_dbg_path); if(path_style == PathStyle_Relative)
{
String8 module_image_folder = str8_chop_last_slash(module_info->module_path);
str8_list_pushf(scratch.arena, &candidates, "%S/%S", module_image_folder, module_info->debug_info_path);
}
str8_list_push(scratch.arena, &candidates, module_info->debug_info_path);
} }
if(exe_dbg_path.size != 0)
// rjf: push heuristic-based debug info paths
{ {
str8_list_push(scratch.arena, &dbg_path_candidates, path); String8 exe_path = module_info->module_path;
String8 exe_path_no_ext = str8_chop_last_dot(exe_path);
str8_list_pushf(scratch.arena, &candidates, "%S.pdb", exe_path_no_ext);
str8_list_pushf(scratch.arena, &candidates, "%S.pdb", exe_path);
str8_list_pushf(scratch.arena, &candidates, "%S.rdi", exe_path_no_ext);
str8_list_pushf(scratch.arena, &candidates, "%S.rdi", exe_path);
} }
if(pdb_dbg_path.size != 0)
{ // rjf: pick first candidate that works
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, pdb_dbg_path); for EachNode(n, String8Node, candidates.first)
str8_list_push(scratch.arena, &dbg_path_candidates, pdb_dbg_path);
}
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", str8_chop_last_dot(path));
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.pdb", path);
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", str8_chop_last_dot(path));
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S.rdi", path);
for(String8Node *n = dbg_path_candidates.first; n != 0; n = n->next)
{ {
String8 candidate_path = n->string; String8 candidate_path = n->string;
FileProperties props = properties_from_file_path(candidate_path); FileProperties props = properties_from_file_path(candidate_path);
@@ -4120,27 +3823,36 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, Rng1U64 vaddr_rang
//- rjf: determine debug info unique identifier //- rjf: determine debug info unique identifier
// //
String8 debug_info_unique_identifier = {0}; String8 debug_info_unique_identifier = {0};
if(pdb_dbg_path.size != 0) if(module_info->debug_info_path.size != 0)
{ {
Guid guid = pdb_dbg_guid; Guid guid = module_info->debug_info_guid;
debug_info_unique_identifier = str8f(scratch.arena, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x", debug_info_unique_identifier = str8f(scratch.arena, "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
guid.data1, guid.data2, guid.data3, guid.data4[0], guid.data4[1], guid.data4[2], guid.data4[3], guid.data4[4], guid.data4[5], guid.data4[6], guid.data4[7], pdb_dbg_age); guid.data1, guid.data2, guid.data3, guid.data4[0], guid.data4[1], guid.data4[2], guid.data4[3], guid.data4[4], guid.data4[5], guid.data4[6], guid.data4[7], module_info->debug_info_age);
} }
////////////////////////////// //////////////////////////////
//- rjf: build local server cache debug info path //- rjf: build local server cache debug info path
// //
String8 local_server_cache_debug_info_path = {0}; String8 local_server_cache_debug_info_path = {0};
if(debug_info_unique_identifier.size != 0 && pdb_dbg_path.size != 0) if(debug_info_unique_identifier.size != 0 && module_info->debug_info_path.size != 0)
{ {
// TODO(rjf): this is not complete - assuming stripped etc. - just following pattern from ntdll.dll for now // TODO(rjf): this is not complete - assuming stripped etc. - just following pattern from ntdll.dll for now
String8 symbol_cache_path = get_process_info()->symbol_cache_path; String8 symbol_cache_path = get_process_info()->symbol_cache_path;
String8 module_name = str8_skip_last_slash(path); String8 module_name = str8_skip_last_slash(module_info->module_path);
String8 dbg_name = str8_skip_last_slash(pdb_dbg_path); String8 dbg_name = str8_skip_last_slash(module_info->debug_info_path);
String8 path = str8f(scratch.arena, "%S/%S/%S/stripped/%S", symbol_cache_path, module_name, debug_info_unique_identifier, dbg_name); String8 path = str8f(scratch.arena, "%S/%S/%S/stripped/%S", symbol_cache_path, module_name, debug_info_unique_identifier, dbg_name);
local_server_cache_debug_info_path = path_normalized_from_string(arena, path); local_server_cache_debug_info_path = path_normalized_from_string(arena, path);
} }
//////////////////////////////
//- rjf: write 1 at attachment marker, to signify attachment
//
if(module_info->raddbg_is_attached_marker_voff != 0)
{
U8 new_value = 1;
d_process_write_struct(process, base_vaddr + module_info->raddbg_is_attached_marker_voff, &new_value);
}
////////////////////////////// //////////////////////////////
//- rjf: insert info into cache //- rjf: insert info into cache
// //
@@ -4169,14 +3881,14 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, Rng1U64 vaddr_rang
node->arena = arena; node->arena = arena;
node->pdatas = pdatas; node->pdatas = pdatas;
node->pdatas_count = pdatas_count; node->pdatas_count = pdatas_count;
node->cfi_rebase = cfi_rebase; node->cfi_rebase = module_info->cfi_rebase;
node->is_unwind_eh = is_unwind_eh; node->is_unwind_eh = is_unwind_eh;
node->eh_frame_hdr = eh_frame_hdr; node->eh_frame_hdr = eh_frame_hdr;
node->eh_ptr_ctx = eh_ptr_ctx; node->eh_ptr_ctx = eh_ptr_ctx;
node->entry_point_voff = entry_point_voff; node->entry_point_voff = module_info->entry_point_voff;
node->local_debug_info_path = initial_debug_info_path; node->local_debug_info_path = initial_debug_info_path;
node->debug_info_unique_identifier= debug_info_unique_identifier; node->debug_info_unique_identifier= debug_info_unique_identifier;
node->raddbg_attached_marker_voff = raddbg_is_attached_section_voff_range.min; node->raddbg_attached_marker_voff = module_info->raddbg_is_attached_marker_voff;
node->raddbg_data = str8_copy(arena, raddbg_data); node->raddbg_data = str8_copy(arena, raddbg_data);
} }
} }
@@ -4186,7 +3898,7 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, Rng1U64 vaddr_rang
} }
internal void internal void
d_ctrl_thread__module_close(D_Handle process, D_Handle module, Rng1U64 vaddr_range) d_ctrl_thread__module_close(D_Handle process, D_Handle module, U64 base_vaddr)
{ {
DMN_Handle process_dmn = d_dmn_from_handle(process); DMN_Handle process_dmn = d_dmn_from_handle(process);
@@ -4221,12 +3933,12 @@ d_ctrl_thread__module_close(D_Handle process, D_Handle module, Rng1U64 vaddr_ran
} }
////////////////////////////// //////////////////////////////
//- rjf: write 0 at attachment market, to signify detachment //- rjf: write 0 at attachment marker, to signify detachment
// //
if(raddbg_attached_marker_voff != 0) if(raddbg_attached_marker_voff != 0)
{ {
U8 new_value = 0; U8 new_value = 0;
d_process_write_struct(process, vaddr_range.min + raddbg_attached_marker_voff, &new_value); d_process_write_struct(process, base_vaddr + raddbg_attached_marker_voff, &new_value);
} }
} }
@@ -4526,6 +4238,13 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
} }
MemoryCopyStruct(&dst_n->v, &src_n->v); MemoryCopyStruct(&dst_n->v, &src_n->v);
dst_n->v.string = push_str8_copy(d_ctrl_state->dmn_event_arena, dst_n->v.string); dst_n->v.string = push_str8_copy(d_ctrl_state->dmn_event_arena, dst_n->v.string);
if(src_n->v.module_info != &dmn_module_info_nil)
{
dst_n->v.module_info = push_array(d_ctrl_state->dmn_event_arena, DMN_ModuleInfo, 1);
MemoryCopyStruct(dst_n->v.module_info, src_n->v.module_info);
dst_n->v.module_info->module_path = str8_copy(d_ctrl_state->dmn_event_arena, dst_n->v.module_info->module_path);
dst_n->v.module_info->debug_info_path = str8_copy(d_ctrl_state->dmn_event_arena, dst_n->v.module_info->debug_info_path);
}
SLLQueuePush(d_ctrl_state->first_dmn_event_node, d_ctrl_state->last_dmn_event_node, dst_n); SLLQueuePush(d_ctrl_state->first_dmn_event_node, d_ctrl_state->last_dmn_event_node, dst_n);
} }
} }
@@ -4607,7 +4326,7 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
D_Event *out_evt1 = d_event_list_push(scratch.arena, &evts); D_Event *out_evt1 = d_event_list_push(scratch.arena, &evts);
String8 module_path = path_normalized_from_string(scratch.arena, event->string); String8 module_path = path_normalized_from_string(scratch.arena, event->string);
U64 exe_timestamp = properties_from_file_path(module_path).modified; U64 exe_timestamp = properties_from_file_path(module_path).modified;
d_ctrl_thread__module_open(process_handle, module_handle, r1u64(event->address, event->address+event->size), module_path, event->elf_phdr_vrange, event->elf_phdr_entsize); d_ctrl_thread__module_open(process_handle, module_handle, event->address, event->module_info);
out_evt1->kind = D_EventKind_NewModule; out_evt1->kind = D_EventKind_NewModule;
out_evt1->msg_id = msg->msg_id; out_evt1->msg_id = msg->msg_id;
out_evt1->entity = module_handle; out_evt1->entity = module_handle;
@@ -4618,8 +4337,8 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
out_evt1->rip_vaddr = event->address; out_evt1->rip_vaddr = event->address;
out_evt1->timestamp = exe_timestamp; out_evt1->timestamp = exe_timestamp;
out_evt1->string = module_path; out_evt1->string = module_path;
out_evt1->tls_index = event->tls_index; out_evt1->tls_index = event->module_info->tls_index;
out_evt1->tls_offset = event->tls_offset; out_evt1->tls_offset = event->module_info->tls_offset;
D_Event *out_evt2 = d_event_list_push(scratch.arena, &evts); D_Event *out_evt2 = d_event_list_push(scratch.arena, &evts);
String8 initial_debug_info_path = d_initial_debug_info_path_from_module(scratch.arena, module_handle); String8 initial_debug_info_path = d_initial_debug_info_path_from_module(scratch.arena, module_handle);
U64 debug_info_timestamp = properties_from_file_path(initial_debug_info_path).modified; U64 debug_info_timestamp = properties_from_file_path(initial_debug_info_path).modified;
@@ -4657,7 +4376,7 @@ d_ctrl_thread__next_dmn_event(Arena *arena, DMN_CtrlCtx *ctrl_ctx, D_Msg *msg, D
D_Entity *module_ent = d_entity_from_handle(module_handle); D_Entity *module_ent = d_entity_from_handle(module_handle);
D_Entity *process_ent = d_process_from_entity(module_ent); D_Entity *process_ent = d_process_from_entity(module_ent);
String8 module_path = event->string; String8 module_path = event->string;
d_ctrl_thread__module_close(process_ent->handle, module_handle, module_ent->vaddr_range); d_ctrl_thread__module_close(process_ent->handle, module_handle, module_ent->vaddr_range.min);
out_evt->kind = D_EventKind_EndModule; out_evt->kind = D_EventKind_EndModule;
out_evt->msg_id = msg->msg_id; out_evt->msg_id = msg->msg_id;
out_evt->entity = module_handle; out_evt->entity = module_handle;
@@ -5482,8 +5201,11 @@ d_ctrl_thread__open_crash_dump(DMN_CtrlCtx *ctrl_ctx, D_Msg *msg)
// rjf: open module // rjf: open module
D_Handle module_handle = dump_modules[idx].module_handle; D_Handle module_handle = dump_modules[idx].module_handle;
Rng1U64 vaddr_range = dump_modules[idx].vaddr_range; Rng1U64 vaddr_range = dump_modules[idx].vaddr_range;
d_ctrl_thread__module_open(process, module_handle, vaddr_range, dump_modules[idx].path, r1u64(0, 0), 0); #if 0
// TODO(rjf): I don't think we can use this demon module info path here
DMN_ModuleInfo module_info = {0};
d_ctrl_thread__module_open(process, module_handle, vaddr_range.min, dump_modules[idx].path, r1u64(0, 0), 0);
#endif
// rjf: open debug info // rjf: open debug info
String8 initial_debug_info_path = d_initial_debug_info_path_from_module(scratch.arena, module_handle); String8 initial_debug_info_path = d_initial_debug_info_path_from_module(scratch.arena, module_handle);
U64 debug_info_timestamp = properties_from_file_path(initial_debug_info_path).modified; U64 debug_info_timestamp = properties_from_file_path(initial_debug_info_path).modified;
+3 -3
View File
@@ -181,8 +181,8 @@ struct D_ModuleImageInfoCacheNode
PE_IntelPdata *pdatas; PE_IntelPdata *pdatas;
U64 pdatas_count; U64 pdatas_count;
U64 cfi_rebase; U64 cfi_rebase;
B32 is_unwind_eh;
String8 dwarf_unwind_data; String8 dwarf_unwind_data;
B32 is_unwind_eh;
EH_FrameHdr eh_frame_hdr; EH_FrameHdr eh_frame_hdr;
EH_PtrCtx eh_ptr_ctx; EH_PtrCtx eh_ptr_ctx;
U64 entry_point_voff; U64 entry_point_voff;
@@ -623,8 +623,8 @@ internal void d_ctrl_thread__append_resolved_process_user_bp_traps(Arena *arena,
internal void d_ctrl_thread__append_program_defined_bp_traps(Arena *arena, D_Entity *bp, DMN_TrapChunkList *traps_out); internal void d_ctrl_thread__append_program_defined_bp_traps(Arena *arena, D_Entity *bp, DMN_TrapChunkList *traps_out);
//- rjf: module lifetime open/close work //- rjf: module lifetime open/close work
internal void d_ctrl_thread__module_open(D_Handle process, D_Handle module, Rng1U64 vaddr_range, String8 path, Rng1U64 elf_phdr_vrange, U64 elf_phdr_entsize); internal void d_ctrl_thread__module_open(D_Handle process, D_Handle module, U64 base_vaddr, DMN_ModuleInfo *module_info);
internal void d_ctrl_thread__module_close(D_Handle process, D_Handle module, Rng1U64 vaddr_range); internal void d_ctrl_thread__module_close(D_Handle process, D_Handle module, U64 base_vaddr);
//- rjf: dump process closing work //- rjf: dump process closing work
internal void d_ctrl_thread__close_dump_process(D_MsgID msg_id, D_Handle process); internal void d_ctrl_thread__close_dump_process(D_MsgID msg_id, D_Handle process);
+1
View File
@@ -119,5 +119,6 @@ dmn_event_list_push(Arena *arena, DMN_EventList *list)
SLLQueuePush(list->first, list->last, n); SLLQueuePush(list->first, list->last, n);
list->count += 1; list->count += 1;
DMN_Event *result = &n->v; DMN_Event *result = &n->v;
result->module_info = &dmn_module_info_nil;
return result; return result;
} }
+51 -8
View File
@@ -69,33 +69,72 @@ struct DMN_HandleArray
//////////////////////////////// ////////////////////////////////
//~ rjf: Event Types //~ rjf: Event Types
typedef struct DMN_ModuleInfo DMN_ModuleInfo;
struct DMN_ModuleInfo
{
// rjf: image architecture
Arch arch;
// rjf: image virtual size
U64 vsize;
// rjf: entry point
U64 entry_point_voff;
// rjf: module path
String8 module_path;
// rjf: debug info key
String8 debug_info_path;
Guid debug_info_guid;
U64 debug_info_timestamp;
U64 debug_info_age;
// rjf: thread-local storage info
U64 tls_index;
U64 tls_offset;
// rjf: unwinding info
Rng1U64 pe_intel_pdatas_vaddr_range;
Rng1U64 eh_frame_header_vaddr_range;
U64 cfi_rebase;
// rjf: special raddbg data
Rng1U64 raddbg_info_voff_range;
U64 raddbg_is_attached_marker_voff;
};
typedef struct DMN_Event DMN_Event; typedef struct DMN_Event DMN_Event;
struct DMN_Event struct DMN_Event
{ {
// rjf: categories
DMN_EventKind kind; DMN_EventKind kind;
DMN_ErrorKind error_kind; DMN_ErrorKind error_kind;
DMN_MemoryEventKind memory_kind; DMN_MemoryEventKind memory_kind;
DMN_ExceptionKind exception_kind; DMN_ExceptionKind exception_kind;
// rjf: entities
DMN_Handle process; DMN_Handle process;
DMN_Handle thread; DMN_Handle thread;
DMN_Handle module; DMN_Handle module;
// rjf: general event properties
Arch arch; Arch arch;
U64 address; U64 address;
U64 size; U64 size;
String8 string; String8 string;
U32 code; // code gives pid & tid on CreateProcess and CreateThread (respectfully) U32 code; // code -> exception code (signo on Linux), pid/tid
U32 flags; // DMN_TrapFlags, if `DMN_EventKind_SetBreakpoint` U32 flags; // DMN_TrapFlags, if `DMN_EventKind_SetBreakpoint`
S32 signo;
S32 sigcode;
Rng1U64 elf_phdr_vrange;
U64 elf_phdr_entsize;
U64 instruction_pointer; U64 instruction_pointer;
U64 stack_pointer; U64 stack_pointer;
U64 user_data; U64 user_data;
B32 exception_repeated; B32 exception_repeated;
U64 tls_index;
U64 tls_offset; // rjf: process info
DMN_TlsModel tls_model; DMN_TlsModel tls_model;
// rjf: module info
DMN_ModuleInfo *module_info;
}; };
typedef struct DMN_EventNode DMN_EventNode; typedef struct DMN_EventNode DMN_EventNode;
@@ -181,6 +220,11 @@ struct DMN_ProcessInfo
U32 pid; U32 pid;
}; };
////////////////////////////////
//~ rjf: Globals
read_only global DMN_ModuleInfo dmn_module_info_nil = {0};
//////////////////////////////// ////////////////////////////////
//~ rjf: Basic Type Functions (Helpers, Implemented Once) //~ rjf: Basic Type Functions (Helpers, Implemented Once)
@@ -247,7 +291,6 @@ internal U64 dmn_process_read(DMN_Handle process, Rng1U64 range, void *dst);
internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src); internal B32 dmn_process_write(DMN_Handle process, Rng1U64 range, void *src);
//- rjf: threads //- rjf: threads
internal Arch dmn_arch_from_thread(DMN_Handle handle);
internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle); internal U64 dmn_stack_base_vaddr_from_thread(DMN_Handle handle);
internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle); internal U64 dmn_tls_root_vaddr_from_thread(DMN_Handle handle);
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block); internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
+1
View File
@@ -13,6 +13,7 @@ DMN_EventKindTable:
{ExitThread} {ExitThread}
{LoadModule} {LoadModule}
{UnloadModule} {UnloadModule}
{ModuleDebugInfo}
{Breakpoint} {Breakpoint}
{Trap} {Trap}
{SingleStep} {SingleStep}
+2 -1
View File
@@ -4,7 +4,7 @@
//- GENERATED CODE //- GENERATED CODE
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
String8 dmn_event_kind_string_table[21] = String8 dmn_event_kind_string_table[22] =
{ {
str8_lit_comp("Null"), str8_lit_comp("Null"),
str8_lit_comp("Error"), str8_lit_comp("Error"),
@@ -15,6 +15,7 @@ str8_lit_comp("CreateThread"),
str8_lit_comp("ExitThread"), str8_lit_comp("ExitThread"),
str8_lit_comp("LoadModule"), str8_lit_comp("LoadModule"),
str8_lit_comp("UnloadModule"), str8_lit_comp("UnloadModule"),
str8_lit_comp("ModuleDebugInfo"),
str8_lit_comp("Breakpoint"), str8_lit_comp("Breakpoint"),
str8_lit_comp("Trap"), str8_lit_comp("Trap"),
str8_lit_comp("SingleStep"), str8_lit_comp("SingleStep"),
+2 -1
View File
@@ -17,6 +17,7 @@ DMN_EventKind_CreateThread,
DMN_EventKind_ExitThread, DMN_EventKind_ExitThread,
DMN_EventKind_LoadModule, DMN_EventKind_LoadModule,
DMN_EventKind_UnloadModule, DMN_EventKind_UnloadModule,
DMN_EventKind_ModuleDebugInfo,
DMN_EventKind_Breakpoint, DMN_EventKind_Breakpoint,
DMN_EventKind_Trap, DMN_EventKind_Trap,
DMN_EventKind_SingleStep, DMN_EventKind_SingleStep,
@@ -62,7 +63,7 @@ DMN_ExceptionKind_COUNT,
} DMN_ExceptionKind; } DMN_ExceptionKind;
C_LINKAGE_BEGIN C_LINKAGE_BEGIN
extern String8 dmn_event_kind_string_table[21]; extern String8 dmn_event_kind_string_table[22];
extern String8 dmn_exception_kind_string_table[5]; extern String8 dmn_exception_kind_string_table[5];
C_LINKAGE_END C_LINKAGE_END
+28 -2
View File
@@ -1571,10 +1571,36 @@ main(int argc, char **argv)
info->initial_path = get_current_path(lnx_state.arena); info->initial_path = get_current_path(lnx_state.arena);
} }
// rjf: grab home directory // rjf: grab program/user data paths
{ {
char *home = getenv("HOME"); char *home = getenv("HOME");
info->user_program_data_path = str8_cstring(home); char *xdg_config_home = getenv("XDG_CONFIG_HOME");
char *xdg_cache_home = getenv("XDG_CACHE_HOME");
char *xdg_state_home = getenv("XDG_STATE_HOME");
if(xdg_config_home != 0)
{
info->user_program_config_data_path = str8_cstring(xdg_config_home);
}
else
{
info->user_program_config_data_path = str8f(lnx_state.arena, "%s/.config", home);
}
if(xdg_cache_home != 0)
{
info->user_program_cache_data_path = str8_cstring(xdg_cache_home);
}
else
{
info->user_program_cache_data_path = str8f(lnx_state.arena, "%s/.cache", home);
}
if(xdg_state_home != 0)
{
info->user_program_logs_data_path = str8_cstring(xdg_state_home);
}
else
{
info->user_program_logs_data_path = str8f(lnx_state.arena, "%s/.local/state", home);
}
} }
scratch_end(scratch); scratch_end(scratch);
+237 -19
View File
@@ -292,6 +292,237 @@ lnx_dmn_process_from_pid(pid_t pid)
return hash_table_search_u64_raw(lnx_dmn_state->pid_ht, pid); return hash_table_search_u64_raw(lnx_dmn_state->pid_ht, pid);
} }
////////////////////////////////
//~ rjf: Module Info Parsing
internal DMN_ModuleInfo *
lnx_dmn_module_info_from_process_module(Arena *arena, pid_t pid, int memory_fd, U64 base_vaddr, U64 name_vaddr, B32 is_main)
{
DMN_ModuleInfo *info = push_array(arena, DMN_ModuleInfo, 1);
Temp scratch = scratch_begin(&arena, 1);
{
//- rjf: read ELF signature
U8 elf_sig_maybe[ELF_Identifier_Max] = {0};
lnx_dmn_read(memory_fd, r1u64(base_vaddr, base_vaddr + sizeof(elf_sig_maybe)), elf_sig_maybe);
//- rjf: unpack elf header info
Arch arch = Arch_Null;
U64 entry_point_voff = 0;
ELF_Type elf_type = ELF_Type_None;
U64 phdrs_off = 0;
U64 phdrs_entry_size = 0;
U64 phdrs_count = 0;
U64 shdrs_off = 0;
U64 shdrs_entry_size = 0;
U64 shdrs_count = 0;
U64 shdrs_strings_idx = 0;
{
// rjf: read ehdr
ELF_Hdr64 ehdr = {0};
switch(elf_sig_maybe[ELF_Identifier_Class])
{
default:
case ELF_Class_None:
{}break;
case ELF_Class_32:
{
ELF_Hdr32 ehdr32 = {0};
lnx_dmn_read_struct(memory_fd, base_vaddr, &ehdr32);
MemoryCopy(ehdr.e_ident, ehdr32.e_ident, sizeof(ehdr.e_ident));
ehdr.e_type = ehdr32.e_type;
ehdr.e_machine = ehdr32.e_machine;
ehdr.e_version = ehdr32.e_version;
ehdr.e_entry = (U64)ehdr32.e_entry;
ehdr.e_phoff = (U64)ehdr32.e_phoff;
ehdr.e_shoff = (U64)ehdr32.e_shoff;
ehdr.e_flags = ehdr32.e_flags;
ehdr.e_ehsize = ehdr32.e_ehsize;
ehdr.e_phentsize = ehdr32.e_phentsize;
ehdr.e_phnum = ehdr32.e_phnum;
ehdr.e_shentsize = ehdr32.e_shentsize;
ehdr.e_shnum = ehdr32.e_shnum;
ehdr.e_shstrndx = ehdr32.e_shstrndx;
}break;
case ELF_Class_64:
{
lnx_dmn_read_struct(memory_fd, base_vaddr, &ehdr);
}break;
}
// rjf: unpack ehdr
arch = arch_from_elf_machine(ehdr.e_machine);
entry_point_voff = ehdr.e_entry - base_vaddr;
elf_type = ehdr.e_type;
phdrs_off = ehdr.e_phoff;
phdrs_entry_size = ehdr.e_phentsize;
phdrs_count = ehdr.e_phnum;
shdrs_off = ehdr.e_shoff;
shdrs_entry_size = ehdr.e_shentsize;
shdrs_count = ehdr.e_shnum;
shdrs_strings_idx = ehdr.e_shstrndx;
}
//- rjf: decide on rebase for this module
U64 module_rebase = 0;
if(elf_type == ELF_Type_Dyn)
{
module_rebase = base_vaddr;
}
//- rjf: determine shdrs/phdrs addresses
U64 phdrs_vaddr = module_rebase + phdrs_off;
U64 phdrs_vaddr_opl = phdrs_vaddr + phdrs_count*phdrs_entry_size;
U64 shdrs_vaddr = module_rebase + shdrs_off;
//- rjf: scan phdrs, unpack info
U64 image_vsize = 0;
Rng1U64 eh_frame_header_vaddr_range = {0};
{
for EachIndex(phdr_idx, phdrs_count)
{
U64 phdr_vaddr = phdrs_vaddr + phdr_idx*phdrs_entry_size;
ELF_Phdr64 phdr = {0};
switch(elf_sig_maybe[ELF_Identifier_Class])
{
default:{}break;
case ELF_Class_32:
{
ELF_Phdr32 phdr32 = {0};
lnx_dmn_read_struct(memory_fd, phdr_vaddr, &phdr32);
phdr.p_type = phdr32.p_type;
phdr.p_flags = phdr32.p_flags;
phdr.p_offset = (U64)phdr32.p_offset;
phdr.p_vaddr = (U64)phdr32.p_vaddr;
phdr.p_paddr = (U64)phdr32.p_paddr;
phdr.p_filesz = (U64)phdr32.p_filesz;
phdr.p_memsz = (U64)phdr32.p_memsz;
phdr.p_align = (U64)phdr32.p_align;
}break;
case ELF_Class_64:
{
lnx_dmn_read_struct(memory_fd, phdr_vaddr, &phdr);
}break;
}
if(phdr.p_type == ELF_PType_Load)
{
image_vsize = (module_rebase + phdr.p_vaddr + phdr.p_memsz) - base_vaddr;
}
if(phdr.p_type == ELF_PType_GnuEHFrame)
{
eh_frame_header_vaddr_range = r1u64(module_rebase + phdr.p_vaddr, module_rebase + phdr.p_vaddr + phdr.p_memsz);
}
}
}
//- rjf: scan shdrs, unpack info
Rng1U64 raddbg_info_voff_range = {0};
U64 raddbg_is_attached_marker_voff = 0;
{
// rjf: read all shdrs
ELF_Shdr64 *shdrs = push_array(scratch.arena, ELF_Shdr64, shdrs_count);
for EachIndex(shdr_idx, shdrs_count)
{
U64 shdr_vaddr = shdrs_vaddr + shdr_idx*shdrs_entry_size;
switch(elf_sig_maybe[ELF_Identifier_Class])
{
case ELF_Class_32:
{
ELF_Shdr32 shdr32 = {0};
lnx_dmn_read_struct(memory_fd, shdr_vaddr, &shdr32);
shdrs[shdr_idx].sh_name = shdr32.sh_name;
shdrs[shdr_idx].sh_type = shdr32.sh_type;
shdrs[shdr_idx].sh_flags = (U64)shdr32.sh_flags;
shdrs[shdr_idx].sh_addr = (U64)shdr32.sh_addr;
shdrs[shdr_idx].sh_offset = (U64)shdr32.sh_offset;
shdrs[shdr_idx].sh_size = (U64)shdr32.sh_size;
shdrs[shdr_idx].sh_link = shdr32.sh_link;
shdrs[shdr_idx].sh_info = shdr32.sh_info;
shdrs[shdr_idx].sh_addralign= (U64)shdr32.sh_addralign;
shdrs[shdr_idx].sh_entsize = (U64)shdr32.sh_entsize;
}break;
case ELF_Class_64:
{
lnx_dmn_read_struct(memory_fd, shdr_vaddr, &shdrs[shdr_idx]);
}break;
}
}
// rjf: get string shdr
ELF_Shdr64 *string_shdr = 0;
if(shdrs_strings_idx < shdrs_count)
{
string_shdr = &shdrs[shdrs_strings_idx];
}
// rjf: scan shdrs, using names
if(string_shdr != 0)
{
for EachIndex(shdr_idx, shdrs_count)
{
ELF_Shdr64 *shdr = &shdrs[shdr_idx];
U64 name_vaddr = string_shdr->sh_addr + shdr->sh_name;
String8 shdr_name = lnx_dmn_read_string(scratch.arena, memory_fd, name_vaddr);
if(str8_match(shdr_name, s(".raddbg"), 0))
{
raddbg_info_voff_range = r1u64(shdr->sh_addr - base_vaddr, shdr->sh_addr - base_vaddr + shdr->sh_size);
}
if(str8_match(shdr_name, s(".rdbgia"), 0))
{
raddbg_is_attached_marker_voff = (shdr->sh_addr - base_vaddr);
}
}
}
}
//- rjf: unpack tls info
U64 tls_index = max_U64;
U64 tls_offset = max_U64;
if(is_main)
{
tls_index = 1;
tls_offset = 0;
}
else if(lnx_dmn_state->is_tls_detected)
{
Rng1U64 tls_modid_range = r1u64(lnx_dmn_state->tls_modid_desc.offset, lnx_dmn_state->tls_modid_desc.offset + lnx_dmn_state->tls_modid_desc.bit_size / 8);
Rng1U64 tls_offset_range = r1u64(lnx_dmn_state->tls_offset_desc.offset, lnx_dmn_state->tls_offset_desc.offset + lnx_dmn_state->tls_offset_desc.bit_size / 8);
tls_modid_range = shift_1u64(tls_modid_range, base_vaddr);
tls_offset_range = shift_1u64(tls_offset_range, base_vaddr);
tls_modid_range.max = Min(tls_modid_range.max, tls_modid_range.min + sizeof(tls_index));
tls_offset_range.max = Min(tls_offset_range.max, tls_offset_range.min + sizeof(tls_offset));
lnx_dmn_read(memory_fd, tls_modid_range, &tls_index);
lnx_dmn_read(memory_fd, tls_offset_range, &tls_offset);
}
//- rjf: read module path
String8 module_path = lnx_dmn_read_string(arena, memory_fd, name_vaddr);
//- rjf: decide on debug info key info
String8 debug_info_path = module_path;
Guid debug_info_guid = {0};
U64 debug_info_timestamp = 0;
U64 debug_info_age = 0;
//- rjf: fill result
info->arch = arch;
info->vsize = image_vsize;
info->entry_point_voff = entry_point_voff;
info->module_path = module_path;
info->debug_info_path = debug_info_path;
info->debug_info_guid = debug_info_guid;
info->debug_info_timestamp = debug_info_timestamp;
info->debug_info_age = debug_info_age;
info->tls_index = tls_index;
info->tls_offset = tls_offset;
info->eh_frame_header_vaddr_range = eh_frame_header_vaddr_range;
info->cfi_rebase = module_rebase;
info->raddbg_info_voff_range = raddbg_info_voff_range;
info->raddbg_is_attached_marker_voff = raddbg_is_attached_marker_voff;
}
scratch_end(scratch);
return info;
}
//////////////////////////////// ////////////////////////////////
//~ rjf: Trap Setting //~ rjf: Trap Setting
@@ -1681,7 +1912,9 @@ internal void
lnx_dmn_push_event_load_module(Arena *arena, DMN_EventList *events, LNX_DMN_Thread *thread, LNX_DMN_Module *module) lnx_dmn_push_event_load_module(Arena *arena, DMN_EventList *events, LNX_DMN_Thread *thread, LNX_DMN_Module *module)
{ {
// TODO: reporting this module breaks ctrl thread // TODO: reporting this module breaks ctrl thread
String8 module_name = lnx_dmn_read_string(arena, thread->process->fd, module->name_vaddr); LNX_DMN_Process *process = thread->process;
DMN_ModuleInfo *module_info = lnx_dmn_module_info_from_process_module(arena, process->pid, process->fd, module->base_vaddr, module->name_vaddr, module->is_main);
String8 module_name = module_info->module_path;
if(!str8_match(module_name, str8_lit("linux-vdso.so.1"), 0)) if(!str8_match(module_name, str8_lit("linux-vdso.so.1"), 0))
{ {
DMN_Event *e = dmn_event_list_push(arena, events); DMN_Event *e = dmn_event_list_push(arena, events);
@@ -1689,14 +1922,11 @@ lnx_dmn_push_event_load_module(Arena *arena, DMN_EventList *events, LNX_DMN_Thre
e->process = lnx_dmn_handle_from_process(thread->process); e->process = lnx_dmn_handle_from_process(thread->process);
e->thread = lnx_dmn_handle_from_thread(thread); e->thread = lnx_dmn_handle_from_thread(thread);
e->module = lnx_dmn_handle_from_module(module); e->module = lnx_dmn_handle_from_module(module);
e->arch = thread->process->ctx->arch; e->arch = module_info->arch;
e->address = module->base_vaddr; e->address = module->base_vaddr;
e->size = module->size; e->size = module->size;
e->string = module_name; e->string = module_name;
e->elf_phdr_vrange = r1u64(module->phvaddr, module->phvaddr + module->phentsize * module->phcount); e->module_info = module_info;
e->elf_phdr_entsize = module->phentsize;
e->tls_index = module->tls_index;
e->tls_offset = module->tls_offset;
} }
} }
@@ -1787,7 +2017,7 @@ lnx_dmn_push_event_exception(Arena *arena, DMN_EventList *events, LNX_DMN_Thread
e->thread = lnx_dmn_handle_from_thread(thread); e->thread = lnx_dmn_handle_from_thread(thread);
e->instruction_pointer = lnx_dmn_thread_read_ip(thread); e->instruction_pointer = lnx_dmn_thread_read_ip(thread);
e->address = e->instruction_pointer; e->address = e->instruction_pointer;
e->signo = signo; e->code = signo;
e->exception_repeated = signo < ArrayCount(is_repeatable) ? is_repeatable[signo] : 0; e->exception_repeated = signo < ArrayCount(is_repeatable) ? is_repeatable[signo] : 0;
if(signo == SIGSEGV) if(signo == SIGSEGV)
@@ -3009,18 +3239,6 @@ dmn_process_write(DMN_Handle process_handle, Rng1U64 range, void *src)
//- rjf: threads //- rjf: threads
internal Arch
dmn_arch_from_thread(DMN_Handle thread_handle)
{
Arch arch = Arch_Null;
LNX_DMN_Thread *thread = lnx_dmn_thread_from_handle(thread_handle);
if(thread)
{
arch = thread->process->ctx->arch;
}
return arch;
}
internal U64 internal U64
dmn_stack_base_vaddr_from_thread(DMN_Handle thread_handle) dmn_stack_base_vaddr_from_thread(DMN_Handle thread_handle)
{ {
+5
View File
@@ -420,6 +420,11 @@ internal LNX_DMN_Auxv lnx_dmn_auxv_from_pid(pid_t pid, ELF_Class elf_class)
internal LNX_DMN_Thread * lnx_dmn_thread_from_pid(pid_t pid); internal LNX_DMN_Thread * lnx_dmn_thread_from_pid(pid_t pid);
internal LNX_DMN_Process * lnx_dmn_process_from_pid(pid_t pid); internal LNX_DMN_Process * lnx_dmn_process_from_pid(pid_t pid);
////////////////////////////////
//~ rjf: Module Info Parsing
internal DMN_ModuleInfo *lnx_dmn_module_info_from_process_module(Arena *arena, pid_t pid, int memory_fd, U64 base_vaddr, U64 link_map_vaddr, B32 is_main);
//////////////////////////////// ////////////////////////////////
//~ Entity //~ Entity
+13 -14
View File
@@ -8817,16 +8817,15 @@ rd_window_frame(void)
Vec4F32 hover_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("hover")); Vec4F32 hover_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("hover"));
// rjf: brighten // rjf: brighten
if(is_hot)
{ {
Vec4F32 color = hover_color; Vec4F32 color = hover_color;
color.w *= 0.05f; color.w *= 0.015f;
if(!is_hot)
{
color.w *= t;
}
R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, 1.f), v4f32(0, 0, 0, 0), 0, 0, border_softness*1.f); R_Rect2DInst *inst = dr_rect(pad_2f32(box->rect, 1.f), v4f32(0, 0, 0, 0), 0, 0, border_softness*1.f);
inst->colors[Corner_00] = color; inst->colors[Corner_00] = color;
inst->colors[Corner_10] = color; inst->colors[Corner_10] = color;
inst->colors[Corner_01] = color;
inst->colors[Corner_11] = color;
MemoryCopyArray(inst->corner_radii, box_corner_radii); MemoryCopyArray(inst->corner_radii, box_corner_radii);
} }
@@ -8834,7 +8833,7 @@ rd_window_frame(void)
if(box->hot_t > 0.01f) DR_ClipScope(intersect_2f32(box->rect, dr_top_clip())) if(box->hot_t > 0.01f) DR_ClipScope(intersect_2f32(box->rect, dr_top_clip()))
{ {
Vec4F32 color = hover_color; Vec4F32 color = hover_color;
color.w *= 0.02f; color.w *= 0.025f;
if(!is_hot) if(!is_hot)
{ {
color.w *= t; color.w *= t;
@@ -8842,7 +8841,7 @@ rd_window_frame(void)
Vec2F32 center = ui_mouse(); Vec2F32 center = ui_mouse();
Vec2F32 box_dim = dim_2f32(box->rect); Vec2F32 box_dim = dim_2f32(box->rect);
F32 max_dim = Max(box_dim.x, box_dim.y); F32 max_dim = Max(box_dim.x, box_dim.y);
F32 radius = box->font_size*12.f; F32 radius = box->font_size*24.f;
radius = Min(max_dim, radius); radius = Min(max_dim, radius);
dr_rect(pad_2f32(r2f32(center, center), radius), color, radius, 0, radius/3.f); dr_rect(pad_2f32(r2f32(center, center), radius), color, radius, 0, radius/3.f);
} }
@@ -9485,7 +9484,7 @@ rd_theme_tree_from_name(Arena *arena, Access *access, String8 theme_name)
} }
if(theme_tree == &md_nil_node) if(theme_tree == &md_nil_node)
{ {
String8 path = str8f(scratch.arena, "%S/%Sraddbg/themes/%S", program_data_folder_prefix_from_os(OperatingSystem_CURRENT), get_process_info()->user_program_data_path, theme_name); String8 path = str8f(scratch.arena, "%S/raddbg/themes/%S", get_process_info()->user_program_config_data_path, theme_name);
U64 endt_us = now_time_us()+100; U64 endt_us = now_time_us()+100;
if(rd_state->frame_index <= 5) if(rd_state->frame_index <= 5)
{ {
@@ -10537,8 +10536,8 @@ rd_init(CmdLine *cmdln)
} }
} }
{ {
String8 user_program_data_path = get_process_info()->user_program_data_path; String8 user_program_config_data_path = get_process_info()->user_program_config_data_path;
String8 user_data_folder = push_str8f(scratch2.arena, "%S/raddbg", user_program_data_path); String8 user_data_folder = str8f(scratch2.arena, "%S/raddbg", user_program_config_data_path);
make_directory(user_data_folder); make_directory(user_data_folder);
if(user_path.size == 0) if(user_path.size == 0)
{ {
@@ -10546,12 +10545,12 @@ rd_init(CmdLine *cmdln)
} }
if(user_path.size == 0) if(user_path.size == 0)
{ {
String8 last_user_path = push_str8f(scratch2.arena, "%S/last_user", user_data_folder); String8 last_user_path = str8f(scratch2.arena, "%S/last_user", user_data_folder);
user_path = data_from_file_path(scratch2.arena, last_user_path); user_path = data_from_file_path(scratch2.arena, last_user_path);
} }
if(user_path.size == 0) if(user_path.size == 0)
{ {
user_path = push_str8f(scratch2.arena, "%S/default.raddbg_user", user_data_folder); user_path = str8f(scratch2.arena, "%S/default.raddbg_user", user_data_folder);
} }
} }
if(project_path.size == 0) if(project_path.size == 0)
@@ -13211,7 +13210,7 @@ rd_frame(void)
case RD_CmdKind_RecordUserAsLastOpened: case RD_CmdKind_RecordUserAsLastOpened:
{ {
String8 file_path = rd_regs()->file_path; String8 file_path = rd_regs()->file_path;
String8 last_user_path = str8f(scratch.arena, "%S/%Sraddbg/last_user", get_process_info()->user_program_data_path, program_data_folder_prefix_from_os(OperatingSystem_CURRENT)); String8 last_user_path = str8f(scratch.arena, "%S/raddbg/last_user", get_process_info()->user_program_config_data_path);
write_data_to_file_path(last_user_path, file_path); write_data_to_file_path(last_user_path, file_path);
}break; }break;
@@ -15777,7 +15776,7 @@ rd_frame(void)
String8 name = rd_regs()->string; String8 name = rd_regs()->string;
if(name.size != 0) if(name.size != 0)
{ {
String8 themes_folder = str8f(scratch.arena, "%S/%Sraddbg/themes", get_process_info()->user_program_data_path, program_data_folder_prefix_from_os(OperatingSystem_CURRENT)); String8 themes_folder = str8f(scratch.arena, "%S/raddbg/themes", get_process_info()->user_program_config_data_path);
if(make_directory(themes_folder)) if(make_directory(themes_folder))
{ {
String8 dst_path = push_str8f(scratch.arena, "%S/%S", themes_folder, name); String8 dst_path = push_str8f(scratch.arena, "%S/%S", themes_folder, name);
+1 -1
View File
@@ -122,7 +122,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(themes)
//- rjf: gather theme files //- rjf: gather theme files
{ {
String8 theme_folder = push_str8f(scratch.arena, "%S/%Sraddbg/themes", get_process_info()->user_program_data_path, program_data_folder_prefix_from_os(OperatingSystem_CURRENT)); String8 theme_folder = push_str8f(scratch.arena, "%S/raddbg/themes", get_process_info()->user_program_config_data_path);
FileIter *it = file_iter_begin(scratch.arena, theme_folder, FileIterFlag_SkipFolders); FileIter *it = file_iter_begin(scratch.arena, theme_folder, FileIterFlag_SkipFolders);
for(FileInfo info = {0}; file_iter_next(scratch.arena, it, &info);) for(FileInfo info = {0}; file_iter_next(scratch.arena, it, &info);)
{ {
+4 -4
View File
@@ -6,9 +6,9 @@
// //
// [ ] jeff stepping bug // [ ] jeff stepping bug
// [ ] wassim memory bug // [ ] wassim memory bug
// [ ] test concepts -> base
// [ ] switch off spoofs for step-over // [ ] switch off spoofs for step-over
// [ ] debugger, d2r, p2r exemplar / determinism testing // [x] test concepts -> base
// [x] debugger, d2r, p2r exemplar / determinism testing
// //
// [ ] symbol server // [ ] symbol server
// [ ] core dump saving/loading // [ ] core dump saving/loading
@@ -540,8 +540,8 @@ entry_point(CmdLine *cmd_line)
g_logs_folder = cmd_line_string(cmd_line, str8_lit("logs")); g_logs_folder = cmd_line_string(cmd_line, str8_lit("logs"));
if(g_logs_folder.size == 0) if(g_logs_folder.size == 0)
{ {
String8 user_program_data_path = get_process_info()->user_program_data_path; String8 user_program_logs_data_path = get_process_info()->user_program_logs_data_path;
g_logs_folder = push_str8f(scratch.arena, "%S/%Sraddbg/logs", program_data_folder_prefix_from_os(OperatingSystem_CURRENT), user_program_data_path); g_logs_folder = push_str8f(scratch.arena, "%S/raddbg/logs", user_program_logs_data_path);
} }
make_directory(g_logs_folder); make_directory(g_logs_folder);
+1 -1
View File
@@ -1865,7 +1865,7 @@ rd_info_from_watch_row_cell(Arena *arena, EV_Row *row, EV_StringFlags string_fla
String8 file_name = str8_from_rdi_string_idx(rdi, path_node->name_string_idx); String8 file_name = str8_from_rdi_string_idx(rdi, path_node->name_string_idx);
// rjf: push line location // rjf: push line location
if(file_name.size != 0) UI_TagF("weak") if(line.file_idx != 0) UI_TagF("weak")
{ {
String8 loc = str8f(arena, "%S:%i", file_name, line.line_num); String8 loc = str8f(arena, "%S:%i", file_name, line.line_num);
DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), font_size*0.85f, 0, 0}; DR_FStrParams params = {rd_font_from_slot(RD_FontSlot_Main), rd_raster_flags_from_slot(RD_FontSlot_Main), ui_color_from_name(str8_lit("text")), font_size*0.85f, 0, 0};
+2 -1
View File
@@ -1922,7 +1922,8 @@ w32_entry_point_caller(int argc, WCHAR **wargv)
U16 *buffer = push_array_no_zero(scratch.arena, U16, size); U16 *buffer = push_array_no_zero(scratch.arena, U16, size);
if(SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, (WCHAR*)buffer))) if(SUCCEEDED(SHGetFolderPathW(0, CSIDL_APPDATA, 0, 0, (WCHAR*)buffer)))
{ {
info->user_program_data_path = str8_from_16(arena, str16_cstring(buffer)); info->user_program_config_data_path = str8_from_16(arena, str16_cstring(buffer));
info->user_program_cache_data_path = info->user_program_logs_data_path = info->user_program_config_data_path;
} }
scratch_end(scratch); scratch_end(scratch);
} }
+385 -127
View File
@@ -337,6 +337,62 @@ w32_dmn_process_write(HANDLE process, Rng1U64 range, void *src)
return result; return result;
} }
internal String8
w32_dmn_str8_cstring_from_process_vaddr(Arena *arena, HANDLE process, U64 vaddr)
{
Temp scratch = scratch_begin(&arena, 1);
String8List pieces = {0};
U64 chunk_cap = 256;
U64 chunk_size = chunk_cap;
U64 vaddr_opl = vaddr + 16384;
U8 *chunk_buffer = push_array(scratch.arena, U8, chunk_cap);
for(U64 read_vaddr = vaddr; read_vaddr < vaddr_opl;)
{
// rjf: zero / read next chunk - shrink chunk size if needed
MemoryZero(chunk_buffer, chunk_size);
U64 bytes_read = 0;
for(;bytes_read == 0 && chunk_size != 0;)
{
bytes_read = w32_dmn_process_read(process, r1u64(vaddr, vaddr+chunk_size), chunk_buffer);
if(bytes_read == 0)
{
chunk_size /= 2;
}
}
// rjf: advance
vaddr += bytes_read;
// rjf: look for null terminator
B32 found_null_terminator = 0;
U64 read_chunk_size = bytes_read;
for(U64 idx = 0; idx < bytes_read; idx += 1)
{
if(chunk_buffer[idx] == 0)
{
read_chunk_size = idx;
found_null_terminator = 1;
break;
}
}
// rjf: nonzero chunk size -> push to piece list
if(read_chunk_size != 0)
{
str8_list_push(scratch.arena, &pieces, str8_copy(scratch.arena, str8(chunk_buffer, read_chunk_size)));
}
// rjf: if this chunk contained a null terminator, or if we didn't read anything -> we're done
if(found_null_terminator || bytes_read == 0)
{
break;
}
}
String8 result = str8_list_join(arena, &pieces, 0);
scratch_end(scratch);
return result;
}
internal String8 internal String8
w32_dmn_read_memory_str(Arena *arena, HANDLE process_handle, U64 address) w32_dmn_read_memory_str(Arena *arena, HANDLE process_handle, U64 address)
{ {
@@ -438,126 +494,319 @@ w32_dmn_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address)
return(result); return(result);
} }
internal W32_DMN_ImageInfo //- rjf: modules
w32_dmn_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr)
internal DMN_ModuleInfo *
w32_dmn_module_info_from_process_module(Arena *arena, HANDLE process, HANDLE module, U64 base_vaddr, U64 module_name_vaddr, B32 module_name_is_unicode, B32 is_main_module)
{ {
// rjf: find PE offset DMN_ModuleInfo *info = push_array(arena, DMN_ModuleInfo, 1);
U32 pe_offset = 0; Temp scratch = scratch_begin(&arena, 1);
{ {
U64 dos_magic_off = base_vaddr; B32 is_good = 1;
U16 dos_magic = 0;
w32_dmn_process_read_struct(process, dos_magic_off, &dos_magic); //- rjf: read DOS header
if(dos_magic == PE_DOS_MAGIC) PE_DosHeader dos_header = {0};
if(is_good)
{ {
U64 pe_offset_off = base_vaddr + OffsetOf(PE_DosHeader, coff_file_offset); w32_dmn_process_read_struct(process, base_vaddr, &dos_header);
w32_dmn_process_read_struct(process, pe_offset_off, &pe_offset); is_good = (dos_header.magic == PE_DOS_MAGIC);
} }
}
// rjf: get COFF header //- rjf: read PE magic
B32 got_coff_header = 0; U32 pe_magic = 0;
U64 coff_header_off = 0; if(is_good)
COFF_FileHeader coff_header = {0};
if(pe_offset > 0)
{
U64 pe_magic_off = base_vaddr + pe_offset;
U32 pe_magic = 0;
w32_dmn_process_read_struct(process, pe_magic_off, &pe_magic);
if(pe_magic == PE_MAGIC)
{ {
coff_header_off = pe_magic_off + sizeof(pe_magic); w32_dmn_process_read_struct(process, base_vaddr + dos_header.coff_file_offset, &pe_magic);
got_coff_header = w32_dmn_process_read_struct(process, coff_header_off, &coff_header); is_good = (pe_magic == PE_MAGIC);
} }
}
W32_DMN_ImageInfo result = zero_struct; //- rjf: read COFF header
if(got_coff_header) U64 file_header_off = dos_header.coff_file_offset + sizeof(pe_magic);
{ COFF_FileHeader file_header = {0};
U64 optional_off = coff_header_off + sizeof(COFF_FileHeader); if(is_good)
Arch arch = arch_from_coff_machine(coff_header.machine);
U64 image_size = 0;
U64 data_dir_count = 0;
U64 data_dir_off = max_U64;
U64 tls_index = max_U64;
// parse optional header
if(pe_has_plus_header(coff_header.machine))
{ {
PE_OptionalHeader32Plus opt_header = {0}; w32_dmn_process_read_struct(process, base_vaddr + file_header_off, &file_header);
if(w32_dmn_process_read_struct(process, optional_off, &opt_header)) }
//- rjf: get architecture
Arch arch = arch_from_coff_machine(file_header.machine);
//- rjf: get module path
String8 module_path = {0};
{
String8 module_path8 = {0};
String16 module_path16 = {0};
// rjf: try to get module path from handle
if(module_path16.size == 0 && module != 0)
{ {
image_size = opt_header.sizeof_image; DWORD cap16 = GetFinalPathNameByHandleW(module, 0, 0, VOLUME_NAME_DOS);
data_dir_count = opt_header.data_dir_count; U16 *buffer16 = push_array_no_zero(scratch.arena, U16, cap16);
data_dir_off = optional_off + sizeof(opt_header); DWORD size16 = GetFinalPathNameByHandleW(module, (WCHAR*)buffer16, cap16, VOLUME_NAME_DOS);
module_path16 = str16(buffer16, size16);
} }
else { Assert(0 && "failed to read optional header"); }
}
else
{
PE_OptionalHeader32 opt_header = {0};
if(w32_dmn_process_read_struct(process, optional_off, &opt_header))
{
image_size = opt_header.sizeof_image;
data_dir_count = opt_header.data_dir_count;
data_dir_off = optional_off + sizeof(opt_header);
}
else { Assert(0 && "failed to read optional header"); }
}
// extract TLS index // rjf: fallback (main module only): process -> full path
if(PE_DataDirectoryIndex_TLS < data_dir_count) if(module_path16.size == 0 && is_main_module)
{
U64 tls_dir_vaddr = data_dir_off + PE_DataDirectoryIndex_TLS * sizeof(PE_DataDirectory);
PE_DataDirectory tls_dir = {0};
if(w32_dmn_process_read_struct(process, tls_dir_vaddr, &tls_dir))
{ {
if(pe_has_plus_header(coff_header.machine)) DWORD size = 4096;
U16 *buf = push_array_no_zero(scratch.arena, U16, size);
if(QueryFullProcessImageNameW(process, 0, (WCHAR*)buf, &size))
{ {
if(tls_dir.virt_size == sizeof(PE_TLSHeader64)) module_path16 = str16(buf, size);
{
PE_TLSHeader64 tls_header = {0};
if(w32_dmn_process_read_struct(process, base_vaddr + tls_dir.virt_off, &tls_header))
{
U64 tls_index64 = 0;
if(w32_dmn_process_read_struct(process, tls_header.index_address, &tls_index64))
{
tls_index = tls_index64;
}
else { Assert(0 && "failed to read TLS Index 64"); }
}
else { Assert(0 && "failed to read TLS Header 64"); }
}
} }
else }
// rjf: fallback (any module - no guarantee): address_of_name -> full path
if(module_path16.size == 0 && module_name_vaddr != 0)
{
U64 ptr_size = bit_size_from_arch(arch)/8;
U64 name_pointer = 0;
if(w32_dmn_process_read(process, r1u64(module_name_vaddr, module_name_vaddr+ptr_size), &name_pointer))
{ {
if(tls_dir.virt_size == sizeof(PE_TLSHeader32)) if(name_pointer != 0)
{ {
PE_TLSHeader32 tls_header = {0}; if(module_name_is_unicode)
if(w32_dmn_process_read_struct(process, base_vaddr + tls_dir.virt_off, &tls_header))
{ {
U32 tls_index32 = 0; module_path16 = w32_dmn_read_memory_str16(scratch.arena, process, name_pointer);
if(w32_dmn_process_read_struct(process, tls_header.index_address, &tls_index32)) }
{ else
tls_index = tls_index32; {
} module_path8 = w32_dmn_read_memory_str(scratch.arena, process, name_pointer);
else { Assert(0 && "failed to read TLS Index 32"); }
} }
else { Assert(0 && "failed to read TLS Header32"); }
} }
} }
} }
else { Assert(0 && "failed to read TLS directory"); }
// rjf: skip the extended path thing if necessary
{
if(module_path16.size >= 4 &&
module_path16.str[0] == L'\\' &&
module_path16.str[1] == L'\\' &&
module_path16.str[2] == L'?' &&
module_path16.str[3] == L'\\')
{
module_path16.size -= 4;
module_path16.str += 4;
}
else if(module_path8.size >= 4 &&
module_path8.str[0] == L'\\' &&
module_path8.str[1] == L'\\' &&
module_path8.str[2] == L'?' &&
module_path8.str[3] == L'\\')
{
module_path8.size -= 4;
module_path8.str += 4;
}
}
// rjf: 16 -> 8
if(module_path16.size != 0)
{
module_path = str8_from_16(arena, module_path16);
}
else if(module_path8.size != 0)
{
module_path = str8_copy(arena, module_path8);
}
} }
// fill out result //- rjf: unpack range of optional extension header
result.arch = arch; U32 opt_ext_size = file_header.optional_header_size;
result.size = image_size; Rng1U64 opt_ext_off_range = r1u64(file_header_off + sizeof(COFF_FileHeader),
result.tls_index = tls_index; file_header_off + sizeof(COFF_FileHeader) + opt_ext_size);
}
else { Assert(0 && "failed to find COFF file header"); }
return result; //- rjf: read optional header
U64 image_vsize = 0;
U64 entry_point_voff = 0;
U64 tls_index = 0;
String8 debug_info_path = {0};
Guid debug_info_guid = {0};
U64 debug_info_timestamp = 0;
U64 debug_info_age = 0;
Rng1U64 pe_intel_pdatas_vaddr_range = {0};
Rng1U64 raddbg_info_voff_range = {0};
U64 raddbg_is_attached_marker_voff = 0;
if(opt_ext_size > 0)
{
// rjf: read magic number
U16 opt_ext_magic = 0;
w32_dmn_process_read_struct(process, base_vaddr + 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};
w32_dmn_process_read_struct(process, base_vaddr + opt_ext_off_range.min, &pe_optional);
image_vsize = pe_optional.sizeof_image;
entry_point_voff = pe_optional.entry_point_va;
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};
w32_dmn_process_read_struct(process, base_vaddr + opt_ext_off_range.min, &pe_optional);
image_vsize = pe_optional.sizeof_image;
entry_point_voff = pe_optional.entry_point_va;
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);
U32 data_dir_count = ClampTop(reported_data_dir_count, data_dir_max);
// 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);
w32_dmn_process_read(process, r1u64(base_vaddr + sec_array_off, base_vaddr + sec_array_off + sec_count*sizeof(COFF_SectionHeader)), sec);
// rjf: grab pdatas range from exceptions section
if(data_dir_count > PE_DataDirectoryIndex_EXCEPTIONS)
{
PE_DataDirectory dir = {0};
w32_dmn_process_read_struct(process, base_vaddr + 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);
pe_intel_pdatas_vaddr_range = r1u64(pdatas_voff_range.min + base_vaddr, pdatas_voff_range.max + base_vaddr);
}
// rjf: grab tls info
if(data_dir_count > PE_DataDirectoryIndex_TLS)
{
PE_DataDirectory tls_dir = {0};
w32_dmn_process_read_struct(process, base_vaddr + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_TLS, &tls_dir);
if(tls_dir.virt_size == sizeof(PE_TLSHeader64))
{
PE_TLSHeader64 tls_header = {0};
w32_dmn_process_read_struct(process, base_vaddr + tls_dir.virt_off, &tls_header);
U64 tls_index64 = 0;
w32_dmn_process_read_struct(process, tls_header.index_address, &tls_index64);
tls_index = tls_index64;
}
else if(tls_dir.virt_size == sizeof(PE_TLSHeader32))
{
PE_TLSHeader32 tls_header = {0};
w32_dmn_process_read_struct(process, base_vaddr + tls_dir.virt_off, &tls_header);
U32 tls_index32 = 0;
w32_dmn_process_read_struct(process, tls_header.index_address, &tls_index32);
tls_index = (U64)tls_index32;
}
}
// rjf: grab data about DWARF debug info, hinted at via symbol array in header
{
U64 symbol_array_off = file_header.symbol_table_foff;
U64 symbol_count = file_header.symbol_count;
if(symbol_array_off != 0)
{
debug_info_path = module_path;
}
}
// rjf: grab data about PDB/RDI debug info, expressed via debug data directory
if(debug_info_path.size == 0 && data_dir_count > PE_DataDirectoryIndex_DEBUG)
{
// rjf: read data dir
PE_DataDirectory dir = {0};
w32_dmn_process_read_struct(process, base_vaddr + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DEBUG, &dir);
U64 dbg_dir_count = dir.virt_size / sizeof(PE_DebugDirectory);
for(U64 dbg_dir_idx = 0; dbg_dir_idx < dbg_dir_count; dbg_dir_idx += 1)
{
// rjf: read debug directory
U64 dir_addr = base_vaddr + dir.virt_off + dbg_dir_idx * sizeof(PE_DebugDirectory);
PE_DebugDirectory dbg_data = {0};
w32_dmn_process_read_struct(process, dir_addr, &dbg_data);
// rjf: extract external file info from codeview header
if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW)
{
U32 cv_magic = 0;
w32_dmn_process_read_struct(process, base_vaddr + dbg_data.voff, &cv_magic);
switch(cv_magic)
{
default:break;
case PE_CODEVIEW_PDB20_MAGIC:
{
PE_CvHeaderPDB20 cv = {0};
U64 read_size = w32_dmn_process_read_struct(process, base_vaddr+dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
U64 pdb_dbg_path_vaddr = base_vaddr + dbg_data.voff + sizeof(cv);
debug_info_timestamp = cv.time_stamp;
debug_info_age = cv.age;
debug_info_path = w32_dmn_str8_cstring_from_process_vaddr(arena, process, pdb_dbg_path_vaddr);
}
}break;
case PE_CODEVIEW_PDB70_MAGIC:
{
PE_CvHeaderPDB70 cv = {0};
U64 read_size = w32_dmn_process_read_struct(process, base_vaddr + dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
U64 pdb_dbg_path_vaddr = base_vaddr + dbg_data.voff + sizeof(cv);
debug_info_guid = cv.guid;
debug_info_age = cv.age;
debug_info_path = w32_dmn_str8_cstring_from_process_vaddr(arena, process, pdb_dbg_path_vaddr);
}
}break;
case PE_CODEVIEW_RDI_MAGIC:
{
PE_CvHeaderRDI cv = {0};
U64 read_size = w32_dmn_process_read_struct(process, base_vaddr + dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
U64 rdi_dbg_path_vaddr = base_vaddr + dbg_data.voff + sizeof(cv);
debug_info_guid = cv.guid;
debug_info_path = w32_dmn_str8_cstring_from_process_vaddr(arena, process, rdi_dbg_path_vaddr);
}
}break;
}
}
}
}
// rjf: find ranges of special raddbg data
{
for EachIndex(idx, sec_count)
{
String8 section_name = str8_cstring((char *)sec[idx].name);
if(str8_match(section_name, str8_lit(".raddbg"), 0))
{
raddbg_info_voff_range.min = sec[idx].voff;
raddbg_info_voff_range.max = sec[idx].voff + sec[idx].vsize;
}
else if(str8_match(section_name, str8_lit(".rdbgia"), 0))
{
raddbg_is_attached_marker_voff = sec[idx].voff;
}
}
}
}
//- rjf: fill info
info->arch = arch;
info->vsize = image_vsize;
info->entry_point_voff = entry_point_voff;
info->module_path = module_path;
info->debug_info_path = debug_info_path;
info->debug_info_guid = debug_info_guid;
info->debug_info_timestamp = debug_info_timestamp;
info->debug_info_age = debug_info_age;
info->tls_index = tls_index;
info->pe_intel_pdatas_vaddr_range = pe_intel_pdatas_vaddr_range;
info->raddbg_info_voff_range = raddbg_info_voff_range;
info->raddbg_is_attached_marker_voff = raddbg_is_attached_marker_voff;
}
scratch_end(scratch);
return info;
} }
//- rjf: threads //- rjf: threads
@@ -1792,25 +2041,31 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
U64 module_base = (U64)evt.u.CreateProcessInfo.lpBaseOfImage; U64 module_base = (U64)evt.u.CreateProcessInfo.lpBaseOfImage;
U64 module_name_vaddr = (U64)evt.u.CreateProcessInfo.lpImageName; U64 module_name_vaddr = (U64)evt.u.CreateProcessInfo.lpImageName;
B32 module_name_is_unicode = (evt.u.CreateProcessInfo.fUnicode != 0); B32 module_name_is_unicode = (evt.u.CreateProcessInfo.fUnicode != 0);
W32_DMN_ImageInfo image_info = w32_dmn_image_info_from_process_base_vaddr(process_handle, module_base);
// rjf: create entities (thread/module are implied for initial - they are not reported by win32) // rjf: parse module info
DMN_ModuleInfo *module_info = w32_dmn_module_info_from_process_module(arena, process_handle, module_handle, module_base, module_name_vaddr, module_name_is_unicode, 1);
// rjf: create process/module entities (module is implied for processes - not reported directly via module events)
W32_DMN_Entity *process = w32_dmn_entity_alloc(w32_dmn_shared->entities_base, W32_DMN_EntityKind_Process, evt.dwProcessId); W32_DMN_Entity *process = w32_dmn_entity_alloc(w32_dmn_shared->entities_base, W32_DMN_EntityKind_Process, evt.dwProcessId);
W32_DMN_Entity *thread = w32_dmn_entity_alloc(process, W32_DMN_EntityKind_Thread, evt.dwThreadId);
W32_DMN_Entity *module = w32_dmn_entity_alloc(process, W32_DMN_EntityKind_Module, module_base); W32_DMN_Entity *module = w32_dmn_entity_alloc(process, W32_DMN_EntityKind_Module, module_base);
{ {
process->handle = process_handle; process->handle = process_handle;
process->arch = image_info.arch; process->arch = module_info->arch;
thread->handle = thread_handle;
thread->arch = image_info.arch;
thread->thread.thread_local_base = tls_base;
module->handle = module_handle; module->handle = module_handle;
module->module.vaddr_range = r1u64(module_base, image_info.size); module->module.vaddr_range = r1u64(module_base, module_base + module_info->vsize);
module->module.is_main = 1; module->module.is_main = 1;
module->module.address_of_name_pointer = module_name_vaddr; module->module.address_of_name_pointer = module_name_vaddr;
module->module.name_is_unicode = module_name_is_unicode; module->module.name_is_unicode = module_name_is_unicode;
} }
// rjf: create main thread entity (implied from process event, see above)
W32_DMN_Entity *thread = w32_dmn_entity_alloc(process, W32_DMN_EntityKind_Thread, evt.dwThreadId);
{
thread->handle = thread_handle;
thread->arch = module_info->arch;
thread->thread.thread_local_base = tls_base;
}
// rjf: put thread into suspended state, so it matches expected initial state // rjf: put thread into suspended state, so it matches expected initial state
SuspendThread(thread_handle); SuspendThread(thread_handle);
@@ -1833,7 +2088,7 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
DMN_Event *e = dmn_event_list_push(arena, &events); DMN_Event *e = dmn_event_list_push(arena, &events);
e->kind = DMN_EventKind_CreateProcess; e->kind = DMN_EventKind_CreateProcess;
e->process = w32_dmn_handle_from_entity(process); e->process = w32_dmn_handle_from_entity(process);
e->arch = image_info.arch; e->arch = module_info->arch;
e->code = evt.dwProcessId; e->code = evt.dwProcessId;
e->tls_model = DMN_TlsModel_WinodwsNt; e->tls_model = DMN_TlsModel_WinodwsNt;
} }
@@ -1844,21 +2099,21 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
e->kind = DMN_EventKind_CreateThread; e->kind = DMN_EventKind_CreateThread;
e->process = w32_dmn_handle_from_entity(process); e->process = w32_dmn_handle_from_entity(process);
e->thread = w32_dmn_handle_from_entity(thread); e->thread = w32_dmn_handle_from_entity(thread);
e->arch = image_info.arch; e->arch = module_info->arch;
e->code = evt.dwThreadId; e->code = evt.dwThreadId;
} }
// rjf: load module // rjf: load module
{ {
DMN_Event *e = dmn_event_list_push(arena, &events); DMN_Event *e = dmn_event_list_push(arena, &events);
e->kind = DMN_EventKind_LoadModule; e->kind = DMN_EventKind_LoadModule;
e->process = w32_dmn_handle_from_entity(process); e->process = w32_dmn_handle_from_entity(process);
e->module = w32_dmn_handle_from_entity(module); e->module = w32_dmn_handle_from_entity(module);
e->arch = image_info.arch; e->arch = module_info->arch;
e->address = module_base; e->address = module_base;
e->size = image_info.size; e->size = module_info->vsize;
e->string = w32_dmn_full_path_from_module(arena, module); e->string = module_info->module_path;
e->tls_index = image_info.tls_index; e->module_info = module_info;
} }
} }
}break; }break;
@@ -2010,29 +2265,32 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
// rjf: extract image info // rjf: extract image info
U64 module_base = (U64)evt.u.LoadDll.lpBaseOfDll; U64 module_base = (U64)evt.u.LoadDll.lpBaseOfDll;
W32_DMN_ImageInfo image_info = w32_dmn_image_info_from_process_base_vaddr(process->handle, module_base); HANDLE module_handle = evt.u.LoadDll.hFile;
U64 module_name_vaddr = (U64)evt.u.LoadDll.lpImageName;
B32 module_name_is_unicode = (evt.u.LoadDll.fUnicode != 0);
DMN_ModuleInfo *module_info = w32_dmn_module_info_from_process_module(arena, process->handle, module_handle, module_base, module_name_vaddr, module_name_is_unicode, 0);
// rjf: create module entity // rjf: create module entity
W32_DMN_Entity *module = w32_dmn_entity_alloc(process, W32_DMN_EntityKind_Module, module_base); W32_DMN_Entity *module = w32_dmn_entity_alloc(process, W32_DMN_EntityKind_Module, module_base);
{ {
module->handle = evt.u.LoadDll.hFile; module->handle = module_handle;
module->arch = image_info.arch; module->arch = module_info->arch;
module->module.vaddr_range = r1u64(module_base, module_base+image_info.size); module->module.vaddr_range = r1u64(module_base, module_base+module_info->vsize);
module->module.address_of_name_pointer = (U64)evt.u.LoadDll.lpImageName; module->module.address_of_name_pointer = module_name_vaddr;
module->module.name_is_unicode = (evt.u.LoadDll.fUnicode != 0); module->module.name_is_unicode = module_name_is_unicode;
} }
// rjf: generate event // rjf: generate event
{ {
DMN_Event *e = dmn_event_list_push(arena, &events); DMN_Event *e = dmn_event_list_push(arena, &events);
e->kind = DMN_EventKind_LoadModule; e->kind = DMN_EventKind_LoadModule;
e->process = w32_dmn_handle_from_entity(process); e->process = w32_dmn_handle_from_entity(process);
e->module = w32_dmn_handle_from_entity(module); e->module = w32_dmn_handle_from_entity(module);
e->arch = module->arch; e->arch = module_info->arch;
e->address = module_base; e->address = module_base;
e->size = image_info.size; e->size = module_info->vsize;
e->string = w32_dmn_full_path_from_module(arena, module); e->string = module_info->module_path;
e->tls_index = image_info.tls_index; e->module_info = module_info;
} }
}break; }break;
+4 -1
View File
@@ -337,11 +337,14 @@ internal String8 w32_dmn_full_path_from_module(Arena *arena, W32_DMN_Entity *mod
//- rjf: processes //- rjf: processes
internal U64 w32_dmn_process_read(HANDLE process, Rng1U64 range, void *dst); internal U64 w32_dmn_process_read(HANDLE process, Rng1U64 range, void *dst);
internal B32 w32_dmn_process_write(HANDLE process, Rng1U64 range, void *src); internal B32 w32_dmn_process_write(HANDLE process, Rng1U64 range, void *src);
internal String8 w32_dmn_str8_cstring_from_process_vaddr(Arena *arena, HANDLE process, U64 vaddr);
internal String8 w32_dmn_read_memory_str(Arena *arena, HANDLE process_handle, U64 address); internal String8 w32_dmn_read_memory_str(Arena *arena, HANDLE process_handle, U64 address);
internal String16 w32_dmn_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address); internal String16 w32_dmn_read_memory_str16(Arena *arena, HANDLE process_handle, U64 address);
#define w32_dmn_process_read_struct(process, vaddr, ptr) w32_dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) #define w32_dmn_process_read_struct(process, vaddr, ptr) w32_dmn_process_read((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
#define w32_dmn_process_write_struct(process, vaddr, ptr) w32_dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr) #define w32_dmn_process_write_struct(process, vaddr, ptr) w32_dmn_process_write((process), r1u64((vaddr), (vaddr)+(sizeof(*ptr))), ptr)
internal W32_DMN_ImageInfo w32_dmn_image_info_from_process_base_vaddr(HANDLE process, U64 base_vaddr);
//- rjf: modules
internal DMN_ModuleInfo *w32_dmn_module_info_from_process_module(Arena *arena, HANDLE process, HANDLE module, U64 base_vaddr, U64 module_name_vaddr, B32 module_name_is_unicode, B32 is_main_module);
//- rjf: threads //- rjf: threads
internal B32 w32_dmn_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block); internal B32 w32_dmn_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block);