From 8d1bfb31a14e9fb156b4cb007fa0304fa93858fa Mon Sep 17 00:00:00 2001 From: York Jasper Niebuhr Date: Tue, 21 Oct 2025 01:02:34 +0200 Subject: [PATCH] Pinpoint plugin update --- playground/spslr_pinpoint.cpp | 198 +++++++++++++++++++++++++++++++++- 1 file changed, 197 insertions(+), 1 deletion(-) diff --git a/playground/spslr_pinpoint.cpp b/playground/spslr_pinpoint.cpp index 2023087..b7963a4 100644 --- a/playground/spslr_pinpoint.cpp +++ b/playground/spslr_pinpoint.cpp @@ -9,6 +9,16 @@ #include #include #include +#include +#include + +#include +#include +#include +#include +#include +#include +#include int plugin_is_GPL_compatible; @@ -101,6 +111,10 @@ const Member* Target::get_member(Member::OFF offset) const { } static void log_target(tree node) { + node = TYPE_MAIN_VARIANT(node); + if (!node) + return; + if (TREE_CODE(node) != RECORD_TYPE) return; @@ -188,7 +202,7 @@ void on_register_attributes(void* event_data, void* data) { static void on_type_complete(void* event_data, void* user_data) { tree type = (tree)event_data; - log_target(TYPE_MAIN_VARIANT(type)); + log_target(type); } // Early hook to make COMPONENT_REF nodes survice front end @@ -325,6 +339,174 @@ static void on_build_component_ref(void* event_data, void* user_data) { *component_ref_node = repl; } +// Identify any missing COMPONENT_REFs (e.g. from CONSTRUCTOR trees) + +static const pass_data log_component_refs_pass_data = { + GIMPLE_PASS, + "log_component_refs", + OPTGROUP_NONE, + TV_NONE, + 0,0,0,0, + TODO_update_ssa +}; + +struct log_component_refs_pass : gimple_opt_pass { + log_component_refs_pass(gcc::context *ctxt); + unsigned int execute(function* fun) override; +}; + +log_component_refs_pass::log_component_refs_pass(gcc::context *ctxt) : gimple_opt_pass(log_component_refs_pass_data, ctxt) {} + +static tree gimple_instrument_offsetof_maybe(tree ref, gimple_stmt_iterator* gsi) { + SPSLROffsetofCallData call_data; + if (!is_relevant_offsetof(ref, call_data.target, call_data.member)) + return NULL_TREE; + + // Build call gimple statement + + location_t loc = EXPR_LOCATION(ref); + tree result_type = TREE_TYPE(ref); + + if (!require_spslr_offsetof_decl()) { + std::cerr << "spslr_pinpoint -> failed to instrument COMPONENT_REF (" << SPSLR_OFFSETOF << " unavailable)" << std::endl; + return NULL_TREE; + } + + call_data.uid = spslr_offsetof_next_uid++; + spslr_offsetof_calls.emplace(call_data.uid, call_data); + + tree call_uid_tree = build_int_cst(long_unsigned_type_node, call_data.uid); + + gimple* call_stmt = gimple_build_call(spslr_offsetof_decl, 1, call_uid_tree); + tree offset_tmp = create_tmp_var(size_type_node, NULL); + gimple_call_set_lhs(call_stmt, offset_tmp); + gsi_insert_before(gsi, call_stmt, GSI_SAME_STMT); + + // Get base as char* + tree base = TREE_OPERAND(ref, 0); + tree base_addr; + + if (TREE_CODE(base) == ADDR_EXPR) { + // base_addr = base; + std::cerr << "spslr_pinpoint -> unexpected ADDR_EXPR as COMPONENT_REF base!" << std::endl; + return NULL_TREE; + } else { + base_addr = build_fold_addr_expr(base); + } + + tree char_ptr_type = build_pointer_type(char_type_node); + tree field_ptr_type = build_pointer_type(result_type); + + // Temporary variable for base pointer needed for GIMPLE + tree base_char_ptr = fold_convert(char_ptr_type, base_addr); + tree base_char_ptr_tmp = create_tmp_var(char_ptr_type, NULL); + gimple* base_char_ptr_tmp_assignment = gimple_build_assign(base_char_ptr_tmp, base_char_ptr); + gsi_insert_before(gsi, base_char_ptr_tmp_assignment, GSI_SAME_STMT); + + // Add result of __spslr_offsetof, cast back to field pointer, then dereference + tree plus = build2_loc(loc, POINTER_PLUS_EXPR, char_ptr_type, base_char_ptr_tmp, offset_tmp); + + tree plus_tmp = create_tmp_var(TREE_TYPE(plus), NULL); + gimple* plus_tmp_assignment = gimple_build_assign(plus_tmp, plus); + gsi_insert_before(gsi, plus_tmp_assignment, GSI_SAME_STMT); + + tree cast_back = fold_convert(field_ptr_type, plus_tmp); + + tree res_ptr_tmp = create_tmp_var(TREE_TYPE(cast_back), NULL); + gimple* res_ptr_tmp_assignment = gimple_build_assign(res_ptr_tmp, cast_back); + gsi_insert_before(gsi, res_ptr_tmp_assignment, GSI_SAME_STMT); + + tree off0 = build_int_cst(sizetype, 0); + tree new_ref = build2_loc(loc, MEM_REF, result_type, res_ptr_tmp, fold_convert(field_ptr_type, off0)); + return new_ref; +} + +static tree log_gimple_operand_component_refs(tree *tp, int *walk_subtrees, void *data) { + gimple_stmt_iterator* gsi = (gimple_stmt_iterator*)data; + *walk_subtrees = 1; + + if (!tp || !*tp) + return NULL_TREE; + + if (TREE_CODE(*tp) != COMPONENT_REF) + return NULL_TREE; + + tree repl = gimple_instrument_offsetof_maybe(*tp, gsi); + if (!repl) + return NULL_TREE; + + // TODO -> Recursively do sub-component-refs + // After top level split, the base is in a separate stmt! + + *tp = repl; + *walk_subtrees = 0; + + gimple_set_modified(gsi_stmt(*gsi), true); + + walk_tree(tp, log_gimple_operand_component_refs, data, NULL); + return NULL_TREE; +} + +unsigned int log_component_refs_pass::execute(function* fun) { + const char* funcname = fun->decl && DECL_NAME(fun->decl) + ? IDENTIFIER_POINTER(DECL_NAME(fun->decl)) + : ""; + + tree fndecl = fun->decl; + if (!fndecl) + return 0; + + gimple_seq body = gimple_body(fndecl); + for (gimple_stmt_iterator gsi = gsi_start(body); !gsi_end_p(gsi); gsi_next(&gsi)) { + gimple* stmt = gsi_stmt(gsi); + + for (int i = 0; i < gimple_num_ops(stmt); i++) { + tree* op = gimple_op_ptr(stmt, i); + if (!op || !*op) + continue; + + walk_tree(op, log_gimple_operand_component_refs, &gsi, NULL); + } + } + + // print_gimple_seq(stderr, gimple_body(fun->decl), 0, TDF_NONE); + return 0; +} + +// Gimple print pass for debugging + +static const pass_data print_pass_data = { + GIMPLE_PASS, + "gimple_print", + OPTGROUP_NONE, + TV_NONE, + 0,0,0,0, 0 +}; + +struct print_pass : gimple_opt_pass { + print_pass(gcc::context *ctxt); + unsigned int execute(function* fun) override; +}; + +print_pass::print_pass(gcc::context *ctxt) : gimple_opt_pass(print_pass_data, ctxt) {} + +unsigned int print_pass::execute(function* fun) { + const char* funcname = fun->decl && DECL_NAME(fun->decl) + ? IDENTIFIER_POINTER(DECL_NAME(fun->decl)) + : ""; + + fprintf(stderr, "[spslr_pinpoint] Function: %s\n", funcname); + basic_block bb; + FOR_EACH_BB_FN(bb, fun) { + for (gimple_stmt_iterator gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { + gimple* stmt = gsi_stmt(gsi); + print_gimple_stmt(stderr, stmt, 0, TDF_SLIM); + } + } + fprintf(stderr, "\n"); + + return 0; +} // Hook everything up in plugin_init @@ -339,5 +521,19 @@ int plugin_init (struct plugin_name_args *plugin_info, struct plugin_gcc_version register_callback(plugin_info->base_name, PLUGIN_FINISH_TYPE, on_type_complete, NULL); register_callback(plugin_info->base_name, PLUGIN_BUILD_COMPONENT_REF, on_build_component_ref, NULL); + struct register_pass_info log_component_refs_pass_info; + log_component_refs_pass_info.pass = new log_component_refs_pass(nullptr); + log_component_refs_pass_info.ref_pass_instance_number = 1; + log_component_refs_pass_info.reference_pass_name = "cfg"; + log_component_refs_pass_info.pos_op = PASS_POS_INSERT_BEFORE; + register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &log_component_refs_pass_info); + + struct register_pass_info print_pass_info; + print_pass_info.pass = new print_pass(nullptr); + print_pass_info.ref_pass_instance_number = 1; + print_pass_info.reference_pass_name = "cfg"; + print_pass_info.pos_op = PASS_POS_INSERT_AFTER; + register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &print_pass_info); + return 0; }