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

## 概要

本ドキュメントは、mrubyランタイムにおけるデバッグ情報管理機能の設計を記述する。irepに付随するデバッグ情報（ファイル名・行番号）の管理・取得を提供する。

### 本機能の処理概要

mrubyのデバッグ情報管理機能は、コンパイルされたバイトコード（irep）とソースコードの対応関係を管理する。プログラムカウンタ（PC）から元のソースファイル名と行番号を逆引きできる仕組みを提供し、エラー時のバックトレース生成やデバッガでのステップ実行を支援する。

**業務上の目的・背景**：デバッグ情報は、実行時エラー発生時にバックトレースで正確なソース位置を表示するために必須である。また、デバッガ（mrdb）でのブレークポイント設定やステップ実行にも利用される。組み込み用途ではデバッグ情報を除去してバイナリサイズを削減することも可能。

**機能の利用シーン**：例外発生時のバックトレース生成、デバッガによるステップ実行、コードダンプ時の行番号表示、バイナリダンプ/ロード時のデバッグセクション処理など。

**主要な処理内容**：
1. PCからファイル名を取得（mrb_debug_get_filename）
2. PCから行番号を取得（mrb_debug_get_line）
3. PCからファイル名と行番号を同時取得（mrb_debug_get_position）
4. デバッグ情報構造体の割り当て（mrb_debug_info_alloc）
5. ファイルごとのデバッグ情報追加（mrb_debug_info_append_file）
6. デバッグ情報の解放（mrb_debug_info_free）
7. 可変長整数エンコード/デコード（packed_map形式）

**関連システム・外部連携**：コンパイラ（codegen.c）がデバッグ情報を生成し、バイナリダンパ/ローダがシリアライズ/デシリアライズする。バックトレース生成（backtrace.c）やコードダンプ（codedump.c）が参照する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はランタイムAPI経由で使用され、画面は関連しない |

## 機能種別

データ管理（デバッグメタデータの管理・参照）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| mrb | mrb_state* | Yes | mrubyインタプリタ状態 | - |
| irep | const mrb_irep* | Yes | 対象のirep | NULLでないこと |
| pc | uint32_t | Yes | プログラムカウンタ | irep->ilen未満 |
| filename | const char* | 追加時Yes | ソースファイル名 | NULLでないこと |
| lines | uint16_t* | 追加時Yes | 行番号配列 | NULLでないこと |

### 入力データソース

- コンパイラから生成されたirep内のdebug_info
- バイナリローダから読み込んだデバッグセクション

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| filename | const char* | ソースファイル名（取得できない場合NULL） |
| line | int32_t | 行番号（取得できない場合-1） |
| debug_info | mrb_irep_debug_info* | 割り当てられたデバッグ情報構造体 |

### 出力先

呼び出し元への戻り値として返却

## 処理フロー

### 処理シーケンス

```
1. ファイル名取得（mrb_debug_get_filename）
   └─ irep->debug_infoの存在確認
      └─ get_file()で二分探索によりPC対応ファイルを特定
         └─ debug_get_filename()でシンボルからファイル名文字列を取得
2. 行番号取得（mrb_debug_get_line）
   └─ get_file()でPC対応ファイルを特定
      └─ debug_get_line()で行タイプに応じた行番号取得
         └─ packed_map形式: 可変長整数デコードで差分を累積
3. デバッグ情報追加（mrb_debug_info_append_file）
   └─ packed_map形式で行番号情報をエンコード
      └─ PC差分と行番号差分を可変長整数でパック
```

### フローチャート

```mermaid
flowchart TD
    A[PC指定] --> B{debug_info存在?}
    B -->|No| C[NULL/-1を返却]
    B -->|Yes| D[get_file: 二分探索]
    D --> E{ファイル見つかった?}
    E -->|No| C
    E -->|Yes| F{行タイプ}
    F -->|packed_map| G[可変長整数デコード]
    F -->|ary| H[直接配列アクセス]
    F -->|flat_map| I[エントリ検索]
    G --> J[行番号返却]
    H --> J
    I --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | PC範囲チェック | pcはirep->ilen未満であること | 全取得関数 |
| BR-02 | 同一ファイル重複防止 | 連続して同じファイル名のappendはスキップ | mrb_debug_info_append_file |
| BR-03 | packed_map形式優先 | 新規追加時はpacked_map形式で行情報をエンコード | mrb_debug_info_append_file |

### 計算ロジック

- 可変長整数（packed_int）: 各バイトの下位7ビットがデータ、最上位ビットが継続フラグ
- 行番号はPC差分と行番号差分のペアとしてエンコード

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| NULL/-1 | 情報なし | debug_infoが未設定 | コンパイル時にデバッグ情報を含める |
| NULL/-1 | 範囲外 | pcがirep->ilen以上 | 正しいPC値を指定 |

### リトライ仕様

リトライは不要。

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

トランザクション機構は存在しない。

## パフォーマンス要件

- ファイル検索は二分探索で O(log n)
- packed_map形式の行番号取得は、エントリの先頭から線形走査（最悪 O(n)）

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

- デバッグ情報にはソースファイルパスが含まれるため、本番環境ではmruby-bin-stripで除去可能

## 備考

- 行タイプは3種類: mrb_debug_line_ary（配列）、mrb_debug_line_flat_map（フラットマップ）、mrb_debug_line_packed_map（パックドマップ）
- 現在の実装ではdebug_get_lineはpacked_map形式のみ対応（ary, flat_mapはbreakで-1を返す）

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | debug.h | `include/mruby/debug.h` | mrb_irep_debug_info, mrb_irep_debug_info_file, mrb_debug_line_type の3構造体 |

**読解のコツ**: mrb_irep_debug_info_fileのlines共用体は行タイプによって異なるメンバを使う。packed_mapが最も圧縮率が高い。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | debug.c | `src/debug.c` | mrb_debug_get_filename（138-146行目）: PCからファイル名取得 |
| 2-2 | debug.c | `src/debug.c` | mrb_debug_get_line（153-161行目）: PCから行番号取得 |
| 2-3 | debug.c | `src/debug.c` | mrb_debug_get_position（170-183行目）: 両方同時取得 |

**主要処理フロー**:
1. **138-146行目**: PC範囲チェック後、get_file→debug_get_filename
2. **153-161行目**: PC範囲チェック後、get_file→debug_get_line

#### Step 3: 内部探索ロジック

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | debug.c | `src/debug.c` | get_file（6-34行目）: 二分探索でPC対応ファイルを特定 |
| 3-2 | debug.c | `src/debug.c` | debug_get_line（106-131行目）: packed_map形式の行番号デコード |

#### Step 4: 可変長整数エンコード/デコード

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | debug.c | `src/debug.c` | mrb_packed_int_encode（60-74行目）: 7ビットVLQエンコード |
| 4-2 | debug.c | `src/debug.c` | mrb_packed_int_decode（84-97行目）: 7ビットVLQデコード |
| 4-3 | debug.c | `src/debug.c` | mrb_packed_int_len（40-49行目）: エンコード後サイズ計算 |

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

```
mrb_debug_get_filename (公開API)
    │
    └─ get_file (二分探索)
           └─ debug_get_filename (シンボル→文字列)

mrb_debug_get_line (公開API)
    │
    └─ get_file (二分探索)
           └─ debug_get_line
                  └─ mrb_packed_int_decode (VLQデコード)

mrb_debug_info_append_file (公開API)
    │
    ├─ mrb_packed_int_len (サイズ計算)
    └─ mrb_packed_int_encode (VLQエンコード)
```

### データフロー図

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

uint32_t pc         ───▶  get_file()           ───▶  debug_info_file*
                           │
debug_info_file*    ───▶  debug_get_line()     ───▶  int32_t (行番号)
                           │
uint16_t[] lines    ───▶  packed_int_encode()  ───▶  uint8_t[] packed_map
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| debug.c | `src/debug.c` | ソース | デバッグ情報管理の実装本体 |
| debug.h | `include/mruby/debug.h` | ヘッダ | デバッグ情報の構造体・API宣言 |
| irep.h | `include/mruby/irep.h` | ヘッダ | mrb_irep構造体のdebug_infoフィールド |
| backtrace.c | `src/backtrace.c` | ソース | バックトレース生成（デバッグ情報の主要消費者） |
| codedump.c | `src/codedump.c` | ソース | コードダンプ（行番号表示で使用） |
| load.c | `src/load.c` | ソース | バイナリローダ（デバッグセクション読み込み） |
| dump.c | `src/dump.c` | ソース | バイナリダンパ（デバッグセクション書き出し） |
