diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt index e855273..f7cb3cf 100644 --- a/plugin/CMakeLists.txt +++ b/plugin/CMakeLists.txt @@ -2,8 +2,8 @@ add_library(selfpatch-slr SHARED main.cpp) set_target_properties(selfpatch-slr PROPERTIES PREFIX "") target_compile_definitions(selfpatch-slr PRIVATE _GNU_SOURCE) +target_compile_options(selfpatch-slr PRIVATE -fno-rtti -fno-exceptions) -message(STATUS "C compiler: ${CMAKE_C_COMPILER}") execute_process(COMMAND ${CMAKE_C_COMPILER} -print-file-name=plugin OUTPUT_VARIABLE GCC_PLUGIN_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "GCC plugin path: ${GCC_PLUGIN_PATH}") target_include_directories(selfpatch-slr PRIVATE ${GCC_PLUGIN_PATH}/include) diff --git a/plugin/main.cpp b/plugin/main.cpp index ffbbff1..0be0038 100644 --- a/plugin/main.cpp +++ b/plugin/main.cpp @@ -1,31 +1,227 @@ #include - -#include "gcc-plugin.h" -#include "plugin-version.h" -#include "tree.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include int plugin_is_GPL_compatible; -static tree handle_slr_attr(tree* node, tree name, tree args, int flags, bool* no_add_attrs) { - if (!node) - return NULL_TREE; +struct MemberAccessInfo { + tree field_decl; // FIELD_DECL des zugegriffenen Mitglieds + unsigned long label_num; + std::string funcname; + location_t loc; +}; - std::cout << "SLR attribute found!" << std::endl; - return NULL_TREE; +static std::vector g_member_accesses; +static unsigned long label_counter = 0; +std::unordered_set targets; + +bool is_target(const char* name) { + std::string str{ name }; + return targets.find(str) != targets.end(); +} + +// ------------------------ +// Sicherer Helfer zum Abrufen des RECORD_TYPE-Namens +// ------------------------ +static const char* safe_get_record_type_name_from_field(tree field) +{ + if (!field) return nullptr; + + tree ctx = DECL_CONTEXT(field); + int depth = 0; + while (ctx && depth < 8 && TREE_CODE(ctx) != RECORD_TYPE) { + if (TREE_CODE(ctx) == TYPE_DECL) + ctx = TREE_TYPE(ctx); + else + ctx = nullptr; + depth++; + } + + if (!ctx || TREE_CODE(ctx) != RECORD_TYPE) + return nullptr; + + tree type_name = TYPE_NAME(ctx); + if (!type_name) + return nullptr; + + tree decl_name = nullptr; + if (TREE_CODE(type_name) == TYPE_DECL) + decl_name = DECL_NAME(type_name); + else if (TREE_CODE(type_name) == IDENTIFIER_NODE) + decl_name = type_name; + + if (!decl_name || TREE_CODE(decl_name) != IDENTIFIER_NODE) + return nullptr; + + return IDENTIFIER_POINTER(decl_name); +} + +// ------------------------ +// Rekursiver Scanner für COMPONENT_REF +// ------------------------ +static void scan_tree_for_components(tree t, const char *funcname, gimple_stmt_iterator *gsi) +{ + if (!t) return; + + tree_code tc = TREE_CODE(t); + + switch(tc) { + case COMPONENT_REF: { + tree field = TREE_OPERAND(t,1); + if (field && TREE_CODE(field) == FIELD_DECL) { + const char* rec_name = safe_get_record_type_name_from_field(field); // struct name + if (rec_name && is_target(rec_name)) { + MemberAccessInfo info; + info.field_decl = field; + info.label_num = ++label_counter; + info.funcname = funcname ? funcname : ""; + info.loc = UNKNOWN_LOCATION; + g_member_accesses.push_back(info); + + // insert label immediately + char buf[64]; + snprintf(buf, sizeof(buf), "mylabel_%lu:", info.label_num); + + vec* inputs = nullptr; + vec* outputs = nullptr; + vec* clobbers = nullptr; + vec* labels = nullptr; + + gimple *asm_stmt = gimple_build_asm_vec( + ggc_strdup(buf), + inputs, + outputs, + clobbers, + labels + ); + + gsi_insert_before(gsi, asm_stmt, GSI_SAME_STMT); + } + } + // Rekursion in das Basisobjekt + scan_tree_for_components(TREE_OPERAND(t,0), funcname, gsi); + break; + } + case INDIRECT_REF: + case CONVERT_EXPR: + case NOP_EXPR: + case VIEW_CONVERT_EXPR: + scan_tree_for_components(TREE_OPERAND(t,0), funcname, gsi); + break; + case ARRAY_REF: + scan_tree_for_components(TREE_OPERAND(t,0), funcname, gsi); + scan_tree_for_components(TREE_OPERAND(t,1), funcname, gsi); + break; + case PLUS_EXPR: case MINUS_EXPR: case MULT_EXPR: case POINTER_PLUS_EXPR: + scan_tree_for_components(TREE_OPERAND(t,0), funcname, gsi); + scan_tree_for_components(TREE_OPERAND(t,1), funcname, gsi); + break; + default: + break; // Blätter + } +} + +// ------------------------ +// GIMPLE-Pass-Ausführung +// ------------------------ +namespace { + +const pass_data gimplabels_pass_data = { + GIMPLE_PASS, + "gimplabels", + OPTGROUP_NONE, + TV_NONE, + 0,0,0,0,0 +}; + +struct gimplabels_pass : gimple_opt_pass { + gimplabels_pass(gcc::context *ctxt) + : gimple_opt_pass(gimplabels_pass_data, ctxt) + {} + + unsigned int execute(function* fun) override { + const char* funcname = fun->decl && DECL_NAME(fun->decl) + ? IDENTIFIER_POINTER(DECL_NAME(fun->decl)) + : ""; + + + // Iteration über alle Grundblöcke und Anweisungen + 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); + for (unsigned i = 0; i < gimple_num_ops(stmt); ++i) { + tree op = gimple_op(stmt, i); + scan_tree_for_components(op, funcname, &gsi); + } + } + } + + std::cout << "Number of accesses: " << g_member_accesses.size() << std::endl; + return 0; + } +}; + +} // anonymer Namensraum + +// ------------------------ +// Plugin-Initialisierung +// ------------------------ + +static tree handle_slr_attr(tree* node, tree name, tree args, int flags, bool* no_add_attrs) { + if (!node) + return NULL_TREE; + + if (TREE_CODE(*node) != RECORD_TYPE) + return *node; // Only allowed on structs + + tree type_name_tree = TYPE_IDENTIFIER(*node); + if (type_name_tree == NULL_TREE) + return *node; + + std::string name_str{ IDENTIFIER_POINTER(type_name_tree) }; + targets.insert(name_str); + + std::cout << "SLR attribute recognized on \"" << name_str << "\"" << std::endl; + return *node; } static struct attribute_spec slr_attr = { "slr", 0, 0, false, false, false, false, handle_slr_attr, NULL }; void register_attributes(void* event_data, void* data) { - register_attribute(&slr_attr); + register_attribute(&slr_attr); } -int plugin_init(struct plugin_name_args* plugin_info, struct plugin_gcc_version* version) { - if (!plugin_default_version_check(version, &gcc_version)) { - std::cerr << "This plugin is for GCC version " << GCCPLUGIN_VERSION_MAJOR << "." << GCCPLUGIN_VERSION_MINOR << std::endl; - return 1; - } +int plugin_init(plugin_name_args *plugin_info, plugin_gcc_version *version) +{ + if (!plugin_default_version_check(version, &gcc_version)) { + fprintf(stderr, "GCC-Version stimmt nicht überein\n"); + return 1; + } register_callback(plugin_info->base_name, PLUGIN_ATTRIBUTES, register_attributes, NULL); - return 0; + + g_member_accesses.clear(); + label_counter = 0; + + struct register_pass_info ginfo; + ginfo.pass = new gimplabels_pass(nullptr); + ginfo.reference_pass_name = "cfg"; + ginfo.ref_pass_instance_number = 1; + ginfo.pos_op = PASS_POS_INSERT_AFTER; + register_callback(plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, nullptr, &ginfo); + + return 0; } + diff --git a/subject/main.c b/subject/main.c index 52d84e3..d7e4a62 100644 --- a/subject/main.c +++ b/subject/main.c @@ -25,6 +25,9 @@ struct B { } __attribute__((slr)); int main(int argc, char** argv) { - // TODO + struct A a = { 'x', 52, NULL }; + struct B b = { 1, 2, 3, NULL, 4.f, a, NULL }; + + b.m2 = 42; return 0; }