2016-07-05 9 views
4

私のユーザーの1人が、私が分析したいと思ういくつかの稀なアクセス違反を報告しました。マップファイル内のAccessViolationのアドレスを解決する

私は正確にそのビルドのソースコードを持っているので、私はMAPファイルを作成することができました。しかし、私はMAPファイル内のAccessViolationによって提供されるアドレスを見つける方法を知らない。

(今後、JclDebugのようなフレームワークを使用して、使用可能なスタックトレースを作成したいと考えています)。

私はセットアップの例があります:アクセス違反がある

procedure CrashMe; 
var 
    k: TMemo; a: TButton; 
begin 
    k.Text := 'abc'; 
    k.Color := clBlack; 
    k.Assign(a); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    CrashMe; 
end; 

を:

アドレス004146CF。住所B2D88B53からの読書。マップファイルに

、私は以下の内容を見つける:00055498:MAPファイルには、0001を言いながら

Start   Length  Name     Class 
0001:00401000 000556A8H .text     CODE 
0002:00457000 00000770H .itext     ICODE 
0003:00458000 00001B0CH .data     DATA 
0004:0045A000 00004CCCH .bss     BSS 
0005:00000000 00000038H .tls     TLS 

.... 

0001:000552F0  Unit1..TForm1 
0001:00055498  Unit1.CrashMe 
0004:00004CC8  Unit1.Form1 
0001:000554C8  Unit1.TForm1.Button1Click 

はなぜAVは、アドレス004146CFと言っていますか?

CODEセグメント(0001)の開始アドレスを減算しても、私はまだ004146CF-00401000 = 136CFを取得しますが、これは私が探しているものではありません。

また、文字列 ":00414"を検索してエラーアドレスを見つけようとしましたが、何も見つかりませんでした。

MAPファイルのAVからアドレスを検索するにはどうすればよいですか?

+3

質問に何が間違っているかを伝える。私は何時間もグーグルで行っており、これらのメモリアドレスの間で正しい変換技術を見つけられませんでした。 –

+0

Jediコードライブラリでコードを検索できます。しかし実際にはマップファイルで提供されているアドレス範囲を走査しています。例外が発生した場所についてどのくらい正確に伝えることができるかは、マップファイル(行番号またはルーチンのみ)の中止によります... しかし、主にJvDebugHandlerを使用することができます。 –

+1

アプリケーションにブレークポイントを設定し、ブレークポイントに達するまでotを実行します。次に、IDEで検索|エラーを見つけてアドレスを入力してください。 – MartynA

答えて

4

なぜ、AVはアドレス004146CFを表し、MAPファイルは0001:00055498と表示しますか?

004146CFプロセスの実際ロードアドレスがコンパイル時に知られていないので.mapファイル内のアドレスが相対であるのに対し、実行時にクラッシュコード命令の実際メモリアドレスです。Iはコードセグメント(0001)

0001

の開始アドレスを引いても

アドレス、言うまでもなく開始アドレスではありません。これは、指定されたセグメントについて、ファイル.mapの先頭に定義された単なるID番号です。 0001:00055498は、0001と識別されるセグメント内の相対アドレス00055498を指します。

私はまだ004146CF-00401000 = 136CFを取得していますが、これも私が探しているものではありません。

通常プロセスのロードアドレスは$400000である(実際の値は、プロジェクトオプションで定義され、デフォルトで$400000である)、それは、このような再などの様々な理由、実行時に異なっていてもよいですベース。 実際のロードアドレスを決定したら、プロセス内のコードセグメントの実際のオフセットを含める必要があります。そのオフセットはです。通常は$1000です(実際の値は、コンパイルされた実行可能ファイルのPEヘッダーで定義されています)。したがって、実行時にメモリアドレスを.mapファイル内のアドレスにマップするには、通常を実行時メモリアドレスから$401000引きます。値と異なる場合があります。

この場合、結果の値136CFは、.mapファイルの0001コードセグメントを検索したいアイテムになります。クラッシュしたコードは、おそらく関数のの中にあり、まれに関数の冒頭にはめったにないので、EXACTが見つかる可能性は低いです。したがって、開始アドレスが136CFに最も近く、それを超えないで.mapアイテムを探します。

.mapファイル全体を表示していないため、スニペットには136CFに近い項目はありません。しかし実際のクラッシュはCrashMe自体にはなく、あなたが期待しているようです。実際にはCrashMe()が内部で呼び出す別の関数の内部にあります。 AVを診断するときは、マップしたい場合は、

procedure TWinControl.SetText(const Value: TCaption); 
begin 
    if GetText <> Value then // <-- here 
    begin 
    if WindowHandle <> 0 then 
     Perform(WM_SETTEXT, 0, string(Value)) 
    else 
     FText := Value; 
    Perform(CM_TEXTCHANGED, 0, 0); 
    end; 
end; 

function TControl.GetText: TCaption; 
{$IF DEFINED(CLR)} 
begin 
    Result := GetTextPiece(GetTextLen); 
end; 
{$ELSE} 
var 
    Len: Integer; 
begin 
    Len := GetTextLen; // <-- here 
    SetString(Result, PChar(nil), Len); 
    if Len <> 0 then 
    begin 
    Len := Len - GetTextBuf(PChar(Result), Len + 1); 
    if Len > 0 then 
     SetLength(Result, Length(Result) - Len); 
    end; 
end; 
{$IFEND} 

function TWinControl.GetTextLen: Integer; 
begin 
    if WindowHandle <> 0 then // <-- here 
    Result := Perform(WM_GETTEXTLENGTH, 0, 0) 
    else 
    Result := Length(FText); // <-- or here 
end; 

TMemo.Textプロパティを設定して、無効なTMemoオブジェクトのFHandleまたはFTextデータメンバにアクセスしようとするとクラッシュした、TWinControl.GetTextLen()を呼び出す、TControl.GetText()を呼び出す、TWinControl.SetText()呼び出しますCrashMe()にクラッシュすると、そのメモリアドレスがCrashMe()の内部にないため、AVのメモリアドレスを持つだけでは不十分です。 CrashMe()がある時点で呼び出され、その後の呼び出しで実際のAVが発生したことを示すために、AVまでの完全なスタックトレースが必要です。 A .mapファイルはスタックトレースを取得するのに役立ちません。JclDebug、MadExcept、EurekaLogなど、クラッシュ時にこれを処理するランタイムライブラリが必要です。

1

詳細マップファイルには、識別子名でソートされたセクションとアドレスでソートされた別のセクション(実際にはRVA、相対仮想アドレス)が含まれている必要があります。物理アドレスをRVAに変換する技術は正しいです。アドレスでソートされたセクションに移動し、$ 136cfに最も近いアドレスを見つけてください。それはクラッシュが起こっている機能でなければなりません。

ただし、デバッグDCUでビルドしていることを確認する必要があります。それ以外の場合は、コードのプログラム部分のアドレスのみが表示されます。

DLL /パッケージの場合、PEファイルで指定されているデフォルト以外のアドレスで読み込まれる可能性が高くなります。この場合、その特定のモジュールのベースアドレスを見つける必要があります。 Modulesビュー(Ctrl-Alt-MまたはView | Debug Views | Modules ...)を開きます。ベースアドレスがクラッシュのアドレスに最も近いが、クラッシュのアドレスよりも大きくないモジュールを探します。そのモジュールのアドレスは "ベースアドレス"になります。この値を使用してRVAを計算し、そのモジュールのMAPファイルに移動して場所を検索します。

関連する問題