| File: Contracts\StackWalk\FrameHandling\WasmFrameHandler.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.Diagnostics.DataContractReader.Data; namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers; /// <summary> /// Frame handler for CoreCLR on WebAssembly. /// </summary> /// <remarks> /// WebAssembly has no native register context (see <see cref="WasmContext"/>). Seeding the /// initial stack walk context therefore comes from the explicit Frame chain rather than a /// captured <c>DT_CONTEXT</c>: the innermost transition frame carries the managed linear stack /// pointer. The base <see cref="BaseFrameHandler.HandleInlinedCallFrame"/> already reads that /// <c>InlinedCallFrame.CallSiteSP</c> (plus the caller return address and callee-saved frame /// pointer) into the three synthetic <see cref="WasmContext"/> slots, which is the common /// P/Invoke-boundary seeding path. The software/faulting exception frame handlers likewise read a /// serialized <see cref="WasmContext"/> blob from the frame's <c>TargetContext</c>. /// /// Hijack frames are a debugger / GC-suspension concept that is not yet supported on WASM. /// </remarks> internal sealed class WasmFrameHandler(Target target, ContextHolder<WasmContext> contextHolder) : BaseFrameHandler(target, contextHolder), IPlatformFrameHandler { private readonly ContextHolder<WasmContext> _holder = contextHolder; public override void HandleInlinedCallFrame(InlinedCallFrame inlinedCallFrame) { base.HandleInlinedCallFrame(inlinedCallFrame); // When the frame directly above this P/Invoke transition is an InterpreterFrame, stash its // address in the synthetic first-argument register so the subsequent interpreter virtual // unwind (InterpreterVirtualUnwind -> GetFirstArgReg) can recover the owning InterpreterFrame. // Mirrors the per-architecture handlers (e.g. AMD64FrameHandler) and the native // SetFirstArgReg(context->InterpreterWalkFramePointer) contract on WASM. Data.Frame? next = GetNextFrame(inlinedCallFrame.Address); if (next is not null && _frameHelpers.GetFrameType(next.Identifier) == FrameType.InterpreterFrame) { if (!_holder.Context.TrySetRegister(WasmContext.InterpreterWalkFramePointerRegister, new TargetNUInt(next.Address.Value))) throw new InvalidOperationException($"Failed to set WASM interpreter frame-pointer register '{WasmContext.InterpreterWalkFramePointerRegister}'."); } } public void HandleHijackFrame(HijackFrame frame) => throw new PlatformNotSupportedException("HijackFrame handling is not supported on WASM."); }