| File: Contracts\StackWalk\Context\Wasm\WasmR2RInfo.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 Microsoft.Diagnostics.DataContractReader.ExecutionManagerHelpers; namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers.Wasm; /// <summary> /// cDAC implementation of <see cref="IWasmR2RInfo"/>, mirroring the native /// <c>ExecutionManager::{FindFunctionTableIndexRangeSection, IsFuncletFunctionIndex, /// GetWasmVirtualIPFromFunctionTableIndex}</c> in <c>src/coreclr/vm/codeman.cpp</c>. It resolves an /// R2R function table entry index against the <c>FunctionTableIndexRangeList</c> to its owning /// module's <see cref="Data.ReadyToRunInfo"/>, then reads the corresponding /// <c>RUNTIME_FUNCTION</c> for the funclet flag, base virtual IP, and unwind data. /// </summary> internal sealed class WasmR2RInfo : IWasmR2RInfo { // RUNTIME_FUNCTION__IsFunclet: the funclet flag is the high bit of BeginAddress (clrnt.h). private const uint FuncletFlag = 0x80000000; private readonly Target _target; private readonly RuntimeFunctionLookup _runtimeFunctions; public WasmR2RInfo(Target target) { _target = target; _runtimeFunctions = RuntimeFunctionLookup.Create(target); } // Mirrors ExecutionManager::FindFunctionTableIndexRangeSection. private Data.FunctionTableIndexRangeSection? FindSection(uint functionTableIndex) { if (!_target.TryReadGlobalPointer(Constants.Globals.FunctionTableIndexRangeList, out TargetPointer? listHeadSlot)) return null; // The global holds the address of the s_pFunctionTableIndexRangeList slot (a pointer-to- // pointer); dereference it once to obtain the actual list head. TargetPointer current = _target.ReadPointer(listHeadSlot.Value); while (current != TargetPointer.Null) { Data.FunctionTableIndexRangeSection section = _target.ProcessedData.GetOrAdd<Data.FunctionTableIndexRangeSection>(current); if (functionTableIndex >= section.MinFunctionTableIndex && functionTableIndex < section.MinFunctionTableIndex + section.NumRuntimeFunctions) { return section; } current = section.Next; } return null; } private Data.ReadyToRunInfo GetReadyToRunInfo(Data.FunctionTableIndexRangeSection section) { Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(section.R2RModule); return _target.ProcessedData.GetOrAdd<Data.ReadyToRunInfo>(module.ReadyToRunInfo); } private Data.RuntimeFunction GetRuntimeFunction(Data.ReadyToRunInfo r2rInfo, uint localIndex) => _runtimeFunctions.GetRuntimeFunction(r2rInfo.RuntimeFunctions, localIndex); public bool TryGetVirtualIPBase(uint functionTableIndex, out ulong baseVirtualIP) { baseVirtualIP = 0; Data.FunctionTableIndexRangeSection? section = FindSection(functionTableIndex); if (section is null) return false; Data.ReadyToRunInfo r2rInfo = GetReadyToRunInfo(section); if (r2rInfo.MinVirtualIP is not TargetPointer minVirtualIP) return false; // Funclets' function-local virtual IPs are relative to their controlling function, so index // backwards past funclet entries to the controlling (non-funclet) function. uint localIndex = functionTableIndex - section.MinFunctionTableIndex; while (true) { Data.RuntimeFunction runtimeFunction = GetRuntimeFunction(r2rInfo, localIndex); if ((runtimeFunction.BeginAddress & FuncletFlag) != 0) { if (localIndex == 0) return false; localIndex--; continue; } baseVirtualIP = minVirtualIP.Value + runtimeFunction.BeginAddress; return true; } } public bool TryGetUnwindData(uint functionTableIndex, out TargetPointer unwindDataAddress) { unwindDataAddress = TargetPointer.Null; Data.FunctionTableIndexRangeSection? section = FindSection(functionTableIndex); if (section is null) return false; Data.ReadyToRunInfo r2rInfo = GetReadyToRunInfo(section); uint localIndex = functionTableIndex - section.MinFunctionTableIndex; Data.RuntimeFunction runtimeFunction = GetRuntimeFunction(r2rInfo, localIndex); unwindDataAddress = new TargetPointer(r2rInfo.LoadedImageBase.Value + runtimeFunction.UnwindData); return true; } }