# 機能設計書 93-デバッグ情報

## 概要

本ドキュメントは、Julia言語ランタイムにおけるデバッグ情報管理機能の設計を記述する。JITコンパイルされたコードに対するDWARFデバッグ情報の管理、スタックウォーク（バックトレース取得）、ソースコード位置情報の解決を担う機能である。

### 本機能の処理概要

**業務上の目的・背景**：JuliaはJITコンパイル方式を採用しており、実行時に生成されるネイティブコードに対してデバッグ情報（関数名、ファイル名、行番号）を関連付ける必要がある。これにより、エラー発生時のバックトレース表示、プロファイリング、デバッガ連携が可能になる。

**機能の利用シーン**：Julia例外発生時のスタックトレース表示、`@profile`マクロによるプロファイリング結果の表示、デバッガ（GDB/LLDB）でのソースレベルデバッグ、致命的シグナル時のバックトレース出力。

**主要な処理内容**：
1. JITDebugInfoRegistryによるコンパイル済みコードのデバッグ情報管理
2. DWARF情報の解析とソース位置の解決（`jl_getFunctionInfo`）
3. スタックウォーク（`rec_backtrace`, `rec_backtrace_ctx`）によるバックトレース取得
4. EHFrame（例外ハンドリングフレーム）の登録・解除
5. コード位置情報のキャッシュと検索
6. オブジェクトファイルのデバッグリンク情報処理

**関連システム・外部連携**：LLVM DebugInfo/DWARFライブラリ、libunwind（スタックアンワインド）、OS固有のスタックウォーク機構（Windows RtlCaptureContext等）。

**権限による制御**：特にない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | ランタイム内部機能のため関連画面なし |

## 機能種別

ランタイムデバッグ情報管理 / スタックウォーク

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| pointer | size_t | Yes | コードアドレス（命令ポインタ） | 有効なメモリアドレス |
| bt_data | jl_bt_element_t* | Yes | バックトレースバッファ | NULLでないこと |
| maxsize | size_t | Yes | バッファの最大サイズ | JL_BT_MAX_ENTRY_SIZE + 1以上 |
| context | bt_context_t* | No | シグナルハンドラからのCPUコンテキスト | NULLの場合は現在のコンテキストを取得 |

### 入力データソース

- JITコンパイラが生成したネイティブコードのアドレス
- シグナルハンドラから提供されるCPUコンテキスト
- LLVMが生成するオブジェクトファイル（DWARF情報含む）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| バックトレース | jl_bt_element_t[] | 命令ポインタの配列（拡張エントリ含む） |
| 関数情報 | jl_frame_t | ファイル名、関数名、行番号、インライン情報 |
| コードインスタンス | jl_code_instance_t* | Juliaメソッドインスタンスへの参照 |

### 出力先

エラーメッセージ出力（stderr）、プロファイリングバッファ、デバッガインターフェース

## 処理フロー

### 処理シーケンス

```
1. デバッグ情報の登録
   ├─ JITコンパイル時にJITDebugInfoRegistryにコード情報を追加
   ├─ EHFrameを__register_frameで登録
   └─ オブジェクトファイルのメモリマップを記録
2. バックトレース取得（rec_backtrace / rec_backtrace_ctx）
   ├─ jl_unw_get / jl_unw_initでカーソル初期化
   ├─ jl_unw_stepnでフレームを順次辿る
   └─ 各フレームのIPとSPを記録
3. ソース位置解決（jl_getFunctionInfo）
   ├─ JITDebugInfoRegistryからコード情報を検索
   ├─ DWARFContext経由でソース位置を解決
   └─ インライン関数の展開
4. バックトレース表示
   └─ jl_fprint_bt_entry_codelocで各フレームを出力
```

### フローチャート

```mermaid
flowchart TD
    A[JITコンパイル完了] --> B[JITDebugInfoRegistryに登録]
    B --> C[EHFrame登録]
    D[例外発生/プロファイル] --> E[rec_backtrace_ctx]
    E --> F[jl_unw_init]
    F --> G[jl_unw_stepn ループ]
    G --> H{更にフレームあり?}
    H -->|Yes| I[IP/SP記録]
    I --> G
    H -->|No| J[バックトレース完成]
    J --> K[jl_getFunctionInfo]
    K --> L[DWARFContext検索]
    L --> M[ソース位置情報取得]
    M --> N[表示/バッファ格納]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-93-01 | 命令ポインタ調整 | 非同期割り込みでない場合、戻りアドレスから1を引いてcall命令のアドレスに調整 | from_signal_handler==0 |
| BR-93-02 | 拡張バックトレースエントリ | Juliaインタープリタフレームはメタデータ付きの拡張エントリとして記録 | pgcstackにタグ付きフレームが存在 |
| BR-93-03 | FDE処理 | Length==0をターミネータとして処理、Offset==0をCIEとして処理 | EHFrame処理時 |

### 計算ロジック

特になし

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | アンワインド失敗 | 不正なスタックフレーム | jl_setjmp/jl_longjmpでsafe_restoreに復帰 |
| - | デバッグ情報なし | stripされたバイナリ | アドレスのみ表示 |

### リトライ仕様

プロファイリング中のアンワインド失敗はWARNINGを出力して継続する。

## トランザクション仕様

該当なし

## パフォーマンス要件

- デバッグ情報検索はコンカレントマップ（`JITDebugInfoRegistry`）を使用し、ロック競合を最小化
- スタックウォークはシグナルハンドラ内でも実行可能（signal-safe）

## セキュリティ考慮事項

デバッグ情報にはソースコードパスが含まれるが、ランタイム内部でのみ使用される。

## 備考

- Windowsでは`RtlCaptureContext`を使用、`jl_in_stackwalk`ミューテックスでスレッドセーフ性を確保
- `JL_DISABLE_LIBUNWIND`が定義されている場合、スタックウォーク機能は無効化される

---

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

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | debuginfo.h | `src/debuginfo.h` | JITDebugInfoRegistryクラスの定義 |
| 1-2 | debug-registry.h | `src/debug-registry.h` | デバッグレジストリのインターフェース |

**読解のコツ**: C++のLLVM APIを多用するため、`llvm::DWARFContext`、`llvm::object::ObjectFile`の基本を理解しておくと読みやすい。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | debuginfo.cpp | `src/debuginfo.cpp` | JITDebugInfoRegistryの実装（47行目〜） |

**主要処理フロー**:
1. **47行目**: グローバルなDebugRegistryインスタンス
2. **85-93行目**: シンボル名のマングリング処理
3. **95-97行目**: コンパイル中コードの登録

#### Step 3: スタックウォーク処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | stackwalk.c | `src/stackwalk.c` | rec_backtrace, jl_unw_stepn関数 |

**主要処理フロー**:
- **34-51行目**: `is_enter_interpreter_frame` - インタープリタフレーム検出
- **72-79行目**: `jl_unw_stepn` - フレーム遍歴ループの開始

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

```
rec_backtrace_ctx (stackwalk.c)
    +-- jl_unw_init()
    +-- jl_unw_stepn()
            +-- jl_unw_step()
            +-- is_enter_interpreter_frame()

jl_getFunctionInfo (debuginfo.cpp)
    +-- JITDebugInfoRegistry::lookupCodeInstance()
    +-- DWARFContext::getLineInfoForAddress()
    +-- resolveInlinedFrames()

JITDebugInfoRegistry (debuginfo.cpp)
    +-- add_code_in_flight()
    +-- mangle()
    +-- processFDEs()
        +-- __register_frame()
```

### データフロー図

```
[入力]                    [処理]                          [出力]

JITコンパイル結果 ──────> JITDebugInfoRegistry ─────────> デバッグ情報DB
                             +-- EHFrame登録

CPUコンテキスト ────────> rec_backtrace_ctx ─────────────> jl_bt_element_t[]
                             +-- jl_unw_stepn

コードアドレス ─────────> jl_getFunctionInfo ────────────> jl_frame_t
                             +-- DWARF解析                  (ファイル名,行番号)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| debuginfo.cpp | `src/debuginfo.cpp` | ソース | デバッグ情報管理の中核実装（C++/LLVM） |
| stackwalk.c | `src/stackwalk.c` | ソース | スタックウォーク（バックトレース取得） |
| debuginfo.h | `src/debuginfo.h` | ヘッダ | JITDebugInfoRegistryの宣言 |
| debug-registry.h | `src/debug-registry.h` | ヘッダ | デバッグレジストリインターフェース |
| julia_internal.h | `src/julia_internal.h` | ヘッダ | rec_backtrace等の宣言 |
