关于 llvm-tooling
llvm-tooling 是面向 LLVM 和 Clang 工具开发者的参考 Skill,涵盖源码分析、调试、重构和语言服务器集成,并提供示例与工具参考。
主要功能
- 01开发 Clang 插件
- 02使用 LibTooling 和 AST Matchers
- 03扩展 LLDB
- 04扩展 Clangd 与 LSP
- 05进行源码到源码转换
适用场景
- 01构建基于 Clang 的源码分析器
- 02添加自定义 LLDB 命令
- 03为 clangd 实现代码操作
- 04自动化 C++ 重构
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ gmh5225/ awesome-llvm-security --skill llvm-tooling安装后在 Claude Code 中输入/llvm-tooling确认已加载。
详细介绍
LLVM 工具开发技能
此技能涵盖使用 LLVM/Clang 基础设施开发用于源代码分析、调试和 IDE 集成的工具。
Clang 插件开发
插件架构
Clang 插件是动态加载的库,可在编译期间扩展 Clang 的功能。
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
class MyVisitor : public clang::RecursiveASTVisitor<MyVisitor> {
public:
bool VisitFunctionDecl(clang::FunctionDecl *FD) {
llvm::outs() << "Found function: " << FD->getName() << "\n";
return true;
}
};
class MyConsumer : public clang::ASTConsumer {
MyVisitor Visitor;
public:
void HandleTranslationUnit(clang::ASTContext &Context) override {
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
}
};
class MyPlugin : public clang::PluginASTAction {
protected:
std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance &CI, llvm::StringRef) override {
return std::make_unique<MyConsumer>();
}
bool ParseArgs(const clang::CompilerInstance &CI,
const std::vector<std::string> &args) override {
return true;
}
};
static clang::FrontendPluginRegistry::Add<MyPlugin>
X("my-plugin", "My custom plugin description");
运行 Clang 插件
# Build plugin
clang++ -shared -fPIC -o MyPlugin.so MyPlugin.cpp \
$(llvm-config --cxxflags --ldflags)
# Run plugin
clang -Xclang -load -Xclang ./MyPlugin.so \
-Xclang -plugin -Xclang my-plugin \
source.cpp
LibTooling
独立工具
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::tooling;
using namespace clang::ast_matchers;
// Define matcher
auto functionMatcher = functionDecl(hasName("targetFunction")).bind("func");
// Callback handler
class FunctionCallback : public MatchFinder::MatchCallback {
public:
void run(const MatchFinder::MatchResult &Result) override {
if (auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("func")) {
llvm::outs() << "Found: " << FD->getQualifiedNameAsString() << "\n";
}
}
};
int main(int argc, const char **argv) {
auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyCategory);
ClangTool Tool(ExpectedParser->getCompilations(),
ExpectedParser->getSourcePathList());
FunctionCallback Callback;
MatchFinder Finder;
Finder.addMatcher(functionMatcher, &Callback);
return Tool.run(newFrontendActionFactory(&Finder).get());
}
AST Matchers 参考
// Declaration matchers
functionDecl() // Match function declarations
varDecl() // Match variable declarations
recordDecl() // Match struct/class/union
fieldDecl() // Match class fields
cxxMethodDecl() // Match C++ methods
cxxConstructorDecl() // Match constructors
// Expression matchers
callExpr() // Match function calls
binaryOperator() // Match binary operators
unaryOperator() // Match unary operators
memberExpr() // Match member access
// Narrowing matchers
hasName("name") // Filter by name
hasType(asString("int")) // Filter by type
isPublic() // Filter by access specifier
hasAnyParameter(...) // Match parameters
// Traversal matchers
hasDescendant(...) // Match anywhere in subtree
hasAncestor(...) // Match in parent chain
has(...) // Match direct children
forEach(...) // Match all children
LLDB 扩展开发
Python 命令
import lldb
def my_command(debugger, command, result, internal_dict):
"""Custom LLDB command implementation"""
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
# Get variable value
var = frame.FindVariable("my_var")
result.AppendMessage(f"my_var = {var.GetValue()}")
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand(
'command script add -f my_module.my_command my_cmd')
脚本化进程
class MyScriptedProcess(lldb.SBScriptedProcess):
def __init__(self, target, args):
super().__init__(target, args)
def get_thread_with_id(self, tid):
# Return thread info
pass
def get_registers_for_thread(self, tid):
# Return register context
pass
def read_memory_at_address(self, addr, size):
# Read memory
pass
LLDB GUI 扩展
- visual-lldb:LLDB 的 GUI 前端
- vegvisir:基于浏览器的 LLDB GUI
- lldbg:轻量级原生 GUI
- CodeLLDB:VSCode 调试器扩展
Clangd / 语言服务器协议
自定义 LSP 扩展
// Implementing custom code actions
class MyCodeActionProvider {
public:
std::vector<CodeAction> getCodeActions(
const TextDocumentIdentifier &File,
const Range &Range,
const CodeActionContext &Context) {
std::vector<CodeAction> Actions;
// Add custom refactoring action
CodeAction Action;
Action.title = "Extract to function";
Action.kind = "refactor.extract";
// Define workspace edits
WorkspaceEdit Edit;
// ... populate edits
Action.edit = Edit;
Actions.push_back(Action);
return Actions;
}
};
Clangd 配置
# .clangd configuration file
CompileFlags:
Add: [-xc++, -std=c++17]
Remove: [-W*]
Diagnostics:
ClangTidy:
Add: [modernize-*, performance-*]
Remove: [modernize-use-trailing-return-type]
Index:
Background: Build
源代码到源代码转换
Clang Rewriter
#include "clang/Rewrite/Core/Rewriter.h"
class MyRewriter : public RecursiveASTVisitor<MyRewriter> {
Rewriter &R;
public:
MyRewriter(Rewriter &R) : R(R) {}
bool VisitFunctionDecl(FunctionDecl *FD) {
// Add comment before function
R.InsertTextBefore(FD->getBeginLoc(), "// Auto-generated\n");
// Replace function name
R.ReplaceText(FD->getLocation(),
FD->getName().size(), "new_name");
return true;
}
};
RefactoringTool
#include "clang/Tooling/Refactoring.h"
class MyRefactoring : public RefactoringCallback {
public:
void run(const MatchFinder::MatchResult &Result) override {
// Generate replacements
Replacement Rep(
*Result.SourceManager,
CharSourceRange::getTokenRange(Range),
"new_text");
Replacements.insert(Rep);
}
};
使用 LLVM 工具开发的知名工具
分析工具
- cppinsights:C++ 模板实例化可视化
- ClangBuildAnalyzer:构建时间分析
- clazy:针对 Qt 的静态分析
重构工具
- clang-rename:符号重命名
- clang-tidy:代码检查和自动修复
- include-what-you-use:优化头文件包含
代码生成
- classgen:提取类型信息以用于 IDA
- constexpr-everything:自动应用 constexpr
- clang-expand:内联函数展开
最佳实践
- 使用 AST Matchers:比手动遍历更易读
- 保留格式:谨慎使用 Rewriter,以保持代码风格
- 处理宏:注意宏展开位置
- 充分测试:C++ 中的边缘情况很多
- 提供良好的诊断信息:清晰的错误消息能提升易用性
资源
如需全面的工具列表,请参阅 README.md 中的 Clang Plugins、Clangd/Language Server 和 LLDB 章节。
获取详细信息
如需详细且最新的资源链接、工具列表或项目参考,请从以下位置获取最新数据:
https://raw.githubusercontent.com/gmh5225/awesome-llvm-security/refs/heads/main/README.md
此 README 包含经过全面整理的以下内容:
- Clang 插件和扩展(Clang Plugins 章节)
- 语言服务器实现(Clangd/Language Server 章节)
- LLDB 调试器工具和 GUI(LLDB 章节)
- 静态分析和重构工具
评论
支持 Markdown