From 967936cef62b32cc97bde2a810e901620d9eb3aa Mon Sep 17 00:00:00 2001 From: Ryan Fleury Date: Fri, 26 Jan 2024 20:37:36 -0800 Subject: [PATCH] pass over rules in picking step-into entry point. right now we don't exactly have a trivial way of checking if an entry point truly was defined by a user. but if line info exists, and the file seems local, and there is a procedure name for an EXE's built-in entry point address, then we can at least guarantee that there is source for the entry point, and thus can serve as an acceptable entry point. this currently does not take into account cases where the OBJ path is not local, but the user overrides the file paths to have source. if the entry point is determined to be non-user-defined, then everything falls back to the usual paths - try WinMain, WinMainCRTStartup, etc., and then override with explicit custom entry points if needed. not great, currently, w.r.t. detecting if the entry point is in user code. maybe can check more info in the unit later... --- src/ctrl/ctrl_core.c | 260 +++++++++++++++++++++++-------------------- 1 file changed, 142 insertions(+), 118 deletions(-) diff --git a/src/ctrl/ctrl_core.c b/src/ctrl/ctrl_core.c index d374335e..a99d8784 100644 --- a/src/ctrl/ctrl_core.c +++ b/src/ctrl/ctrl_core.c @@ -2027,150 +2027,174 @@ ctrl_thread__launch_and_init(CTRL_Msg *msg) 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: grab parsed name map - RADDBG_ParsedNameMap map = {0}; - raddbg_name_map_parse(rdbg, unparsed_map, &map); - - // rjf: look up binary's built-in entry point name - String8 builtin_entry_point_name = {0}; - if(rdbg->scope_vmap != 0 && rdbg->procedures != 0) + for(String8Node *n = msg->strings.first; n != 0; n = n->next) { - U64 builtin_entry_point_voff = dbgi->pe.entry_point; - U64 scope_idx = raddbg_vmap_idx_from_voff(rdbg->scope_vmap, rdbg->scope_vmap_count, builtin_entry_point_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_ptr = raddbg_string_from_idx(rdbg, procedure->name_string_idx, &name_size); - builtin_entry_point_name = str8(name_ptr, name_size); - } - - // rjf: grab entry point symbol names we might want to run to - 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: determine if built-in entry point is not one of the defaults, and thus - // specified by user - B32 builtin_entry_point_is_special = 0; - if(builtin_entry_point_name.size != 0) - { - builtin_entry_point_is_special = 1; - for(U64 idx = 0; idx < ArrayCount(default_entry_points); idx += 1) + U32 procedure_id = 0; { - if(str8_match(default_entry_points[idx], builtin_entry_point_name, 0)) + String8 name = n->string; + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); + if(node != 0) { - builtin_entry_point_is_special = 0; - break; - } - } - } - - // rjf: builtin entry point is unique -> use entry point voff - U64 voff = 0; - if(voff == 0 && builtin_entry_point_is_special) - { - voff = dbgi->pe.entry_point; - } - - // rjf: find voff for one of the custom entry points attached to this msg - if(voff == 0) - { - for(String8Node *n = msg->strings.first; n != 0; n = n->next) - { - U32 procedure_id = 0; - { - 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) + } + if(procedure_id != 0) + { + U64 new_voff = raddbg_first_voff_from_proc(rdbg, procedure_id); + if(new_voff != 0) { - voff = raddbg_first_voff_from_proc(rdbg, procedure_id); + entry_voff = new_voff; break; } } } - - // rjf: find voff for one of the user's custom entry points - if(voff == 0) + } + + // rjf: find voff for one of the user's custom entry points + if(rdbg->procedures != 0 && unparsed_map != 0) + { + for(String8Node *n = ctrl_state->user_entry_points.first; n != 0; n = n->next) { - for(String8Node *n = ctrl_state->user_entry_points.first; n != 0; n = n->next) + U32 procedure_id = 0; { - U32 procedure_id = 0; + String8 name = n->string; + RADDBG_NameMapNode *node = raddbg_name_map_lookup(rdbg, &map, name.str, name.size); + if(node != 0) { - 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) - { - voff = raddbg_first_voff_from_proc(rdbg, procedure_id); - break; - } } - } - - // rjf: find voff for one of the default entry points - if(voff == 0) - { - for(U64 idx = 0; voff == 0 && idx < ArrayCount(default_entry_points); idx += 1) + if(procedure_id != 0) { - U32 procedure_id = 0; + U64 new_voff = raddbg_first_voff_from_proc(rdbg, procedure_id); + if(new_voff != 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) - { - voff = raddbg_first_voff_from_proc(rdbg, procedure_id); + entry_voff = new_voff; break; } } } - - // rjf: nonzero voff? => store - if(voff != 0) - { - U64 base_vaddr = demon_base_vaddr_from_module(module); - entry_vaddr = base_vaddr + voff; - entry_vaddr_proc = run_ctrls.run_entities[process_idx]; - } + } + + // rjf: nonzero voff? => store + if(entry_voff != 0) + { + U64 base_vaddr = demon_base_vaddr_from_module(module); + entry_vaddr = base_vaddr + entry_voff; + entry_vaddr_proc = run_ctrls.run_entities[process_idx]; } // rjf: found entry point -> insert into trap controls