2012-02-24 21 views
1

私は、Visual C++ランタイムによってx64でC++例外処理がどのように実装されているかを理解しようとしています。ExceptionCodeがSTATUS_UNWIND_CONSOLIDATEの場合、RtlRestoreContextは何をしますか?

http://www.nynaeve.net/?p=110でSEH実装のNynaeveブログを読むと、RtlUnwindExはフレーム統合のアンワインドのためにSTATUS_UNWIND_CONSOLIDATEに設定されたExceptionCodeでRtlRestoreContextを呼び出しているようです。

RtlRestoreContextはどうしたらいいのですか? MSDNのhttp://msdn.microsoft.com/en-us/site/ms680605に記載されているように、「RtlRestoreContextは、コールバック関数を呼び出す前にコンテキストレコードで指定されたフレームとそのフレーム間でコールフレームを統合します。

「フレームとコンテキストレコードで指定されたフレームとの間でコールフレームを統合する」とはどういう意味ですか?これはどのようにして "コールバック関数で発生するかもしれない例外処理からフレームを隠す"のでしょうか? 「フレーム統合」とは何を意味し、フレームが統合されるのはどこですか?

CtlキャッチハンドラがRtlRestoreContextによって呼び出され、別の例外がスローされるとします。何らかのSEHブロックによって保護された(再)スローされた例外ですか?または、このフレーム統合ビジネスは何とかそれを処理しますか?はいの場合、どうですか?

答えて

0

によって何を意味するのかということかもしれませ参照してください。このコードは、オリジナルのコンテキストからRtlRestoreContextに渡されたスタック上の偽のマシンフレームを設定します([r8]と比較して、RIPとRSPのみが満たされています)。次に、元のコンテキストをマシンフレームの下に割り当てられたスタックスペースにコピーします。

機械フレーム(UWOP_PUSH_MACHFRAMEの下)の詳細については、http://msdn.microsoft.com/en-us/library/ck9asaa9.aspxを参照してください。

0:004> u ntdll!RtlRestoreContext+0x296 
00000000`771f0c05 83ec30   sub  esp,30h 
00000000`771f0c08 4c8bc4   mov  r8,rsp 
00000000`771f0c0b 4881ecd0040000 sub  rsp,4D0h 
00000000`771f0c12 488bf1   mov  rsi,rcx 
00000000`771f0c15 488bfc   mov  rdi,rsp 
00000000`771f0c18 b99a000000  mov  ecx,9Ah 
00000000`771f0c1d f348a5   rep movs qword ptr [rdi],qword ptr [rsi] 
00000000`771f0c20 488b842498000000 mov  rax,qword ptr [rsp+98h] 
0:004> u 
ntdll!RtlRestoreContext+0x2ba: 
00000000`771f0c28 49894018  mov  qword ptr [r8+18h],rax 
00000000`771f0c2c 488b8424f8000000 mov  rax,qword ptr [rsp+0F8h] 
00000000`771f0c34 498900   mov  qword ptr [r8],rax 
00000000`771f0c37 488bca   mov  rcx,rdx 
00000000`771f0c3a eb12   jmp  ntdll!RcFrameConsolidation (00000000`771f0c4e) 

コードは、ブログで話している疑似関数NTDLL!RcFrameConsolidationにジャンプします。

我々は関数テーブルを調べて、この機能のためにエントリをUNWIND場合、我々はそれが偽のスタックフレームの設定に対応するメタデータが含まれていることを参照してください。

0:004>.fnent ntdll!rcframeconsolidation 

...snip... 

Unwind info at 00000000`772c8e0c, 52 bytes 
    version 1, flags 0, prolog 0, codes 27 
    00: offs 0, unwind op 8, op info f UWOP_SAVE_XMM128 FrameOffset: 290 reg: xmm15. 
    02: offs 0, unwind op 8, op info e UWOP_SAVE_XMM128 FrameOffset: 280 reg: xmm14. 
    04: offs 0, unwind op 8, op info d UWOP_SAVE_XMM128 FrameOffset: 270 reg: xmm13. 
    06: offs 0, unwind op 8, op info c UWOP_SAVE_XMM128 FrameOffset: 260 reg: xmm12. 
    08: offs 0, unwind op 8, op info b UWOP_SAVE_XMM128 FrameOffset: 250 reg: xmm11. 
    0a: offs 0, unwind op 8, op info a UWOP_SAVE_XMM128 FrameOffset: 240 reg: xmm10. 
    0c: offs 0, unwind op 8, op info 9 UWOP_SAVE_XMM128 FrameOffset: 230 reg: xmm9. 
    0e: offs 0, unwind op 8, op info 8 UWOP_SAVE_XMM128 FrameOffset: 220 reg: xmm8. 
    10: offs 0, unwind op 8, op info 7 UWOP_SAVE_XMM128 FrameOffset: 210 reg: xmm7. 
    12: offs 0, unwind op 8, op info 6 UWOP_SAVE_XMM128 FrameOffset: 200 reg: xmm6. 
    14: offs 0, unwind op 4, op info f UWOP_SAVE_NONVOL FrameOffset: f0 reg: r15. 
    16: offs 0, unwind op 4, op info e UWOP_SAVE_NONVOL FrameOffset: e8 reg: r14. 
    18: offs 0, unwind op 4, op info d UWOP_SAVE_NONVOL FrameOffset: e0 reg: r13. 
    1a: offs 0, unwind op 4, op info c UWOP_SAVE_NONVOL FrameOffset: d8 reg: r12. 
    1c: offs 0, unwind op 4, op info 7 UWOP_SAVE_NONVOL FrameOffset: b0 reg: rdi. 
    1e: offs 0, unwind op 4, op info 6 UWOP_SAVE_NONVOL FrameOffset: a8 reg: rsi. 
    20: offs 0, unwind op 4, op info 5 UWOP_SAVE_NONVOL FrameOffset: a0 reg: rbp. 
    22: offs 0, unwind op 4, op info 3 UWOP_SAVE_NONVOL FrameOffset: 90 reg: rbx. 
    24: offs 0, unwind op 1, op info 0 UWOP_ALLOC_LARGE FrameOffset: 4d0. 
    26: offs 0, unwind op a, op info 0 UWOP_PUSH_MACHFRAME. 

この効果は、「トリック」にありますVirtualUnwindEx /例外処理コードは、ContextRecordによって記述された関数がRtlRestoreContextの直接の呼び出し側であると考えることになります。

VirtualUnwindの観点から見ると、コールスタックはOriginalContext - > RtlRestoreContext - > [ユーザ指定のコールバック]であり、間に何もない。

したがって、スタックが 'unwound'の場合、ContextRecordで記述されたフレームとRtlRestoreContextの現在のコンテキストの中間のすべてのフレームが「忘れられています」。すなわち、フレームは単一の機能として解かれた単一のフレームに統合されている。 したがって、ExceptionRecordで渡されたコールバック関数内で例外が発生すると、それらの中間フレーム内の例外ハンドラはすべて非表示になります。 ブログが指摘しているように、この機能は言語例外処理に大いに役立ちます。

MSドキュメントも指摘しているように、中間スタックフレームのローカルは、コールバックを呼び出す前に破壊されません。これは、ある言語の例外オブジェクトがその関数のスタックフレームに割り当てられた場合に便利です。

関連する問題