summaryrefslogtreecommitdiff
path: root/src/debug/daccess/stack.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/debug/daccess/stack.cpp')
-rw-r--r--src/debug/daccess/stack.cpp1434
1 files changed, 1434 insertions, 0 deletions
diff --git a/src/debug/daccess/stack.cpp b/src/debug/daccess/stack.cpp
new file mode 100644
index 0000000000..b235366bb5
--- /dev/null
+++ b/src/debug/daccess/stack.cpp
@@ -0,0 +1,1434 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//*****************************************************************************
+// File: stack.cpp
+//
+
+//
+// CLRData stack walking.
+//
+//*****************************************************************************
+
+#include "stdafx.h"
+
+//----------------------------------------------------------------------------
+//
+// ClrDataStackWalk.
+//
+//----------------------------------------------------------------------------
+
+ClrDataStackWalk::ClrDataStackWalk(ClrDataAccess* dac,
+ Thread* thread,
+ ULONG32 flags)
+{
+ m_dac = dac;
+ m_dac->AddRef();
+ m_instanceAge = m_dac->m_instanceAge;
+ m_thread = thread;
+ m_walkFlags = flags;
+ m_refs = 1;
+ m_stackPrev = 0;
+
+ INDEBUG( m_framesUnwound = 0; )
+}
+
+ClrDataStackWalk::~ClrDataStackWalk(void)
+{
+ m_dac->Release();
+}
+
+STDMETHODIMP
+ClrDataStackWalk::QueryInterface(THIS_
+ IN REFIID interfaceId,
+ OUT PVOID* iface)
+{
+ if (IsEqualIID(interfaceId, IID_IUnknown) ||
+ IsEqualIID(interfaceId, __uuidof(IXCLRDataStackWalk)))
+ {
+ AddRef();
+ *iface = static_cast<IUnknown*>
+ (static_cast<IXCLRDataStackWalk*>(this));
+ return S_OK;
+ }
+ else
+ {
+ *iface = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG)
+ClrDataStackWalk::AddRef(THIS)
+{
+ return InterlockedIncrement(&m_refs);
+}
+
+STDMETHODIMP_(ULONG)
+ClrDataStackWalk::Release(THIS)
+{
+ SUPPORTS_DAC_HOST_ONLY;
+ LONG newRefs = InterlockedDecrement(&m_refs);
+ if (newRefs == 0)
+ {
+ delete this;
+ }
+ return newRefs;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::GetContext(
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ])
+{
+ HRESULT status;
+
+ if (contextSize)
+ {
+ *contextSize = ContextSizeForFlags(contextFlags);
+ }
+
+ if (!CheckContextSizeForFlags(contextBufSize, contextFlags))
+ {
+ return E_INVALIDARG;
+ }
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (!m_frameIter.IsValid())
+ {
+ status = S_FALSE;
+ }
+ else
+ {
+ *(PT_CONTEXT)contextBuf = m_context;
+ UpdateContextFromRegDisp(&m_regDisp, (PT_CONTEXT)contextBuf);
+ status = S_OK;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::SetContext(
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ])
+{
+ return SetContext2(m_frameIter.m_crawl.IsActiveFrame() ?
+ CLRDATA_STACK_SET_CURRENT_CONTEXT :
+ CLRDATA_STACK_SET_UNWIND_CONTEXT,
+ contextSize, context);
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::SetContext2(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ])
+{
+ HRESULT status;
+
+ if ((flags & ~(CLRDATA_STACK_SET_CURRENT_CONTEXT |
+ CLRDATA_STACK_SET_UNWIND_CONTEXT)) != 0 ||
+ !CheckContextSizeForBuffer(contextSize, context))
+ {
+ return E_INVALIDARG;
+ }
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ // Copy the context to local state so
+ // that its lifetime extends beyond this call.
+ m_context = *(PT_CONTEXT)context;
+ m_thread->FillRegDisplay(&m_regDisp, &m_context);
+ m_frameIter.ResetRegDisp(&m_regDisp, (flags & CLRDATA_STACK_SET_CURRENT_CONTEXT) != 0);
+ m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
+ FilterFrames();
+ status = S_OK;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::Next(void)
+{
+ HRESULT status = E_FAIL;
+
+ INDEBUG( static const int kFrameToReturnForever = 56; )
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (!m_frameIter.IsValid())
+ {
+ status = S_FALSE;
+ }
+ else
+#if defined(_DEBUG)
+ // m_framesUnwound is not incremented unless the special config value is set below in this function.
+ if (m_framesUnwound < kFrameToReturnForever)
+#endif // defined(_DEBUG)
+ {
+ // Default the previous stack value.
+ m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
+ StackWalkAction action = m_frameIter.Next();
+ switch(action)
+ {
+ case SWA_CONTINUE:
+ // We sucessfully unwound a frame so update
+ // the previous stack pointer before going into
+ // filtering to get the amount of stack skipped
+ // by the filtering.
+ m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
+ FilterFrames();
+ status = m_frameIter.IsValid() ? S_OK : S_FALSE;
+ break;
+ case SWA_ABORT:
+ status = S_FALSE;
+ break;
+ default:
+ status = E_FAIL;
+ break;
+ }
+ }
+
+#if defined(_DEBUG)
+ // Test hook: when testing on debug builds, we want an easy way to test that the target
+ // stack behaves as if it's smashed in a particular way. It would be very difficult to create
+ // a test that carefully broke the stack in a way that would force the stackwalker to report
+ // success on the same frame forever, and have that corruption be reliable over time. However, it's
+ // pretty easy for us to control the number of frames on the stack for tests that use this specific
+ // internal flag.
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DumpGeneration_IntentionallyCorruptDataFromTarget))
+ {
+ if (m_framesUnwound >= kFrameToReturnForever)
+ {
+ status = S_OK;
+ }
+ else
+ {
+ m_framesUnwound++;
+ }
+ }
+#endif // defined(_DEBUG)
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::GetStackSizeSkipped(
+ /* [out] */ ULONG64 *stackSizeSkipped)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (m_stackPrev)
+ {
+ *stackSizeSkipped =
+ (TADDR)GetRegdisplaySP(&m_regDisp) - m_stackPrev;
+ status = S_OK;
+ }
+ else
+ {
+ status = S_FALSE;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::GetFrameType(
+ /* [out] */ CLRDataSimpleFrameType *simpleType,
+ /* [out] */ CLRDataDetailedFrameType *detailedType)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (m_frameIter.IsValid())
+ {
+ RawGetFrameType(simpleType, detailedType);
+ status = S_OK;
+ }
+ else
+ {
+ status = S_FALSE;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::GetFrame(
+ /* [out] */ IXCLRDataFrame **frame)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ ClrDataFrame* dataFrame = NULL;
+ if (!m_frameIter.IsValid())
+ {
+ status = E_INVALIDARG;
+ goto Exit;
+ }
+
+ CLRDataSimpleFrameType simpleType;
+ CLRDataDetailedFrameType detailedType;
+
+ RawGetFrameType(&simpleType, &detailedType);
+ dataFrame =
+ new (nothrow) ClrDataFrame(m_dac, simpleType, detailedType,
+ m_frameIter.m_crawl.GetAppDomain(),
+ m_frameIter.m_crawl.GetFunction());
+ if (!dataFrame)
+ {
+ status = E_OUTOFMEMORY;
+ goto Exit;
+ }
+
+ dataFrame->m_context = m_context;
+ UpdateContextFromRegDisp(&m_regDisp, &dataFrame->m_context);
+ m_thread->FillRegDisplay(&dataFrame->m_regDisp,
+ &dataFrame->m_context);
+
+ *frame = static_cast<IXCLRDataFrame*>(dataFrame);
+ status = S_OK;
+
+ Exit: ;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataStackWalk::Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ switch(reqCode)
+ {
+ case CLRDATA_REQUEST_REVISION:
+ if (inBufferSize != 0 ||
+ inBuffer ||
+ outBufferSize != sizeof(ULONG32))
+ {
+ status = E_INVALIDARG;
+ }
+ else
+ {
+ *(ULONG32*)outBuffer = 1;
+ status = S_OK;
+ }
+ break;
+
+ case CLRDATA_STACK_WALK_REQUEST_SET_FIRST_FRAME:
+ // This code should be removed once the Windows debuggers stop using the old DAC API.
+ if ((inBufferSize != sizeof(ULONG32)) ||
+ (outBufferSize != 0))
+ {
+ status = E_INVALIDARG;
+ break;
+ }
+
+ m_frameIter.SetIsFirstFrame(*(ULONG32 UNALIGNED *)inBuffer != 0);
+ status = S_OK;
+ break;
+
+ case DACSTACKPRIV_REQUEST_FRAME_DATA:
+ if ((inBufferSize != 0) ||
+ (inBuffer != NULL) ||
+ (outBufferSize != sizeof(DacpFrameData)))
+ {
+ status = E_INVALIDARG;
+ break;
+ }
+ if (!m_frameIter.IsValid())
+ {
+ status = E_INVALIDARG;
+ break;
+ }
+
+ DacpFrameData* frameData;
+
+ frameData = (DacpFrameData*)outBuffer;
+ frameData->frameAddr =
+ TO_CDADDR(PTR_HOST_TO_TADDR(m_frameIter.m_crawl.GetFrame()));
+ status = S_OK;
+ break;
+
+ default:
+ status = E_INVALIDARG;
+ break;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT
+ClrDataStackWalk::Init(void)
+{
+ if (m_thread->IsUnstarted())
+ {
+ return E_FAIL;
+ }
+
+ if (m_thread->GetFilterContext())
+ {
+ m_context = *m_thread->GetFilterContext();
+ }
+ else
+ {
+ DacGetThreadContext(m_thread, &m_context);
+ }
+ m_thread->FillRegDisplay(&m_regDisp, &m_context);
+
+ m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
+
+ ULONG32 iterFlags = NOTIFY_ON_NO_FRAME_TRANSITIONS;
+
+ // If the filter is only allowing method frames
+ // turn on the appropriate iterator flag.
+ if ((m_walkFlags & SIMPFRAME_ALL) ==
+ CLRDATA_SIMPFRAME_MANAGED_METHOD)
+ {
+ iterFlags |= FUNCTIONSONLY;
+ }
+
+ m_frameIter.Init(m_thread, NULL, &m_regDisp, iterFlags);
+ if (m_frameIter.GetFrameState() == StackFrameIterator::SFITER_UNINITIALIZED)
+ {
+ return E_FAIL;
+ }
+ FilterFrames();
+
+ return S_OK;
+}
+
+void
+ClrDataStackWalk::FilterFrames(void)
+{
+ //
+ // Advance to a state compatible with the
+ // current filtering flags.
+ //
+
+ while (m_frameIter.IsValid())
+ {
+ switch(m_frameIter.GetFrameState())
+ {
+ case StackFrameIterator::SFITER_FRAMELESS_METHOD:
+ if (m_walkFlags & CLRDATA_SIMPFRAME_MANAGED_METHOD)
+ {
+ return;
+ }
+ break;
+ case StackFrameIterator::SFITER_FRAME_FUNCTION:
+ case StackFrameIterator::SFITER_SKIPPED_FRAME_FUNCTION:
+ case StackFrameIterator::SFITER_NO_FRAME_TRANSITION:
+ if (m_walkFlags & CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE)
+ {
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ m_frameIter.Next();
+ }
+}
+
+void
+ClrDataStackWalk::RawGetFrameType(
+ /* [out] */ CLRDataSimpleFrameType* simpleType,
+ /* [out] */ CLRDataDetailedFrameType* detailedType)
+{
+ if (simpleType)
+ {
+ switch(m_frameIter.GetFrameState())
+ {
+ case StackFrameIterator::SFITER_FRAMELESS_METHOD:
+ *simpleType = CLRDATA_SIMPFRAME_MANAGED_METHOD;
+ break;
+ case StackFrameIterator::SFITER_FRAME_FUNCTION:
+ case StackFrameIterator::SFITER_SKIPPED_FRAME_FUNCTION:
+ *simpleType = CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE;
+ break;
+ default:
+ *simpleType = CLRDATA_SIMPFRAME_UNRECOGNIZED;
+ break;
+ }
+ }
+
+ if (detailedType)
+ {
+ if (m_frameIter.m_crawl.GetFrame() && m_frameIter.m_crawl.GetFrame()->GetFrameAttribs() & Frame::FRAME_ATTR_EXCEPTION)
+ *detailedType = CLRDATA_DETFRAME_EXCEPTION_FILTER;
+ else
+ *detailedType = CLRDATA_DETFRAME_UNRECOGNIZED;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// ClrDataFrame.
+//
+//----------------------------------------------------------------------------
+
+ClrDataFrame::ClrDataFrame(ClrDataAccess* dac,
+ CLRDataSimpleFrameType simpleType,
+ CLRDataDetailedFrameType detailedType,
+ AppDomain* appDomain,
+ MethodDesc* methodDesc)
+{
+ m_dac = dac;
+ m_dac->AddRef();
+ m_instanceAge = m_dac->m_instanceAge;
+ m_simpleType = simpleType;
+ m_detailedType = detailedType;
+ m_appDomain = appDomain;
+ m_methodDesc = methodDesc;
+ m_refs = 1;
+ m_methodSig = NULL;
+ m_localSig = NULL;
+}
+
+ClrDataFrame::~ClrDataFrame(void)
+{
+ delete m_methodSig;
+ delete m_localSig;
+ m_dac->Release();
+}
+
+STDMETHODIMP
+ClrDataFrame::QueryInterface(THIS_
+ IN REFIID interfaceId,
+ OUT PVOID* iface)
+{
+ if (IsEqualIID(interfaceId, IID_IUnknown) ||
+ IsEqualIID(interfaceId, __uuidof(IXCLRDataFrame)))
+ {
+ AddRef();
+ *iface = static_cast<IUnknown*>
+ (static_cast<IXCLRDataFrame*>(this));
+ return S_OK;
+ }
+ else if (IsEqualIID(interfaceId, __uuidof(IXCLRDataFrame2)))
+ {
+ AddRef();
+ *iface = static_cast<IUnknown*>
+ (static_cast<IXCLRDataFrame2*>(this));
+ return S_OK;
+ }
+ else
+ {
+ *iface = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+STDMETHODIMP_(ULONG)
+ClrDataFrame::AddRef(THIS)
+{
+ return InterlockedIncrement(&m_refs);
+}
+
+STDMETHODIMP_(ULONG)
+ClrDataFrame::Release(THIS)
+{
+ SUPPORTS_DAC_HOST_ONLY;
+ LONG newRefs = InterlockedDecrement(&m_refs);
+ if (newRefs == 0)
+ {
+ delete this;
+ }
+ return newRefs;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetContext(
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ])
+{
+ HRESULT status;
+
+ if (contextSize)
+ {
+ *contextSize = ContextSizeForFlags(contextFlags);
+ }
+
+ if (!CheckContextSizeForFlags(contextBufSize, contextFlags))
+ {
+ return E_INVALIDARG;
+ }
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ *(PT_CONTEXT)contextBuf = m_context;
+ status = S_OK;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetFrameType(
+ /* [out] */ CLRDataSimpleFrameType *simpleType,
+ /* [out] */ CLRDataDetailedFrameType *detailedType)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ *simpleType = m_simpleType;
+ *detailedType = m_detailedType;
+ status = S_OK;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetAppDomain(
+ /* [out] */ IXCLRDataAppDomain **appDomain)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (m_appDomain)
+ {
+ ClrDataAppDomain* dataAppDomain =
+ new (nothrow) ClrDataAppDomain(m_dac, m_appDomain);
+ if (!dataAppDomain)
+ {
+ status = E_OUTOFMEMORY;
+ }
+ else
+ {
+ *appDomain = static_cast<IXCLRDataAppDomain*>(dataAppDomain);
+ status = S_OK;
+ }
+ }
+ else
+ {
+ *appDomain = NULL;
+ status = S_FALSE;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetNumArguments(
+ /* [out] */ ULONG32 *numArgs)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (!m_methodDesc)
+ {
+ status = E_NOINTERFACE;
+ }
+ else
+ {
+ MetaSig* sig;
+
+ status = GetMethodSig(&sig, numArgs);
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetArgumentByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **arg,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ])
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (nameLen)
+ {
+ *nameLen = 0;
+ }
+
+ if (!m_methodDesc)
+ {
+ status = E_NOINTERFACE;
+ goto Exit;
+ }
+
+ MetaSig* sig;
+ ULONG32 numArgs;
+
+ if (FAILED(status = GetMethodSig(&sig, &numArgs)))
+ {
+ goto Exit;
+ }
+
+ if (index >= numArgs)
+ {
+ status = E_INVALIDARG;
+ goto Exit;
+ }
+
+ if ((bufLen && name) || nameLen)
+ {
+ if (index == 0 && sig->HasThis())
+ {
+ if (nameLen)
+ {
+ *nameLen = 5;
+ }
+
+ StringCchCopy(name, bufLen, W("this"));
+ }
+ else
+ {
+ if (!m_methodDesc->IsNoMetadata())
+ {
+ IMDInternalImport* mdImport = m_methodDesc->GetMDImport();
+ mdParamDef paramToken;
+ LPCSTR paramName;
+ USHORT seq;
+ DWORD attr;
+
+ // Param indexing is 1-based.
+ ULONG32 mdIndex = index + 1;
+
+ // 'this' doesn't show up in the signature but
+ // is present in the dac API indexing so adjust the
+ // index down for methods with 'this'.
+ if (sig->HasThis())
+ {
+ mdIndex--;
+ }
+
+ status = mdImport->FindParamOfMethod(
+ m_methodDesc->GetMemberDef(),
+ mdIndex,
+ &paramToken);
+ if (status == S_OK)
+ {
+ status = mdImport->GetParamDefProps(
+ paramToken,
+ &seq,
+ &attr,
+ &paramName);
+ if ((status == S_OK) && (paramName != NULL))
+ {
+ if ((status = ConvertUtf8(paramName,
+ bufLen, nameLen, name)) != S_OK)
+ {
+ goto Exit;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (nameLen)
+ {
+ *nameLen = 1;
+ }
+
+ name[0] = 0;
+ }
+ }
+ }
+
+ status = ValueFromDebugInfo(sig, true, index, index, arg);
+
+ Exit: ;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetNumLocalVariables(
+ /* [out] */ ULONG32 *numLocals)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (!m_methodDesc)
+ {
+ status = E_NOINTERFACE;
+ }
+ else
+ {
+ MetaSig* sig;
+
+ status = GetLocalSig(&sig, numLocals);
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetLocalVariableByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **localVariable,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ])
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (!m_methodDesc)
+ {
+ status = E_NOINTERFACE;
+ goto Exit;
+ }
+
+ MetaSig* sig;
+ ULONG32 numLocals;
+
+ if (FAILED(status = GetLocalSig(&sig, &numLocals)))
+ {
+ goto Exit;
+ }
+
+ if (index >= numLocals)
+ {
+ status = E_INVALIDARG;
+ goto Exit;
+ }
+
+ MetaSig* argSig;
+ ULONG32 numArgs;
+
+ if (FAILED(status = GetMethodSig(&argSig, &numArgs)))
+ {
+ goto Exit;
+ }
+
+ // Can't get names for locals in the Whidbey runtime.
+ if (bufLen && name)
+ {
+ if (nameLen)
+ {
+ *nameLen = 1;
+ }
+
+ name[0] = 0;
+ }
+
+ // The locals are indexed immediately following the arguments
+ // in the NativeVarInfos.
+ status = ValueFromDebugInfo(sig, false, index, index + numArgs,
+ localVariable);
+
+ Exit: ;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetNumTypeArguments(
+ /* [out] */ ULONG32 *numTypeArgs)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ // XXX Microsoft.
+ status = E_NOTIMPL;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetTypeArgumentByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataTypeInstance **typeArg)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ // XXX Microsoft.
+ status = E_NOTIMPL;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetExactGenericArgsToken(
+ /* [out] */ IXCLRDataValue ** genericToken)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (!m_methodDesc)
+ {
+ status = E_NOINTERFACE;
+ goto Exit;
+ }
+
+ MetaSig* sig;
+ ULONG32 numLocals;
+
+ if (FAILED(status = GetLocalSig(&sig, &numLocals)))
+ {
+ goto Exit;
+ }
+
+ // The locals are indexed immediately following the arguments
+ // in the NativeVarInfos.
+ status = ValueFromDebugInfo(sig, false, 1, (DWORD)ICorDebugInfo::TYPECTXT_ILNUM,
+ genericToken);
+ Exit: ;
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetCodeName(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *symbolLen,
+ /* [size_is][out] */ __out_ecount_opt(bufLen) WCHAR symbolBuf[ ])
+{
+ HRESULT status = E_FAIL;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ TADDR pcAddr = PCODEToPINSTR(GetControlPC(&m_regDisp));
+ status = m_dac->
+ RawGetMethodName(TO_CDADDR(pcAddr), flags,
+ bufLen, symbolLen, symbolBuf,
+ NULL);
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::GetMethodInstance(
+ /* [out] */ IXCLRDataMethodInstance **method)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ if (!m_methodDesc)
+ {
+ status = E_NOINTERFACE;
+ }
+ else
+ {
+ ClrDataMethodInstance* dataMethod =
+ new (nothrow) ClrDataMethodInstance(m_dac,
+ m_appDomain,
+ m_methodDesc);
+ *method = static_cast<IXCLRDataMethodInstance*>(dataMethod);
+ status = dataMethod ? S_OK : E_OUTOFMEMORY;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT STDMETHODCALLTYPE
+ClrDataFrame::Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer)
+{
+ HRESULT status;
+
+ DAC_ENTER_SUB(m_dac);
+
+ EX_TRY
+ {
+ switch(reqCode)
+ {
+ case CLRDATA_REQUEST_REVISION:
+ if (inBufferSize != 0 ||
+ inBuffer ||
+ outBufferSize != sizeof(ULONG32))
+ {
+ status = E_INVALIDARG;
+ }
+ else
+ {
+ *(ULONG32*)outBuffer = 1;
+ status = S_OK;
+ }
+ break;
+
+ default:
+ status = E_INVALIDARG;
+ break;
+ }
+ }
+ EX_CATCH
+ {
+ if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
+ {
+ EX_RETHROW;
+ }
+ }
+ EX_END_CATCH(SwallowAllExceptions)
+
+ DAC_LEAVE();
+ return status;
+}
+
+HRESULT
+ClrDataFrame::GetMethodSig(MetaSig** sig,
+ ULONG32* count)
+{
+ if (!m_methodSig)
+ {
+ m_methodSig = new (nothrow) MetaSig(m_methodDesc);
+ if (!m_methodSig)
+ {
+ return E_OUTOFMEMORY;
+ }
+ }
+
+ *sig = m_methodSig;
+ *count = m_methodSig->NumFixedArgs() +
+ (m_methodSig->HasThis() ? 1 : 0);
+ return *count ? S_OK : S_FALSE;
+}
+
+HRESULT
+ClrDataFrame::GetLocalSig(MetaSig** sig,
+ ULONG32* count)
+{
+ HRESULT hr;
+ if (!m_localSig)
+ {
+ // It turns out we cannot really get rid of this check. Dynamic methods
+ // (including IL stubs) do not have their local sig's available after JIT time.
+ if (!m_methodDesc->IsIL())
+ {
+ *sig = NULL;
+ *count = 0;
+ return S_FALSE;
+ }
+
+ COR_ILMETHOD_DECODER methodDecoder(m_methodDesc->GetILHeader());
+ mdSignature localSig = methodDecoder.GetLocalVarSigTok() ?
+ methodDecoder.GetLocalVarSigTok() : mdSignatureNil;
+ if (localSig == mdSignatureNil)
+ {
+ *sig = NULL;
+ *count = 0;
+ return S_FALSE;
+ }
+
+ ULONG tokenSigLen;
+ PCCOR_SIGNATURE tokenSig;
+ IfFailRet(m_methodDesc->GetModule()->GetMDImport()->GetSigFromToken(
+ localSig,
+ &tokenSigLen,
+ &tokenSig));
+
+ SigTypeContext typeContext(m_methodDesc, TypeHandle());
+ m_localSig = new (nothrow)
+ MetaSig(tokenSig,
+ tokenSigLen,
+ m_methodDesc->GetModule(),
+ &typeContext,
+ MetaSig::sigLocalVars);
+ if (!m_localSig)
+ {
+ return E_OUTOFMEMORY;
+ }
+ }
+
+ *sig = m_localSig;
+ *count = m_localSig->NumFixedArgs();
+ return S_OK;
+}
+
+HRESULT
+ClrDataFrame::ValueFromDebugInfo(MetaSig* sig,
+ bool isArg,
+ DWORD sigIndex,
+ DWORD varInfoSlot,
+ IXCLRDataValue** _value)
+{
+ HRESULT status;
+ ULONG32 numVarInfo;
+ NewHolder<ICorDebugInfo::NativeVarInfo> varInfo(NULL);
+ ULONG32 codeOffset;
+ ULONG32 valueFlags;
+ ULONG32 i;
+
+ TADDR ip = PCODEToPINSTR(GetControlPC(&m_regDisp));
+ if ((status = m_dac->GetMethodVarInfo(m_methodDesc,
+ ip,
+ &numVarInfo,
+ &varInfo,
+ &codeOffset)) != S_OK)
+ {
+ // We have signature info indicating that there
+ // are values, but couldn't find any location info.
+ // Optimized routines may have eliminated all
+ // traditional variable locations, so just treat
+ // this as a no-location case just like not being
+ // able to find a matching lifetime.
+ numVarInfo = 0;
+ }
+
+ for (i = 0; i < numVarInfo; i++)
+ {
+ if (varInfo[i].startOffset <= codeOffset &&
+ varInfo[i].endOffset >= codeOffset &&
+ varInfo[i].varNumber == varInfoSlot &&
+ varInfo[i].loc.vlType != ICorDebugInfo::VLT_INVALID)
+ {
+ break;
+ }
+ }
+
+ ULONG64 baseAddr;
+ NativeVarLocation locs[MAX_NATIVE_VAR_LOCS];
+ ULONG32 numLocs;
+
+ if (i >= numVarInfo)
+ {
+ numLocs = 0;
+ }
+ else
+ {
+ numLocs = NativeVarLocations(varInfo[i].loc, &m_context,
+ NumItems(locs), locs);
+ }
+
+ if (numLocs == 1 && !locs[0].contextReg)
+ {
+ baseAddr = TO_CDADDR(locs[0].addr);
+ }
+ else
+ {
+ baseAddr = 0;
+ }
+
+ TypeHandle argType;
+
+ sig->Reset();
+ if (isArg && sigIndex == 0 && sig->HasThis())
+ {
+ argType = TypeHandle(m_methodDesc->GetMethodTable());
+ valueFlags = CLRDATA_VALUE_IS_REFERENCE;
+ }
+ else
+ {
+ // 'this' doesn't show up in the signature but
+ // is present in the indexing so adjust the
+ // index down for methods with 'this'.
+ if (isArg && sig->HasThis())
+ {
+
+ sigIndex--;
+ }
+
+ do
+ {
+ sig->NextArg();
+ }
+ while (sigIndex-- > 0);
+
+ // == FailIfNotLoaded
+ // Will also return null if type is not restored
+ argType = sig->GetLastTypeHandleThrowing(ClassLoader::DontLoadTypes);
+ if (argType.IsNull())
+ {
+ // XXX Microsoft - Sometimes types can't be looked
+ // up and this at least allows the value to be used,
+ // but is it the right behavior?
+ argType = TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U8));
+ valueFlags = 0;
+ }
+ else
+ {
+ valueFlags = GetTypeFieldValueFlags(argType, NULL, 0, false);
+
+ // If this is a primitive variable and the actual size is smaller than what we have been told,
+ // then lower the size so that we won't read in trash memory (e.g. reading 4 bytes for a short).
+ if ((valueFlags & CLRDATA_VALUE_IS_PRIMITIVE) != 0)
+ {
+ if (numLocs == 1)
+ {
+ UINT actualSize = argType.GetSize();
+ if (actualSize < locs[0].size)
+ {
+ locs[0].size = actualSize;
+ }
+ }
+ }
+ }
+ }
+
+ ClrDataValue* value = new (nothrow)
+ ClrDataValue(m_dac,
+ m_appDomain,
+ NULL,
+ valueFlags,
+ argType,
+ baseAddr,
+ numLocs,
+ locs);
+ if (!value)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ *_value = value;
+ return S_OK;
+}