5

Win64構造化例外トレース(x64例外処理サポートに対するプログラミング、パート7:すべてをまとめる、またはスタックウォークルーチンの構築から)を読みながら、コードStackWalk64.cppを変換しました。

procedure DumpExceptionStack();
var
  LContext : CONTEXT;
  LUnwindHistoryTable : _UNWIND_HISTORY_TABLE;
  LRuntimeFunction : Pointer;
  LImageBase : ULONGLONG;
    HandlerData : Pointer;
    EstablisherFrame : ULONG64;
    NvContext : KNONVOLATILE_CONTEXT_POINTERS;

  LLineNumber                    : integer;
  LModuleName                    : UnicodeString;
  LPublicAddr                    : pointer;
  LPublicName                    : UnicodeString;
  LUnitName                      : UnicodeString;
begin
    //
    // First, we'll get the caller's context.
    //
  RtlCaptureContext(LContext);

    //
    // Initialize the (optional) unwind history table.
    //
  LUnwindHistoryTable := Default(_UNWIND_HISTORY_TABLE);

  // LUnwindHistoryTable.Unwind := True;

    //
    // This unwind loop intentionally skips the first call frame, as it shall
    // correspond to the call to StackTrace64, which we aren't interested in.
    //
  repeat
        //
        // Try to look up unwind metadata for the current function.
        //
        LRuntimeFunction := RtlLookupFunctionEntry(LContext.Rip,
                                               LImageBase,
                                               LUnwindHistoryTable);

    NvContext := Default(KNONVOLATILE_CONTEXT_POINTERS);

    if not Assigned(LRuntimeFunction) then
    begin
            //
            // If we don't have a RUNTIME_FUNCTION, then we've encountered
            // a leaf function.  Adjust the stack approprately.
            //

      //LContext.Rip  := (ULONG64)(*(PULONG64)Context.Rsp);
      LContext.Rip  := ULONG64(Pointer(LContext.Rsp)^);
            LContext.Rsp := LContext.Rsp + 8;
    end
    else
    begin
            //
            // Otherwise, call upon RtlVirtualUnwind to execute the unwind for
            // us.
            //
            RtlVirtualUnwind(UNW_FLAG_NHANDLER,
                       LImageBase,
                       LContext.Rip,
                       LRuntimeFunction,
                       LContext,
                       HandlerData,
                       EstablisherFrame,
                       NvContext);
    end;

        //
        // If we reach an RIP of zero, this means that we've walked off the end
        // of the call stack and are done.
        //
    if LContext.Rip = 0 then
      Break;

        //
        // Display the context.  Note that we don't bother showing the XMM
        // context, although we have the nonvolatile portion of it.
        //
    if madMapFile.GetMapFileInfos(Pointer(LContext.Rip),
                                  LModuleName,
                                  LUnitName,
                                  LPublicName,
                                  LPublicAddr,
                                  LLineNumber) then
    begin
      Writeln(Format('%p %s.%s %d', [Pointer(LContext.Rip), LUnitName, LPublicName, LLineNumber{, LSEHType}]));
    end;
  until LContext.Rip = 0;
end;

それから私はそれを次のように呼びます:

procedure Main();
begin
  try
    try
      try
        try
          DumpExceptionStack();
        finally
          //
        end;
      except
        on E : Exception do
         raise
      end;
    except
      on E : Exception do
       raise
    end;
  except
    on E : Exception do
     raise
  end;
end;

アプリケーション(コンソールアプリケーションのみ)を実行すると、のエントリは1つしか取得できませんMainが、4つ(ネストされた例外が3つ、最後に1つ)あると予想していました。

私が誤って解釈した可能性があり、それDumpExceptionStackは例外がスローされたときに私が興味を持っている結果を与えるだけです?その場合、必要な変更は、すべての例外スタックを取得することです(可能な場合)。Main?の4つの出力があります

4

1 に答える 1

4

x64例外モデルは、スタックベースのx86モデルとは対照的に、テーブルベースです。これは、例外スタックが存在しないことを意味します。いずれにせよ、例外を含めて最終的にブロックしようとするストークウォークルーチンを見たことがありません。これも例外ではありません。関数呼び出しスタックをウォークします。

単一の関数内の例外フローは、スコープテーブルによって制御されます。関数では、コードが呼び出しの時点で例外を発生させた場合DumpExceptionStack、複数のスコープテーブルエントリが例外の場所と一致します。例外は、最も内側の一致するスコープによって処理されます。スコープの開始アドレスと終了アドレスの間の距離を使用して、どのスコープが最も内側にあるかを推測できます。その最も内側のスコープが例外を処理しない場合、または例外を再発生させる場合、次に最も内側のスコープが例外を処理するように求められます。関数の一致するスコープがすべてなくなるまで、以下同様です。

于 2013-01-06T22:56:52.360 に答える