2017-01-07 9 views
4

WindowsのSEHについて、これはarticleです。 ここにソースコードmyseh.cppWindowsのSEH、コールスタックトレースバックがなくなった

私はmyseh.cppをデバッグしました。私はprintf("Hello from an exception handler\n");の行に24とDWORD handler = (DWORD)_except_handler;をそれぞれ36行で2つのブレークポイントを設定しました。

私はそれを実行し、それはラインで壊れた:36。私はスタックトレースを以下のように見ました。行くよう

enter image description hereAccessViolationExceptionは、その後、それはラインで破ったためmov [eax], 1 で発生しました:24。私はスタックトレースを以下のように見ました。 enter image description here

同じスレッドが、mainフレームは消えていました! _except_handleの代わりに。そしてESPは0018f6c8から0018ef34に飛んでいた;それは0018f6c80018ef34 例外の処理後の大きなギャップである。

_except_handleは、カーネルモードではなくユーザーモードで実行する必要があります。 _except_handleが返された後、スレッドはring0に変わり、その後WindowsカーネルはCONTEXT EAX&scratch &に変更し、ring3に戻しました。したがって、スレッドは継続的に実行されました。

私は例外を扱うウィンドウのメカニズムについての好奇心:mainを呼び出すフレームは消えていた WHY?

ESPは(私は大きなピッチを意味する)?0018ef340018f6c8から飛び降りWHY、それらのESPアドレスが同じスレッドのスタックに属していますか?カーネルはring3のESPでいくつかのトリックを果たしましたか?その場合、ハンドラコールバックのフレームとして0018ef34のアドレスを選択した理由は何ですか?どうもありがとう!

+0

はい同じスレッドのスタックです。カーネルは 'CONTEXT'と' EXCEPTION_RECORD'をユーザスレッドスタックにコピーします。オフコースの騒ぎEspの例外 - これは既にEspの深刻な減少。 'KiUserExceptionDispatcher'コールバックがこのコピーされた' CONTEXT'レコードと 'EXCEPTION_RECORD'レコードへのポインタとともにカーネルから呼び出されます。最後にあなたの '_except_handler'が呼び出されました。 'ContextRecord-> Esp'を探すなら、' main() 'の' Esp'と全く同じであることに気付くことができます。実際のハンドラの実装では '\ VC \ crt \ src \ i386 \ chandler4.c'と' \ VC \ crt \ src \ amd64 \ chandler.c'を参照してください。 – RbMm

+0

ええ、私は、例外が発生したときにCONTEXTをハードウェアのスナップショット。だから、 'ContextRecord-> Esp == Esp(main) 'である。実際には、スタックトレースを失うデバッガのデフォルト設定に責任を負うべきである。 Btw、私は '* ContextRecord'の修正可能性を知っています、それはカーネルがring3に戻る前に望むようにハードウェアのコンテキストを回復する平均です。 WHYは 'const *'ではなく '*'型の第2引数 'ExceptionRecord'ですか? – TanakaYasen

+0

ExceptionRecordは実際にはconstではありません。 ExceptionFlagsは例外処理中に変更されます。私たちはスタックで2回歩いています! 'ExceptionFlags'に' EXCEPTION_UNWIND'フラグをセットし、 '__try/__ finally'ハンドラのスタックを再び歩く' RtlUnwindEx'と呼ばれる 'EXECEPTION_EXECUTE_HANDLER'と' _except_handlerX'を返すまで、 '__try/__ except'ブロックを探します。 'winnt.h'と' wdm.h'に 'IS_DISPATCHING(Flag)'と 'IS_UNWINDING(Flag)'マクロがあるか調べてください - 'chandler.c'も調べてくださいif(IS_DISPATCHING(ExceptionRecord-> ExceptionFlags))switch – RbMm

答えて

7

デフォルトのデバッガ設定を使用していますが、すべての詳細を表示するには十分ではありません。彼らはあなた自身のコードに集中し、できるだけ早くデバッグセッションを開始できるように選ばれました。

[外部コード]ブロックは、書いたコードに属さないスタックフレームの部分があることを示します。彼らはオペレーティングシステムに属していません。 [ツール]> [オプション]> [デバッグ]> [全般]を使用し、[コードを有効にする]オプションを有効にします。

[フレームが正しくありません...]という警告は、デバッガにスタックを正しく歩くための正確なPDBがないことを示しています。 [ツール]> [オプション]> [デバッグ]> [シンボル]を使用して、[Microsoft Symbol Servers]オプションを選択し、キャッシュの場所を選択します。デバッガは、オペレーティングシステムのDLLを使用してデバッグする必要があるPDBをダウンロードします。しばらく時間がかかるかもしれませんが、一度だけ行われます。

大規模なESPの変更を考えると、CONTEXT構造体はかなり大きく、スタック上の領域を占有します。 Win10バージョン1607およびVS2015アップデート2に記録

ConsoleApplication1942.exe!_except_handler(_EXCEPTION_RECORD * ExceptionRecord, void * EstablisherFrame, _CONTEXT * ContextRecord, void * DispatcherContext) Line 22 C++ 
[email protected]() Unknown 
[email protected]() Unknown 
[email protected]() Unknown 
ConsoleApplication1942.exe!main() Line 46 C++ 
ConsoleApplication1942.exe!invoke_main() Line 64 C++ 
ConsoleApplication1942.exe!__scrt_common_main_seh() Line 255 C++ 
ConsoleApplication1942.exe!__scrt_common_main() Line 300 C++ 
ConsoleApplication1942.exe!mainCRTStartup() Line 17 C++ 
[email protected]@12() Unknown 
ntdll.dll!__RtlUserThreadStart() Unknown 
[email protected]() Unknown 

:あなたは今、似たものを見るべきこれらの変更後

。これはSEHハンドラを書く正しい方法ではなく、より良い例をthis postで見つけてください。

+0

ありがとうございます。私は、この例は実際のものではなく最も基本的な概念を伝えることを目的としていることを知っています。 – TanakaYasen

関連する問題