# 機能設計書：llvm-symbolizer

## 1. 機能概要

### 1.1 機能名
llvm-symbolizer - アドレスからシンボル名への変換ツール

### 1.2 機能説明
llvm-symbolizerは、addr2lineと同様に動作するユーティリティで、タプル（モジュール名、モジュールオフセット）をコードロケーション（関数名、ファイル、行番号、列番号）に変換します。compiler-rtツール（特にAddressSanitizerやThreadSanitizer）がエラーレポート内のスタックトレースをシンボル化するために使用できます。llvm-addr2lineとしても動作し、GNU addr2lineとの互換性を提供します。

### 1.3 関連する画面/API
- CLI（コマンドラインインターフェース）
- 入力：アドレス（標準入力またはコマンドライン引数）
- 出力：シンボル情報（関数名、ファイル名、行番号など）

---

## 2. 入出力設計

### 2.1 入力
| 項目 | 型 | 必須 | 説明 |
|------|-----|------|------|
| addresses | アドレス群 | No | シンボル化するアドレス（複数指定可、標準入力からも読み取り） |
| -e, --obj | ファイルパス | No | シンボル化対象のオブジェクトファイル |
| --build-id | ビルドID | No | ビルドIDでオブジェクトを指定 |

### 2.2 出力
| 項目 | 型 | 説明 |
|------|-----|------|
| symbol info | テキスト/JSON | 関数名、ファイル名、行番号、列番号 |
| exit code | 整数 | 0: 成功、1: エラー |

### 2.3 コマンドラインオプション
| オプション | 説明 |
|-----------|------|
| -e, --obj | シンボル化対象のオブジェクトファイル |
| --build-id | ビルドIDでオブジェクトを指定 |
| --adjust-vma=<offset> | VMAを調整 |
| --basenames | ファイル名のみ表示（パス省略） |
| --relativenames | 相対パスで表示 |
| -C, --demangle | シンボル名をデマングル（デフォルト: llvm-symbolizer） |
| --no-demangle | デマングルしない（デフォルト: addr2line） |
| --dwp=<file> | .dwpファイルを指定 |
| --fallback-debug-path | フォールバックデバッグパス |
| -f, --functions[=<value>] | 関数名を出力（none/short/linkage） |
| -i, --inlines | インライン関数を展開（デフォルト: llvm-symbolizer） |
| --no-inlines | インライン展開しない（デフォルト: addr2line） |
| -a, --addresses | 入力アドレスも出力に含める |
| -p, --pretty-print | 整形して出力 |
| --print-source-context-lines=<N> | ソースコードコンテキストを表示 |
| -s, --basenames | （-basenamesの別名） |
| --relative-address | 相対アドレスを使用 |
| --output-style=<style> | 出力スタイル（LLVM/GNU/JSON） |
| --debuginfod | debuginfodを有効化 |
| --no-debuginfod | debuginfodを無効化 |
| --debug-file-directory | デバッグファイルディレクトリ |
| --filter-markup | マークアップフィルタモード |
| --color[=<value>] | 色出力（always/never/auto） |
| --cache-size=<N> | キャッシュサイズ |
| --verbose | 詳細出力 |
| --help | ヘルプを表示 |
| --version | バージョンを表示 |

---

## 3. 処理フロー

### 3.1 基本フロー

```
[開始]
   │
   ▼
[コマンドライン引数解析]
   │
   ▼
[オプション設定]
   │
   ▼
[LLVMSymbolizer初期化]
   │
   ▼
[入力ソース判定]
   │
   ├─► --filter-markup ──► filterMarkup()
   │
   ├─► コマンドライン引数 ──► symbolizeInput() [各アドレス]
   │
   └─► 標準入力 ──► symbolizeInput() [各行]
   │
   ▼
[終了]
```

### 3.2 シンボル化処理フロー

```
symbolizeInput()
   │
   ▼
[parseCommand() - 入力解析]
   │
   ├─► CODE/DATA/FRAME コマンド判定
   │
   ├─► FILE:/BUILDID: プレフィックス処理
   │
   └─► モジュール名、オフセット抽出
   │
   ▼
[executeCommand()]
   │
   ├─► DATA ──► Symbolizer.symbolizeData()
   │
   ├─► FRAME ──► Symbolizer.symbolizeFrame()
   │
   ├─► シンボル名指定 ──► Symbolizer.findSymbol()
   │
   ├─► インライン展開 ──► Symbolizer.symbolizeInlinedCode()
   │
   └─► 通常 ──► Symbolizer.symbolizeCode()
   │
   ▼
[print() - 結果出力]
```

### 3.3 入力コマンドパース

```
parseCommand()
   │
   ▼
[コマンド種別判定]
   │
   ├─► "CODE " ──► Command::Code
   │
   ├─► "DATA " ──► Command::Data
   │
   ├─► "FRAME " ──► Command::Frame
   │
   └─► なし ──► Command::Code（デフォルト）
   │
   ▼
[入力ファイル指定解析]
   │
   ├─► "FILE:" ──► ファイルパス指定
   │
   └─► "BUILDID:" ──► ビルドID指定
   │
   ▼
[アドレス/シンボル指定解析]
   │
   ├─► 数値 ──► オフセットとして解釈
   │
   └─► 文字列 ──► シンボル名（+オフセット）として解釈
```

---

## 4. データ構造

### 4.1 出力スタイル

```cpp
enum class OutputStyle {
    LLVM,  // LLVM形式（デフォルト: llvm-symbolizer）
    GNU,   // GNU addr2line形式（デフォルト: llvm-addr2line）
    JSON   // JSON形式
};
```

### 4.2 コマンド種別

```cpp
enum class Command {
    Code,   // コードシンボル化
    Data,   // データシンボル化
    Frame,  // フレームシンボル化
};
```

### 4.3 関数名出力種別

```cpp
enum class FunctionNameKind {
    None,         // 関数名なし
    ShortName,    // 短縮名
    LinkageName   // リンケージ名（デフォルト）
};
```

### 4.4 シンボライザオプション

```cpp
LLVMSymbolizer::Options Opts;
Opts.PathStyle = ...;           // パス表示形式
Opts.SkipLineZero = ...;        // 行0をスキップ
Opts.DebugFileDirectory = ...;  // デバッグファイルディレクトリ
Opts.DefaultArch = ...;         // デフォルトアーキテクチャ
Opts.Demangle = ...;            // デマングル有効
Opts.DWPName = ...;             // .dwpファイル名
Opts.PrintFunctions = ...;      // 関数名出力種別
Opts.RelativeAddresses = ...;   // 相対アドレス使用
Opts.UntagAddresses = ...;      // アドレスタグ除去
Opts.UseDIA = ...;              // DIA SDK使用（Windows）
Opts.UseSymbolTable = true;     // シンボルテーブル使用
Opts.MaxCacheSize = ...;        // キャッシュサイズ
```

---

## 5. 主要機能

### 5.1 llvm-addr2lineモード
- ツール名に"addr2line"が含まれると自動検出
- GNU addr2line互換の動作
- デフォルトでデマングル無効、インライン展開無効

### 5.2 debuginfodサポート
- ビルドIDからデバッグシンボルを自動取得
- HTTPクライアントを使用
- `--debuginfod`/`--no-debuginfod`で制御

### 5.3 マークアップフィルタ
- 標準入力からマークアップを読み取りシンボル化
- `--filter-markup`で有効化

### 5.4 複数出力形式
- LLVM形式：詳細情報
- GNU形式：addr2line互換
- JSON形式：機械処理向け

---

## 6. エラーハンドリング

### 6.1 エラーケース
| エラー | 原因 | 対応 |
|--------|------|------|
| オブジェクトファイル読み込み失敗 | ファイル不存在・形式不正 | エラー出力、終了コード1 |
| --build-idと--obj同時指定 | 非互換オプション | エラー出力、終了コード1 |
| 無効なビルドID形式 | パースエラー | エラー出力、終了コード1 |
| 入力ファイル指定の重複 | FILE:とBUILDID:の重複 | エラー出力 |
| モジュールオフセット未指定 | 入力形式エラー | エラー出力 |

### 6.2 エラー出力

```cpp
static void printError(const ErrorInfoBase &EI, StringRef AuxInfo) {
    WithColor::error(errs(), ToolName);
    if (!AuxInfo.empty())
        errs() << "'" << AuxInfo << "': ";
    EI.log(errs());
    errs() << '\n';
}
```

---

## 7. 技術仕様

### 7.1 環境変数
- `LLVM_SYMBOLIZER_OPTS`：llvm-symbolizerの初期オプション
- `LLVM_ADDR2LINE_OPTS`：llvm-addr2lineの初期オプション

### 7.2 入力形式
```
[CODE|DATA|FRAME] [FILE:<path>|BUILDID:<hash>] <address>
[CODE|DATA|FRAME] [FILE:<path>|BUILDID:<hash>] <symbol>[+<offset>]
```

### 7.3 アドレス解釈（addr2lineモード）
- 16進数として解釈
- "0x"/"0X"プレフィックスは省略可能
- "+"プレフィックスも許容

### 7.4 空入力の扱い
- 空文字列は応答確認用として処理
- エラーを出さず、unknownの行情報を返す

---

## 8. 制約事項

### 8.1 オプション制約
- `--build-id`と`--obj`は同時指定不可
- `--use-dia`はWindows DIAサポート時のみ有効

### 8.2 プラットフォーム依存
- DIA SDKはWindowsのみ
- debuginfodはHTTPクライアントが必要

---

## 9. 非機能要件

### 9.1 パフォーマンス
- モジュール情報のキャッシュ
- `--cache-size`でキャッシュサイズを制御
- `pruneCache()`で定期的にキャッシュをクリア

### 9.2 互換性
- GNU addr2lineとの互換性
- 複数の出力形式（LLVM/GNU/JSON）

---

## 10. コードリーディングガイド

### 10.1 エントリーポイント
- **ファイル**: `llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp`
- **関数**: `llvm_symbolizer_main()` (476-609行目)

### 10.2 重要な関数
| 関数名 | 行番号 | 説明 |
|--------|--------|------|
| llvm_symbolizer_main() | 476-609 | エントリーポイント |
| parseOptions() | 385-412 | オプション解析 |
| symbolizeInput() | 335-374 | 入力をシンボル化 |
| parseCommand() | 160-279 | コマンド文字列をパース |
| executeCommand() | 281-328 | コマンドを実行 |
| enableDebuginfod() | 121-132 | debuginfodを有効化 |
| filterMarkup() | 466-474 | マークアップフィルタ処理 |
| decideHowToPrintFunctions() | 428-438 | 関数名出力方法を決定 |
| print() | 93-111 | 結果を出力 |
| printError() | 85-91 | エラーを出力 |

### 10.3 プログラム呼び出し階層図

```
llvm_symbolizer_main()
├── parseOptions()                              [484行目]
│   ├── setInitialOptionsFromEnvironment()      [391-392行目]
│   └── parseArgs()                             [394-398行目]
├── [オプション設定]                             [486-536行目]
│   ├── parseIntArg()                           [489行目]
│   └── decideHowToPrintFunctions()             [507行目]
├── LLVMSymbolizer()                            [538行目]
├── enableDebuginfod()                          [540-541行目]
│   ├── setBuildIDFetcher()                     [128-129行目]
│   └── HTTPClient::initialize()                [131行目]
├── [処理分岐]
│   ├── filterMarkup()                          [543-546行目]
│   │   └── MarkupFilter::filter()              [471行目]
│   └── symbolizeInput() [各アドレス]            [596-604行目]
│       ├── parseCommand()                      [353-355行目]
│       │   ├── [コマンド判定]                  [165-174行目]
│       │   ├── [FILE:/BUILDID:解析]            [177-226行目]
│       │   └── [アドレス/シンボル解析]          [228-278行目]
│       └── executeCommand()                    [368-373行目]
│           ├── symbolizeData()                 [293行目]
│           ├── symbolizeFrame()                [297行目]
│           ├── findSymbol()                    [301行目]
│           ├── symbolizeInlinedCode()          [305,315行目]
│           └── symbolizeCode()                 [324行目]
└── [Printer出力]
    ├── LLVMPrinter                             [570行目]
    ├── GNUPrinter                              [566行目]
    └── JSONPrinter                             [568行目]
```

### 10.4 データフロー図

```
入力
   │
   ├─► コマンドライン引数（アドレス）
   │
   ├─► 標準入力（対話式/パイプ）
   │
   └─► --filter-markup（マークアップ）
            │
            ▼
    ┌─────────────────────┐
    │ parseCommand()      │
    │ 入力文字列解析      │
    └─────────────────────┘
            │
            ▼
    ┌─────────────────────┐
    │ モジュール特定       │
    │ ├─ ファイルパス     │
    │ └─ ビルドID        │
    └─────────────────────┘
            │
            ▼
    ┌─────────────────────┐
    │ LLVMSymbolizer      │
    │ getOrCreateModuleInfo│
    └─────────────────────┘
            │
            ▼
    ┌─────────────────────┐
    │ executeCommand()    │
    │ ├─ symbolizeCode    │
    │ ├─ symbolizeData    │
    │ ├─ symbolizeFrame   │
    │ ├─ symbolizeInlinedCode │
    │ └─ findSymbol       │
    └─────────────────────┘
            │
            ▼ DILineInfo / DIGlobal / DILocal
    ┌─────────────────────┐
    │ DIPrinter           │
    │ ├─ LLVMPrinter      │
    │ ├─ GNUPrinter       │
    │ └─ JSONPrinter      │
    └─────────────────────┘
            │
            ▼
      標準出力
```

### 10.5 関連ファイル一覧

| ファイルパス | 役割 |
|-------------|------|
| llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp | メインソースファイル（610行） |
| llvm/tools/llvm-symbolizer/Opts.td | オプション定義（TableGen） |
| llvm/include/llvm/DebugInfo/Symbolize/Symbolize.h | LLVMSymbolizerクラス |
| llvm/include/llvm/DebugInfo/Symbolize/DIPrinter.h | 出力プリンター |
| llvm/include/llvm/DebugInfo/Symbolize/Markup.h | マークアップ定義 |
| llvm/include/llvm/DebugInfo/Symbolize/MarkupFilter.h | マークアップフィルター |
| llvm/include/llvm/Debuginfod/Debuginfod.h | debuginfodサポート |
| llvm/include/llvm/Debuginfod/BuildIDFetcher.h | ビルドIDフェッチャー |

---

## 11. 使用例

### 11.1 基本的な使用
```bash
llvm-symbolizer -e program 0x400000
```

### 11.2 標準入力から読み取り
```bash
echo "0x400000" | llvm-symbolizer -e program
```

### 11.3 複数アドレスをシンボル化
```bash
llvm-symbolizer -e program 0x400000 0x400100 0x400200
```

### 11.4 addr2lineモード
```bash
llvm-addr2line -e program 0x400000
```

### 11.5 インライン関数を展開
```bash
llvm-symbolizer -e program --inlines 0x400000
```

### 11.6 デマングル
```bash
llvm-symbolizer -e program --demangle 0x400000
```

### 11.7 JSON出力
```bash
llvm-symbolizer -e program --output-style=JSON 0x400000
```

### 11.8 debuginfodを使用
```bash
llvm-symbolizer --debuginfod --build-id=abc123 0x400000
```

### 11.9 コマンド形式の入力
```bash
echo "CODE FILE:program 0x400000" | llvm-symbolizer
echo "DATA FILE:program 0x600000" | llvm-symbolizer
```

### 11.10 シンボル名で検索
```bash
echo "main" | llvm-symbolizer -e program
echo "main+0x10" | llvm-symbolizer -e program
```

---

## 12. 改訂履歴

| 版数 | 日付 | 変更内容 | 担当者 |
|------|------|----------|--------|
| 1.0 | 2026-02-01 | 初版作成 | llvm-symbolizer機能設計書生成 |
