5

[MethodImpl(MethodImplOptions.InternalCall)]おそらく C++ で実装されている BCL メソッドの実装をデバッグしたいと考えています。(この特定のケースでは、System.String.nativeCompareOrdinal を見ています。) これは主に、私がおせっかいで、それがどのように実装されているか知りたいからです。

ただし、Visual Studio デバッガーはそのメソッドにステップインすることを拒否しています。この呼び出しにブレークポイントを設定できます。

"Hello".Equals("hello", StringComparison.OrdinalIgnoreCase);

次に、[デバッグ] > [ウィンドウ] > [逆アセンブリ] を表示し、Equals 呼び出しにステップ インして、callx86 命令に到達するまでステップ実行します。しかし、その上で「ステップ イン」を使用しようとするとcall(Reflector からは nativeCompareOrdinal 呼び出しであることがわかっています)、必要なように nativeCompareOrdinal 内の最初の命令にステップ インしません。 Equals の次の x86 命令。

x64 アプリでは混合モードのデバッグがサポートされていないため、x86 としてビルドしています。[ツール] > [オプション] > [デバッグ] で [マイ コードのみ] のチェックを外し、[プロジェクト プロパティ] > [デバッグ] タブで [アンマネージ コードのデバッグを有効にする] をチェックしましたが、call. また、プロセスを開始してからデバッガーをアタッチし、マネージド デバッガーとネイティブ デバッガーの両方を明示的にアタッチしようとしましたが、それでもその InternalCall メソッドにステップ インしません。

Visual Studio デバッガーをアンマネージ メソッドにステップインさせるにはどうすればよいですか?

4

1 に答える 1

5

はい、トリッキーです。CALL 命令で表示されるオフセットは偽物です。さらに、現在のフォーカスがマネージ関数にある場合、アンマネージ コード アドレスに移動することはできません。

まず、アンマネージ コードのデバッグを有効にし、呼び出しにブレークポイントを設定します。コードを実行し、ブレーク ポイントにヒットしたら、Debug + Windows + Disassembly を使用します。

            "Hello".Equals("hello", StringComparison.OrdinalIgnoreCase);
00000025  call        6E53D5D0 
0000002a  nop              

デバッガーは絶対アドレスを表示しようとしますが、実際の命令アドレスではなく偽のインクリメンタル アドレスを使用するため、正しく表示されません。したがって、最初に真の相対値を復元します: 0x6E53D5D0 - 0x2A = 0x6E53D5A6.

次に、実際のコード アドレスを見つける必要があります。Debug + Windows + Registers を実行し、EIP レジスタの値を確認します。私の場合は0x009A0095です。5 を追加して nop を取得し、相対オフセットを追加します: 0x9A0095 + 5 + 0x6E53D5A6 = 0x6EEDD640。関数の実アドレス。

Debug + Windows + Call Stack を選択し、アンマネージ スタック フレームをダブルクリックします。これで、[逆アセンブリ] ウィンドウの [アドレス] ボックスに計算されたアドレスを入力できます。プレフィックスは 0x です。

6EEDD640  push        ebp  
6EEDD641  mov         ebp,esp 
6EEDD643  push        edi  
6EEDD644  push        esi  
6EEDD645  push        ebx  
6EEDD646  sub         esp,18h 
etc...

スタック フレームのセットアップ コードが表示されれば、ビンゴです。それにブレークポイントを設定し、F5 キーを押します。


もちろん、利用可能なソース コードがないため、マシン コードをステップ実行することになります。SSCLI20 ソース コードを見ると、このコードが何を行っているかをよりよく理解できます。現在のバージョンの CLR の実際のコードと一致するという保証はありませんが、私の経験では、1.0 以降に存在するこれらの低レベル コード チャンクは高度に保存されています。実装は clr\src\classlibnative\nls にありますが、どのソース コード ファイルかは不明です。「nativeCompareOrdinal」という名前は付けられません。これは、ecall.cpp によって使用される内部名です。

于 2010-09-23T15:14:33.037 に答える