When reading Win64 structured exceptions on a trace (from Programming Versus x64 Exception Handling Support, Part 7: Combining All of This or Building a Stack Procedure ), I converted the code to 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 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;
Then I call it with the following:
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;
When I run the application (just a console application), I get only one entry for Main , but I expected that there would be four (three nested exceptions and one, finally).
Maybe I misinterpreted and that DumpExceptionStack will only give the result that interests me when the exception is thrown? If so, what would be the necessary changes to get all exception stacks (if possible) - i.e. have four outputs for Main ?