# 帳票設計書 1-CrashReport (JSON)

## 概要

本ドキュメントは、.NET Runtimeのcreatedumpツールにおけるクラッシュレポート（JSON形式）の生成仕様を定義する帳票設計書である。

### 本帳票の処理概要

本帳票は、.NETアプリケーションがクラッシュした際に、デバッグおよび障害解析に必要な情報をJSON形式で出力するクラッシュレポートである。

**業務上の目的・背景**：.NETアプリケーションの運用において、予期しないクラッシュが発生した場合、その原因を特定し迅速に修正するためには詳細な障害情報が不可欠である。本帳票は、スタックトレース、スレッド情報、モジュール情報、例外情報を構造化されたJSON形式で提供することで、開発者やサポートエンジニアが効率的に障害解析を行えるようにする。

**帳票の利用シーン**：本帳票は、プロダクション環境でアプリケーションがクラッシュした際に自動生成される。開発者はこのレポートを用いてクラッシュの原因を特定し、サポートチームは顧客からの問い合わせ対応時に障害情報を参照する。また、クラッシュ解析ツールやテレメトリサービスと連携して自動的に障害を分類・集計することも可能である。

**主要な出力内容**：
1. プロトコルバージョン情報（解析ツールとの互換性確保のため）
2. 構成情報（アーキテクチャ、ランタイムバージョン）
3. プロセス名（クラッシュしたアプリケーションの識別）
4. スレッド情報（各スレッドの状態、クラッシュスレッドの特定）
5. スタックフレーム情報（マネージド/ネイティブコードのコールスタック）
6. 例外情報（例外タイプ、HResult、マネージド例外オブジェクト）
7. システム情報（macOSの場合：OSバージョン、ハードウェアモデル）

**帳票の出力タイミング**：アプリケーションのクラッシュ発生時に、createdumpツールによってダンプファイル（.dmpファイル）と同時に自動生成される。ダンプファイル名に `.crashreport.json` サフィックスを付加したファイルとして出力される。

**帳票の利用者**：開発者、DevOpsエンジニア、サポートエンジニア、SREチーム、障害解析ツール

## 帳票種別

診断レポート / クラッシュダンプ付属レポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| N/A | コマンドラインツール | createdump コマンド | クラッシュ発生時に自動生成 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON |
| 用紙サイズ | N/A（電子ファイル） |
| 向き | N/A |
| ファイル名 | {dumpFileName}.crashreport.json |
| 出力方法 | ファイルシステムへの直接書き込み |
| 文字コード | UTF-8 |

### JSON固有設定

| 項目 | 内容 |
|-----|------|
| インデント | 1スペース（JSON_INDENT_VALUE=1） |
| 整形出力 | 有（人間可読形式） |

## 帳票レイアウト

### レイアウト概要

JSONオブジェクトとして階層構造を持つレポート形式である。

```
{
  "payload": {
    "protocol_version": "...",
    "configuration": { ... },
    "process_name": "...",
    "threads": [ ... ]
  },
  "parameters": { ... }
}
```

### ヘッダー部（payloadオブジェクト）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | protocol_version | プロトコルバージョン | 固定値 | "1.0.0" |
| 2 | configuration.architecture | CPUアーキテクチャ | コンパイル時マクロ | "amd64" / "arm64" / "arm" |
| 3 | configuration.version | ランタイムバージョン | sccsid変数 | バージョン文字列 |
| 4 | process_name | プロセス名 | MainModule()->ModuleName() | ファイル名のみ |

### 明細部（threadsオブジェクト）

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | is_managed | マネージドスレッドか | thread->IsManaged() | "true" / "false" | - |
| 2 | crashed | クラッシュスレッドか | thread->Tid() == CrashThread() | "true" / "false" | - |
| 3 | managed_exception_object | マネージド例外オブジェクト | thread->ManagedExceptionObject() | 16進数 | - |
| 4 | managed_exception_type | 例外タイプ | thread->ManagedExceptionType() | 文字列 | - |
| 5 | managed_exception_hresult | HResult | thread->ManagedExceptionHResult() | 16進数 | - |
| 6 | native_thread_id | ネイティブスレッドID | thread->Tid() | 16進数 | - |
| 7 | ctx.IP | 命令ポインタ | thread->GetInstructionPointer() | 16進数 | - |
| 8 | ctx.SP | スタックポインタ | thread->GetStackPointer() | 16進数 | - |
| 9 | ctx.BP | フレームポインタ | thread->GetFramePointer() | 16進数 | - |
| 10 | stack_frames | スタックフレーム配列 | thread->StackFrames() | 配列 | - |

### フッター部（parametersオブジェクト）

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | ExceptionType | 例外タイプコード | シグナル番号から変換 | 16進数コード |
| 2 | OSVersion | OSバージョン（macOSのみ） | kern.osproductversion | 文字列 |
| 3 | SystemModel | システムモデル（macOSのみ） | hw.model | 文字列 |
| 4 | SystemManufacturer | 製造元（macOSのみ） | 固定値 | "apple" |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| クラッシュ発生 | アプリケーションがクラッシュしていること | Yes |
| ダンプファイル生成 | createdumpによりダンプファイルが生成されること | Yes |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | スレッドID | 取得順 |
| 2 | スタックフレーム | スタック順（上から下） |

### 改ページ条件

N/A（JSONファイルのため改ページなし）

## データベース参照仕様

### 参照テーブル一覧

N/A（データベース参照なし、メモリ上の情報を直接取得）

### メモリデータ参照詳細

#### CrashInfoクラス

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| MainModule() | process_name | - | メインモジュール情報 |
| Threads() | threads配列 | - | 全スレッド情報 |
| CrashThread() | crashed判定 | - | クラッシュしたスレッドID |
| Signal() | ExceptionType | - | 受信したシグナル番号 |

#### ThreadInfoクラス

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| IsManaged() | is_managed | - | マネージドスレッド判定 |
| Tid() | native_thread_id | - | スレッドID |
| ManagedExceptionObject() | managed_exception_object | != 0 | 例外オブジェクトアドレス |
| ManagedExceptionType() | managed_exception_type | !empty() | 例外タイプ名 |
| ManagedExceptionHResult() | managed_exception_hresult | != 0 | HRESULT値 |
| GetInstructionPointer() | ctx.IP | - | 命令ポインタ |
| GetStackPointer() | ctx.SP | - | スタックポインタ |
| GetFramePointer() | ctx.BP | - | フレームポインタ |
| StackFrames() | stack_frames | - | スタックフレーム一覧 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| native_image_offset | InstructionPointer - ModuleAddress | N/A | モジュール内オフセット |
| ExceptionType | シグナル番号からコードへの変換 | N/A | 下表参照 |

### 例外タイプ変換表

| シグナル | ExceptionTypeコード | 説明 |
|---------|-------------------|------|
| ManagedException | 0x05000000 | マネージド例外 |
| SIGILL | 0x50000000 | 不正命令 |
| SIGFPE | 0x70000000 | 浮動小数点例外 |
| SIGBUS | 0x60000000 | バスエラー |
| SIGTRAP | 0x03000000 | トラップ |
| SIGSEGV | 0x20000000 | セグメンテーション違反 |
| SIGTERM | 0x02000000 | 終了シグナル |
| SIGABRT | 0x30000000 | アボート |
| その他 | 0x00000000 | 不明 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[クラッシュ発生] --> B[createdump起動]
    B --> C[CrashReportWriter生成]
    C --> D[OpenWriter - JSONファイルオープン]
    D --> E{オープン成功?}
    E -->|Yes| F[WriteCrashReport - payloadオブジェクト書き込み]
    E -->|No| G[エラーログ出力]
    F --> H[configurationセクション書き込み]
    H --> I[threadsセクション書き込み]
    I --> J[各スレッドのstack_frames書き込み]
    J --> K[parametersセクション書き込み]
    K --> L[CloseWriter - JSONファイルクローズ]
    L --> M[成功メッセージ出力]
    G --> N[終了]
    M --> N
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| ファイルオープン失敗 | open()がエラーを返した場合 | "Could not create json file '%s': %s (%d)" | ディスク容量・権限を確認 |
| 書き込み失敗 | DumpWriter::WriteData()が失敗 | "Writing the crash report file FAILED" | 部分ファイルを削除 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数十スレッド、各スレッド数百フレーム |
| 目標出力時間 | ダンプ生成と同時（数秒以内） |
| 同時出力数上限 | 1（クラッシュ時のシングル出力） |

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

- クラッシュレポートにはメモリアドレス情報が含まれるため、ASLR（Address Space Layout Randomization）のバイパスに悪用される可能性がある
- 本番環境では、クラッシュレポートの保管場所へのアクセス制御を適切に設定すること
- クラッシュレポートをサポートチームに送信する際は、機密情報（環境変数、引数等）が含まれていないか確認すること

## 備考

- 本帳票はLinux/macOS環境で動作するcreatedumpツールによって生成される
- Windows環境では別の仕組み（Windows Error Reporting等）が使用される
- JSON出力はインデント付きの人間可読形式であり、解析ツールによるパースも容易である

---

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

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

### 推奨読解順序

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

まず、クラッシュレポートに含まれるデータを保持するクラス構造を理解することが重要である。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | crashreportwriter.h | `src/coreclr/debug/createdump/crashreportwriter.h` | CrashReportWriterクラスの構造、メンバー変数（m_fd, m_indent, m_comma, m_crashInfo）を理解する |
| 1-2 | crashinfo.h | `src/coreclr/debug/createdump/crashinfo.h` | CrashInfoクラスの構造、Threads(), MainModule(), CrashThread()等の情報取得メソッドを理解する |
| 1-3 | threadinfo.h | `src/coreclr/debug/createdump/threadinfo.h` | ThreadInfoクラスの構造、スレッド情報の保持方法を理解する |
| 1-4 | stackframe.h | `src/coreclr/debug/createdump/stackframe.h` | StackFrameクラスの構造、スタックフレーム情報の詳細を理解する |

**読解のコツ**: C++のヘッダファイルからクラス構造を把握し、publicメソッドのシグネチャから提供される機能を理解する。

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

処理の起点となるファイル・関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | crashreportwriter.cpp | `src/coreclr/debug/createdump/crashreportwriter.cpp` | WriteCrashReport(dumpFileName)メソッドがエントリーポイント |

**主要処理フロー**:
1. **行32-53**: WriteCrashReport(const std::string& dumpFileName) - ファイル名を受け取り、.crashreport.jsonサフィックスを付加してJSONファイルを生成
2. **行39**: OpenWriter() - JSONファイルをオープン
3. **行42**: WriteCrashReport() - 内部メソッドを呼び出してJSON内容を書き込み
4. **行43**: CloseWriter() - JSONファイルをクローズ

#### Step 3: JSON書き込み処理を理解する

JSON構造の生成ロジックを詳細に理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | crashreportwriter.cpp | `src/coreclr/debug/createdump/crashreportwriter.cpp` | WriteCrashReport()内部メソッドでJSON構造を生成 |

**主要処理フロー**:
- **行58-59**: payloadオブジェクトの開始とprotocol_versionの書き込み
- **行61-74**: configurationセクション（アーキテクチャ、バージョン）の書き込み
- **行77-81**: process_nameの書き込み（MainModuleから取得）
- **行83-176**: threadsセクションの書き込み（各スレッドをループ処理）
- **行178-188**: parametersセクションの書き込み（例外タイプ、OS情報）

#### Step 4: スタックフレーム書き込み処理を理解する

個々のスタックフレーム情報の書き込み処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | crashreportwriter.cpp | `src/coreclr/debug/createdump/crashreportwriter.cpp` | WriteStackFrame()メソッドの処理内容 |

**主要処理フロー**:
- **行218-268**: WriteStackFrame() - 1フレームの詳細情報をJSON形式で出力
- **行221-226**: 基本情報（is_managed, module_address, stack_pointer等）
- **行227-231**: マネージドフレームの場合はtoken, il_offsetを追加
- **行232-241**: メソッド名の取得と書き込み
- **行242-266**: モジュール情報の取得と書き込み

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

```
WriteCrashReport(dumpFileName)
    │
    ├─ OpenWriter(crashReportFile)
    │      └─ open() / Write("{")
    │
    ├─ WriteCrashReport() [内部]
    │      ├─ OpenObject("payload")
    │      ├─ WriteValue("protocol_version", ...)
    │      ├─ OpenObject("configuration")
    │      │      ├─ WriteValue("architecture", ...)
    │      │      └─ WriteValue("version", ...)
    │      ├─ CloseObject()
    │      ├─ WriteValue("process_name", ...)
    │      ├─ OpenArray("threads")
    │      │      └─ [各スレッドに対して]
    │      │             ├─ OpenObject()
    │      │             ├─ WriteValueBool("is_managed", ...)
    │      │             ├─ WriteValueBool("crashed", ...)
    │      │             ├─ WriteValue64("native_thread_id", ...)
    │      │             ├─ OpenObject("ctx")
    │      │             ├─ OpenArray("stack_frames")
    │      │             │      └─ WriteStackFrame(frame)
    │      │             └─ CloseObject()
    │      ├─ CloseArray()
    │      ├─ CloseObject()
    │      └─ OpenObject("parameters")
    │
    └─ CloseWriter()
           └─ Write("}")
```

### データフロー図

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

CrashInfo             CrashReportWriter              JSONファイル
    │                       │                            │
    ├─ MainModule() ──────▶ process_name ──────────────▶ payload.process_name
    │                       │
    ├─ Threads() ─────────▶ スレッド情報ループ ─────────▶ payload.threads[]
    │      │                │
    │      └─ StackFrames()─▶ WriteStackFrame() ───────▶ threads[].stack_frames[]
    │
    ├─ CrashThread() ──────▶ crashed判定 ───────────────▶ threads[].crashed
    │
    └─ Signal() ───────────▶ 例外タイプ変換 ────────────▶ parameters.ExceptionType

sysctlbyname()        WriteSysctl()
(macOSのみ)                │
    ├─ kern.osproductversion ────────────────────────▶ parameters.OSVersion
    └─ hw.model ─────────────────────────────────────▶ parameters.SystemModel
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| crashreportwriter.cpp | `src/coreclr/debug/createdump/crashreportwriter.cpp` | ソース | JSON形式クラッシュレポートの生成処理本体 |
| crashreportwriter.h | `src/coreclr/debug/createdump/crashreportwriter.h` | ヘッダ | CrashReportWriterクラスの定義 |
| crashinfo.h | `src/coreclr/debug/createdump/crashinfo.h` | ヘッダ | クラッシュ情報を保持するCrashInfoクラスの定義 |
| threadinfo.h | `src/coreclr/debug/createdump/threadinfo.h` | ヘッダ | スレッド情報を保持するThreadInfoクラスの定義 |
| stackframe.h | `src/coreclr/debug/createdump/stackframe.h` | ヘッダ | スタックフレーム情報を保持するStackFrameクラスの定義 |
| moduleinfo.h | `src/coreclr/debug/createdump/moduleinfo.h` | ヘッダ | モジュール情報を保持するModuleInfoクラスの定義 |
| createdump.h | `src/coreclr/debug/createdump/createdump.h` | ヘッダ | createdumpツール全体の共通ヘッダ |
| dumpwriter.h | `src/coreclr/debug/createdump/dumpwriter.h` | ヘッダ | ダンプ書き込みユーティリティ |
| _version.c | - | 生成ファイル | ランタイムバージョン文字列（sccsid変数）を定義 |
