diff --git a/pinpoint/pinpoint_config.h b/pinpoint/pinpoint_config.h index b7f4afe..e73004a 100644 --- a/pinpoint/pinpoint_config.h +++ b/pinpoint/pinpoint_config.h @@ -2,3 +2,4 @@ #define SPSLR_ATTRIBUTE "spslr" #define SPSLR_PINPOINT_STAGE0_SEPARATOR "__spslr_offsetof" +#define SPSLR_PINPOINT_STAGE1_SEPARATOR "__spslr_pin" /* suffixed with "_" */ diff --git a/pinpoint/stage1/asm_offset_pass.cpp b/pinpoint/stage1/asm_offset_pass.cpp index 399fb23..df577cc 100644 --- a/pinpoint/stage1/asm_offset_pass.cpp +++ b/pinpoint/stage1/asm_offset_pass.cpp @@ -1,8 +1,95 @@ #include -#include +#include + +#include +#include + +static UID next_separator_uid = 0; +static std::unordered_map separators; + +static char asm_str_buf[1024]; + +static const char* make_asm_noarch(UID uid) { + snprintf(asm_str_buf, sizeof(asm_str_buf), SPSLR_PINPOINT_STAGE1_SEPARATOR "_%lu:", uid); + return nullptr; +} + +static const char* make_asm_x86_64(UID uid) { + // Asm has 1 output (%0) and 2 inputs for target (%1) and offset (%2) + snprintf(asm_str_buf, sizeof(asm_str_buf), SPSLR_PINPOINT_STAGE1_SEPARATOR "_%lu: mov %2, %0", uid); + return asm_str_buf; +} + +static const char* make_asm(UID uid, S1Separator::ARCH& arch) { +#if defined(__x86_64__) || defined(__amd64__) + arch = S1Separator::X86_64; + return make_asm_x86_64(uid); +#else + arch = S1Separator::NONE; + return make_asm_noarch(uid); +#endif +} + +static tree make_asm_operand(const char* constraint_text, tree operand_tree) { + tree constraint_str = build_string(strlen (constraint_text) + 1, constraint_text); + tree inner_list = build_tree_list(integer_zero_node, constraint_str); + tree outer_list = build_tree_list(inner_list, operand_tree); + return outer_list; +} + +static gimple* make_stage1_separator(tree lhs, UID target, std::size_t offset) { + if (!lhs) + return nullptr; + + UID uid = next_separator_uid++; + + S1Separator separator; + separator.target = target; + separator.offset = offset; + + const char* asm_str = make_asm(uid, separator.arch); + if (!asm_str) + pinpoint_fatal("make_stage1_separator failed to generate asm string"); + + tree arg0 = build_int_cst(size_type_node, target); + tree arg1 = build_int_cst(size_type_node, offset); + + vec* outputs = NULL; + vec* inputs = NULL; + + vec_safe_push(outputs, make_asm_operand("=r", lhs)); + vec_safe_push(inputs, make_asm_operand("i", arg0)); + vec_safe_push(inputs, make_asm_operand("i", arg1)); + + gasm* new_gasm = gimple_build_asm_vec(ggc_strdup(asm_str), inputs, outputs, NULL, NULL); + if (!new_gasm) + return nullptr; + + SSA_NAME_DEF_STMT(lhs) = new_gasm; + + separators.emplace(uid, separator); + return new_gasm; +} static void separator_assemble_maybe(gimple_stmt_iterator* gsi) { - // TODO + if (!gsi) + return; + + gimple* stmt = gsi_stmt(*gsi); + if (!stmt) + return; + + UID target; + std::size_t offset; + + if (!is_stage0_separator(stmt, target, offset)) + return; + + gimple* replacement = make_stage1_separator(gimple_call_lhs(stmt), target, offset); + if (!replacement) + pinpoint_fatal(); + + gsi_replace(gsi, replacement, true); } static const pass_data asm_offset_pass_data = { diff --git a/pinpoint/stage1/stage1.h b/pinpoint/stage1/stage1.h index b6d9236..211e484 100644 --- a/pinpoint/stage1/stage1.h +++ b/pinpoint/stage1/stage1.h @@ -1,7 +1,17 @@ #pragma once +#include #include +struct S1Separator { + enum ARCH { + NONE, X86_64 + } arch; + + UID target; + std::size_t offset; +}; + struct asm_offset_pass : gimple_opt_pass { asm_offset_pass(gcc::context* ctxt); unsigned int execute(function* fn) override; diff --git a/subject/CMakeLists.txt b/subject/CMakeLists.txt index 90598c1..3930930 100644 --- a/subject/CMakeLists.txt +++ b/subject/CMakeLists.txt @@ -1,4 +1,4 @@ add_executable(subject main.c) add_dependencies(subject spslr_pinpoint spslr_finalize spslr_selfpatch) target_link_libraries(subject PRIVATE spslr_selfpatch) -target_compile_options(subject PRIVATE -fplugin=$ -fdump-tree-separate_offset) +target_compile_options(subject PRIVATE -fplugin=$ -fdump-tree-separate_offset -fdump-tree-asm_offset)