DebugEngineのクイックスタート

提供: Support
移動先: 案内検索

このドキュメントは、DebugEngineのGetting startedの抄訳です。

DebugEngineとは?

ほとんどの場合、開発者はコードのデバッグ、エラーの追跡、時間の経過に伴う変数の値の変化の確認に費やします。Delphiでは、Delphiのデバッグ情報にアクセスし、問題を簡単に見つけることができるプロ仕様のデバッグツールがいくつか存在します。

最も優れたDelphi デバッグフレームワークの1つがDebugEngineで、デバッグ関連(スタックトレース、CPU レジスタスナップショット、デバッグ情報等)のユーティリティを集めたオープンソースのスイートです。

はじめに

DebugEngineの機能を使用する前に、Delphi がアプリケーションの詳細なマップファイルを生成していることを確認する必要があります。このマップファイルには、セグメント、ユニット、シンボル情報など、多くの有用な情報が含まれています。DebugEngine が正常に動作するためには、これらの情報が必要です。

プロジェクトを開き、"ターゲット "を選択します(Win64/Win32または両方)。次に、「プロジェクト」>「オプション」>「コンパイル」>「デバッグ」を選択し、「デバッグ情報」オプションが「デバッグ情報」を選択されている確認します。

Thumb03000260ujpn.png

「プロジェクト」>「オプション」>「Delphi コンパイラ」>「リンク」を選択し、「マップファイル」オプションを「詳細」に変更し、「保存」ボタンを押します。

Thumb03000261ujpn.png

上記の設定により、アプリケーションをコンパイルするたびに、Delphiはプロジェクトに関連した詳細なマップファイルを生成します。ここからはDebugEngineが主導権を握り、このマップ(Delphiのマップファイル)を「SMAP 」と呼ばれるファイル形式に変換します。SMAPファイルは、Delphiのマップファイルのバイナリ形式で、構造化されており、サイズも小さく、オリジナルのマップ(Delphiのマップ)に比べて非常に高速に処理されます。

SMAPファイルを実行ファイルにリンクする

DebugEngineはマップファイルを別の場所から読み込むことができます。

  • ディスク(ストレージ)
  • リソース
  • セクション

アプリケーションの中でsmapファイルをリンクさせたい場合は、コマンドラインツール「DD.exe」を使用します。

DDコマンドラインツールの利用

Usage:DD [コマンド] [オプション] [AppFile、MapFile]


コマンド:

パラメータ 説明
-h ヘルプの表示
-c Delphiのマップをsmapファイル形式に変換
-i ターゲットアプリケーションへのデバッグ情報(smap)の挿入
-r ターゲットアプリケーションからDelphiのデバッグ情報を削除

オプション:

パラメータ 説明
-p smapファイルを圧縮
-s 可能であれば、デバッグ情報を新しいセクションに挿入します。それが不可能な場合、デバッグ情報はアプリケーションのリソースに挿入されます。
パラメータ 説明
AppFile 実行可能なファイル
パラメータ 説明
MapFile コマンドとして-cが指定されている場合は、Delphiのマップファイルになり、-iが指定されている場合は、SMAPファイルになります。

使用例:

Delphiのマップをsmapファイルに変換:

DD -c -p "MyApp.map"

デバッグ情報の挿入:

DD -i "MyApp.exe" "MyApp.smap"

DebugEngineの構成は?

DebugEngine はユニットに分割されています。各ユニットは指定されたジョブを実行します。

ユニット名 説明
DebugEngine.Core DebugEngineのコアユニット
DebugEngine.DebugInfo マップコンバータ、マップパーサー、およびアドレス情報機能が含まれています。 このユニットでは、DelphiマップとSMAPファイルにに関連するすべてのものを見つけることができます。
DebugEngine.DebugUtils デバッグ情報の挿入、削除、復元を行う関数が含まれています。
DebugEngine.AsmRegUtils 低レベルレジスタのスナップショット関数とベクトルレジスタ表現
DebugEngine.Trace スタックトレース。このトピックについて詳しくは、スタックトレースのwiki(英語)ページをご覧ください。
DebugEngine.Disasm 便利なdisasmルーチン
DebugEngine.MemoryHack 文字列の検出
DebugEngine.PeUtils PEファイルフォーマットに関する機能
DebugEngine.HookException DebugEngine のスタックトレースを Delphi に統合します。このユニットをプロジェクトに使用すると、エラー発生時にスタックトレースを取得することができます。

アドレス情報の取得

GetAddressInfo関数を使用して、シンボルのアドレス、名前、行番号を取得します。

function GetAddressInfo(Address: Pointer; out Info: TAddressInfo; const Mask: TAddressInfoMask = aimNone): Boolean;

GetAddressInfo関数の各パラメータ

パラメータ 説明
Address 情報を入手するためのアドレス
Info 指定されたアドレスのレコード情報の出力
Mask 指定した情報のみを照会する機能で、処理するアドレスが多すぎる場合に非常に役立ち、指定することで関数の速度が向上します。以下のようなTAddressInfoMask(列挙型)があります。
  • aimNone = マスクは適用されません。 GetAddressInfo関数はすべての情報を照会
  • SymbolAddress
  • SymbolName
  • UnitName
  • DebugSource
  • LineNumber
  • SourceLocation
  • aimAddress = GetAddressInfo関数は、クエリのみを実行
  • SymbolAddress
  • DebugSource
  • aimSymbolName = GetAddressInfo関数は、クエリのみを実行
  • SymbolAddress
  • SymbolName
  • UnitName
  • DebugSource

シンボルのアドレス取得

シンボルのアドレスを取得するにはGetSymbolAddress関数を使用します。

function GetSymbolAddress(ModuleHandle: THandle; const UnitName, SymbolName: string): Pointer;

GetSymbolAddress関数の各パラメータ

パラメータ 説明
ModuleHandle シンボルが配置されているモジュールハンドルです。ゼロ(0)を渡した場合、この関数は現在のモジュールハンドルを使用します。
UnitName オプションで、シンボルが宣言されたユニット名です。これは、多くのユニットが同じシンボルを宣言している場合に便利です。
SymbolName シンボル名
戻り値 この関数の呼び出しに成功した場合、戻り値はシンボルのアドレスを返し、それ以外の場合はnilを返します。

使用例:

var
  P: Pointer;
begin
  { Private variable System.MemoryManager }
  P := GetSymbolAddress(0, 'System', 'MemoryManager');
  { Private method System.SetExceptionHandler }
  P := GetSymbolAddress(0, '', 'SetExceptionHandler'); 
  { Protected method TCustomForm.CloseModal } 
  P := GetSymbolAddress(0, '', 'TCustomForm.CloseModal');
  { Windows api }
  P := GetSymbolAddress(GetModuleHandle(user32), '', 'MessageBoxA');
end;

エラー発生時のDebugEngineスタックトレースの使用

DebugEngine.HookExceptionユニットをプロジェクトにインクルードするだけです。そして、エラーが発生するたびに、エラーが発生した時点からのスタックトレースを得ることができます。 使用例:

uses 
  DebugEngine.HookException;

{...}

procedure Foo;
begin
  try
    DoSomething;
  except
    on E: Exception do
      ShowMessage(E.StackTrace);
  end;
end;

DISASM(逆アセンブル)とコメント ファンクション

この機能を使用するには、まずUnivDisasm.Config.incファイルを更新し、表示機能が必要であることをUnivDisasmに通知する必要があります (Define NEED_DISPLAY)。デフォルトでは、最適化のためにこのオプションをオフにしています。そのため、DisasmAndCommentFunction関数を使用する場合は、再度有効にする必要があります。

function DisasmAndCommentFunction(FunctionStartAddress: Pointer; var FunctionEndAddress: Pointer; CallBackFunction: TDisasmCallBack; UserData: Pointer): Boolean;

DisasmAndCommentFunction関数の各パラメータ

パラメータ 説明
FunctionStartAddress Disasmを行いたい関数のアドレス
FunctionEndAddress Disasmが停止する終了アドレスです。指定しない場合、UnivDisasmは最初のret命令で中断します。
CallBackFunction TDisasmCallBack関数へのポインタです。この関数は、DisasmAndCommentFunctionが命令をデコードするたびに呼び出されます。
UserData CallBackFunction関数に渡すオプションデータ

使用例:

procedure DisasmCallBack(var Info: TDisasmInfo; UserData: Pointer);
var
  S: String;
begin
  with TMemo(UserData).Lines, Info do
  begin
    S := Format('[$%p]:    %s', [Address, InstStr]);
    if not comment.IsEmpty then
      S := S + '    ; ' + comment;
    Add(S);
  end;
end;

var
  P: Pointer;
begin
  P := nil;
  {LogMem = TMemo}
  LogMem.Clear;
  LogMem.Lines.BeginUpdate;
  try
    DisasmAndCommentFunction(@TMain.BtnLegRegSnapClick, P, DisasmCallBack, LogMem);
  finally
    LogMem.Lines.EndUpdate;
  end;

DebugEngineについて

DebugEngineは、Mozilla Public License 2.0のライセンス規定されているオープンソースプロジェクトで、 こちらから入手できます。なお、エンバカデロではこの製品に関するテクニカルサポートサービスは提供しておりません。