このページでは

デバッグヘルパー

Qt Creator は、Pythonスクリプトを使用して、デバッガーバックエンド(GDB、LLDB、およびCDBが現在サポートされています)からの生のメモリコンテンツと型情報データを、LocalsおよびExpressionsビューでユーザーに表示される形式に変換します。

GDB のプリティプリンターや LLDB のデータフォーマッターとは異なり、Qt Creator のデバッグヘルパーはネイティブのデバッグバックエンドとは独立しています。つまり、同じコードをLinuxのGDB、macOSのLLDB、WindowsのCDB、またはサポートされている3つのバックエンドの少なくとも1つが利用可能な他のプラットフォームで使用することができます。

システムにインストールされている、またはアプリケーションが使用するライブラリにリンクされているデフォルトのGDBプリティプリンタを使用するには、Preferences>Debugger >GDB >Load system GDB pretty printers にアクセスしてください。詳細については、GDB を参照してください。

デバッガ環境設定のGDBタブ

組み込みデバッグ・ヘルパーのカスタマイズ

組み込みのデバッグ・ヘルパーがロードされ、完全に初期化された後にコマンドを実行させることができます。追加のデバッグ・ヘルパーをロードしたり、既存のヘルパーを変更したりするには、Preferences>Debugger >Locals & Expressions に進み、Debugging Helper Customization フィールドにコマンドを入力します。

デバッガ環境設定の「ローカルと式」タブ

GDB使用時にシグナル受信に関するエラーメッセージが表示される場合は、シグナ ルを処理するためのGDBコマンドを指定できます。例えば、次のようなエラー・メッセージが表示された場合、SIGSTOP シグナルを無視するように GDB に指示できます:The debugged process stopped because it received a signal from the operating system. Signal name: SIGSTOP.

GDB がSIGSTOP シグナルを処理しないようにするには、Debugging Helper Customization フィールドに以下のコマンドを追加します:

handle SIGSTOP nopass
handle SIGSTOP nostop

デバッグ中にアプリケーションがシグナルを受信するとすぐにメッセージ・ ボックスを表示するには、Preferences>Debugger >GDB >Show a message box when receiving a signal.

カスタム・デバッグ・ヘルパーの追加

独自の型のデバッグ・ヘルパーを追加するには、コンパイルは不要で、Pythonを数行追加するだけです。スクリプトは、複数のバージョンの Qt や独自のライブラリを同時に扱うことができます。

カスタム型用のデバッグヘルパーを追加するには、デバッガーのスタートアップファイル(例えば、~/.gdbinit~/.lldbinit )にデバッグヘルパーの実装を追加するか、Additional Startup Commands環境設定>Debugger >GDB で直接指定します。

独自のデータ型用のデバッグヘルパーの実装を始めるには、Qt インストールまたはスタンドアロンQt Creator インストールのファイルshare/qtcreator/debugger/personaltypes.py にその実装を記述します。macOSでは、このファイルはQt Creator アプリケーションパッケージにバンドルされており、Contents/resources/debugger フォルダにあります。

personaltypes.py ファイルには実装例が1つあります:

# def qdump__MapNode(d, value):
#    d.putValue("This is the value column contents")
#    d.putExpandable()
#    if d.isExpanded():
#        with Children(d):
#            # Compact simple case.
#            d.putSubItem("key", value["key"])
#            # Same effect, with more customization possibilities.
#            with SubItem(d, "data")
#                d.putItem("data", value["data"])

デバッグ・ヘルパーを追加する:

  1. share/qtcreator/debugger/personaltypes.py ファイルを開いて編集します。例えば、Qt のインストールが Windows のQt5 ディレクトリにある場合、C:\Qt5\Tools\QtCreator\share\qtcreator\debugger を見てください。macOSでは Qt5/Qt Creator.app/Contents/resources/debugger.
  2. ダンパーの実装をpersonaltypes.py ファイルの最後に追加します。デバッグヘルパーの実装についての詳細は、以下のセクションを参照してください。
  3. Qt Creator を更新したとき(Qt を更新したときなど)にpersonaltypes.py が上書きされないようにするには、ファイルシステム内のQt Creator 以外の安全な場所にコピーし、Preferences>Debugger >Locals & Expressions >Extra Debugging Helper でその場所を指定してください。

カスタムデバッギングヘルパーは、Qt Creator でデバッグセッションを開始するか、デバッガーログビューのコンテキストメニューからReload Debugging Helpers を選択すると、personaltypes.py から自動的にピックアップされます。

デバッグヘルパーの概要

デバッグヘルパーの実装は通常、1 つの Python 関数で構成され、qdump__NS__Foo という名前が必要です。NS::Foo は検査するクラスまたはクラステンプレートです。:: のスコープ解決演算子はダブルアンダースコアに置き換えられることに注意してください:__ 。名前空間の入れ子は可能です。テンプレート引数は、関数名の作成には使用されません。

  • namespace Project { template<typename T> struct Foo {... } } 型のデバッグ・ヘルパーを実装する関数の名前はqdump__Project__Foo です。
  • std::__1::vector<T>::iterator 型のデバッグ・ヘルパーを実装する関数の名前はqdump__std____1__vector__iterator です。

Qt Creatorデバッガ・プラグインは、この型のオブジェクトを表示したいときにこの関数を呼び出します。この関数には以下のパラメータが渡されます:

  • d 型のDumper 、現在の設定を持ち、LocalsExpressions のビューの一部を表すオブジェクトを構築する機能を提供するオブジェクト。
  • value Value 型の、gdb.Valueまたはlldb.SBValue をラップしたオブジェクト。

qdump__* 関数は、LocalsExpressions のビューでオブジェクトとその子の表示を構築するために使用される特定の情報をDumperオブジェクトに供給する必要があります。

def qdump__QFiniteStack(d, value):
    alloc = value["_alloc"].integer()
    size = value["_size"].integer()
    d.putItemCount(size)
    if d.isExpanded():
        d.putArrayData(value["_array"], size, value.type[0])

注意: LLDBとGDBの両方のバックエンドで使用可能なダンパ関数を作成するには、gdb.*lldb.* 名前空間への直接アクセスを避け、代わりにDumper クラスの関数を使用してください。

デバッグ・ヘルパーでオブジェクトのベース・インスタンスにアクセスするには、value.base() 関数または以下のサンプル・コードを使用してください:

def qdump__A(d, value):
   t = value.members(True)[0].type
   dptr, base_v = value.split('p{%s}' % t.name)
   d.putItem(base_v)

デバッグヘルパーは、型名が正規表現にマッチするたびに呼び出されるように設定できます。そのためには、デバッグヘルパーの関数名はqdump__ (アンダースコア2文字)で始まる必要があります。さらに、この関数には、型名がマッチする正規表現を指定するデフォルト値のregex という3番目のパラメータが必要です。

例えば、Nim 0.12コンパイラーは、コンパイルするすべてのジェネリック・シーケンスに、TY1TY2 のような人工的な名前を割り当てます。これらをQt Creator で視覚化するために、以下のデバッグ・ヘルパーを使用することができます:

def qdump__NimGenericSequence__(d, value, regex = "^TY.*$"):
    size = value["Sup"]["len"]
    base = value["data"].dereference()
    typeobj = base.dereference().type
    d.putArrayData(base, size, typeobj)

デバッグ・ヘルパーの実装

デバッグヘルパーは、GDB/MIとJSONに似たフォーマットで、表示されたデータ項目の説明を作成する。

Locals およびExpressions ビューの各行について、以下のような文字列を作成し、デバッガープラグインにチャネリングする必要があります。

{ iname='some internal name',           # optional
  address='object address in memory',   # optional
  name='contents of the name column',   # optional
  value='contents of the value column',
  type='contents of the type column',
  numchild='number of children',        # zero/nonzero is sufficient
  children=[              # only needed if item is expanded in view
     {iname='internal name of first child',
       },
     {iname='internal name of second child',
       },

  ]}

iname フィールドの値はオブジェクトの内部名で、ドット区切りの識別子リストで構成され、ビュー内のオブジェクトの表現位置に対応しています。存在しない場合は、親オブジェクトのiname 、ドット、連番を連結して生成される。

name フィールドの値は、ビューのName 列に表示されます。指定されない場合、代わりに括弧内の単純な数値が使用されます。

フォーマットの安定性は保証されていませんので、ワイヤーフォーマットを直接生成するのではなく、Python Dumperクラスの抽象化レイヤー、特にDumper クラス自身とDumper:ValueDumper:Type 抽象化レイヤーを使用することを強く推奨します。これらは、inameaddr フィールドを処理し、単純な型の子、参照、ポインタ、列挙型、既知および未知の構造体を処理するための完全なフレームワークと、一般的な状況を処理するためのいくつかの便利な関数を提供します。

CDBをデバッガーのバックエンドとして使用する場合、Preferences>Debugger >CDB >Use Python dumper を選択することで、Pythonダンパを有効にすることができます。

デバッガ環境設定のCDBタブ

以下のセクションでは、qtcreator\share\qtcreator\debugger\dumper.py で指定されている、広く使用されているDumperクラスとメンバについて説明します。

Dumperクラス

Dumper クラスは一般的な簿記、低レベル関数、便利関数を持っています:

  • putItem(self, value) - マスタ関数は、基本型、参照、ポインタ、列挙型を直接処理し、複合型の基底クラスとクラス・メンバを繰り返し処理し、必要に応じてqdump__* 関数を呼び出します。
  • putIntItem(self, name, value) - と同等:
    with SubItem(self, name):
        self.putValue(value)
        self.putType("int")
  • putBoolItem(self, name, value) - と同等:
    with SubItem(self, name):
        self.putValue(value)
        self.putType("bool")
  • putCallItem(self, name, rettype, value, func, *args) - デバッガ・バックエンドを使用して、value で指定された値にrettype を返す関数呼び出しfunc を配置し、結果の項目を出力します。

    ネイティブ呼び出しは非常に強力で、たとえばデバッグ対象プロセスで既存のデバッグまたはロギング機能を活用できます。しかし、以下の理由により、ネイティブ・コールは制御された環境でのみ、またデータにアクセスする他の方法がない場合にのみ使用する必要があります:

    • コードの直接実行は危険である。コードの直接実行は危険であり、デバッグ対象プロセスの特権でネイティブ・コードを実行し、デバッグ対象プロセスを破壊するだけでなく、ディスクやネットワークにアクセスする可能性がある。
    • コアファイルの検査時にコールを実行することはできない。
    • コールは、デバッガーでのセットアップと実行にコストがかかります。
  • putArrayData(self, address, itemCount, type) -address にある配列のようなオブジェクトの型typeitemCount で指定された数の子を作成します。
  • putSubItem(self, component, value) - に相当する:
    with SubItem(self, component):
        self.putItem(value)

    ネストされた関数呼び出しによって発生した例外はキャッチされ、putItem によって生成されたすべての出力は、その出力に置き換えられます:

    except RuntimeError:
        d.put('value="<invalid>",type="<unknown>",numchild="0",')
  • put(self, value) - 出力文字列に直接追加する低レベル関数。これは出力を追加する最速の方法でもある。
  • putField(self, name, value) -name='value' フィールドを追加する。
  • childRange(self) - 現在のChildren スコープで指定された子の範囲を返します。
  • putItemCount(self, count) -value='<%d items>' フィールドを出力に追加します。
  • putName(self, name) -name='' フィールドを追加する。
  • putType(self, type, priority=0) -type が親のデフォルトの子型と一致するか、putType が現在の項目に対してより高い値priority で既に呼び出されていない限り、type='' フィールドを追加します。
  • putBetterType(self, type) - 最後に記録されたtype を上書きする。
  • putExpandable(self) - 現在の値に対する子項目の存在を通知します。デフォルトは子項目なしです。
  • putNumChild(self, numchild) - 現在の値に対する子項目の存在 (numchild > 0) または非存在を通知します。
  • putValue(self, value, encoding = None) - ファイルvalue='' を追加し、オプションでその後にフィールドvalueencoding='' を追加する。value は、すべて英数字からなる文字列に変換できる必要がある。英数字のみの要件を満たすために、実際の値を何らかの方法でエンコードする必要があった場合に備えて、encoding パラメータを使用してエンコードを指定することができる。パラメータencoding は、codec:itemsize:quote 形式の文字列で、codec は、latin1utf8utf16ucs4intfloat のいずれかである。itemsize は、codec によって暗示されていない場合、オブジェクトの基本コンポーネントのサイズを与え、quote は、値を引用符で囲んで表示するかどうかを指定する。

    # Safe transport of quirky data. Put quotes around the result.
    d.putValue(d.hexencode("ABC\"DEF"), "utf8:1:1")
  • putStringValue(self, value) - 例:QString をエンコードし、正しいencoding 設定でputValue を呼び出す。
  • putByteArrayValue(self, value) -QByteArray をエンコードし、正しいencoding 設定でputValue を呼び出す。
  • isExpanded(self) - 現在のアイテムがビューで展開されているかどうかをチェックします。
  • createType(self, pattern, size = None) -Dumper.Type オブジェクトを作成します。正確な操作はpattern に依存します。
    • pattern がよく知られた型の名前と一致する場合、この型を記述したDumper.Type オブジェクトが返されます。
    • pattern がネイティブ・バックエンドで既知の型の名前である場合、返される型はネイティブ型を記述します。
    • そうでない場合、pattern は、構造体のフィールドを記述する一連の項目を以下のように解釈して型記述を構築するために使用される。フィールド記述は、以下のように1文字以上で構成される:
      • q - 符号付き8バイト整数値
      • Q - 符号なし8バイト整数値
      • i - 符号付き4バイト整数値
      • I - 符号なし4バイト整数値
      • h - 符号付き 2 バイト積分値
      • H - 符号なし2バイト積分値
      • b - 符号あり1バイト積分値
      • B - 符号なし1バイト積分値
      • d - 8バイトIEEE 754浮動小数点値
      • f - 4バイトIEEE 754浮動小数点値
      • p - ポインタ、つまりターゲット・アーキテクチャに応じた適切なサイズの符号なし積分値。
      • @ - 適切なパディング。サイズは前後のフィールドとターゲット・アーキテクチャによって決定される。
      • <n>s - <n>バイトのブロブ、暗黙のアライメントは1。
      • <typename> Dumper.Type - 適切なサイズと適切なアラインメントを持つブロブ。typename

Dumper.Typeクラス

Dumper.Type 。このクラスは、データ(通常はC++のクラスや構造体、構造体へのポインタ、または積分型や浮動小数点型などのプリミティブ型)の型を記述します。

型オブジェクト、つまりDumper.Type クラスのインスタンスは、デバッガー・バックエンドによって作成できます。通常は、デバッグ・バイナリに組み込まれているか、デバッグ・バイナリとともに出荷されているデバッグ情報を評価するか、デバッグ・ヘルパーによってオンザフライで作成されます。

Qt Creator は、ほとんどの Qt クラスの型情報をオンザフライで提供するため、オブジェクトのイントロスペクションのために Qt のDebugビルドを使用する必要がなくなります。

Dumper.Type クラスには、広く使われている以下のメンバ関数があります:

  • name - 文字列としてのこの型の名前、または型が無名である場合はNone
  • size(self) - この型のオブジェクトのサイズをバイト単位で返します。
  • bitsize(self) - Bit関数は、この型のオブジェクトのサイズをビット単位で返します。
  • alignment(self) - Alignment関数は、この型のオブジェクトに必要なアライメントをバイト単位で返します。
  • deference(self) -None 、それ以外の場合はポインタ型の参照解除型を返します。
  • pointer(self) - この型への参照解除が可能なポインタ型を返します。
  • target(self) - 配列型に対しては項目型を、ポインタや参照に対しては非参照型を返す便利な関数です。
  • stripTypedefs(self) - この型がエイリアスである場合、基礎となる型を返します。
  • templateArgument(self, position, numeric = False) - テンプレート化された型であれば、position にあるテンプレート・パラメータを返します。numericTrue の場合、パラメータを積分値として返します。
  • fields(self) - この型の基本クラスとデータ・メンバを記述したDumper:Fields のリストを返します。

Dumper.Fieldクラス

Dumper.Field クラスは、型オブジェクトの基本クラスまたはデータ・メンバを記述します:

  • isBaseClass - ベース・クラスとデータ・メンバーを区別します。
  • fieldType(self) - このベース・クラスまたはデータ・メンバーの型を返します。
  • parentType(self) - 所有する型を返します。
  • bitsize(self) - このフィールドのサイズをビット単位で返します。
  • bitpos(self) - Bit関数は、所有型内のこのフィールドのオフセットをビット単位で返します。

Dumper.Valueクラス

Dumper.Value クラスは、C++ クラスのインスタンスやプリミティブなデータ型など、データの一部を記述します。また、ファイル・コンテンツ、非連続オブジェクト、コレクションなど、メモリ上で直接表現できない人工的なアイテムを記述するためにも使用できます。

Dumper.Value は、常に関連するDumper.Type を持つ。値の実際のデータには、主に2つの表現があります:

  • Pythonmemoryview のような Python バッファプロトコルに従った Python オブジェクト、またはbytes オブジェクトです。size() はこの値の型のサイズと一致しなければなりません。
  • 現在のアドレス空間におけるオブジェクトの先頭へのポインタを表す積分値。オブジェクトのサイズは、その型のsize() で与えられる。

Dumper.Value の内部表現に関する知識は、デバッガー・ヘルパーを作成する際には通常必要ありません。

Dumper.Value クラスのメンバ関数とプロパティは以下のとおりです:

  • integer(self) - この値を適切なサイズの符号付き積分値として解釈して返します。
  • pointer(self) - 現在のアドレス空間におけるポインタとしてのこの値の解釈を返します。
  • members(self, includeBases) - この値のベース・オブジェクトとデータ・メンバを表すDumper.Value オブジェクトのリストを返す。
  • dereference(self) - ポインタを記述する値の場合は、参照解除された値を返し、そうでない場合はNone を返す。
  • cast(self, type) - この値と同じデータを持つ値を返しますが、型はtype です。
  • address(self) - この値が現在のアドレス空間内の連続した領域で構成されている場合はそのアドレスを返し、そうでない場合はNone を返す。
  • data(self) - この値のデータを Pythonbytes オブジェクトとして返します。
  • split(self, pattern) - この値のデータからpattern に従って作成された値のリストを返します。使用可能なパターンはDumper.createType と同じです。
  • dynamicTypeName(self) - この値が基底クラスオブジェクトである場合、この値の動的型の名前を取得しようとします。それが不可能な場合はNone を返します。

子とサブ項目クラス

子項目を作成しようとすると、データが初期化されていなかったり破損している場合にエラーになることがあります。このような状況で優雅に回復するには、ChildrenSubItem コンテキスト・マネージャを使用して、入れ子になったアイテムを作成します。

Children コンストラクタ__init__(self, dumper, numChild = 1, childType = None, childNumChild = None, maxNumChild = None, addrBase = None, addrStep = None) は、1つの必須引数と複数のオプション引数を使用する。必須引数は現在のDumper オブジェクトを指す。オプションの引数は、子オブジェクトの数numChild を指定するために使用することができ、それぞれの孫のタイプchildType_childNumChild_ があります。maxNumChild が指定された場合、その数の子だけが表示される。これは、コンテナの内容をダンプするときに使用する。パラメータaddrBaseaddrStep を使うと、子ダンプが生成するデータ量を減らすことができる。アドレスがaddrBase + n * addrStep と等しい場合、n番目の子アイテムのアドレス表示は抑制される。

if d.isExpanded():
    with Children(d):
        with SubItem(d):
            d.putName("key")
            d.putItem(key)
        with SubItem(d):
            d.putName("value")
            d.putItem(value)

これは、次のように書くとより便利であることに注意:

d.putNumChild(2)
if d.isExpanded():
    with Children(d):
        d.putSubItem("key", key)
        d.putSubItem("value", value)

How To: デバッグデバッグデバッガデバッガも参照してください

Copyright © The Qt Company Ltd. and other contributors. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.