DebugEngineのクイックスタート
このドキュメントは、DebugEngineのGetting startedの抄訳です。
目次
DebugEngineとは?
ほとんどの場合、開発者はコードのデバッグ、エラーの追跡、時間の経過に伴う変数の値の変化の確認に費やします。Delphiでは、Delphiのデバッグ情報にアクセスし、問題を簡単に見つけることができるプロ仕様のデバッグツールがいくつか存在します。
最も優れたDelphi デバッグフレームワークの1つがDebugEngineで、デバッグ関連(スタックトレース、CPU レジスタスナップショット、デバッグ情報等)のユーティリティを集めたオープンソースのスイートです。
はじめに
DebugEngineの機能を使用する前に、Delphi がアプリケーションの詳細なマップファイルを生成していることを確認する必要があります。このマップファイルには、セグメント、ユニット、シンボル情報など、多くの有用な情報が含まれています。DebugEngine が正常に動作するためには、これらの情報が必要です。
プロジェクトを開き、"ターゲット "を選択します(Win64/Win32または両方)。次に、「プロジェクト」>「オプション」>「コンパイル」>「デバッグ」を選択し、「デバッグ情報」オプションが「デバッグ情報」を選択されている確認します。
「プロジェクト」>「オプション」>「Delphi コンパイラ」>「リンク」を選択し、「マップファイル」オプションを「詳細」に変更し、「保存」ボタンを押します。
上記の設定により、アプリケーションをコンパイルするたびに、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(列挙型)があります。
|
シンボルのアドレス取得
シンボルのアドレスを取得するには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のライセンス規定されているオープンソースプロジェクトで、 こちらから入手できます。なお、エンバカデロではこの製品に関するテクニカルサポートサービスは提供しておりません。