mcpField
L
llvm-tooling

llvm-tooling

github.com/gmh5225開発89054 回インストール4 週間前に更新
リポジトリ

llvm-tooling について

llvm-tooling は、LLVM と Clang の基盤でツールを開発する人向けのリファレンススキルです。ソース解析、デバッグ、リファクタリング、言語サーバー連携を例とともに扱います。

主な機能

  1. 01Clang プラグインの開発
  2. 02LibTooling と AST Matchers
  3. 03LLDB の拡張
  4. 04Clangd と LSP の拡張
  5. 05ソース間変換

活用シーン

  1. 01Clang ベースのソース解析ツールの作成
  2. 02カスタム LLDB コマンドの追加
  3. 03clangd 向けコードアクションの実装
  4. 04C++ リファクタリングの自動化

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/gmh5225/awesome-llvm-security --skill llvm-tooling

インストール後、Claude Code で/llvm-toolingを入力して読み込まれたか確認します。

詳細

LLVM ツール開発スキル

このスキルでは、ソースコードの解析、デバッグ、IDE 統合のために LLVM/Clang インフラストラクチャを使用するツールの開発について説明します。

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/Language Server Protocol

カスタム 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 Tooling で構築された注目のツール

解析ツール
  • cppinsights:C++ テンプレートのインスタンス化を可視化
  • ClangBuildAnalyzer:ビルド時間の解析
  • clazy:Qt に特化した静的解析
リファクタリングツール
  • clang-rename:シンボルの名前変更
  • clang-tidy:リンティングと自動修正
  • include-what-you-use:インクルードの最適化
コード生成
  • classgen:IDA 用の型情報を抽出
  • constexpr-everything:constexpr を自動適用
  • clang-expand:関数のインライン展開

ベストプラクティス

  1. AST Matchers を使用する:手動での走査よりも読みやすくなります
  2. 書式を維持する:スタイルを保つため、Rewriter は慎重に使用します
  3. マクロを処理する:マクロ展開位置に注意します
  4. 十分にテストする:C++ には多くのエッジケースがあります
  5. わかりやすい診断を提供する:明確なエラーメッセージにより、使いやすさが向上します

リソース

ツールの包括的な一覧については、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 セクション)
  • 静的解析およびリファクタリングツール

コメント