diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp index 6fc569b45554c2..39b63573bc69b3 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.cpp +++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp @@ -7223,7 +7223,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetAssemblyFromModule(VMPTR_Modul HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ParseContinuation( CORDB_ADDRESS continuationAddress, - OUT PCODE* pDiagnosticIP, + OUT CORDB_ADDRESS* pDiagnosticIP, OUT CORDB_ADDRESS* pNextContinuation, OUT UINT32* pState) { @@ -7274,7 +7274,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::ParseContinuation( return E_FAIL; } - *pDiagnosticIP = pResumeInfo->pDiagnosticIP; + *pDiagnosticIP = static_cast(pResumeInfo->pDiagnosticIP); *pNextContinuation = static_cast(dac_cast(OBJECTREFToObject(pNext))); *pState = state; diff --git a/src/coreclr/debug/daccess/dacdbiimpl.h b/src/coreclr/debug/daccess/dacdbiimpl.h index 24c0c6865b13c7..283b04f6813255 100644 --- a/src/coreclr/debug/daccess/dacdbiimpl.h +++ b/src/coreclr/debug/daccess/dacdbiimpl.h @@ -145,7 +145,7 @@ class DacDbiInterfaceImpl : HRESULT STDMETHODCALLTYPE EnableGCNotificationEvents(BOOL fEnable); HRESULT STDMETHODCALLTYPE GetAssemblyFromModule(VMPTR_Module vmModule, OUT VMPTR_Assembly *pvmAssembly); HRESULT STDMETHODCALLTYPE ParseContinuation(CORDB_ADDRESS continuationAddress, - OUT PCODE *pDiagnosticIP, + OUT CORDB_ADDRESS *pDiagnosticIP, OUT CORDB_ADDRESS *pNextContinuation, OUT UINT32 *pState); HRESULT STDMETHODCALLTYPE EnumerateAsyncLocals(VMPTR_MethodDesc vmMethod, CORDB_ADDRESS codeAddr, UINT32 state, FP_ASYNC_LOCAL_CALLBACK fpCallback, CALLBACK_DATA pUserData); @@ -716,7 +716,7 @@ class DacDbiInterfaceImpl : ULONG32 GetStackParameterSize(EECodeInfo * pCodeInfo); // Return the FramePointer of the current frame at which the stackwalker is stopped. - HRESULT STDMETHODCALLTYPE GetFramePointer(StackWalkHandle pSFIHandle, OUT FramePointer * pRetVal); + HRESULT STDMETHODCALLTYPE GetFramePointer(StackWalkHandle pSFIHandle, OUT CORDB_ADDRESS * pRetVal); FramePointer GetFramePointerWorker(StackFrameIterator * pIter); diff --git a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp index 3ef32a23964011..c1f12b04b5292a 100644 --- a/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp +++ b/src/coreclr/debug/daccess/dacdbiimplstackwalk.cpp @@ -581,7 +581,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::EnumerateInternalFrames(VMPTR_Thr frameData.stubFrame.frameType = GetInternalFrameType(pFrame); if (frameData.stubFrame.frameType != STUBFRAME_NONE) { - frameData.fp = FramePointer::MakeFramePointer(PTR_HOST_TO_TADDR(pFrame)); + frameData.fp = PTR_TO_CORDB_ADDRESS(PTR_HOST_TO_TADDR(pFrame)); frameData.vmCurrentAppDomainToken.SetHostPtr(pAppDomain); @@ -638,7 +638,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetStackParameterSize(CORDB_ADDRE } // Return the FramePointer of the current frame at which the stackwalker is stopped. -HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetFramePointer(StackWalkHandle pSFIHandle, OUT FramePointer * pRetVal) +HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetFramePointer(StackWalkHandle pSFIHandle, OUT CORDB_ADDRESS * pRetVal) { DD_ENTER_MAY_THROW; @@ -647,7 +647,7 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetFramePointer(StackWalkHandle p { StackFrameIterator * pIter = GetIteratorFromHandle(pSFIHandle); - *pRetVal = GetFramePointerWorker(pIter); + *pRetVal = PTR_TO_CORDB_ADDRESS(GetFramePointerWorker(pIter).GetSPValue()); } EX_CATCH_HRESULT(hr); return hr; @@ -746,7 +746,7 @@ void DacDbiInterfaceImpl::InitFrameData(StackFrameIterator * pIter, // do common initialization of Debugger_STRData for both managed stack frames and explicit frames // - pFrameData->fp = GetFramePointerWorker(pIter); + pFrameData->fp = PTR_TO_CORDB_ADDRESS(GetFramePointerWorker(pIter).GetSPValue()); pFrameData->vmCurrentAppDomainToken.SetHostPtr(AppDomain::GetCurrentDomain()); @@ -754,8 +754,8 @@ void DacDbiInterfaceImpl::InitFrameData(StackFrameIterator * pIter, { pFrameData->eType = Debugger_STRData::cRuntimeNativeFrame; - _ASSERTE(pFrameData->ctx != NULL); - GetStackWalkCurrentContext(pIter, pFrameData->ctx); + _ASSERTE(pFrameData->ctx != 0); + GetStackWalkCurrentContext(pIter, (DT_CONTEXT *)CORDB_ADDRESS_TO_PTR(pFrameData->ctx)); } else if (ft == kManagedStackFrame) { @@ -785,8 +785,8 @@ void DacDbiInterfaceImpl::InitFrameData(StackFrameIterator * pIter, pFrameData->eType = Debugger_STRData::cMethodFrame; - _ASSERTE(pFrameData->ctx != NULL); - GetStackWalkCurrentContext(pIter, pFrameData->ctx); + _ASSERTE(pFrameData->ctx != 0); + GetStackWalkCurrentContext(pIter, (DT_CONTEXT *)CORDB_ADDRESS_TO_PTR(pFrameData->ctx)); // // initialize the fields in Debugger_STRData::v @@ -948,7 +948,7 @@ void DacDbiInterfaceImpl::InitParentFrameInfo(CrawlFrame * pCF, // to the ExInfo when we are checking if a particular frame is the parent frame. // - pJITFuncData->fpParentOrSelf = FramePointer::MakeFramePointer(sfParent.SP); + pJITFuncData->fpParentOrSelf = PTR_TO_CORDB_ADDRESS(sfParent.SP); pJITFuncData->parentNativeOffset = dwParentOffset; } else @@ -961,7 +961,7 @@ void DacDbiInterfaceImpl::InitParentFrameInfo(CrawlFrame * pCF, // to the ExInfo when we are checking if a particular frame is the parent frame. // - pJITFuncData->fpParentOrSelf = FramePointer::MakeFramePointer(sfSelf.SP); + pJITFuncData->fpParentOrSelf = PTR_TO_CORDB_ADDRESS(sfSelf.SP); pJITFuncData->parentNativeOffset = 0; } } diff --git a/src/coreclr/debug/di/process.cpp b/src/coreclr/debug/di/process.cpp index cf1dc0d0ee0571..66d33e4ff16f5c 100644 --- a/src/coreclr/debug/di/process.cpp +++ b/src/coreclr/debug/di/process.cpp @@ -2407,7 +2407,7 @@ COM_METHOD CordbProcess::GetAsyncStack(CORDB_ADDRESS continuationAddress, ICorDe ThrowHR(E_INVALIDARG); } - PCODE diagnosticIP; + CORDB_ADDRESS diagnosticIP; CORDB_ADDRESS nextContinuation; UINT32 state; if (FAILED(m_pDacPrimitives->ParseContinuation( diff --git a/src/coreclr/debug/di/rsstackwalk.cpp b/src/coreclr/debug/di/rsstackwalk.cpp index 3842f08e2a06c2..e3b5a081926832 100644 --- a/src/coreclr/debug/di/rsstackwalk.cpp +++ b/src/coreclr/debug/di/rsstackwalk.cpp @@ -583,7 +583,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) // populated context through this pointer. DT_CONTEXT frameCtx; ZeroMemory(&frameCtx, sizeof(frameCtx)); - frameData.ctx = &frameCtx; + frameData.ctx = PTR_TO_CORDB_ADDRESS(&frameCtx); IDacDbiInterface::FrameType ft = IDacDbiInterface::kInvalid; @@ -686,7 +686,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) // Create the native frame. CordbNativeFrame* pNativeFrame = new CordbNativeFrame(m_pCordbThread, - frameData.fp, + FramePointer::MakeFramePointer(CORDB_ADDRESS_TO_PTR(frameData.fp)), pNativeCode, (SIZE_T)pJITFuncData->nativeOffset, (TADDR)frameData.v.taAmbientESP, @@ -829,7 +829,7 @@ HRESULT CordbStackWalk::GetFrameWorker(ICorDebugFrame ** ppFrame) _ASSERTE(pCurrentAppDomain != NULL); CordbRuntimeUnwindableFrame * pRuntimeFrame = new CordbRuntimeUnwindableFrame(m_pCordbThread, - frameData.fp, + FramePointer::MakeFramePointer(CORDB_ADDRESS_TO_PTR(frameData.fp)), pCurrentAppDomain, &frameCtx); @@ -896,7 +896,7 @@ HRESULT CordbAsyncStackWalk::PopulateFrame() while (true) { - PCODE diagnosticIP; + CORDB_ADDRESS diagnosticIP = 0; CORDB_ADDRESS nextContinuation; UINT32 state; @@ -993,7 +993,7 @@ HRESULT CordbAsyncStackWalk::Next() if (m_continuationAddress == 0) ThrowHR(CORDBG_E_PAST_END_OF_STACK); - PCODE diagnosticIP; + CORDB_ADDRESS diagnosticIP = 0; CORDB_ADDRESS nextContinuation; UINT32 state; IfFailThrow(m_pProcess->GetDAC()->ParseContinuation( diff --git a/src/coreclr/debug/di/rsthread.cpp b/src/coreclr/debug/di/rsthread.cpp index 3eb4ee573fdb37..42ba92d32da33f 100644 --- a/src/coreclr/debug/di/rsthread.cpp +++ b/src/coreclr/debug/di/rsthread.cpp @@ -2286,7 +2286,7 @@ void CordbThread::GetActiveInternalFramesCallback(const Debugger_STRData * pFram // Create a CordbInternalFrame. CordbInternalFrame * pInternalFrame = new CordbInternalFrame(pThis, - pFrameData->fp, + FramePointer::MakeFramePointer(CORDB_ADDRESS_TO_PTR(pFrameData->fp)), pAppDomain, pFrameData); @@ -5433,7 +5433,7 @@ CordbMiscFrame::CordbMiscFrame() CordbMiscFrame::CordbMiscFrame(Debugger_JITFuncData * pJITFuncData) { this->parentIP = (SIZE_T)pJITFuncData->parentNativeOffset; - this->fpParentOrSelf = pJITFuncData->fpParentOrSelf; + this->fpParentOrSelf = FramePointer::MakeFramePointer(CORDB_ADDRESS_TO_PTR(pJITFuncData->fpParentOrSelf)); this->fIsFilterFunclet = (pJITFuncData->fIsFilterFrame == TRUE); } diff --git a/src/coreclr/debug/inc/dacdbiinterface.h b/src/coreclr/debug/inc/dacdbiinterface.h index f63cd9fbcc79b9..08ff6dd5c66227 100644 --- a/src/coreclr/debug/inc/dacdbiinterface.h +++ b/src/coreclr/debug/inc/dacdbiinterface.h @@ -1234,7 +1234,7 @@ IDacDbiInterface : public IUnknown // The FramePointer of an explicit frame is just the stack address of the explicit frame. // - virtual HRESULT STDMETHODCALLTYPE GetFramePointer(StackWalkHandle pSFIHandle, OUT FramePointer * pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE GetFramePointer(StackWalkHandle pSFIHandle, OUT CORDB_ADDRESS * pRetVal) = 0; // // Check whether the specified CONTEXT is the CONTEXT of the leaf frame. This function doesn't care @@ -2195,7 +2195,7 @@ IDacDbiInterface : public IUnknown virtual HRESULT STDMETHODCALLTYPE ParseContinuation( CORDB_ADDRESS continuationAddress, - OUT PCODE* pDiagnosticIP, + OUT CORDB_ADDRESS* pDiagnosticIP, OUT CORDB_ADDRESS* pNextContinuation, OUT UINT32* pState) = 0; diff --git a/src/coreclr/debug/inc/dacdbistructures.h b/src/coreclr/debug/inc/dacdbistructures.h index 0f4d5f8cfeb127..1bf8508cd766a5 100644 --- a/src/coreclr/debug/inc/dacdbistructures.h +++ b/src/coreclr/debug/inc/dacdbistructures.h @@ -519,7 +519,11 @@ struct MSLAYOUT Debugger_JITFuncData BOOL fIsFilterFrame; ULONG64 parentNativeOffset; - FramePointer fpParentOrSelf; + // Normalized to a fixed 64-bit width (CORDB_ADDRESS) rather than a host-sized + // FramePointer so this IPC struct has an identical layout on all bitnesses, + // allowing a 64-bit DBI to consume a 32-bit target. The RS converts to/from + // FramePointer at the boundary. + CORDB_ADDRESS fpParentOrSelf; // indicates if the MethodDesc is a generic function or a method inside a generic class (or // both!). @@ -538,8 +542,15 @@ struct MSLAYOUT Debugger_JITFuncData #endif // ARM context structures have a 16-byte alignment requirement struct MSLAYOUT Debugger_STRData { - FramePointer fp; - DT_CONTEXT * ctx; + // fp and ctx are normalized to a fixed 64-bit width (CORDB_ADDRESS) rather than + // host-sized types (FramePointer / DT_CONTEXT*) so this IPC struct has an identical + // layout regardless of host or target bitness, allowing a 64-bit DBI to consume a + // 32-bit target. The RS converts to/from the host representation at the boundary: + // - fp carries a (target) stack/frame pointer value. + // - ctx carries the (host) address of a dbi-allocated DT_CONTEXT buffer that the + // DAC writes the populated context through. + CORDB_ADDRESS fp; + CORDB_ADDRESS ctx; VMPTR_AppDomain vmCurrentAppDomainToken; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/StackWalk_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/StackWalk_1.cs index 126eb929c3ad39..e6133ca487312f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/StackWalk_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/StackWalk/StackWalk_1.cs @@ -855,6 +855,14 @@ private bool Next(StackWalkData handle) case StackWalkState.InitialNativeContext: case StackWalkState.NativeMarker: { + // Native UnwindStackWalkFrame captures cbStackParameterSize as a fresh + // per-step local that defaults to 0, and only sets it when the frame being + // left is a frameless managed method (SFITER_FRAMELESS_METHOD). The x86 + // callee-popped-args ESP adjustment is therefore applied only at an immediate + // managed-frameless -> native-marker (M2U) transition. Leaving a native frame + // must reset the size to 0 so consecutive native-marker frames don't reuse a + // stale parameter size from an earlier managed frame. + handle.LastFramelessStackParameterSize = 0; TargetCodePointer ip = handle.Context.InstructionPointer; HijackKind hijackKind = _target.Contracts.Debugger.GetHijackKind(ip); if (hijackKind != HijackKind.None) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs index 37f627dd76238a..0bdb6247f65291 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs @@ -195,7 +195,7 @@ public struct Debugger_JITFuncData public ulong vmNativeCodeMethodDescToken; public Interop.BOOL fIsFilterFrame; public ulong parentNativeOffset; - public ulong fpParentOrSelf; + public ulong fpParentOrSelf; // FramePointer, normalized to a fixed 64-bit width (CORDB_ADDRESS) public Interop.BOOL isInstantiatedGeneric; public Interop.BOOL justAfterILThrow; } @@ -226,12 +226,18 @@ public struct DebuggerIPCE_STRData_StubFrame // Holds data for each stack frame or chain. This data is passed from the RC to // the DI during a stack walk. Mirrors the native Debugger_STRData struct -// defined in src/coreclr/debug/inc/dbgipcevents.h. +// defined in src/coreclr/debug/inc/dacdbistructures.h. // -// `ctx` is a pointer into dbi-allocated memory. -// The DAC writes the populated context through this pointer rather -// than storing it inline. Code paths that do not produce a context -// (e.g. EnumerateInternalFrames for cStubFrame entries) leave it as 0. +// `fp` (a stack/frame pointer) and `ctx` (the address of a dbi-allocated +// DT_CONTEXT buffer) are normalized on the native side to a fixed 64-bit width +// (CORDB_ADDRESS), rather than host-sized FramePointer / DT_CONTEXT*, so this IPC +// struct has an identical layout regardless of host or target bitness. That lets +// a 64-bit DBI consume a 32-bit target. They are therefore modeled as ulong here, +// matching the VMPTR/CORDB_ADDRESS fields which are always 8 bytes. +// +// `ctx` addresses dbi-allocated memory: the DAC writes the populated context +// through it rather than storing it inline. Code paths that do not produce a +// context (e.g. EnumerateInternalFrames for cStubFrame entries) leave it as 0. [StructLayout(LayoutKind.Explicit)] public struct Debugger_STRData { @@ -242,10 +248,11 @@ public enum EType cRuntimeNativeFrame = 2, } - [FieldOffset(0)] public ulong fp; // FramePointer - [FieldOffset(8)] public ulong ctx; // DT_CONTEXT* + [FieldOffset(0)] public ulong fp; // FramePointer (normalized to CORDB_ADDRESS) + [FieldOffset(8)] public ulong ctx; // DT_CONTEXT* address (normalized to CORDB_ADDRESS) [FieldOffset(16)] public ulong vmCurrentAppDomainToken; // VMPTR_AppDomain [FieldOffset(24)] public EType eType; + // The v (method frame) and stubFrame variants overlap, mirroring the native anonymous union. [FieldOffset(32)] public DebuggerIPCE_STRData_MethodFrame v; [FieldOffset(32)] public DebuggerIPCE_STRData_StubFrame stubFrame; }