💎

Rubyの中の人:デバッガーの仕掛けを追う

に公開

image.png

はじめに

こんにちは。JetBrainsの公式代理店NATTOSYSTEMの私です。

JetBrains RubyMine チームのブログ記事Inside Ruby Debuggers ― TracePoint, Instruction Sequence, and CRuby API(2025-06-11公開)は、Rubyデバッガが内部で使っている3つの基盤技術を解説しています。

Ruby 開発者の皆さん

デバッグはソフトウェア開発の重要な部分ですが、多くの開発者はデバッガーの実際の仕組みを理解せずに使用しています。RubyMineチームは長年にわたりRuby用のデバッグツールの開発に取り組んでおり、その過程で得た知見の一部を共有したいと思います。

記事は EuRuKo 2024RubyKaigi 2025 の講演「Demystifying Debuggers」をもとに構成されている。


1.TracePoint ― 実行中コードへのフック

特徴 説明
目的 メソッド呼び出し・行実行・例外など特定イベント発生時にコールバックを実行する。
導入 Ruby 2.0(2013年)
強み Thread/Fiber と相性が良い。Ractorは限定的。
TracePoint.new(:call){

最小デバッガ例

TracePoint のコールバック内で gets と eval を使えば、数行で入力→評価→表示という対話式デバッガが完成。ブレークポイント停止・変数操作の仕組みを体験できる。


2.Instruction Sequence (ISeq) ― Rubyバイトコードの姿

特徴 説明
役割 Rubyソースを VM が実行するバイトコードへコンパイルした結果を保持。Ruby の「アセンブリ」。
取得 RubyVM::InstructionSequence.of(method_obj)
可視化 iseq.disasm で人が読める形式に。行イベント(Li)、呼び出し(Ca)、戻り(Re)などのマーカー付き。

デバッガとの関係

Bytecode 上にマーカーを追加・変更することで、行ステップや高度なブレークポイント(if 文の途中など)を実現する。TracePoint はこれらのマーカーが発火した瞬間にフックする。


3.CRuby CレベルAPI ― さらに深い制御

主なAPI 用途
rb_tracepoint_new C拡張側で柔軟に TracePoint を生成・制御。スマートステップの実装に必須。
rb_debug_inspector_open VM状態を変えずにフレーム情報を取得。コールスタックを前後に移動できる。
rb_iseqw_to_iseq, rb_iseq_original_iseq Ruby値⇔C構造体の iseq 変換。

メリット

フレームナビゲーションや「次に入るべきコードを判断するスマートステップ」など高度機能が実装可能。

デメリット

  • CRuby 専用のため JRuby/TruffleRuby では動作しない。
  • 非公開 API のため Ruby バージョン依存が大きくメンテナンス負荷が高い。

まとめ

TracePoint で “いつ止まるか” を決め、Instruction Sequence で “どこで止まるか” を細かく指定し、必要に応じて CRuby API が “より賢く止まる” 機能を補完する。

3つの技術は層構造:

Rubyレベル の TracePoint
→ VMバイトコード層 の ISeq
→ Cレベル の内部API。

仕組みを理解すると、pry-byebug や RubyMine など既存デバッガが提供する「ブレークポイント」「ステップ実行」「フレーム移動」の裏側が見えてくる。

最小デバッガを自作してみると、デバッガ原理の学習・実践に大いに役立つ。

Happy debugging!

フィードバックをフィードバックをお待ちしています

Jetbrains製品に関するご質問・ご感想をぜひお寄せください。


📝 この記事は一部AIによって要約・編集されたものです。

株式会社NATTOSYSTEM

Discussion