* Implement source/line number support for Exception.StackTrace.
Uses a new helper class (StackTraceSymbols) in System.Diagnostics.StackTrace assembly
to get source/line info for portable PDBs. On Windows both types of pdbs are support;
on xplat only portable PDBs.
The first part of the work is in the GetStackFramesInternal pinvoke to return the neccessary
info needed by the portable pdb reader: MethodToken, assembly path, loaded PE image address
and if in-memory symbol file, the address.
The second part is in the StackFrameHelper in mscorlib. It attempts to load the System.Diagnostics.StackTrace,
gets the new type and creates a delegate to the helper function which is called for each stack
frame.
* Code review feedback.
private void BuildStackFrame(int skipFrames, bool fNeedFileInfo)
{
- StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, null);
-
- StackTrace.GetStackFramesInternal (StackF, 0, null);
-
- int iNumOfFrames = StackF.GetNumberOfFrames();
-
- skipFrames += StackTrace.CalculateFramesToSkip (StackF, iNumOfFrames);
-
- if ((iNumOfFrames - skipFrames) > 0)
+ using (StackFrameHelper StackF = new StackFrameHelper(null))
{
- method = StackF.GetMethodBase (skipFrames);
- offset = StackF.GetOffset (skipFrames);
- ILOffset = StackF.GetILOffset (skipFrames);
- if (fNeedFileInfo)
+ StackF.InitializeSourceInfo(0, fNeedFileInfo, null);
+
+ int iNumOfFrames = StackF.GetNumberOfFrames();
+
+ skipFrames += StackTrace.CalculateFramesToSkip(StackF, iNumOfFrames);
+
+ if ((iNumOfFrames - skipFrames) > 0)
{
- strFileName = StackF.GetFilename (skipFrames);
- iLineNumber = StackF.GetLineNumber (skipFrames);
- iColumnNumber = StackF.GetColumnNumber (skipFrames);
- }
+ method = StackF.GetMethodBase(skipFrames);
+ offset = StackF.GetOffset(skipFrames);
+ ILOffset = StackF.GetILOffset(skipFrames);
+ if (fNeedFileInfo)
+ {
+ strFileName = StackF.GetFilename(skipFrames);
+ iLineNumber = StackF.GetLineNumber(skipFrames);
+ iColumnNumber = StackF.GetColumnNumber(skipFrames);
+ }
+ }
}
}
}
// See the LICENSE file in the project root for more information.
namespace System.Diagnostics {
+ using System;
+ using System.Collections;
using System.Text;
using System.Threading;
- using System;
using System.Security;
using System.Security.Permissions;
using System.IO;
// to the unmanaged definition of the StackFrameHelper class, in
// VM\DebugDebugger.h. The binder will catch some of these layout problems.
[Serializable]
- internal class StackFrameHelper
+ internal class StackFrameHelper : IDisposable
{
[NonSerialized]
private Thread targetThread;
[NonSerialized]
private IntPtr[] rgMethodHandle;
+ private String[] rgAssemblyPath;
+ private IntPtr[] rgLoadedPeAddress;
+ private int[] rgiLoadedPeSize;
+ private IntPtr[] rgInMemoryPdbAddress;
+ private int[] rgiInMemoryPdbSize;
+ // if rgiMethodToken[i] == 0, then don't attempt to get the portable PDB source/info
+ private int[] rgiMethodToken;
private String[] rgFilename;
private int[] rgiLineNumber;
private int[] rgiColumnNumber;
[OptionalField]
private bool[] rgiLastFrameFromForeignExceptionStackTrace;
#endif // FEATURE_EXCEPTIONDISPATCHINFO
+ private GetSourceLineInfoDelegate getSourceLineInfo;
private int iFrameCount;
- private bool fNeedFileInfo;
+ private delegate void GetSourceLineInfoDelegate(string assemblyPath, IntPtr loadedPeAddress, int loadedPeSize,
+ IntPtr inMemoryPdbAddress, int inMemoryPdbSize, int methodToken, int ilOffset,
+ out string sourceFile, out int sourceLine, out int sourceColumn);
+
+ private static Type s_symbolsType = null;
+ private static MethodInfo s_symbolsMethodInfo = null;
+
+ [ThreadStatic]
+ private static int t_reentrancy = 0;
- public StackFrameHelper(bool fNeedFileLineColInfo, Thread target)
+ public StackFrameHelper(Thread target)
{
targetThread = target;
rgMethodBase = null;
rgMethodHandle = null;
+ rgiMethodToken = null;
rgiOffset = null;
rgiILOffset = null;
+ rgAssemblyPath = null;
+ rgLoadedPeAddress = null;
+ rgiLoadedPeSize = null;
+ rgInMemoryPdbAddress = null;
+ rgiInMemoryPdbSize = null;
+ dynamicMethods = null;
rgFilename = null;
rgiLineNumber = null;
rgiColumnNumber = null;
- dynamicMethods = null;
+ getSourceLineInfo = null;
#if FEATURE_EXCEPTIONDISPATCHINFO
rgiLastFrameFromForeignExceptionStackTrace = null;
// limit in the future, then we should expose it in the managed API so applications can
// override it.
iFrameCount = 0;
+ }
- fNeedFileInfo = fNeedFileLineColInfo;
+ //
+ // Initializes the stack trace helper. If fNeedFileInfo is true, initializes rgFilename,
+ // rgiLineNumber and rgiColumnNumber fields using the portable PDB reader if not already
+ // done by GetStackFramesInternal (on Windows for old PDB format).
+ //
+ internal void InitializeSourceInfo(int iSkip, bool fNeedFileInfo, Exception exception)
+ {
+ StackTrace.GetStackFramesInternal(this, iSkip, fNeedFileInfo, exception);
+
+ if (!fNeedFileInfo)
+ return;
+
+ // Check if this function is being reentered because of an exception in the code below
+ if (t_reentrancy > 0)
+ return;
+
+ t_reentrancy++;
+ try
+ {
+ if (s_symbolsMethodInfo == null)
+ {
+ s_symbolsType = Type.GetType("System.Diagnostics.StackTraceSymbols, System.Diagnostics.StackTrace, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", throwOnError: false);
+ if (s_symbolsType == null)
+ return;
+
+ s_symbolsMethodInfo = s_symbolsType.GetMethod("GetSourceLineInfo");
+ if (s_symbolsMethodInfo == null)
+ return;
+ }
+
+ if (getSourceLineInfo == null)
+ {
+ // Create an instance of System.Diagnostics.Stacktrace.Symbols
+ object target = Activator.CreateInstance(s_symbolsType);
+
+ // Create an instance delegate for the GetSourceLineInfo method
+ getSourceLineInfo = (GetSourceLineInfoDelegate)s_symbolsMethodInfo.CreateDelegate(typeof(GetSourceLineInfoDelegate), target);
+ }
+
+ for (int index = 0; index < iFrameCount; index++)
+ {
+ // If there was some reason not to try get get the symbols from the portable PDB reader like the module was
+ // ENC or the source/line info was already retrieved, the method token is 0.
+ if (rgiMethodToken[index] != 0)
+ {
+ getSourceLineInfo(rgAssemblyPath[index], rgLoadedPeAddress[index], rgiLoadedPeSize[index],
+ rgInMemoryPdbAddress[index], rgiInMemoryPdbSize[index], rgiMethodToken[index],
+ rgiILOffset[index], out rgFilename[index], out rgiLineNumber[index], out rgiColumnNumber[index]);
+ }
+ }
+ }
+ finally
+ {
+ t_reentrancy--;
+ }
}
-
+
+ void IDisposable.Dispose()
+ {
+ if (getSourceLineInfo != null)
+ {
+ IDisposable disposable = getSourceLineInfo.Target as IDisposable;
+ if (disposable != null)
+ {
+ disposable.Dispose();
+ }
+ }
+ }
+
[System.Security.SecuritySafeCritical]
public virtual MethodBase GetMethodBase(int i)
{
public virtual int GetOffset(int i) { return rgiOffset[i];}
public virtual int GetILOffset(int i) { return rgiILOffset[i];}
- public virtual String GetFilename(int i) { return rgFilename[i];}
- public virtual int GetLineNumber(int i) { return rgiLineNumber[i];}
- public virtual int GetColumnNumber(int i) { return rgiColumnNumber[i];}
+ public virtual String GetFilename(int i) { return rgFilename == null ? null : rgFilename[i];}
+ public virtual int GetLineNumber(int i) { return rgiLineNumber == null ? 0 : rgiLineNumber[i];}
+ public virtual int GetColumnNumber(int i) { return rgiColumnNumber == null ? 0 : rgiColumnNumber[i];}
#if FEATURE_EXCEPTIONDISPATCHINFO
public virtual bool IsLastFrameFromForeignExceptionStackTrace(int i)
[System.Security.SecuritySafeCritical]
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- internal static extern void GetStackFramesInternal(StackFrameHelper sfh, int iSkip, Exception e);
+ internal static extern void GetStackFramesInternal(StackFrameHelper sfh, int iSkip, bool fNeedFileInfo, Exception e);
internal static int CalculateFramesToSkip(StackFrameHelper StackF, int iNumFrames)
{
-
int iRetVal = 0;
String PackageName = "System.Diagnostics";
// Retrieves an object with stack trace information encoded.
// It leaves out the first "iSkip" lines of the stacktrace.
//
- private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread,
- Exception e)
+ private void CaptureStackTrace(int iSkip, bool fNeedFileInfo, Thread targetThread, Exception e)
{
m_iMethodsToSkip += iSkip;
-
- StackFrameHelper StackF = new StackFrameHelper(fNeedFileInfo, targetThread);
-
- GetStackFramesInternal(StackF, 0, e);
-
- m_iNumOfFrames = StackF.GetNumberOfFrames();
-
- if (m_iMethodsToSkip > m_iNumOfFrames)
- m_iMethodsToSkip = m_iNumOfFrames;
- if (m_iNumOfFrames != 0)
+ using (StackFrameHelper StackF = new StackFrameHelper(targetThread))
{
- frames = new StackFrame[m_iNumOfFrames];
+ StackF.InitializeSourceInfo(0, fNeedFileInfo, e);
- for (int i = 0; i < m_iNumOfFrames; i++)
+ m_iNumOfFrames = StackF.GetNumberOfFrames();
+
+ if (m_iMethodsToSkip > m_iNumOfFrames)
+ m_iMethodsToSkip = m_iNumOfFrames;
+
+ if (m_iNumOfFrames != 0)
{
- bool fDummy1 = true;
- bool fDummy2 = true;
- StackFrame sfTemp = new StackFrame(fDummy1, fDummy2);
+ frames = new StackFrame[m_iNumOfFrames];
+
+ for (int i = 0; i < m_iNumOfFrames; i++)
+ {
+ bool fDummy1 = true;
+ bool fDummy2 = true;
+ StackFrame sfTemp = new StackFrame(fDummy1, fDummy2);
- sfTemp.SetMethodBase(StackF.GetMethodBase(i));
- sfTemp.SetOffset(StackF.GetOffset(i));
- sfTemp.SetILOffset(StackF.GetILOffset(i));
+ sfTemp.SetMethodBase(StackF.GetMethodBase(i));
+ sfTemp.SetOffset(StackF.GetOffset(i));
+ sfTemp.SetILOffset(StackF.GetILOffset(i));
#if FEATURE_EXCEPTIONDISPATCHINFO
sfTemp.SetIsLastFrameFromForeignExceptionStackTrace(StackF.IsLastFrameFromForeignExceptionStackTrace(i));
#endif // FEATURE_EXCEPTIONDISPATCHINFO
- if (fNeedFileInfo)
- {
- sfTemp.SetFileName(StackF.GetFilename (i));
- sfTemp.SetLineNumber(StackF.GetLineNumber(i));
- sfTemp.SetColumnNumber(StackF.GetColumnNumber(i));
- }
+ if (fNeedFileInfo)
+ {
+ sfTemp.SetFileName(StackF.GetFilename(i));
+ sfTemp.SetLineNumber(StackF.GetLineNumber(i));
+ sfTemp.SetColumnNumber(StackF.GetColumnNumber(i));
+ }
- frames[i] = sfTemp;
- }
+ frames[i] = sfTemp;
+ }
- // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace,
- // but this is not desired if building a stack trace from an exception.
- if (e == null)
- m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames);
+ // CalculateFramesToSkip skips all frames in the System.Diagnostics namespace,
+ // but this is not desired if building a stack trace from an exception.
+ if (e == null)
+ m_iMethodsToSkip += CalculateFramesToSkip(StackF, m_iNumOfFrames);
- m_iNumOfFrames -= m_iMethodsToSkip;
- if (m_iNumOfFrames < 0)
- {
- m_iNumOfFrames = 0;
- }
- }
+ m_iNumOfFrames -= m_iMethodsToSkip;
+ if (m_iNumOfFrames < 0)
+ {
+ m_iNumOfFrames = 0;
+ }
+ }
- // In case this is the same object being re-used, set frames to null
- else
- frames = null;
+ // In case this is the same object being re-used, set frames to null
+ else
+ frames = null;
+ }
}
// Property to get the number of frames in the stack trace
FCIMPLEND
-FCIMPL3(void, DebugStackTrace::GetStackFramesInternal,
+FCIMPL4(void, DebugStackTrace::GetStackFramesInternal,
StackFrameHelper* pStackFrameHelperUNSAFE,
INT32 iSkip,
+ CLR_BOOL fNeedFileInfo,
Object* pExceptionUNSAFE
)
{
if (pException == NULL)
{
// Thread is NULL if it's the current thread.
- data.TargetThread = pStackFrameHelper->TargetThread;
+ data.TargetThread = pStackFrameHelper->targetThread;
GetStackFrames(NULL, (void*)-1, &data);
}
else
if (data.cElements != 0)
{
-#ifdef FEATURE_COMINTEROP
- if (pStackFrameHelper->fNeedFileInfo)
+#if defined(FEATURE_ISYM_READER) && defined(FEATURE_COMINTEROP)
+ if (fNeedFileInfo)
{
// Calls to COM up ahead.
EnsureComStarted();
}
-#endif // FEATURE_COMINTEROP
-
- MethodTable *pMT = MscorlibBinder::GetClass(CLASS__METHOD_HANDLE);
- TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(pMT), ELEMENT_TYPE_SZARRAY);
+#endif // FEATURE_ISYM_READER && FEATURE_COMINTEROP
// Allocate memory for the MethodInfo objects
- BASEARRAYREF MethodInfoArray = (BASEARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I, data.cElements);
- //printf("\nmethod table = %X\n", pMT);
-
- SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgMethodHandle), (OBJECTREF)MethodInfoArray,
+ BASEARRAYREF methodInfoArray = (BASEARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgMethodHandle), (OBJECTREF)methodInfoArray,
pStackFrameHelper->GetAppDomain());
// Allocate memory for the Offsets
- OBJECTREF Offsets = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
-
- SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiOffset), (OBJECTREF)Offsets,
+ OBJECTREF offsets = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiOffset), (OBJECTREF)offsets,
pStackFrameHelper->GetAppDomain());
// Allocate memory for the ILOffsets
- OBJECTREF ILOffsets = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ OBJECTREF ilOffsets = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiILOffset), (OBJECTREF)ilOffsets,
+ pStackFrameHelper->GetAppDomain());
- SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiILOffset), (OBJECTREF)ILOffsets,
+ // Allocate memory for the array of assembly file names
+ PTRARRAYREF assemblyPathArray = (PTRARRAYREF) AllocateObjectArray(data.cElements, g_pStringClass);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgAssemblyPath), (OBJECTREF)assemblyPathArray,
pStackFrameHelper->GetAppDomain());
- // if we need Filename, linenumber, etc., then allocate memory for the same
- // Allocate memory for the Filename string objects
- PTRARRAYREF FilenameArray = (PTRARRAYREF) AllocateObjectArray(data.cElements, g_pStringClass);
+ // Allocate memory for the LoadedPeAddress
+ BASEARRAYREF loadedPeAddressArray = (BASEARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgLoadedPeAddress), (OBJECTREF)loadedPeAddressArray,
+ pStackFrameHelper->GetAppDomain());
- SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgFilename), (OBJECTREF)FilenameArray,
+ // Allocate memory for the LoadedPeSize
+ OBJECTREF loadedPeSizeArray = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiLoadedPeSize), (OBJECTREF)loadedPeSizeArray,
pStackFrameHelper->GetAppDomain());
- // Allocate memory for the Offsets
- OBJECTREF LineNumbers = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ // Allocate memory for the InMemoryPdbAddress
+ BASEARRAYREF inMemoryPdbAddressArray = (BASEARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgInMemoryPdbAddress), (OBJECTREF)inMemoryPdbAddressArray,
+ pStackFrameHelper->GetAppDomain());
- SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiLineNumber), (OBJECTREF)LineNumbers,
+ // Allocate memory for the InMemoryPdbSize
+ OBJECTREF inMemoryPdbSizeArray = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiInMemoryPdbSize), (OBJECTREF)inMemoryPdbSizeArray,
pStackFrameHelper->GetAppDomain());
- // Allocate memory for the ILOffsets
- OBJECTREF ColumnNumbers = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ // Allocate memory for the MethodTokens
+ OBJECTREF methodTokens = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiMethodToken), (OBJECTREF)methodTokens,
+ pStackFrameHelper->GetAppDomain());
+
+ // Allocate memory for the Filename string objects
+ PTRARRAYREF filenameArray = (PTRARRAYREF) AllocateObjectArray(data.cElements, g_pStringClass);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgFilename), (OBJECTREF)filenameArray,
+ pStackFrameHelper->GetAppDomain());
- SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiColumnNumber), (OBJECTREF)ColumnNumbers,
+ // Allocate memory for the LineNumbers
+ OBJECTREF lineNumbers = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiLineNumber), (OBJECTREF)lineNumbers,
+ pStackFrameHelper->GetAppDomain());
+
+ // Allocate memory for the ColumnNumbers
+ OBJECTREF columnNumbers = AllocatePrimitiveArray(ELEMENT_TYPE_I4, data.cElements);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiColumnNumber), (OBJECTREF)columnNumbers,
pStackFrameHelper->GetAppDomain());
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
IsLastFrameFromForeignStackTraceFlags = AllocatePrimitiveArray(ELEMENT_TYPE_BOOLEAN, data.cElements);
SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiLastFrameFromForeignExceptionStackTrace), (OBJECTREF)IsLastFrameFromForeignStackTraceFlags,
- pStackFrameHelper->GetAppDomain());
+ pStackFrameHelper->GetAppDomain());
}
else
{
SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->rgiLastFrameFromForeignExceptionStackTrace), NULL,
- pStackFrameHelper->GetAppDomain());
+ pStackFrameHelper->GetAppDomain());
}
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)
if (iNumDynamics)
{
- PTRARRAYREF DynamicDataArray = (PTRARRAYREF) AllocateObjectArray(iNumDynamics, g_pObjectClass);
-
- SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->dynamicMethods), (OBJECTREF)DynamicDataArray,
+ PTRARRAYREF dynamicDataArray = (PTRARRAYREF) AllocateObjectArray(iNumDynamics, g_pObjectClass);
+ SetObjectReference( (OBJECTREF *)&(pStackFrameHelper->dynamicMethods), (OBJECTREF)dynamicDataArray,
pStackFrameHelper->GetAppDomain());
}
int iNumValidFrames = 0;
- for (int i=0; i<data.cElements; i++)
+ for (int i = 0; i < data.cElements; i++)
{
- size_t *pElem = (size_t*)pStackFrameHelper->rgMethodHandle->GetDataPtr();
-
// The managed stacktrace classes always returns typical method definition, so we don't need to bother providing exact instantiation.
// Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(data.pElements[i].pFunc, data.pElements[i].pExactGenericArgsToken, &pExactMethod, &thExactType);
MethodDesc* pFunc = data.pElements[i].pFunc;
pFunc = pFunc->StripMethodInstantiation();
_ASSERTE(pFunc->IsRuntimeMethodHandle());
+ // Method handle
+ size_t *pElem = (size_t*)pStackFrameHelper->rgMethodHandle->GetDataPtr();
pElem[iNumValidFrames] = (size_t)pFunc;
- // native offset
- I4 *pI4 = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiOffset)
- ->GetDirectPointerToNonObjectElements();
- pI4 [iNumValidFrames] = data.pElements[i].dwOffset;
+ // Native offset
+ I4 *pI4 = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiOffset)->GetDirectPointerToNonObjectElements();
+ pI4[iNumValidFrames] = data.pElements[i].dwOffset;
// IL offset
- I4 *pILI4 = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiILOffset)
- ->GetDirectPointerToNonObjectElements();
- pILI4 [iNumValidFrames] = data.pElements[i].dwILOffset;
+ I4 *pILI4 = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiILOffset)->GetDirectPointerToNonObjectElements();
+ pILI4[iNumValidFrames] = data.pElements[i].dwILOffset;
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
if (data.fDoWeHaveAnyFramesFromForeignStackTrace)
}
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)
- BOOL fFileInfoSet = FALSE;
MethodDesc *pMethod = data.pElements[i].pFunc;
// If there are any dynamic methods, and this one is one of them, store
OBJECTREF pResolver = pDMD->GetLCGMethodResolver()->GetManagedResolver();
_ASSERTE(pResolver != NULL);
- ((PTRARRAYREF)pStackFrameHelper->dynamicMethods)->SetAt (iCurDynamic++, pResolver);
+ ((PTRARRAYREF)pStackFrameHelper->dynamicMethods)->SetAt(iCurDynamic++, pResolver);
}
- else
- if (pMethod->GetMethodTable()->Collectible())
+ else if (pMethod->GetMethodTable()->Collectible())
{
OBJECTREF pLoaderAllocator = pMethod->GetMethodTable()->GetLoaderAllocator()->GetExposedObject();
_ASSERTE(pLoaderAllocator != NULL);
- ((PTRARRAYREF)pStackFrameHelper->dynamicMethods)->SetAt (iCurDynamic++, pLoaderAllocator);
+ ((PTRARRAYREF)pStackFrameHelper->dynamicMethods)->SetAt(iCurDynamic++, pLoaderAllocator);
}
}
-#ifdef FEATURE_ISYM_READER
Module *pModule = pMethod->GetModule();
// If it's an EnC method, then don't give back any line info, b/c the PDB is out of date.
#ifdef EnC_SUPPORTED
if (pModule->IsEditAndContinueEnabled())
{
- EditAndContinueModule *eacm = (EditAndContinueModule *) pModule;
+ EditAndContinueModule *eacm = (EditAndContinueModule *)pModule;
if (eacm->GetApplyChangesCount() != 1)
{
- fIsEnc = true;
- }
+ fIsEnc = true;
+ }
}
#endif
-
- // check if the user wants the filenumber, linenumber info...
- if (!fIsEnc && pStackFrameHelper->fNeedFileInfo)
+ BOOL fFileInfoSet = FALSE;
+
+#ifdef FEATURE_ISYM_READER
+ // Check if the user wants the filenumber, linenumber info...
+ if (!fIsEnc && fNeedFileInfo)
{
- // Use the MethodDesc...
ULONG32 sourceLine = 0;
ULONG32 sourceColumn = 0;
WCHAR wszFileName[MAX_LONGPATH];
ULONG32 fileNameLength = 0;
-
{
// Note: we need to enable preemptive GC when accessing the unmanages symbol store.
GCX_PREEMP();
hr = documents [j]->GetURL (MAX_LONGPATH, &fileNameLength, wszFileName);
_ASSERTE ( SUCCEEDED(hr) || (hr == E_OUTOFMEMORY) || (hr == HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY)) );
-
// indicate that the requisite information has been set!
fFileInfoSet = TRUE;
} // GCX_PREEMP()
- if (fFileInfoSet == TRUE)
+ if (fFileInfoSet)
{
// Set the line and column numbers
- I4 *pI4Line = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiLineNumber)
- ->GetDirectPointerToNonObjectElements();
- I4 *pI4Column = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiColumnNumber)
- ->GetDirectPointerToNonObjectElements();
+ I4 *pI4Line = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiLineNumber)->GetDirectPointerToNonObjectElements();
+ pI4Line[iNumValidFrames] = sourceLine;
- pI4Line [iNumValidFrames] = sourceLine;
- pI4Column [iNumValidFrames] = sourceColumn;
+ I4 *pI4Column = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiColumnNumber)->GetDirectPointerToNonObjectElements();
+ pI4Column[iNumValidFrames] = sourceColumn;
// Set the file name
OBJECTREF obj = (OBJECTREF) StringObject::NewString(wszFileName);
}
#endif // FEATURE_ISYM_READER
- if (fFileInfoSet == FALSE)
+ // If the above isym reader code did NOT set the source info either because it is ifdef'ed out (on xplat)
+ // or because the pdb is the new portable format on Windows then set the information needed to called the
+ // portable pdb reader in the StackTraceHelper. The source/line info isn't valid on ENC'ed modules.
+ if (!fFileInfoSet && !fIsEnc)
{
- I4 *pI4Line = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiLineNumber)
- ->GetDirectPointerToNonObjectElements();
- I4 *pI4Column = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiColumnNumber)
- ->GetDirectPointerToNonObjectElements();
- pI4Line [iNumValidFrames] = 0;
- pI4Column [iNumValidFrames] = 0;
+ // Save MethodToken for the function
+ I4 *pMethodToken = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiMethodToken)->GetDirectPointerToNonObjectElements();
+ pMethodToken[iNumValidFrames] = pMethod->GetMemberDef();
- pStackFrameHelper->rgFilename->SetAt(iNumValidFrames, NULL);
-
+ PEFile *pPEFile = pModule->GetFile();
+
+ // Get the address and size of the loaded PE image
+ COUNT_T peSize;
+ PTR_CVOID peAddress = pPEFile->GetLoadedImageContents(&peSize);
+
+ // Save the PE address and size
+ PTR_CVOID *pLoadedPeAddress = (PTR_CVOID *)pStackFrameHelper->rgLoadedPeAddress->GetDataPtr();
+ pLoadedPeAddress[iNumValidFrames] = peAddress;
+
+ I4 *pLoadedPeSize = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiLoadedPeSize)->GetDirectPointerToNonObjectElements();
+ pLoadedPeSize[iNumValidFrames] = (I4)peSize;
+
+ // If there is a in memory symbol stream
+ CGrowableStream* stream = pModule->GetInMemorySymbolStream();
+ if (stream != NULL)
+ {
+ MemoryRange range = stream->GetRawBuffer();
+
+ // Save the in-memory PDB address and size
+ PTR_VOID *pInMemoryPdbAddress = (PTR_VOID *)pStackFrameHelper->rgInMemoryPdbAddress->GetDataPtr();
+ pInMemoryPdbAddress[iNumValidFrames] = range.StartAddress();
+
+ I4 *pInMemoryPdbSize = (I4 *)((I4ARRAYREF)pStackFrameHelper->rgiInMemoryPdbSize)->GetDirectPointerToNonObjectElements();
+ pInMemoryPdbSize[iNumValidFrames] = (I4)range.Size();
+ }
+ else
+ {
+ // Set the pdb path (assembly file name)
+ const SString& assemblyPath = pPEFile->GetPath();
+ if (!assemblyPath.IsEmpty())
+ {
+ OBJECTREF obj = (OBJECTREF)StringObject::NewString(assemblyPath);
+ pStackFrameHelper->rgAssemblyPath->SetAt(iNumValidFrames, obj);
+ }
+ }
}
iNumValidFrames++;
}
pStackFrameHelper->iFrameCount = iNumValidFrames;
-
- /*
- int *pArray = (int*)OBJECTREFToObject(pStackFrameHelper->rgMethodHandle);
- printf("array { MT - %X, size = %d", pArray[0], pArray[1]);
- for (int i=0; i<pArray[1]; i++)
- {
- printf(", method desc in array[%d] = %X", i, pArray[i + 2]);
- }
- printf("}\n");
- */
-
}
else
{
-class StackFrameHelper:public Object
+class StackFrameHelper : public Object
{
// READ ME:
// Modifying the order or fields of this object may require other changes to the
// classlib defintion of the StackFrameHelper class.
public:
- THREADBASEREF TargetThread;
+ THREADBASEREF targetThread;
I4ARRAYREF rgiOffset;
I4ARRAYREF rgiILOffset;
BASEARRAYREF rgMethodBase;
PTRARRAYREF dynamicMethods;
BASEARRAYREF rgMethodHandle;
+ PTRARRAYREF rgAssemblyPath;
+ BASEARRAYREF rgLoadedPeAddress;
+ I4ARRAYREF rgiLoadedPeSize;
+ BASEARRAYREF rgInMemoryPdbAddress;
+ I4ARRAYREF rgiInMemoryPdbSize;
+ // if rgiMethodToken[i] == 0, then don't attempt to get the portable PDB source/info
+ I4ARRAYREF rgiMethodToken;
PTRARRAYREF rgFilename;
I4ARRAYREF rgiLineNumber;
I4ARRAYREF rgiColumnNumber;
+
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
BOOLARRAYREF rgiLastFrameFromForeignExceptionStackTrace;
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)
+
+ OBJECTREF getSourceLineInfo;
int iFrameCount;
- CLR_BOOL fNeedFileInfo;
protected:
StackFrameHelper() {}
}
};
- static FCDECL3(void,
+ static FCDECL4(void,
GetStackFramesInternal,
StackFrameHelper* pStackFrameHelper,
INT32 iSkip,
+ CLR_BOOL fNeedFileInfo,
Object* pException
);
DEFINE_METHOD(STACK_BUILDER_SINK, PRIVATE_PROCESS_MESSAGE,_PrivateProcessMessage, IM_IntPtr_ArrObj_Obj_RefArrObj_RetObj)
#endif
-DEFINE_CLASS_U(Diagnostics, StackFrameHelper, StackFrameHelper)
-DEFINE_FIELD_U(targetThread, StackFrameHelper, TargetThread)
+DEFINE_CLASS_U(Diagnostics, StackFrameHelper, StackFrameHelper)
+DEFINE_FIELD_U(targetThread, StackFrameHelper, targetThread)
DEFINE_FIELD_U(rgiOffset, StackFrameHelper, rgiOffset)
DEFINE_FIELD_U(rgiILOffset, StackFrameHelper, rgiILOffset)
DEFINE_FIELD_U(rgMethodBase, StackFrameHelper, rgMethodBase)
DEFINE_FIELD_U(dynamicMethods, StackFrameHelper, dynamicMethods)
DEFINE_FIELD_U(rgMethodHandle, StackFrameHelper, rgMethodHandle)
+DEFINE_FIELD_U(rgAssemblyPath, StackFrameHelper, rgAssemblyPath)
+DEFINE_FIELD_U(rgLoadedPeAddress, StackFrameHelper, rgLoadedPeAddress)
+DEFINE_FIELD_U(rgiLoadedPeSize, StackFrameHelper, rgiLoadedPeSize)
+DEFINE_FIELD_U(rgInMemoryPdbAddress, StackFrameHelper, rgInMemoryPdbAddress)
+DEFINE_FIELD_U(rgiInMemoryPdbSize, StackFrameHelper, rgiInMemoryPdbSize)
+DEFINE_FIELD_U(rgiMethodToken, StackFrameHelper, rgiMethodToken)
DEFINE_FIELD_U(rgFilename, StackFrameHelper, rgFilename)
DEFINE_FIELD_U(rgiLineNumber, StackFrameHelper, rgiLineNumber)
DEFINE_FIELD_U(rgiColumnNumber, StackFrameHelper, rgiColumnNumber)
#if defined(FEATURE_EXCEPTIONDISPATCHINFO)
DEFINE_FIELD_U(rgiLastFrameFromForeignExceptionStackTrace, StackFrameHelper, rgiLastFrameFromForeignExceptionStackTrace)
#endif // defined(FEATURE_EXCEPTIONDISPATCHINFO)
+DEFINE_FIELD_U(getSourceLineInfo, StackFrameHelper, getSourceLineInfo)
DEFINE_FIELD_U(iFrameCount, StackFrameHelper, iFrameCount)
-DEFINE_FIELD_U(fNeedFileInfo, StackFrameHelper, fNeedFileInfo)
DEFINE_CLASS(STACK_TRACE, Diagnostics, StackTrace)
DEFINE_METHOD(STACK_TRACE, GET_MANAGED_STACK_TRACE_HELPER, GetManagedStackTraceStringHelper, SM_Bool_RetStr)