Changed debug directory parser to handle multiple entries. Added

parser for RDI debug info entry. Changed debug info lookup order so
debugger tries to load path specified in exe first and if debug info
is missing then debugger will do heuristic searches.
This commit is contained in:
Nikita Smith
2024-10-17 18:51:35 -07:00
parent 652dcafbbf
commit c8a5fc4806
+63 -54
View File
@@ -3472,7 +3472,13 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
U64 pdatas_count = 0;
U64 entry_point_voff = 0;
Rng1U64 tls_vaddr_range = {0};
String8 builtin_debug_info_path = {0};
U32 pdb_dbg_time = 0;
U32 pdb_dbg_age = 0;
OS_Guid pdb_dbg_guid = {0};
String8 pdb_dbg_path = str8_zero();
U32 rdi_dbg_time = 0;
OS_Guid rdi_dbg_guid = {0};
String8 rdi_dbg_path = str8_zero();
ProfScope("unpack relevant PE info")
{
B32 is_valid = 1;
@@ -3608,65 +3614,62 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
tls_vaddr_range = r1u64(tls_header.index_address, tls_header.index_address+sizeof(U32));
// rjf: grab data about debug info
U32 dbg_time = 0;
U32 dbg_age = 0;
OS_Guid dbg_guid = {0};
if(data_dir_count > PE_DataDirectoryIndex_DEBUG)
{
// rjf: read data dir
PE_DataDirectory dir = {0};
dmn_process_read_struct(process.dmn_handle, vaddr_range.min + opt_ext_off_range.min + reported_data_dir_offset + sizeof(PE_DataDirectory)*PE_DataDirectoryIndex_DEBUG, &dir);
// rjf: read debug directory
PE_DebugDirectory dbg_data = {0};
dmn_process_read_struct(process.dmn_handle, vaddr_range.min+(U64)dir.virt_off, &dbg_data);
// rjf: extract external file info from codeview header
if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW)
U64 dbg_dir_count = dir.virt_size / sizeof(PE_DebugDirectory);
for(U64 dbg_dir_idx = 0; dbg_dir_idx < dbg_dir_count; dbg_dir_idx += 1)
{
U64 dbg_path_off = 0;
U64 dbg_path_size = 0;
U64 cv_offset = dbg_data.voff;
U32 cv_magic = 0;
dmn_process_read_struct(process.dmn_handle, vaddr_range.min+cv_offset, &cv_magic);
switch(cv_magic)
// rjf: read debug directory
U64 dir_addr = vaddr_range.min + dir.virt_off + dbg_dir_idx * sizeof(PE_DebugDirectory);
PE_DebugDirectory dbg_data = {0};
dmn_process_read_struct(process.dmn_handle, dir_addr, &dbg_data);
// rjf: extract external file info from codeview header
if(dbg_data.type == PE_DebugDirectoryType_CODEVIEW)
{
default:break;
case PE_CODEVIEW_PDB20_MAGIC:
U32 cv_magic = 0;
dmn_process_read_struct(process.dmn_handle, vaddr_range.min + dbg_data.voff, &cv_magic);
switch(cv_magic)
{
PE_CvHeaderPDB20 cv = {0};
dmn_process_read_struct(process.dmn_handle, vaddr_range.min+cv_offset, &cv);
dbg_time = cv.time;
dbg_age = cv.age;
dbg_path_off = cv_offset + sizeof(cv);
}break;
case PE_CODEVIEW_PDB70_MAGIC:
{
PE_CvHeaderPDB70 cv = {0};
dmn_process_read_struct(process.dmn_handle, vaddr_range.min+cv_offset, &cv);
dbg_guid = cv.guid;
dbg_age = cv.age;
dbg_path_off = cv_offset + sizeof(cv);
}break;
}
if(dbg_path_off > 0)
{
Temp scratch = scratch_begin(0, 0);
String8List parts = {0};
for(U64 off = dbg_path_off;; off += 256)
{
U8 bytes[256] = {0};
dmn_process_read(process.dmn_handle, r1u64(vaddr_range.min+off, vaddr_range.min+off+sizeof(bytes)), bytes);
U64 size = cstring8_length(&bytes[0]);
String8 part = str8(bytes, size);
str8_list_push(scratch.arena, &parts, part);
if(size < sizeof(bytes))
default:break;
case PE_CODEVIEW_PDB20_MAGIC:
{
break;
}
PE_CvHeaderPDB20 cv;
U64 read_size = dmn_process_read_struct(process.dmn_handle, vaddr_range.min+dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
pdb_dbg_time = cv.time;
pdb_dbg_age = cv.age;
pdb_dbg_path = dmn_process_read_cstring(arena, process.dmn_handle, vaddr_range.min + dbg_data.voff + sizeof(cv));
}
}break;
case PE_CODEVIEW_PDB70_MAGIC:
{
PE_CvHeaderPDB70 cv;
U64 read_size = dmn_process_read_struct(process.dmn_handle, vaddr_range.min + dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
pdb_dbg_guid = cv.guid;
pdb_dbg_age = cv.age;
pdb_dbg_path = dmn_process_read_cstring(arena, process.dmn_handle, vaddr_range.min + dbg_data.voff + sizeof(cv));
}
}break;
case PE_CODEVIEW_RDI_MAGIC:
{
PE_CvHeaderRDI cv;
U64 read_size = dmn_process_read_struct(process.dmn_handle, vaddr_range.min + dbg_data.voff, &cv);
if(read_size == sizeof(cv))
{
rdi_dbg_guid = cv.guid;
rdi_dbg_path = dmn_process_read_cstring(arena, process.dmn_handle, vaddr_range.min + dbg_data.voff + sizeof(cv));
}
}break;
}
builtin_debug_info_path = str8_list_join(arena, &parts, 0);
scratch_end(scratch);
}
}
}
@@ -3676,16 +3679,22 @@ ctrl_thread__module_open(CTRL_Handle process, CTRL_Handle module, Rng1U64 vaddr_
//////////////////////////////
//- rjf: pick default initial debug info path
//
String8 initial_debug_info_path = builtin_debug_info_path;
String8 initial_debug_info_path = str8_zero();
{
Temp scratch = scratch_begin(0, 0);
String8 exe_folder = str8_chop_last_slash(path);
String8 builtin_debug_info_path__absolute = builtin_debug_info_path;
String8 builtin_debug_info_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, builtin_debug_info_path);
String8 rdi_path__absolute = rdi_dbg_path;
String8 rdi_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, rdi_dbg_path);
String8 pdb_path__absolute = pdb_dbg_path;
String8 pdb_path__relative = push_str8f(scratch.arena, "%S/%S", exe_folder, pdb_dbg_path);
String8 dbg_path_candidates[] =
{
/* inferred (treated as relative): */ builtin_debug_info_path__relative,
/* inferred (treated as absolute): */ builtin_debug_info_path__absolute,
/* inferred (treated as absolute): */ rdi_path__absolute,
/* inferred (treated as relative): */ rdi_path__relative,
/* inferred (treated as absolute): */ pdb_path__absolute,
/* inferred (treated as relative): */ pdb_path__relative,
/* "foo.exe" -> "foo.rdi" */ push_str8f(scratch.arena, "%S.rdi", str8_chop_last_dot(path)),
/* "foo.exe" -> "foo.exe.rdi" */ push_str8f(scratch.arena, "%S.rdi", path),
/* "foo.exe" -> "foo.pdb" */ push_str8f(scratch.arena, "%S.pdb", str8_chop_last_dot(path)),
/* "foo.exe" -> "foo.exe.pdb" */ push_str8f(scratch.arena, "%S.pdb", path),
};