switch entry point detection/trap strategy to finding *all* possible candidates, and trapping all of them, rather than forcing the ctrl thread to decide on one specific entry point voff

This commit is contained in:
Ryan Fleury
2024-02-05 08:41:18 -08:00
parent 0be4680ec9
commit 762013899f
3 changed files with 129 additions and 217 deletions
-58
View File
@@ -541,64 +541,6 @@ try_s64_from_str8_c_rules(String8 string, S64 *x){
return(is_integer);
}
//- rjf: string -> integer (base64 & base16)
internal U64
base64_size_from_data_size(U64 size_in_bytes){
U64 bits = size_in_bytes*8;
U64 base64_size = (bits + 5)/6;
return(base64_size);
}
internal U64
base64_from_data(U8 *dst, U8 *src, U64 src_size){
U8 *dst_base = dst;
U8 *opl = src + src_size;
U32 bit_num = 0;
if (src < opl){
U8 byte = *src;
for (;;){
U32 x = 0;
for (U32 i = 0; i < 6; i += 1){
x |= ((byte >> bit_num) & 1) << i;
bit_num += 1;
if (bit_num == 8){
bit_num = 0;
src += 1;
byte = (src < opl)?(*src):0;
}
}
*dst = base64[x];
dst += 1;
if (src >= opl){
break;
}
}
}
return(dst - dst_base);
}
internal U64
base16_size_from_data_size(U64 size_in_bytes){
U64 base16_size = size_in_bytes*2;
return(base16_size);
}
internal U64
base16_from_data(U8 *dst, U8 *src, U64 src_size){
U8 *dst_base = dst;
U8 *opl = src + src_size;
for (;src < opl;){
U8 byte = *src;
*dst = integer_symbols[byte & 0xF];
dst += 1;
*dst = integer_symbols[byte >> 4];
dst += 1;
src += 1;
}
return(dst - dst_base);
}
//- rjf: integer -> string
internal String8
-6
View File
@@ -236,12 +236,6 @@ internal S64 s64_from_str8(String8 string, U32 radix);
internal B32 try_u64_from_str8_c_rules(String8 string, U64 *x);
internal B32 try_s64_from_str8_c_rules(String8 string, S64 *x);
//- rjf: string -> integer (base64 & base16)
internal U64 base64_size_from_data_size(U64 size_in_bytes);
internal U64 base64_from_data(U8 *dst, U8 *src, U64 src_size);
internal U64 base16_size_from_data_size(U64 size_in_bytes);
internal U64 base16_from_data(U8 *dst, U8 *src, U64 src_size);
//- rjf: integer -> string
internal String8 str8_from_memory_size(Arena *arena, U64 z);
internal String8 str8_from_u64(Arena *arena, U64 u64, U32 radix, U8 min_digits, U8 digit_group_separator);
+129 -153
View File
@@ -1948,7 +1948,9 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
ProfBeginFunction();
Temp scratch = scratch_begin(0, 0);
//////////////////////////////
//- rjf: launch
//
OS_LaunchOptions opts = {0};
{
opts.cmd_line = msg->cmd_line_string_list;
@@ -1958,7 +1960,9 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
}
U32 id = demon_launch_process(&opts);
//////////////////////////////
//- rjf: record start
//
{
CTRL_EventList evts = {0};
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
@@ -1966,14 +1970,13 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
ctrl_c2u_push_events(&evts);
}
//////////////////////////////
//- rjf: run to initialization (entry point)
//
DEMON_Event *stop_event = 0;
if(id != 0)
{
DEMON_Handle unfrozen_process[8] = {0};
DEMON_TrapChunkList demon_traps = {0};
U64 entry_vaddr = 0;
DEMON_Handle entry_vaddr_proc = 0;
DEMON_RunCtrls run_ctrls = {0};
run_ctrls.run_entities_are_unfrozen = 1;
run_ctrls.run_entities_are_processes = 1;
@@ -1984,7 +1987,7 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
{
default:{}break;
// rjf: new process -> freeze process
//- rjf: new process -> freeze process
case DEMON_EventKind_CreateProcess:
if(run_ctrls.run_entity_count < ArrayCount(unfrozen_process))
{
@@ -1993,22 +1996,32 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
run_ctrls.run_entity_count += 1;
}break;
// rjf: breakpoint -> if it's the entry point, we're done. otherwise, keep going
//- rjf: breakpoint -> if it's the entry point, we're done. otherwise, keep going
case DEMON_EventKind_Breakpoint:
if(event->instruction_pointer == entry_vaddr)
{
done = 1;
stop_event = event;
for(DEMON_TrapChunkNode *n = run_ctrls.traps.first; n != 0; n = n->next)
{
for(U64 idx = 0; idx < n->count; idx += 1)
{
if(n->v[idx].address == event->instruction_pointer)
{
done = 1;
stop_event = event;
goto end_look_for_entry_match;
}
}
}
end_look_for_entry_match:;
}break;
// rjf: exception -> done
//- rjf: exception -> done
case DEMON_EventKind_Exception:
{
done = 1;
stop_event = event;
}break;
// rjf: process ended? -> remove from unfrozen processes. zero processes -> done.
//- rjf: process ended? -> remove from unfrozen processes. zero processes -> done.
case DEMON_EventKind_ExitProcess:
{
for(U64 idx = 0; idx < run_ctrls.run_entity_count; idx += 1)
@@ -2028,123 +2041,29 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
}
}break;
// rjf: done with handshake -> ready to find entry point. search launched processes
//- rjf: done with handshake -> ready to find entry point. search launched processes
case DEMON_EventKind_HandshakeComplete:
{
DBGI_Scope *scope = dbgi_scope_open();
// rjf: find entry point vaddr
//- rjf: add traps for all possible entry points
for(U64 process_idx = 0; process_idx < run_ctrls.run_entity_count; process_idx += 1)
{
//- rjf: unpack first module info
DEMON_HandleArray modules = demon_modules_from_process(scratch.arena, run_ctrls.run_entities[process_idx]);
if(modules.count == 0) { continue; }
DEMON_Handle module = modules.handles[0];
U64 module_base_vaddr = demon_base_vaddr_from_module(module);
String8 exe_path = demon_full_path_from_module(scratch.arena, module);
DBGI_Parse *dbgi = dbgi_parse_from_exe_path(scope, exe_path, max_U64);
RADDBG_Parsed *rdbg = &dbgi->rdbg;
RADDBG_NameMap *unparsed_map = raddbg_name_map_from_kind(rdbg, RADDBG_NameMapKind_Procedures);
RADDBG_ParsedNameMap map = {0};
raddbg_name_map_parse(rdbg, unparsed_map, &map);
String8 default_entry_points[] =
{
str8_lit("WinMain"),
str8_lit("wWinMain"),
str8_lit("main"),
str8_lit("wmain"),
str8_lit("WinMainCRTStartup"),
str8_lit("wWinMainCRTStartup"),
str8_lit("mainCRTStartup"),
str8_lit("wmainCRTStartup"),
};
// rjf: default to picking PE header's entry
B32 entry_is_user_defined = 0;
U64 entry_voff = dbgi->pe.entry_point;
if(rdbg->scope_vmap != 0 && rdbg->procedures != 0 &&
rdbg->unit_vmap != 0 && rdbg->units != 0 &&
rdbg->file_paths)
{
U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, entry_voff);
RADDBG_Scope *scope = &rdbg->scopes[scope_idx];
U64 proc_idx = scope->proc_idx;
RADDBG_Procedure *procedure = &rdbg->procedures[proc_idx];
U64 name_size = 0;
U8 *name_base = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size);
String8 name = str8(name_base, name_size);
U64 unit_idx = raddbg_vmap_idx_from_voff(rdbg->unit_vmap, rdbg->unit_vmap_count, entry_voff);
RADDBG_Unit *unit = &rdbg->units[unit_idx];
RADDBG_ParsedLineInfo unit_line_info = {0};
raddbg_line_info_from_unit(rdbg, unit, &unit_line_info);
U64 line_info_idx = raddbg_line_info_idx_from_voff(&unit_line_info, entry_voff);
if(name_size != 0 && line_info_idx < unit_line_info.count)
{
String8 obj_path = {0};
{
String8List obj_path_nodes = {0};
for(U32 idx = unit->object_file_path_node; idx != 0; idx = rdbg->file_paths[idx].parent_path_node)
{
RADDBG_FilePathNode *n = &rdbg->file_paths[idx];
U64 n_name_size = 0;
U8 *n_name_base = raddbg_string_from_idx(rdbg, n->name_string_idx, &n_name_size);
str8_list_push_front(scratch.arena, &obj_path_nodes, str8(n_name_base, n_name_size));
}
StringJoin join = {0};
join.sep = str8_lit("/");
obj_path = str8_list_join(scratch.arena, &obj_path_nodes, &join);
}
FileProperties props = os_properties_from_file_path(obj_path);
if(props.modified)
{
entry_is_user_defined = 1;
}
}
B32 entry_point_matches_defaults = 0;
for(U64 idx = 0; idx < ArrayCount(default_entry_points); idx += 1)
{
if(str8_match(name, default_entry_points[idx], 0))
{
entry_point_matches_defaults = 1;
}
}
if(!entry_point_matches_defaults && name.size != 0)
{
entry_is_user_defined = 1;
}
}
// rjf: find voff for one of the default entry points
if(!entry_is_user_defined)
{
for(U64 idx = 0; idx < ArrayCount(default_entry_points); idx += 1)
{
U32 procedure_id = 0;
{
String8 name = default_entry_points[idx];
RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size);
if(node != 0)
{
U32 id_count = 0;
U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count);
if(id_count > 0)
{
procedure_id = ids[0];
}
}
}
if(procedure_id != 0)
{
U64 new_voff = raddbg_first_voff_from_proc(rdbg, procedure_id);
if(new_voff != 0)
{
entry_voff = new_voff;
break;
}
}
}
}
// rjf: find voff for one of the custom entry points attached to this msg
if(rdbg->procedures != 0 && unparsed_map != 0)
//- rjf: add trap for user-specified entry point, if specified
B32 entries_found = 0;
if(!entries_found)
{
for(String8Node *n = msg->strings.first; n != 0; n = n->next)
{
@@ -2152,30 +2071,25 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
{
String8 name = n->string;
RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size);
if(node != 0)
U32 id_count = 0;
U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count);
if(id_count > 0)
{
U32 id_count = 0;
U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count);
if(id_count > 0)
{
procedure_id = ids[0];
}
procedure_id = ids[0];
}
}
if(procedure_id != 0)
U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id);
if(voff != 0)
{
U64 new_voff = raddbg_first_voff_from_proc(rdbg, procedure_id);
if(new_voff != 0)
{
entry_voff = new_voff;
break;
}
entries_found = 1;
DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff};
demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap);
}
}
}
// rjf: find voff for one of the user's custom entry points
if(rdbg->procedures != 0 && unparsed_map != 0)
//- rjf: add traps for all custom user entry points
if(!entries_found)
{
for(String8Node *n = ctrl_state->user_entry_points.first; n != 0; n = n->next)
{
@@ -2183,46 +2097,102 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
{
String8 name = n->string;
RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size);
if(node != 0)
U32 id_count = 0;
U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count);
if(id_count > 0)
{
U32 id_count = 0;
U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count);
if(id_count > 0)
{
procedure_id = ids[0];
}
procedure_id = ids[0];
}
}
if(procedure_id != 0)
U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id);
if(voff != 0)
{
U64 new_voff = raddbg_first_voff_from_proc(rdbg, procedure_id);
if(new_voff != 0)
{
entry_voff = new_voff;
break;
}
DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff};
demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap);
break;
}
}
}
// rjf: nonzero voff? => store
if(entry_voff != 0)
//- rjf: add traps for all high-level entry points
if(!entries_found)
{
U64 base_vaddr = demon_base_vaddr_from_module(module);
entry_vaddr = base_vaddr + entry_voff;
entry_vaddr_proc = run_ctrls.run_entities[process_idx];
String8 hi_entry_points[] =
{
str8_lit("WinMain"),
str8_lit("wWinMain"),
str8_lit("main"),
str8_lit("wmain"),
};
for(U64 idx = 0; idx < ArrayCount(hi_entry_points); idx += 1)
{
U32 procedure_id = 0;
{
String8 name = hi_entry_points[idx];
RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size);
U32 id_count = 0;
U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count);
if(id_count > 0)
{
procedure_id = ids[0];
}
}
U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id);
if(voff != 0)
{
entries_found = 1;
DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff};
demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap);
}
}
}
// rjf: found entry point -> insert into trap controls
if(entry_vaddr != 0)
//- rjf: add trap for PE header entry
if(!entries_found)
{
DEMON_Trap trap = {entry_vaddr_proc, entry_vaddr};
demon_trap_chunk_list_push(scratch.arena, &demon_traps, 256, &trap);
run_ctrls.traps = demon_traps;
U64 voff = dbgi->pe.entry_point;
if(voff != 0)
{
DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff};
demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap);
}
}
// rjf: no entry point found -> done
else
//- rjf: add traps for all low-level entry points
if(!entries_found)
{
String8 lo_entry_points[] =
{
str8_lit("WinMainCRTStartup"),
str8_lit("wWinMainCRTStartup"),
str8_lit("mainCRTStartup"),
str8_lit("wmainCRTStartup"),
};
for(U64 idx = 0; idx < ArrayCount(lo_entry_points); idx += 1)
{
U32 procedure_id = 0;
{
String8 name = lo_entry_points[idx];
RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size);
U32 id_count = 0;
U32 *ids = raddbg_matches_from_map_node(rdbg, node, &id_count);
if(id_count > 0)
{
procedure_id = ids[0];
}
}
U64 voff = raddbg_first_voff_from_proc(rdbg, procedure_id);
if(voff != 0)
{
entries_found = 1;
DEMON_Trap trap = {run_ctrls.run_entities[process_idx], module_base_vaddr + voff};
demon_trap_chunk_list_push(scratch.arena, &run_ctrls.traps, 256, &trap);
}
}
}
//- rjf: no entry point found -> done
if(!entries_found)
{
done = 1;
stop_event = event;
@@ -2235,7 +2205,9 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
}
}
//////////////////////////////
//- rjf: record bad stop
//
if(stop_event == 0 && id == 0)
{
CTRL_EventList evts = {0};
@@ -2245,7 +2217,9 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
ctrl_c2u_push_events(&evts);
}
//////////////////////////////
//- rjf: record stop
//
{
CTRL_EventList evts = {0};
CTRL_Event *event = ctrl_event_list_push(scratch.arena, &evts);
@@ -2264,7 +2238,9 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg)
ctrl_c2u_push_events(&evts);
}
//////////////////////////////
//- rjf: push request resolution event
//
{
CTRL_EventList evts = {0};
CTRL_Event *evt = ctrl_event_list_push(scratch.arena, &evts);