mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-08 06:48:41 +00:00
eliminate backend-specific module parsing from debug engine ctrl thread; just pass that info back via the demon event
This commit is contained in:
+1
-1
@@ -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 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 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]
|
||||
// .f1 = { .win = "wsl ./build.sh raddbg", .linux = "", .out = "*compilation*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, },
|
||||
|
||||
+1
-1
@@ -7,6 +7,7 @@ target:
|
||||
working_directory: build
|
||||
arguments: "--user:raddbg_test.user --project:raddbg_test.project"
|
||||
debug_subprocesses: 0
|
||||
enabled: 1
|
||||
}
|
||||
target:
|
||||
{
|
||||
@@ -42,5 +43,4 @@ target:
|
||||
executable: "build/torture.exe"
|
||||
working_directory: build
|
||||
arguments: "rdi_from_pdb/* --gui"
|
||||
enabled: 1
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ struct ProcessInfo
|
||||
String8 binary_file_path;
|
||||
String8 binary_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;
|
||||
String8List module_load_paths;
|
||||
String8List environment;
|
||||
|
||||
@@ -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
|
||||
|
||||
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);
|
||||
|
||||
//- rjf: set up per-module info
|
||||
Arena *arena = arena_alloc();
|
||||
U64 entry_point_voff = 0;
|
||||
U32 rdi_dbg_time = 0;
|
||||
Guid rdi_dbg_guid = {0};
|
||||
String8 exe_dbg_path = {0};
|
||||
String8 rdi_dbg_path = {0};
|
||||
String8 raddbg_data = {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;
|
||||
String8 raddbg_data = d_data_from_process_vaddr_range(arena, process, shift_1u64(module_info->raddbg_info_voff_range, base_vaddr), 0);
|
||||
U64 pdatas_count = dim_1u64(module_info->pe_intel_pdatas_vaddr_range) / sizeof(PE_IntelPdata);
|
||||
String8 pdatas_data = d_data_from_process_vaddr_range(arena, process, module_info->pe_intel_pdatas_vaddr_range, 0);
|
||||
pdatas_count = Min(pdatas_count, pdatas_data.size / sizeof(PE_IntelPdata));
|
||||
PE_IntelPdata *pdatas = (PE_IntelPdata *)pdatas_data.str;
|
||||
EH_PtrCtx eh_ptr_ctx = {.pc_vaddr = max_U64, .text_vaddr = max_U64, .data_vaddr = max_U64, .func_vaddr = max_U64, .ptr_align = 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 };
|
||||
|
||||
//- 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)
|
||||
B32 is_unwind_eh = 0;
|
||||
if(module_info->eh_frame_header_vaddr_range.min != 0)
|
||||
{
|
||||
ProfScope("unpack relevant PE info")
|
||||
{
|
||||
B32 is_valid = 1;
|
||||
|
||||
//- rjf: read DOS header
|
||||
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:;
|
||||
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;
|
||||
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);
|
||||
is_unwind_eh = 1;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- 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 dbg_path_candidates = {0};
|
||||
//
|
||||
//~ TODO(rjf): @linux_port PLEASE READ RYAN vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
||||
//
|
||||
// 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)
|
||||
String8List candidates = {0};
|
||||
|
||||
// rjf: push module-embedded debug info paths, try both relative-to-exe & absolute
|
||||
if(module_info->debug_info_path.size != 0)
|
||||
{
|
||||
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);
|
||||
PathStyle path_style = path_style_from_str8(module_info->debug_info_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)
|
||||
{
|
||||
str8_list_pushf(scratch.arena, &dbg_path_candidates, "%S/%S", exe_folder, pdb_dbg_path);
|
||||
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)
|
||||
|
||||
// rjf: pick first candidate that works
|
||||
for EachNode(n, String8Node, candidates.first)
|
||||
{
|
||||
String8 candidate_path = n->string;
|
||||
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
|
||||
//
|
||||
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",
|
||||
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
|
||||
//
|
||||
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
|
||||
String8 symbol_cache_path = get_process_info()->symbol_cache_path;
|
||||
String8 module_name = str8_skip_last_slash(path);
|
||||
String8 dbg_name = str8_skip_last_slash(pdb_dbg_path);
|
||||
String8 module_name = str8_skip_last_slash(module_info->module_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);
|
||||
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
|
||||
//
|
||||
@@ -4169,14 +3881,14 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, Rng1U64 vaddr_rang
|
||||
node->arena = arena;
|
||||
node->pdatas = pdatas;
|
||||
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->eh_frame_hdr = eh_frame_hdr;
|
||||
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->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);
|
||||
}
|
||||
}
|
||||
@@ -4186,7 +3898,7 @@ d_ctrl_thread__module_open(D_Handle process, D_Handle module, Rng1U64 vaddr_rang
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
String8 module_path = path_normalized_from_string(scratch.arena, event->string);
|
||||
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->msg_id = msg->msg_id;
|
||||
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->timestamp = exe_timestamp;
|
||||
out_evt1->string = module_path;
|
||||
out_evt1->tls_index = event->tls_index;
|
||||
out_evt1->tls_offset = event->tls_offset;
|
||||
out_evt1->tls_index = event->module_info->tls_index;
|
||||
out_evt1->tls_offset = event->module_info->tls_offset;
|
||||
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);
|
||||
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 *process_ent = d_process_from_entity(module_ent);
|
||||
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->msg_id = msg->msg_id;
|
||||
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
|
||||
D_Handle module_handle = dump_modules[idx].module_handle;
|
||||
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
|
||||
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;
|
||||
|
||||
@@ -181,8 +181,8 @@ struct D_ModuleImageInfoCacheNode
|
||||
PE_IntelPdata *pdatas;
|
||||
U64 pdatas_count;
|
||||
U64 cfi_rebase;
|
||||
B32 is_unwind_eh;
|
||||
String8 dwarf_unwind_data;
|
||||
B32 is_unwind_eh;
|
||||
EH_FrameHdr eh_frame_hdr;
|
||||
EH_PtrCtx eh_ptr_ctx;
|
||||
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);
|
||||
|
||||
//- 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_close(D_Handle process, D_Handle module, Rng1U64 vaddr_range);
|
||||
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, U64 base_vaddr);
|
||||
|
||||
//- rjf: dump process closing work
|
||||
internal void d_ctrl_thread__close_dump_process(D_MsgID msg_id, D_Handle process);
|
||||
|
||||
@@ -119,5 +119,6 @@ dmn_event_list_push(Arena *arena, DMN_EventList *list)
|
||||
SLLQueuePush(list->first, list->last, n);
|
||||
list->count += 1;
|
||||
DMN_Event *result = &n->v;
|
||||
result->module_info = &dmn_module_info_nil;
|
||||
return result;
|
||||
}
|
||||
|
||||
+51
-8
@@ -69,33 +69,72 @@ struct DMN_HandleArray
|
||||
////////////////////////////////
|
||||
//~ 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;
|
||||
struct DMN_Event
|
||||
{
|
||||
// rjf: categories
|
||||
DMN_EventKind kind;
|
||||
DMN_ErrorKind error_kind;
|
||||
DMN_MemoryEventKind memory_kind;
|
||||
DMN_ExceptionKind exception_kind;
|
||||
|
||||
// rjf: entities
|
||||
DMN_Handle process;
|
||||
DMN_Handle thread;
|
||||
DMN_Handle module;
|
||||
|
||||
// rjf: general event properties
|
||||
Arch arch;
|
||||
U64 address;
|
||||
U64 size;
|
||||
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`
|
||||
S32 signo;
|
||||
S32 sigcode;
|
||||
Rng1U64 elf_phdr_vrange;
|
||||
U64 elf_phdr_entsize;
|
||||
U64 instruction_pointer;
|
||||
U64 stack_pointer;
|
||||
U64 user_data;
|
||||
B32 exception_repeated;
|
||||
U64 tls_index;
|
||||
U64 tls_offset;
|
||||
|
||||
// rjf: process info
|
||||
DMN_TlsModel tls_model;
|
||||
|
||||
// rjf: module info
|
||||
DMN_ModuleInfo *module_info;
|
||||
};
|
||||
|
||||
typedef struct DMN_EventNode DMN_EventNode;
|
||||
@@ -181,6 +220,11 @@ struct DMN_ProcessInfo
|
||||
U32 pid;
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ rjf: Globals
|
||||
|
||||
read_only global DMN_ModuleInfo dmn_module_info_nil = {0};
|
||||
|
||||
////////////////////////////////
|
||||
//~ 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);
|
||||
|
||||
//- 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_tls_root_vaddr_from_thread(DMN_Handle handle);
|
||||
internal B32 dmn_thread_read_reg_block(DMN_Handle handle, void *reg_block);
|
||||
|
||||
@@ -13,6 +13,7 @@ DMN_EventKindTable:
|
||||
{ExitThread}
|
||||
{LoadModule}
|
||||
{UnloadModule}
|
||||
{ModuleDebugInfo}
|
||||
{Breakpoint}
|
||||
{Trap}
|
||||
{SingleStep}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//- GENERATED CODE
|
||||
|
||||
C_LINKAGE_BEGIN
|
||||
String8 dmn_event_kind_string_table[21] =
|
||||
String8 dmn_event_kind_string_table[22] =
|
||||
{
|
||||
str8_lit_comp("Null"),
|
||||
str8_lit_comp("Error"),
|
||||
@@ -15,6 +15,7 @@ str8_lit_comp("CreateThread"),
|
||||
str8_lit_comp("ExitThread"),
|
||||
str8_lit_comp("LoadModule"),
|
||||
str8_lit_comp("UnloadModule"),
|
||||
str8_lit_comp("ModuleDebugInfo"),
|
||||
str8_lit_comp("Breakpoint"),
|
||||
str8_lit_comp("Trap"),
|
||||
str8_lit_comp("SingleStep"),
|
||||
|
||||
@@ -17,6 +17,7 @@ DMN_EventKind_CreateThread,
|
||||
DMN_EventKind_ExitThread,
|
||||
DMN_EventKind_LoadModule,
|
||||
DMN_EventKind_UnloadModule,
|
||||
DMN_EventKind_ModuleDebugInfo,
|
||||
DMN_EventKind_Breakpoint,
|
||||
DMN_EventKind_Trap,
|
||||
DMN_EventKind_SingleStep,
|
||||
@@ -62,7 +63,7 @@ DMN_ExceptionKind_COUNT,
|
||||
} DMN_ExceptionKind;
|
||||
|
||||
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];
|
||||
|
||||
C_LINKAGE_END
|
||||
|
||||
@@ -1571,10 +1571,36 @@ main(int argc, char **argv)
|
||||
info->initial_path = get_current_path(lnx_state.arena);
|
||||
}
|
||||
|
||||
// rjf: grab home directory
|
||||
// rjf: grab program/user data paths
|
||||
{
|
||||
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);
|
||||
|
||||
+237
-19
@@ -292,6 +292,237 @@ lnx_dmn_process_from_pid(pid_t 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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
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->thread = lnx_dmn_handle_from_thread(thread);
|
||||
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->size = module->size;
|
||||
e->string = module_name;
|
||||
e->elf_phdr_vrange = r1u64(module->phvaddr, module->phvaddr + module->phentsize * module->phcount);
|
||||
e->elf_phdr_entsize = module->phentsize;
|
||||
e->tls_index = module->tls_index;
|
||||
e->tls_offset = module->tls_offset;
|
||||
e->module_info = module_info;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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->instruction_pointer = lnx_dmn_thread_read_ip(thread);
|
||||
e->address = e->instruction_pointer;
|
||||
e->signo = signo;
|
||||
e->code = signo;
|
||||
e->exception_repeated = signo < ArrayCount(is_repeatable) ? is_repeatable[signo] : 0;
|
||||
|
||||
if(signo == SIGSEGV)
|
||||
@@ -3009,18 +3239,6 @@ dmn_process_write(DMN_Handle process_handle, Rng1U64 range, void *src)
|
||||
|
||||
//- 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
|
||||
dmn_stack_base_vaddr_from_thread(DMN_Handle thread_handle)
|
||||
{
|
||||
|
||||
@@ -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_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
|
||||
|
||||
|
||||
+13
-14
@@ -8817,16 +8817,15 @@ rd_window_frame(void)
|
||||
Vec4F32 hover_color = ui_color_from_tags_key_name(box->tags_key, str8_lit("hover"));
|
||||
|
||||
// rjf: brighten
|
||||
if(is_hot)
|
||||
{
|
||||
Vec4F32 color = hover_color;
|
||||
color.w *= 0.05f;
|
||||
if(!is_hot)
|
||||
{
|
||||
color.w *= t;
|
||||
}
|
||||
color.w *= 0.015f;
|
||||
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_10] = color;
|
||||
inst->colors[Corner_01] = color;
|
||||
inst->colors[Corner_11] = color;
|
||||
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()))
|
||||
{
|
||||
Vec4F32 color = hover_color;
|
||||
color.w *= 0.02f;
|
||||
color.w *= 0.025f;
|
||||
if(!is_hot)
|
||||
{
|
||||
color.w *= t;
|
||||
@@ -8842,7 +8841,7 @@ rd_window_frame(void)
|
||||
Vec2F32 center = ui_mouse();
|
||||
Vec2F32 box_dim = dim_2f32(box->rect);
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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_data_folder = push_str8f(scratch2.arena, "%S/raddbg", user_program_data_path);
|
||||
String8 user_program_config_data_path = get_process_info()->user_program_config_data_path;
|
||||
String8 user_data_folder = str8f(scratch2.arena, "%S/raddbg", user_program_config_data_path);
|
||||
make_directory(user_data_folder);
|
||||
if(user_path.size == 0)
|
||||
{
|
||||
@@ -10546,12 +10545,12 @@ rd_init(CmdLine *cmdln)
|
||||
}
|
||||
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);
|
||||
}
|
||||
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)
|
||||
@@ -13211,7 +13210,7 @@ rd_frame(void)
|
||||
case RD_CmdKind_RecordUserAsLastOpened:
|
||||
{
|
||||
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);
|
||||
}break;
|
||||
|
||||
@@ -15777,7 +15776,7 @@ rd_frame(void)
|
||||
String8 name = rd_regs()->string;
|
||||
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))
|
||||
{
|
||||
String8 dst_path = push_str8f(scratch.arena, "%S/%S", themes_folder, name);
|
||||
|
||||
@@ -122,7 +122,7 @@ E_TYPE_EXPAND_INFO_FUNCTION_DEF(themes)
|
||||
|
||||
//- 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);
|
||||
for(FileInfo info = {0}; file_iter_next(scratch.arena, it, &info);)
|
||||
{
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
//
|
||||
// [ ] jeff stepping bug
|
||||
// [ ] wassim memory bug
|
||||
// [ ] test concepts -> base
|
||||
// [ ] 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
|
||||
// [ ] core dump saving/loading
|
||||
@@ -540,8 +540,8 @@ entry_point(CmdLine *cmd_line)
|
||||
g_logs_folder = cmd_line_string(cmd_line, str8_lit("logs"));
|
||||
if(g_logs_folder.size == 0)
|
||||
{
|
||||
String8 user_program_data_path = get_process_info()->user_program_data_path;
|
||||
g_logs_folder = push_str8f(scratch.arena, "%S/%Sraddbg/logs", program_data_folder_prefix_from_os(OperatingSystem_CURRENT), 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/raddbg/logs", user_program_logs_data_path);
|
||||
}
|
||||
make_directory(g_logs_folder);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
// 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);
|
||||
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};
|
||||
|
||||
@@ -1922,7 +1922,8 @@ w32_entry_point_caller(int argc, WCHAR **wargv)
|
||||
U16 *buffer = push_array_no_zero(scratch.arena, U16, size);
|
||||
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);
|
||||
}
|
||||
|
||||
+385
-127
@@ -337,6 +337,62 @@ w32_dmn_process_write(HANDLE process, Rng1U64 range, void *src)
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
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: find PE offset
|
||||
U32 pe_offset = 0;
|
||||
DMN_ModuleInfo *info = push_array(arena, DMN_ModuleInfo, 1);
|
||||
Temp scratch = scratch_begin(&arena, 1);
|
||||
{
|
||||
U64 dos_magic_off = base_vaddr;
|
||||
U16 dos_magic = 0;
|
||||
w32_dmn_process_read_struct(process, dos_magic_off, &dos_magic);
|
||||
if(dos_magic == PE_DOS_MAGIC)
|
||||
B32 is_good = 1;
|
||||
|
||||
//- rjf: read DOS header
|
||||
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, pe_offset_off, &pe_offset);
|
||||
w32_dmn_process_read_struct(process, base_vaddr, &dos_header);
|
||||
is_good = (dos_header.magic == PE_DOS_MAGIC);
|
||||
}
|
||||
}
|
||||
|
||||
// rjf: get COFF header
|
||||
B32 got_coff_header = 0;
|
||||
U64 coff_header_off = 0;
|
||||
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)
|
||||
//- rjf: read PE magic
|
||||
U32 pe_magic = 0;
|
||||
if(is_good)
|
||||
{
|
||||
coff_header_off = pe_magic_off + sizeof(pe_magic);
|
||||
got_coff_header = w32_dmn_process_read_struct(process, coff_header_off, &coff_header);
|
||||
w32_dmn_process_read_struct(process, base_vaddr + dos_header.coff_file_offset, &pe_magic);
|
||||
is_good = (pe_magic == PE_MAGIC);
|
||||
}
|
||||
}
|
||||
|
||||
W32_DMN_ImageInfo result = zero_struct;
|
||||
if(got_coff_header)
|
||||
{
|
||||
U64 optional_off = coff_header_off + sizeof(COFF_FileHeader);
|
||||
|
||||
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))
|
||||
//- rjf: read COFF header
|
||||
U64 file_header_off = dos_header.coff_file_offset + sizeof(pe_magic);
|
||||
COFF_FileHeader file_header = {0};
|
||||
if(is_good)
|
||||
{
|
||||
PE_OptionalHeader32Plus opt_header = {0};
|
||||
if(w32_dmn_process_read_struct(process, optional_off, &opt_header))
|
||||
w32_dmn_process_read_struct(process, base_vaddr + file_header_off, &file_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;
|
||||
data_dir_count = opt_header.data_dir_count;
|
||||
data_dir_off = optional_off + sizeof(opt_header);
|
||||
DWORD cap16 = GetFinalPathNameByHandleW(module, 0, 0, VOLUME_NAME_DOS);
|
||||
U16 *buffer16 = push_array_no_zero(scratch.arena, U16, cap16);
|
||||
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
|
||||
if(PE_DataDirectoryIndex_TLS < data_dir_count)
|
||||
{
|
||||
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))
|
||||
// rjf: fallback (main module only): process -> full path
|
||||
if(module_path16.size == 0 && is_main_module)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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"); }
|
||||
}
|
||||
module_path16 = str16(buf, size);
|
||||
}
|
||||
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(w32_dmn_process_read_struct(process, base_vaddr + tls_dir.virt_off, &tls_header))
|
||||
if(module_name_is_unicode)
|
||||
{
|
||||
U32 tls_index32 = 0;
|
||||
if(w32_dmn_process_read_struct(process, tls_header.index_address, &tls_index32))
|
||||
{
|
||||
tls_index = tls_index32;
|
||||
}
|
||||
else { Assert(0 && "failed to read TLS Index 32"); }
|
||||
module_path16 = w32_dmn_read_memory_str16(scratch.arena, process, name_pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
module_path8 = w32_dmn_read_memory_str(scratch.arena, process, name_pointer);
|
||||
}
|
||||
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
|
||||
result.arch = arch;
|
||||
result.size = image_size;
|
||||
result.tls_index = tls_index;
|
||||
}
|
||||
else { Assert(0 && "failed to find COFF file header"); }
|
||||
//- 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);
|
||||
|
||||
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
|
||||
@@ -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_name_vaddr = (U64)evt.u.CreateProcessInfo.lpImageName;
|
||||
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 *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);
|
||||
{
|
||||
process->handle = process_handle;
|
||||
process->arch = image_info.arch;
|
||||
thread->handle = thread_handle;
|
||||
thread->arch = image_info.arch;
|
||||
thread->thread.thread_local_base = tls_base;
|
||||
process->arch = module_info->arch;
|
||||
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.address_of_name_pointer = module_name_vaddr;
|
||||
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
|
||||
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);
|
||||
e->kind = DMN_EventKind_CreateProcess;
|
||||
e->process = w32_dmn_handle_from_entity(process);
|
||||
e->arch = image_info.arch;
|
||||
e->arch = module_info->arch;
|
||||
e->code = evt.dwProcessId;
|
||||
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->process = w32_dmn_handle_from_entity(process);
|
||||
e->thread = w32_dmn_handle_from_entity(thread);
|
||||
e->arch = image_info.arch;
|
||||
e->arch = module_info->arch;
|
||||
e->code = evt.dwThreadId;
|
||||
}
|
||||
|
||||
// rjf: load module
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_LoadModule;
|
||||
e->process = w32_dmn_handle_from_entity(process);
|
||||
e->module = w32_dmn_handle_from_entity(module);
|
||||
e->arch = image_info.arch;
|
||||
e->address = module_base;
|
||||
e->size = image_info.size;
|
||||
e->string = w32_dmn_full_path_from_module(arena, module);
|
||||
e->tls_index = image_info.tls_index;
|
||||
e->kind = DMN_EventKind_LoadModule;
|
||||
e->process = w32_dmn_handle_from_entity(process);
|
||||
e->module = w32_dmn_handle_from_entity(module);
|
||||
e->arch = module_info->arch;
|
||||
e->address = module_base;
|
||||
e->size = module_info->vsize;
|
||||
e->string = module_info->module_path;
|
||||
e->module_info = module_info;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
@@ -2010,29 +2265,32 @@ dmn_ctrl_run(Arena *arena, DMN_CtrlCtx *ctx, DMN_RunCtrls *ctrls)
|
||||
|
||||
// rjf: extract image info
|
||||
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
|
||||
W32_DMN_Entity *module = w32_dmn_entity_alloc(process, W32_DMN_EntityKind_Module, module_base);
|
||||
{
|
||||
module->handle = evt.u.LoadDll.hFile;
|
||||
module->arch = image_info.arch;
|
||||
module->module.vaddr_range = r1u64(module_base, module_base+image_info.size);
|
||||
module->module.address_of_name_pointer = (U64)evt.u.LoadDll.lpImageName;
|
||||
module->module.name_is_unicode = (evt.u.LoadDll.fUnicode != 0);
|
||||
module->handle = module_handle;
|
||||
module->arch = module_info->arch;
|
||||
module->module.vaddr_range = r1u64(module_base, module_base+module_info->vsize);
|
||||
module->module.address_of_name_pointer = module_name_vaddr;
|
||||
module->module.name_is_unicode = module_name_is_unicode;
|
||||
}
|
||||
|
||||
// rjf: generate event
|
||||
{
|
||||
DMN_Event *e = dmn_event_list_push(arena, &events);
|
||||
e->kind = DMN_EventKind_LoadModule;
|
||||
e->process = w32_dmn_handle_from_entity(process);
|
||||
e->module = w32_dmn_handle_from_entity(module);
|
||||
e->arch = module->arch;
|
||||
e->address = module_base;
|
||||
e->size = image_info.size;
|
||||
e->string = w32_dmn_full_path_from_module(arena, module);
|
||||
e->tls_index = image_info.tls_index;
|
||||
e->kind = DMN_EventKind_LoadModule;
|
||||
e->process = w32_dmn_handle_from_entity(process);
|
||||
e->module = w32_dmn_handle_from_entity(module);
|
||||
e->arch = module_info->arch;
|
||||
e->address = module_base;
|
||||
e->size = module_info->vsize;
|
||||
e->string = module_info->module_path;
|
||||
e->module_info = module_info;
|
||||
}
|
||||
}break;
|
||||
|
||||
|
||||
@@ -337,11 +337,14 @@ internal String8 w32_dmn_full_path_from_module(Arena *arena, W32_DMN_Entity *mod
|
||||
//- rjf: processes
|
||||
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 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 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_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
|
||||
internal B32 w32_dmn_thread_read_reg_block(Arch arch, HANDLE thread, void *reg_block);
|
||||
|
||||
Reference in New Issue
Block a user