如何在GCC插件中获取每个if条件的tree及对应location_t?
GCC插件获取if语句条件AST与位置的实现方案
无需修改GCC源码,可通过注册Tree遍历钩子或添加GIMPLE Pass两种方式实现需求,以下是具体方案:
方案一:注册Tree遍历钩子(前端AST阶段)
GCC提供tree_hooks机制,允许在AST节点处理完成时插入自定义逻辑,与你修改c_parser_if_statement的时机接近,能直接获取原始条件AST与位置:
插件代码示例
#include "gcc-plugin.h" #include "tree.h" #include "c-tree.h" #include "tree-pass.h" #include "plugin-version.h" #include "print-tree.h" int plugin_is_GPL_compatible; // 处理if语句的自定义逻辑 static void handle_if_stmt(tree stmt) { if (TREE_CODE(stmt) != IF_STMT) return; // 获取if语句的条件表达式AST tree cond_expr = IF_STMT_COND(stmt); tree cond = COND_EXPR_COND(cond_expr); // 获取条件左括号的起始位置(与原c_parser_peek_token取到的位置一致) location_t cond_loc = get_start_loc(cond_expr); // 替换为你的My_Method逻辑,示例为打印调试信息 fprintf(stderr, "IF条件位置:%d行%d列\n", LOCATION_LINE(cond_loc), LOCATION_COLUMN(cond_loc)); fprintf(stderr, "IF条件AST:"); print_tree(stderr, cond); fprintf(stderr, "\n"); } // 注册Tree钩子 static void register_tree_hooks(void) { static struct tree_hooks custom_hooks = tree_hooks; custom_hooks.finish_stmt = handle_if_stmt; tree_hooks = &custom_hooks; } // 插件初始化入口 int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { if (!plugin_default_version_check(version, &gcc_version)) { fprintf(stderr, "插件与GCC版本不兼容\n"); return 1; } register_tree_hooks(); return 0; }
编译与使用
将代码保存为if_plugin.c,编译插件:
gcc -fPIC -shared -o if_plugin.so if_plugin.c -I$(gcc -print-file-name=plugin)/include
编译目标代码时加载插件:
gcc -fplugin=./if_plugin.so test.c
方案二:添加GIMPLE Pass(中间代码阶段)
如果需要在GIMPLE中间代码阶段处理,可自定义Pass遍历函数体中的条件语句:
核心代码片段
#include "gcc-plugin.h" #include "tree.h" #include "gimple.h" #include "tree-pass.h" #include "plugin-version.h" int plugin_is_GPL_compatible; // Pass执行函数 static unsigned int process_if_cond(void) { if (!current_function_decl) return 0; basic_block bb; gimple_stmt_iterator gsi; FOR_EACH_BB_FN(bb, cfun) { for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { gimple stmt = gsi_stmt(gsi); if (gimple_code(stmt) == GIMPLE_COND) { // 获取条件表达式与位置 tree cond = gimple_cond_condition(stmt); location_t loc = gimple_location(stmt); // 自定义处理逻辑 fprintf(stderr, "GIMPLE条件位置:%d行%d列\n", LOCATION_LINE(loc), LOCATION_COLUMN(loc)); } } } return 0; } // 定义Pass数据 static struct pass_data if_pass_data = { .type = GIMPLE_PASS, .name = "if_cond_pass", .optinfo_flags = OPTGROUP_NONE, .tv_id = TV_NONE, .properties_required = 0, .properties_provided = 0, .properties_destroyed = 0, .todo_flags_start = 0, .todo_flags_finish = 0, }; // 实现Pass类 class if_pass : public gimple_opt_pass { public: if_pass(gcc::context *ctxt) : gimple_opt_pass(if_pass_data, ctxt) {} unsigned int execute(function *fun) override { current_function_decl = fun->decl; return process_if_cond(); } }; // 插件初始化注册Pass int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) { if (!plugin_default_version_check(version, &gcc_version)) { fprintf(stderr, "插件与GCC版本不兼容\n"); return 1; } register_pass(new if_pass(g), PASS_POS_INSERT_AFTER, "cfg", NULL, NULL); return 0; }
关键说明
- 方案一对应前端语法分析后的AST阶段,直接获取原始条件结构,与你修改
c_parser_if_statement的场景匹配度最高 - 方案二基于中间代码,适合需要在优化阶段处理的场景
- 所有API均来自GCC公开的插件接口,无需修改核心源码
内容的提问来源于stack exchange,提问作者BD26
相关产品推荐
相关产品推荐

