1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
7 // File: DebuggerModule.cpp
9 // Stuff for tracking DebuggerModules.
11 //*****************************************************************************
14 #include "../inc/common.h"
16 #include "eeconfig.h" // This is here even for retail & free builds...
19 #include "ilformatter.h"
20 #include "debuginfostore.h"
21 #include "../../vm/methoditer.h"
23 #ifndef DACCESS_COMPILE
25 bool DbgIsSpecialILOffset(DWORD offset)
27 LIMITED_METHOD_CONTRACT;
29 return (offset == (ULONG) ICorDebugInfo::PROLOG ||
30 offset == (ULONG) ICorDebugInfo::EPILOG ||
31 offset == (ULONG) ICorDebugInfo::NO_MAPPING);
34 // Helper to use w/ the debug stores.
35 BYTE* InteropSafeNew(void * , size_t cBytes)
37 BYTE * p = new (interopsafe, nothrow) BYTE[cBytes];
43 // This is only fur internal debugging.
46 static void _dumpVarNativeInfo(ICorDebugInfo::NativeVarInfo* vni)
50 LOG((LF_CORDB, LL_INFO1000000, "Var %02d: 0x%04x-0x%04x vlt=",
52 vni->startOffset, vni->endOffset,
55 switch (vni->loc.vlType)
57 case ICorDebugInfo::VLT_REG:
58 LOG((LF_CORDB, LL_INFO1000000, "REG reg=%d\n", vni->loc.vlReg.vlrReg));
61 case ICorDebugInfo::VLT_REG_BYREF:
62 LOG((LF_CORDB, LL_INFO1000000, "REG_BYREF reg=%d\n", vni->loc.vlReg.vlrReg));
65 case ICorDebugInfo::VLT_STK:
66 LOG((LF_CORDB, LL_INFO1000000, "STK reg=%d off=0x%04x (%d)\n",
67 vni->loc.vlStk.vlsBaseReg,
68 vni->loc.vlStk.vlsOffset,
69 vni->loc.vlStk.vlsOffset));
72 case ICorDebugInfo::VLT_STK_BYREF:
73 LOG((LF_CORDB, LL_INFO1000000, "STK_BYREF reg=%d off=0x%04x (%d)\n",
74 vni->loc.vlStk.vlsBaseReg,
75 vni->loc.vlStk.vlsOffset,
76 vni->loc.vlStk.vlsOffset));
79 case ICorDebugInfo::VLT_REG_REG:
80 LOG((LF_CORDB, LL_INFO1000000, "REG_REG reg1=%d reg2=%d\n",
81 vni->loc.vlRegReg.vlrrReg1,
82 vni->loc.vlRegReg.vlrrReg2));
85 case ICorDebugInfo::VLT_REG_STK:
86 LOG((LF_CORDB, LL_INFO1000000, "REG_STK reg=%d basereg=%d off=0x%04x (%d)\n",
87 vni->loc.vlRegStk.vlrsReg,
88 vni->loc.vlRegStk.vlrsStk.vlrssBaseReg,
89 vni->loc.vlRegStk.vlrsStk.vlrssOffset,
90 vni->loc.vlRegStk.vlrsStk.vlrssOffset));
93 case ICorDebugInfo::VLT_STK_REG:
94 LOG((LF_CORDB, LL_INFO1000000, "STK_REG basereg=%d off=0x%04x (%d) reg=%d\n",
95 vni->loc.vlStkReg.vlsrStk.vlsrsBaseReg,
96 vni->loc.vlStkReg.vlsrStk.vlsrsOffset,
97 vni->loc.vlStkReg.vlsrStk.vlsrsOffset,
98 vni->loc.vlStkReg.vlsrReg));
101 case ICorDebugInfo::VLT_STK2:
102 LOG((LF_CORDB, LL_INFO1000000, "STK_STK reg=%d off=0x%04x (%d)\n",
103 vni->loc.vlStk2.vls2BaseReg,
104 vni->loc.vlStk2.vls2Offset,
105 vni->loc.vlStk2.vls2Offset));
108 case ICorDebugInfo::VLT_FPSTK:
109 LOG((LF_CORDB, LL_INFO1000000, "FPSTK reg=%d\n",
110 vni->loc.vlFPstk.vlfReg));
113 case ICorDebugInfo::VLT_FIXED_VA:
114 LOG((LF_CORDB, LL_INFO1000000, "FIXED_VA offset=%d (%d)\n",
115 vni->loc.vlFixedVarArg.vlfvOffset,
116 vni->loc.vlFixedVarArg.vlfvOffset));
121 LOG((LF_CORDB, LL_INFO1000000, "???\n"));
127 #if defined(WIN64EXCEPTIONS)
128 void DebuggerJitInfo::InitFuncletAddress()
138 m_funcletCount = (int)g_pEEInterface->GetFuncletStartOffsets((const BYTE*)m_addrOfCode, NULL, 0);
140 if (m_funcletCount == 0)
142 _ASSERTE(m_rgFunclet == NULL);
146 m_rgFunclet = (DWORD*)(new (interopsafe, nothrow) DWORD[m_funcletCount]);
148 // All bets are off for stepping this method.
149 if (m_rgFunclet == NULL)
155 // This will get the offsets relative to the parent method start as if
156 // the funclet was in contiguous memory (i.e. not hot/cold split).
157 g_pEEInterface->GetFuncletStartOffsets((const BYTE*)m_addrOfCode, m_rgFunclet, m_funcletCount);
161 // DebuggerJitInfo::GetFuncletOffsetByIndex()
163 // Given a funclet index, return its starting offset.
165 // parameters: index - index of the funclet
167 // return value: starting offset of the specified funclet, or -1 if the index is invalid
169 DWORD DebuggerJitInfo::GetFuncletOffsetByIndex(int index)
171 LIMITED_METHOD_CONTRACT;
173 if (index < 0 || index >= m_funcletCount)
178 return m_rgFunclet[index];
182 // DebuggerJitInfo::GetFuncletIndex()
184 // Given an offset or an absolute address, return the index of the funclet containing it.
186 // parameters: offsetOrAddr - an offset or an absolute address in the method
187 // mode - whether the first argument is an offset or an absolute address
189 // return value: the index of the funclet containing the specified offset or address,
190 // or -1 if it's invalid
192 int DebuggerJitInfo::GetFuncletIndex(CORDB_ADDRESS offsetOrAddr, GetFuncletIndexMode mode)
197 if (mode == GFIM_BYOFFSET)
199 offset = (DWORD)offsetOrAddr;
202 // If the address doesn't fall in any of the funclets (or if the
203 // method doesn't have any funclet at all), then return PARENT_METHOD_INDEX.
205 // What if there's an overflow?
207 if (!m_codeRegionInfo.IsMethodAddress((const BYTE *)(mode == GFIM_BYOFFSET ? (size_t)m_codeRegionInfo.OffsetToAddress(offset) : offsetOrAddr)))
209 return PARENT_METHOD_INDEX;
212 if ( ( m_funcletCount == 0 ) ||
213 ( (mode == GFIM_BYOFFSET) && (offset < m_rgFunclet[0]) ) ||
214 ( (mode == GFIM_BYADDRESS) && (offsetOrAddr < (size_t)m_codeRegionInfo.OffsetToAddress(m_rgFunclet[0])) ) )
216 return PARENT_METHOD_INDEX;
219 for (int i = 0; i < m_funcletCount; i++)
221 if (i == (m_funcletCount - 1))
225 else if ( ( (mode == GFIM_BYOFFSET) && (offset < m_rgFunclet[i+1]) ) ||
226 ( (mode == GFIM_BYADDRESS) && (offsetOrAddr < (size_t)m_codeRegionInfo.OffsetToAddress(m_rgFunclet[i+1])) ) )
235 #endif // WIN64EXCEPTIONS
237 // It is entirely possible that we have multiple sequence points for the
238 // same IL offset (because of funclets, optimization, etc.). Just to be
239 // uniform in all cases, let's return the sequence point with the smallest
240 // native offset if fWantFirst is TRUE.
241 #if defined(WIN64EXCEPTIONS)
242 #define ADJUST_MAP_ENTRY(_map, _wantFirst) \
244 for ( ; (_map) > m_sequenceMap && (((_map)-1)->ilOffset == (_map)->ilOffset); (_map)--); \
246 for ( ; (_map) < m_sequenceMap + (m_sequenceMapCount-1) && (((_map)+1)->ilOffset == (_map)->ilOffset); (_map)++);
248 #define ADJUST_MAP_ENTRY(_map, _wantFirst)
251 DebuggerJitInfo::DebuggerJitInfo(DebuggerMethodInfo *minfo, MethodDesc *fd) :
253 m_pLoaderModule(fd->GetLoaderModule()),
254 m_jitComplete(false),
256 m_encBreakpointsApplied(false),
257 #endif //EnC_SUPPORTED
260 m_sizeOfCode(0), m_prevJitInfo(NULL), m_nextJitInfo(NULL),
263 m_sequenceMapCount(0),
265 m_callsiteMapCount(0),
266 m_sequenceMapSorted(false),
267 m_varNativeInfo(NULL), m_varNativeInfoCount(0),
268 m_fAttemptInit(false)
269 #if defined(WIN64EXCEPTIONS)
272 #endif // defined(WIN64EXCEPTIONS)
276 // A DJI is just the debugger's cache of interesting information +
277 // various debugger-specific state for a method (like Enc).
278 // So only be createing DJIs when a debugger is actually attached.
279 // The profiler also piggy-backs on the DJIs.
280 // @Todo - the managed stackwalker in the BCL also builds on DJIs.
281 //_ASSERTE(CORDebuggerAttached() || CORProfilerPresent());
284 m_encVersion = minfo->GetCurrentEnCVersion();
285 _ASSERTE(m_encVersion >= CorDB_DEFAULT_ENC_FUNCTION_VERSION);
286 LOG((LF_CORDB,LL_EVERYTHING, "DJI::DJI : created at 0x%x\n", this));
288 // Debugger doesn't track LightWeight codegen methods.
289 // We should never even be creating a DJI for one.
290 _ASSERTE(!m_fd->IsDynamicMethod());
293 DebuggerILToNativeMap *DebuggerJitInfo::MapILOffsetToMapEntry(SIZE_T offset, BOOL *exact, BOOL fWantFirst)
300 CAN_TAKE_LOCK; // GetSequenceMapCount calls LazyInitBounds() which can eventually
301 // call ExecutionManager::IncrementReader
305 // Ideally we should be able to assert this, since the binary search in this function
306 // assumes that the sequence points are sorted by IL offset (NO_MAPPING, PROLOG, and EPILOG
307 // are actually -1, -2, and -3, respectively). However, the sequence points in pdb's use
308 // -1 to mean "end of the method", which is different from our semantics of using 0.
309 // _ASSERTE(offset != NO_MAPPING && offset != PROLOG && offset != EPILOG);
312 // Binary search for matching map element.
315 DebuggerILToNativeMap *mMin = GetSequenceMap();
316 DebuggerILToNativeMap *mMax = mMin + GetSequenceMapCount();
318 _ASSERTE(m_sequenceMapSorted);
319 _ASSERTE( mMin < mMax ); //otherwise we have no code
328 while (mMin + 1 < mMax)
330 _ASSERTE(mMin>=m_sequenceMap);
331 DebuggerILToNativeMap *mMid = mMin + ((mMax - mMin)>>1);
332 _ASSERTE(mMid>=m_sequenceMap);
334 if (offset == mMid->ilOffset)
340 ADJUST_MAP_ENTRY(mMid, fWantFirst);
343 else if (offset < mMid->ilOffset && mMid->ilOffset != (ULONG) ICorDebugInfo::PROLOG)
353 if (exact && offset == mMin->ilOffset)
357 ADJUST_MAP_ENTRY(mMin, fWantFirst);
362 void DebuggerJitInfo::InitILToNativeOffsetIterator(ILToNativeOffsetIterator &iterator, SIZE_T ilOffset)
366 iterator.Init(this, ilOffset);
370 DebuggerJitInfo::NativeOffset DebuggerJitInfo::MapILOffsetToNative(DebuggerJitInfo::ILOffset ilOffset)
380 NativeOffset resultOffset;
382 DebuggerILToNativeMap *map = MapILOffsetToMapEntry(ilOffset.m_ilOffset, &(resultOffset.m_fExact));
384 #if defined(WIN64EXCEPTIONS)
385 // See if we want the map entry for the parent.
386 if (ilOffset.m_funcletIndex <= PARENT_METHOD_INDEX)
389 PREFIX_ASSUME( map != NULL );
390 LOG((LF_CORDB, LL_INFO10000, "DJI::MILOTN: ilOff 0x%x to nat 0x%x exact:0x%x (Entry IL Off:0x%x)\n",
391 ilOffset.m_ilOffset, map->nativeStartOffset, resultOffset.m_fExact, map->ilOffset));
393 resultOffset.m_nativeOffset = map->nativeStartOffset;
395 #if defined(WIN64EXCEPTIONS)
399 // funcletIndex is guaranteed to be >= 0 at this point.
400 if (ilOffset.m_funcletIndex > (m_funcletCount - 1))
402 resultOffset.m_fExact = FALSE;
403 resultOffset.m_nativeOffset = ((SIZE_T)-1);
407 // Initialize the funclet range.
408 // ASSUMES that funclets are contiguous which they currently are...
409 DWORD funcletStartOffset = GetFuncletOffsetByIndex(ilOffset.m_funcletIndex);
410 DWORD funcletEndOffset;
411 if (ilOffset.m_funcletIndex < (m_funcletCount - 1))
413 funcletEndOffset = GetFuncletOffsetByIndex(ilOffset.m_funcletIndex + 1);
417 funcletEndOffset = (DWORD)m_sizeOfCode;
420 SIZE_T ilTargetOffset = map->ilOffset;
422 DebuggerILToNativeMap *mapEnd = GetSequenceMap() + GetSequenceMapCount();
424 for (; map < mapEnd && map->ilOffset == ilTargetOffset; map++)
426 if ((map->nativeStartOffset >= funcletStartOffset) &&
427 (map->nativeStartOffset < funcletEndOffset))
429 // This is the normal case where the start offset falls in
430 // the range of the funclet.
431 resultOffset.m_nativeOffset = map->nativeStartOffset;
436 if (map == mapEnd || map->ilOffset != ilTargetOffset)
438 resultOffset.m_fExact = FALSE;
439 resultOffset.m_nativeOffset = ((SIZE_T)-1);
443 #endif // WIN64EXCEPTIONS
449 DebuggerJitInfo::ILToNativeOffsetIterator::ILToNativeOffsetIterator()
451 LIMITED_METHOD_CONTRACT;
454 m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET;
455 #ifdef WIN64EXCEPTIONS
456 m_currentILOffset.m_funcletIndex = PARENT_METHOD_INDEX;
460 void DebuggerJitInfo::ILToNativeOffsetIterator::Init(DebuggerJitInfo* dji, SIZE_T ilOffset)
465 m_currentILOffset.m_ilOffset = ilOffset;
466 #ifdef WIN64EXCEPTIONS
467 m_currentILOffset.m_funcletIndex = PARENT_METHOD_INDEX;
470 m_currentNativeOffset = m_dji->MapILOffsetToNative(m_currentILOffset);
473 bool DebuggerJitInfo::ILToNativeOffsetIterator::IsAtEnd()
475 LIMITED_METHOD_CONTRACT;
477 return (m_currentILOffset.m_ilOffset == INVALID_IL_OFFSET);
480 SIZE_T DebuggerJitInfo::ILToNativeOffsetIterator::Current(BOOL* pfExact)
482 LIMITED_METHOD_CONTRACT;
486 *pfExact = m_currentNativeOffset.m_fExact;
488 return m_currentNativeOffset.m_nativeOffset;
491 SIZE_T DebuggerJitInfo::ILToNativeOffsetIterator::CurrentAssertOnlyOne(BOOL* pfExact)
495 SIZE_T nativeOffset = Current(pfExact);
503 void DebuggerJitInfo::ILToNativeOffsetIterator::Next()
505 #if defined(WIN64EXCEPTIONS)
506 NativeOffset tmpNativeOffset;
508 for (m_currentILOffset.m_funcletIndex += 1;
509 m_currentILOffset.m_funcletIndex < m_dji->GetFuncletCount();
510 m_currentILOffset.m_funcletIndex++)
512 tmpNativeOffset = m_dji->MapILOffsetToNative(m_currentILOffset);
513 if (tmpNativeOffset.m_nativeOffset != ((SIZE_T)-1) &&
514 tmpNativeOffset.m_nativeOffset != m_currentNativeOffset.m_nativeOffset)
516 m_currentNativeOffset = tmpNativeOffset;
521 if (m_currentILOffset.m_funcletIndex == m_dji->GetFuncletCount())
523 m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET;
525 #else // !WIN64EXCEPTIONS
526 m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET;
527 #endif // !WIN64EXCEPTIONS
532 // SIZE_T DebuggerJitInfo::MapSpecialToNative(): Maps something like
533 // a prolog to a native offset.
534 // CordDebugMappingResult mapping: Mapping type to be looking for.
535 // SIZE_T which: Which one. <TODO>For now, set to zero. <@todo Later, we'll
536 // change this to some value that we get back from MapNativeToILOffset
537 // to indicate which of the (possibly multiple epilogs) that may
538 // be present.</TODO>
540 SIZE_T DebuggerJitInfo::MapSpecialToNative(CorDebugMappingResult mapping,
549 PRECONDITION(NULL != pfAccurate);
553 LOG((LF_CORDB, LL_INFO10000, "DJI::MSTN map:0x%x which:0x%x\n", mapping, which));
558 DebuggerILToNativeMap *m = GetSequenceMap();
559 DebuggerILToNativeMap *mEnd = m + GetSequenceMapCount();
564 _ASSERTE(m>=GetSequenceMap());
568 if (DbgIsSpecialILOffset(m->ilOffset))
573 _ASSERTE( (mapping == MAPPING_PROLOG &&
574 m->ilOffset == (ULONG) ICorDebugInfo::PROLOG) ||
575 (mapping == MAPPING_EPILOG &&
576 m->ilOffset == (ULONG) ICorDebugInfo::EPILOG) ||
577 ((mapping == MAPPING_NO_INFO || mapping == MAPPING_UNMAPPED_ADDRESS) &&
578 m->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
581 (*pfAccurate) = TRUE;
582 LOG((LF_CORDB, LL_INFO10000, "DJI::MSTN found mapping to nat:0x%x\n",
583 m->nativeStartOffset));
584 return m->nativeStartOffset;
590 LOG((LF_CORDB, LL_INFO10000, "DJI::MSTN No mapping found :(\n"));
591 (*pfAccurate) = FALSE;
596 #if defined(WIN64EXCEPTIONS)
598 // DebuggerJitInfo::MapILOffsetToNativeForSetIP()
600 // This function maps an IL offset to a native offset, taking into account cloned finallys and nested EH clauses.
602 // parameters: offsetILTo - the destination IP, in IL offset
603 // funcletIndexFrom - the funclet index of the source IP
604 // pEHRT - tree structure for keeping track of EH clause information
605 // pExact - pointer for returning whether the mapping is exact or not
607 // return value: destination IP, in native offset
609 SIZE_T DebuggerJitInfo::MapILOffsetToNativeForSetIP(SIZE_T offsetILTo, int funcletIndexFrom,
610 EHRangeTree* pEHRT, BOOL* pExact)
621 DebuggerILToNativeMap* pMap = MapILOffsetToMapEntry(offsetILTo, pExact, TRUE);
622 DebuggerILToNativeMap* pMapEnd = GetSequenceMap() + GetSequenceMapCount();
624 _ASSERTE(pMap == m_sequenceMap ||
625 (pMap - 1)->ilOffset == (ULONG)ICorDebugInfo::NO_MAPPING ||
626 (pMap - 1)->ilOffset == (ULONG)ICorDebugInfo::PROLOG ||
627 (pMap - 1)->ilOffset == (ULONG)ICorDebugInfo::EPILOG ||
628 pMap->ilOffset > (pMap - 1)->ilOffset);
630 SIZE_T offsetNatTo = pMap->nativeStartOffset;
632 if (m_funcletCount == 0 ||
634 FAILED(pEHRT->m_hrInit))
639 // Multiple sequence points may have the same IL offset, which means that the code is duplicated in
640 // multiple funclets and/or in the parent method. If the destination offset maps to multiple sequence
641 // points (and hence to multiple funclets), we try to find the a sequence point which is in the same
642 // funclet as the source sequence point. If we can't find one, then the operation is going to fail
643 // anyway, so we just return the first sequence point we find.
644 for (DebuggerILToNativeMap* pMapCur = pMap + 1;
645 (pMapCur < pMapEnd) && (pMapCur->ilOffset == pMap->ilOffset);
648 int funcletIndexTo = GetFuncletIndex(pMapCur->nativeStartOffset, DebuggerJitInfo::GFIM_BYOFFSET);
649 if (funcletIndexFrom == funcletIndexTo)
651 return pMapCur->nativeStartOffset;
659 // void DebuggerJitInfo::MapILRangeToMapEntryRange(): MIRTMER
660 // calls MapILOffsetToNative for the startOffset (putting the
661 // result into start), and the endOffset (putting the result into end).
662 // SIZE_T startOffset: IL offset from beginning of function.
663 // SIZE_T endOffset: IL offset from beginngin of function,
664 // or zero to indicate that the end of the function should be used.
665 // DebuggerILToNativeMap **start: Contains start & end
666 // native offsets that correspond to startOffset. Set to NULL if
667 // there is no mapping info.
668 // DebuggerILToNativeMap **end: Contains start & end native
669 // offsets that correspond to endOffset. Set to NULL if there
670 // is no mapping info.
671 void DebuggerJitInfo::MapILRangeToMapEntryRange(SIZE_T startOffset,
673 DebuggerILToNativeMap **start,
674 DebuggerILToNativeMap **end)
684 LOG((LF_CORDB, LL_INFO1000000,
685 "DJI::MIRTMER: IL 0x%04x-0x%04x\n",
686 startOffset, endOffset));
688 if (GetSequenceMapCount() == 0)
695 *start = MapILOffsetToMapEntry(startOffset);
698 // end points to the last range that endOffset maps to, not past
700 // We want to return the last IL, and exclude the epilog
703 *end = GetSequenceMap() + GetSequenceMapCount() - 1;
704 _ASSERTE(*end>=m_sequenceMap);
706 while ( ((*end)->ilOffset == (ULONG) ICorDebugInfo::EPILOG||
707 (*end)->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
708 && (*end) > m_sequenceMap)
711 _ASSERTE(*end>=m_sequenceMap);
716 *end = MapILOffsetToMapEntry(endOffset - 1, NULL
719 _ASSERTE(*end>=m_sequenceMap);
722 LOG((LF_CORDB, LL_INFO1000000,
723 "DJI::MIRTMER: IL 0x%04x-0x%04x --> 0x%04x 0x%08x-0x%08x\n"
724 " --> 0x%04x 0x%08x-0x%08x\n",
725 startOffset, endOffset,
727 (*start)->nativeStartOffset, (*start)->nativeEndOffset,
729 (*end)->nativeStartOffset, (*end)->nativeEndOffset));
732 // @dbgtodo Microsoft inspection: This function has been replicated in DacDbiStructures so
733 // this version can be deleted when inspection is complete.
735 // DWORD DebuggerJitInfo::MapNativeOffsetToIL(): Given a native
736 // offset for the DebuggerJitInfo, compute
737 // the IL offset from the beginning of the same method.
738 // Returns: Offset of the IL instruction that contains
739 // the native offset,
740 // SIZE_T nativeOffset: [IN] Native Offset
741 // CorDebugMappingResult *map: [OUT] explains the
742 // quality of the matching & special cases
743 // SIZE_T which: It's possible to have multiple EPILOGs, or
744 // multiple unmapped regions within a method. This opaque value
745 // specifies which special region we're talking about. This
746 // param has no meaning if map & (MAPPING_EXACT|MAPPING_APPROXIMATE)
747 // Basically, this gets handed back to MapSpecialToNative, later.
748 DWORD DebuggerJitInfo::MapNativeOffsetToIL(SIZE_T nativeOffsetToMap,
749 CorDebugMappingResult *map,
758 PRECONDITION(map != NULL);
759 PRECONDITION(which != NULL);
763 DWORD nativeOffset = (DWORD)nativeOffsetToMap;
766 DebuggerILToNativeMap *m = GetSequenceMap();
767 DebuggerILToNativeMap *mEnd = m + GetSequenceMapCount();
769 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: nativeOffset = 0x%x\n", nativeOffset));
775 _ASSERTE(m>=m_sequenceMap);
778 if (m->ilOffset == (ULONG) ICorDebugInfo::PROLOG )
779 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: m->natStart:0x%x m->natEnd:0x%x il:PROLOG\n", m->nativeStartOffset, m->nativeEndOffset));
780 else if (m->ilOffset == (ULONG) ICorDebugInfo::EPILOG )
781 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: m->natStart:0x%x m->natEnd:0x%x il:EPILOG\n", m->nativeStartOffset, m->nativeEndOffset));
782 else if (m->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
783 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: m->natStart:0x%x m->natEnd:0x%x il:NO MAP\n", m->nativeStartOffset, m->nativeEndOffset));
785 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: m->natStart:0x%x m->natEnd:0x%x il:0x%x src:0x%x\n", m->nativeStartOffset, m->nativeEndOffset, m->ilOffset, m->source));
788 if (m->ilOffset == (ULONG) ICorDebugInfo::PROLOG ||
789 m->ilOffset == (ULONG) ICorDebugInfo::EPILOG ||
790 m->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
795 if (nativeOffset >= m->nativeStartOffset
796 && ((m->nativeEndOffset == 0 &&
797 m->ilOffset != (ULONG) ICorDebugInfo::PROLOG)
798 || nativeOffset < m->nativeEndOffset))
800 ULONG ilOff = m->ilOffset;
802 if( m->ilOffset == (ULONG) ICorDebugInfo::PROLOG )
804 if (skipPrologs && nativeOffset < m->nativeEndOffset)
806 // If the caller requested to skip prologs, we simply restart the walk
807 // with the offset set to the end of the prolog.
808 nativeOffset = m->nativeEndOffset;
813 (*map) = MAPPING_PROLOG;
814 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: MAPPING_PROLOG\n"));
817 else if (m->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
820 (*map) = MAPPING_UNMAPPED_ADDRESS ;
821 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_"
822 "UNMAPPED_ADDRESS\n"));
824 else if( m->ilOffset == (ULONG) ICorDebugInfo::EPILOG )
827 (*map) = MAPPING_EPILOG;
828 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_EPILOG\n"));
830 else if (nativeOffset == m->nativeStartOffset)
832 (*map) = MAPPING_EXACT;
833 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_EXACT\n"));
837 (*map) = MAPPING_APPROXIMATE;
838 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_"
848 (*map) = MAPPING_NO_INFO;
849 LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:NO_INFO\n"));
853 /******************************************************************************
855 ******************************************************************************/
856 DebuggerJitInfo::~DebuggerJitInfo()
858 TRACE_FREE(m_sequenceMap);
859 if (m_sequenceMap != NULL)
861 DeleteInteropSafe(((BYTE *)m_sequenceMap));
864 TRACE_FREE(m_varNativeInfo);
865 if (m_varNativeInfo != NULL)
867 DeleteInteropSafe(m_varNativeInfo);
870 #if defined(WIN64EXCEPTIONS)
873 DeleteInteropSafe(m_rgFunclet);
876 #endif // WIN64EXCEPTIONS
880 // Trash pointers to garbage.
881 // Don't null out since there may be runtime checks against NULL.
882 // Set to a non-null random pointer value that will cause an immediate AV on deref.
883 m_fd = (MethodDesc*) 0x1;
884 m_methodInfo = (DebuggerMethodInfo*) 0x1;
885 m_prevJitInfo = (DebuggerJitInfo*) 0x01;
886 m_nextJitInfo = (DebuggerJitInfo*) 0x01;
890 LOG((LF_CORDB,LL_EVERYTHING, "DJI::~DJI : deleted at 0x%p\n", this));
893 // Lazy initialize the Debugger-Jit-Info
894 void DebuggerJitInfo::LazyInitBounds()
901 PRECONDITION(ThisMaybeHelperThread());
902 PRECONDITION(!g_pDebugger->HasDebuggerDataLock());
905 LOG((LF_CORDB, LL_EVERYTHING, "DJI::LazyInitBounds: this=0x%x m_fAttemptInit %s\n", this, m_fAttemptInit == true ? "true": "false"));
907 // Only attempt lazy-init once
915 LOG((LF_CORDB, LL_EVERYTHING, "DJI::LazyInitBounds: this=0x%x Initing\n", this));
917 // Should have already been jitted
918 _ASSERTE(this->m_jitComplete);
920 MethodDesc * mdesc = this->m_fd;
921 DebugInfoRequest request;
923 _ASSERTE(this->m_addrOfCode != NULL); // must have address to disambguate the Enc cases.
924 // Caller already resolved generics when they craeted the DJI, so we don't need to repeat.
925 // Note the MethodDesc may not yet have the jitted info, so we'll also use the starting address we got in the jit complete callback.
926 request.InitFromStartingAddr(mdesc, (PCODE)this->m_addrOfCode);
930 ICorDebugInfo::OffsetMapping *pMap = NULL;
932 ICorDebugInfo::NativeVarInfo *pVars = NULL;
934 BOOL fSuccess = DebugInfoManager::GetBoundariesAndVars(
936 InteropSafeNew, NULL, // allocator
940 LOG((LF_CORDB,LL_EVERYTHING, "DJI::LazyInitBounds: this=0x%x GetBoundariesAndVars success=0x%x\n", this, fSuccess));
942 Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
948 this->SetBoundaries(cMap, pMap);
949 this->SetVars(cVars, pVars);
951 m_fAttemptInit = true;
955 DeleteInteropSafe(pMap);
956 DeleteInteropSafe(pVars);
958 // DebuggerDataLockHolder out of scope - release implied
962 LOG((LF_CORDB,LL_WARNING, "DJI::LazyInitBounds: this=0x%x Exception was thrown and caught\n", this));
963 // Just catch the exception. The DJI maps may or may-not be intialized,
964 // but they should still be in a consistent state, so we should be ok.
966 EX_END_CATCH(SwallowAllExceptions)
969 /******************************************************************************
970 * SetVars() takes ownership of pVars
971 ******************************************************************************/
972 void DebuggerJitInfo::SetVars(ULONG32 cVars, ICorDebugInfo::NativeVarInfo *pVars)
974 LIMITED_METHOD_CONTRACT;
976 _ASSERTE(m_varNativeInfo == NULL);
978 m_varNativeInfo = pVars;
979 m_varNativeInfoCount = cVars;
981 LOG((LF_CORDB, LL_INFO1000000, "D::sV: var count is %d\n",
982 m_varNativeInfoCount));
985 for (unsigned int i = 0; i < m_varNativeInfoCount; i++)
987 ICorDebugInfo::NativeVarInfo* vni = &(m_varNativeInfo[i]);
988 _dumpVarNativeInfo(vni);
993 CHECK DebuggerJitInfo::Check() const
995 LIMITED_METHOD_CONTRACT;
1000 // Invariants for a DebuggerJitInfo
1001 // These should always be true at any well defined point.
1002 CHECK DebuggerJitInfo::Invariant() const
1004 LIMITED_METHOD_CONTRACT;
1005 CHECK((m_sequenceMapCount == 0) == (m_sequenceMap == NULL));
1006 CHECK(m_methodInfo != NULL);
1007 CHECK(m_fd != NULL);
1013 #if !defined(DACCESS_COMPILE)
1014 /******************************************************************************
1015 * SetBoundaries() takes ownership of pMap
1016 ******************************************************************************/
1017 void DebuggerJitInfo::SetBoundaries(ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap)
1024 PRECONDITION(CheckPointer(this));
1028 LOG((LF_CORDB,LL_EVERYTHING, "DJI::SetBoundaries: this=0x%x cMap=0x%x pMap=0x%x\n", this, cMap, pMap));
1029 _ASSERTE((cMap == 0) == (pMap == NULL));
1030 _ASSERTE(m_sequenceMap == NULL);
1037 // We assume that the map is sorted by native offset
1040 for(ICorDebugInfo::OffsetMapping * pEntry = pMap;
1041 pEntry < (pMap + cMap - 1);
1044 _ASSERTE(pEntry->nativeOffset <= (pEntry+1)->nativeOffset);
1050 // <TODO>@todo perf: allocating these on the heap is slow. We could do
1051 // better knowing that these live for the life of the run, just
1052 // like the DebuggerJitInfo's.</TODO>
1054 m_sequenceMap = (DebuggerILToNativeMap *)new (interopsafe) DebuggerILToNativeMap[cMap];
1055 LOG((LF_CORDB,LL_EVERYTHING, "DJI::SetBoundaries: this=0x%x m_sequenceMap=0x%x\n", this, m_sequenceMap));
1056 _ASSERTE(m_sequenceMap != NULL); // we'll throw on null
1058 m_sequenceMapCount = cMap;
1060 DebuggerILToNativeMap *m = m_sequenceMap;
1062 // For the instrumented-IL case, we need to remove all duplicate entries.
1063 // So we keep a record of the last old IL offset. If the current old IL
1064 // offset is the same as the last old IL offset, we remove it.
1065 // Pick a unique initial value (-10) so that the 1st doesn't accidentally match.
1066 int ilPrevOld = -10;
1068 InstrumentedILOffsetMapping mapping =
1069 m_methodInfo->GetRuntimeModule()->GetInstrumentedILOffsetMapping(m_methodInfo->m_token);
1072 // <TODO>@todo perf: we could do the vast majority of this
1073 // post-processing work the first time the sequence point map is
1074 // demanded. That would allow us to simply hold the raw array for
1075 // 95% of the functions jitted while debugging, and 100% of them
1076 // when just running/tracking.</TODO>
1077 const DWORD call_inst = (DWORD)ICorDebugInfo::CALL_INSTRUCTION;
1078 for(ULONG32 idxJitMap = 0; idxJitMap < cMap; idxJitMap++)
1080 const ICorDebugInfo::OffsetMapping * const pMapEntry = &pMap[idxJitMap];
1081 _ASSERTE(m >= m_sequenceMap);
1082 _ASSERTE(m < m_sequenceMap + m_sequenceMapCount);
1084 ilLast = max((int)ilLast, (int)pMapEntry->ilOffset);
1086 // Simply copy everything over, since we translate to
1087 // CorDebugMappingResults immediately prior to handing
1089 m->nativeStartOffset = pMapEntry->nativeOffset;
1090 m->ilOffset = pMapEntry->ilOffset;
1091 m->source = pMapEntry->source;
1093 // Keep in mind that if we have an instrumented code translation
1094 // table, we may have asked for completely different IL offsets
1095 // than the user thinks we did.....
1097 // If we did instrument, then we can't have any sequence points that
1098 // are "in-between" the old-->new map that the profiler gave us.
1100 // (6 old -> 36 new)
1101 // (8 old -> 50 new)
1102 // And the jit gives us an entry for 44 new, that will map back to 6 old.
1103 // Since the map can only have one entry for 6 old, we remove 44 new.
1104 if (m_methodInfo->HasInstrumentedILMap())
1106 int ilThisOld = m_methodInfo->TranslateToInstIL(&mapping,
1107 pMapEntry->ilOffset,
1108 bInstrumentedToOriginal);
1110 if (ilThisOld == ilPrevOld)
1112 // If this translated to the same old IL offset as the last entry,
1113 // then this is "in between". Skip it.
1114 m_sequenceMapCount--; // one less seq point in the DJI's map
1117 m->ilOffset = ilThisOld;
1118 ilPrevOld = ilThisOld;
1121 if (m > m_sequenceMap && (m->source & call_inst) != call_inst)
1123 DebuggerILToNativeMap *last = m-1;
1124 if ((last->source & call_inst) == call_inst)
1125 last = (last > m_sequenceMap) ? last - 1 : NULL;
1127 if (last && (last->source & call_inst) != call_inst && m->ilOffset == last->ilOffset)
1129 // JIT gave us an extra entry (probably zero), so mush
1130 // it into the one we've already got.
1131 // <TODO> Why does this happen?</TODO>
1132 m_sequenceMapCount--;
1138 // Move to next entry in the debugger's table
1142 DeleteInteropSafe(pMap);
1144 _ASSERTE(m == m_sequenceMap + m_sequenceMapCount);
1148 // Set nativeEndOffset in debugger's il->native map
1149 // Do this before we resort by IL.
1151 for(i = 0; i < m_sequenceMapCount - 1; i++)
1153 // We need to not use CALL_INSTRUCTION's IL start offset.
1154 unsigned int j = i + 1;
1155 while ((m_sequenceMap[j].source & call_inst) == call_inst && j < m_sequenceMapCount-1)
1158 m_sequenceMap[i].nativeEndOffset = m_sequenceMap[j].nativeStartOffset;
1161 m_sequenceMap[i].nativeEndOffset = 0;
1162 m_sequenceMap[i].source = (ICorDebugInfo::SourceTypes)
1163 ((DWORD) m_sequenceMap[i].source |
1164 (DWORD)ICorDebugInfo::NATIVE_END_OFFSET_UNKNOWN);
1166 // Now resort by IL.
1167 MapSortIL isort(m_sequenceMap, m_sequenceMapCount);
1171 m_sequenceMapSorted = true;
1173 m_callsiteMapCount = m_sequenceMapCount;
1174 while (m_sequenceMapCount > 0 && (m_sequenceMap[m_sequenceMapCount-1].source & call_inst) == call_inst)
1175 m_sequenceMapCount--;
1177 m_callsiteMap = m_sequenceMap + m_sequenceMapCount;
1178 m_callsiteMapCount -= m_sequenceMapCount;
1180 LOG((LF_CORDB, LL_INFO100000, "DJI::SetBoundaries: this=0x%x boundary count is %d (%d callsites)\n",
1181 this, m_sequenceMapCount, m_callsiteMapCount));
1184 for (unsigned int count = 0; count < m_sequenceMapCount + m_callsiteMapCount; count++)
1186 if( m_sequenceMap[count].ilOffset ==
1187 (ULONG) ICorDebugInfo::PROLOG )
1188 LOG((LF_CORDB, LL_INFO1000000,
1189 "D::sB: PROLOG --> 0x%08x -- 0x%08x",
1190 m_sequenceMap[count].nativeStartOffset,
1191 m_sequenceMap[count].nativeEndOffset));
1192 else if ( m_sequenceMap[count].ilOffset ==
1193 (ULONG) ICorDebugInfo::EPILOG )
1194 LOG((LF_CORDB, LL_INFO1000000,
1195 "D::sB: EPILOG --> 0x%08x -- 0x%08x",
1196 m_sequenceMap[count].nativeStartOffset,
1197 m_sequenceMap[count].nativeEndOffset));
1198 else if ( m_sequenceMap[count].ilOffset ==
1199 (ULONG) ICorDebugInfo::NO_MAPPING )
1200 LOG((LF_CORDB, LL_INFO1000000,
1201 "D::sB: NO MAP --> 0x%08x -- 0x%08x",
1202 m_sequenceMap[count].nativeStartOffset,
1203 m_sequenceMap[count].nativeEndOffset));
1205 LOG((LF_CORDB, LL_INFO1000000,
1206 "D::sB: 0x%04x (Real:0x%04x) --> 0x%08x -- 0x%08x",
1207 m_sequenceMap[count].ilOffset,
1208 m_methodInfo->TranslateToInstIL(&mapping,
1209 m_sequenceMap[count].ilOffset,
1210 bOriginalToInstrumented),
1211 m_sequenceMap[count].nativeStartOffset,
1212 m_sequenceMap[count].nativeEndOffset));
1214 LOG((LF_CORDB, LL_INFO1000000, " Src:0x%x\n", m_sequenceMap[count].source));
1219 #endif // !DACCESS_COMPILE
1221 // Init a DJI after it's jitted.
1222 void DebuggerJitInfo::Init(TADDR newAddress)
1224 // Shouldn't initialize while holding the lock b/c intialzing may call functions that lock,
1225 // and thus we'd have a locking violation.
1226 _ASSERTE(!g_pDebugger->HasDebuggerDataLock());
1228 this->m_addrOfCode = (ULONG_PTR)PTR_TO_CORDB_ADDRESS((BYTE*) newAddress);
1229 this->m_jitComplete = true;
1231 this->m_codeRegionInfo.InitializeFromStartAddress(PINSTRToPCODE((TADDR)this->m_addrOfCode));
1232 this->m_sizeOfCode = this->m_codeRegionInfo.getSizeOfTotalCode();
1234 this->m_encVersion = this->m_methodInfo->GetCurrentEnCVersion();
1236 #if defined(WIN64EXCEPTIONS)
1237 this->InitFuncletAddress();
1238 #endif // WIN64EXCEPTIONS
1240 LOG((LF_CORDB,LL_INFO10000,"De::JITCo:Got DJI 0x%p(V %d),"
1241 "Hot section from 0x%p to 0x%p "
1242 "Cold section from 0x%p to 0x%p "
1243 "varCount=%d seqCount=%d\n",
1244 this, this->m_encVersion,
1245 this->m_codeRegionInfo.getAddrOfHotCode(),
1246 this->m_codeRegionInfo.getAddrOfHotCode() + this->m_codeRegionInfo.getSizeOfHotCode(),
1247 this->m_codeRegionInfo.getAddrOfColdCode(),
1248 this->m_codeRegionInfo.getAddrOfColdCode() + this->m_codeRegionInfo.getSizeOfColdCode(),
1249 (ULONG)this->m_addrOfCode,
1250 (ULONG)this->m_addrOfCode+(ULONG)this->m_sizeOfCode,
1251 this->GetVarNativeInfoCount(),
1252 this->GetSequenceMapCount()));
1254 #if defined(LOGGING)
1255 for (unsigned int i = 0; i < this->GetSequenceMapCount(); i++)
1257 LOG((LF_CORDB, LL_INFO10000, "De::JITCo: seq map 0x%x - "
1258 "IL offset 0x%x native start offset 0x%x native end offset 0x%x source 0x%x\n",
1259 i, this->GetSequenceMap()[i].ilOffset,
1260 this->GetSequenceMap()[i].nativeStartOffset,
1261 this->GetSequenceMap()[i].nativeEndOffset,
1262 this->GetSequenceMap()[i].source));
1268 /******************************************************************************
1270 ******************************************************************************/
1271 ICorDebugInfo::SourceTypes DebuggerJitInfo::GetSrcTypeFromILOffset(SIZE_T ilOffset)
1282 DebuggerILToNativeMap *pMap = MapILOffsetToMapEntry(ilOffset, &exact);
1284 LOG((LF_CORDB, LL_INFO100000, "DJI::GSTFILO: for il 0x%x, got entry 0x%p,"
1285 "(il 0x%x) nat 0x%x to 0x%x, SourceTypes 0x%x, exact:%x\n", ilOffset, pMap,
1286 pMap->ilOffset, pMap->nativeStartOffset, pMap->nativeEndOffset, pMap->source,
1291 return ICorDebugInfo::SOURCE_TYPE_INVALID;
1294 return pMap->source;
1297 /******************************************************************************
1299 ******************************************************************************/
1300 DebuggerMethodInfo::~DebuggerMethodInfo()
1311 DeleteJitInfoList();
1313 LOG((LF_CORDB,LL_EVERYTHING, "DMI::~DMI : deleted at 0x%p\n", this));
1316 // Translate between old & new offsets (w/ respect to Instrumented IL).
1318 // Don't interpolate
1319 ULONG32 DebuggerMethodInfo::TranslateToInstIL(const InstrumentedILOffsetMapping * pMapping,
1323 LIMITED_METHOD_CONTRACT;
1326 SIZE_T cMap = pMapping->GetCount();
1327 // some negative IL offsets have special meaning. Don't translate
1328 // those (just return as is). See ICorDebugInfo::MappingTypes
1329 if ((cMap == 0) || (offOrig < 0))
1334 ARRAY_PTR_COR_IL_MAP rgMap = pMapping->GetOffsets();
1337 // - map is sorted in increasing order by both old & new
1341 // Translate: old --> new
1343 // Treat it as prolog if offOrig is not in remapping range
1344 if ((offOrig < rgMap[0].oldOffset) || (offOrig == (ULONG32)ICorDebugInfo::PROLOG))
1346 return (ULONG32)ICorDebugInfo::PROLOG;
1349 if (offOrig == (ULONG32)ICorDebugInfo::EPILOG)
1351 return (ULONG32)ICorDebugInfo::EPILOG;
1354 if (offOrig == (ULONG32)ICorDebugInfo::NO_MAPPING)
1356 return (ULONG32)ICorDebugInfo::NO_MAPPING;
1359 for(iMap = 1; iMap < cMap; iMap++)
1361 if (offOrig < rgMap[iMap].oldOffset)
1362 return rgMap[iMap-1].newOffset;
1365 return rgMap[iMap - 1].newOffset;
1369 // Translate: new --> old
1371 // Treat it as prolog if offOrig is not in remapping range
1372 if ((offOrig < rgMap[0].newOffset) || (offOrig == (ULONG32)ICorDebugInfo::PROLOG))
1374 return (ULONG32)ICorDebugInfo::PROLOG;
1377 if (offOrig == (ULONG32)ICorDebugInfo::EPILOG)
1379 return (ULONG32)ICorDebugInfo::EPILOG;
1382 if (offOrig == (ULONG32)ICorDebugInfo::NO_MAPPING)
1384 return (ULONG32)ICorDebugInfo::NO_MAPPING;
1387 for(iMap = 1; iMap < cMap; iMap++)
1389 if (offOrig < rgMap[iMap].newOffset)
1390 return rgMap[iMap-1].oldOffset;
1393 return rgMap[iMap - 1].oldOffset;
1397 /******************************************************************************
1398 * Constructor for DebuggerMethodInfo
1399 ******************************************************************************/
1400 DebuggerMethodInfo::DebuggerMethodInfo(Module *module, mdMethodDef token) :
1401 m_currentEnCVersion(CorDB_DEFAULT_ENC_FUNCTION_VERSION),
1404 m_prevMethodInfo(NULL),
1405 m_nextMethodInfo(NULL),
1406 m_latestJitInfo(NULL),
1407 m_fHasInstrumentedILMap(false)
1413 WRAPPER(GC_TRIGGERS);
1418 LOG((LF_CORDB,LL_EVERYTHING, "DMI::DMI : created at 0x%p\n", this));
1420 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1422 DebuggerModule * pModule = GetPrimaryModule();
1424 m_fJMCStatus = false;
1426 // If there's no module, then this isn't a JMC function.
1427 // This can happen since DMIs are created for debuggable code, and
1428 // Modules are only created if a debugger is actually attached.
1429 if (pModule != NULL)
1431 // Use the accessor so that we keep the module's count properly updated.
1432 SetJMCStatus(pModule->GetRuntimeModule()->GetJMCStatus());
1437 /******************************************************************************
1438 * Get the primary debugger module for this DMI. This is 1:1 w/ an EE Module.
1439 ******************************************************************************/
1440 DebuggerModule* DebuggerMethodInfo::GetPrimaryModule()
1450 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1452 DebuggerModuleTable * pTable = g_pDebugger->GetModuleTable();
1454 // If we're tracking debug info but no debugger's attached, then
1455 // we won't have a table for the modules yet.
1459 DebuggerModule * pModule = pTable->GetModule(GetRuntimeModule());
1460 if (pModule == NULL)
1462 // We may be missing the module even if we have the table.
1463 // 1.) If there's no debugger attached (so we're not getting ModuleLoad events).
1464 // 2.) If we're asking for this while in DllMain of the module we're currently loading,
1465 // we won't have gotten the ModuleLoad event yet.
1469 // Only give back primary modules...
1470 DebuggerModule * p2 = pModule->GetPrimaryModule();
1471 _ASSERTE(p2 != NULL);
1476 /******************************************************************************
1477 * Get the runtime module for this DMI
1478 ******************************************************************************/
1479 Module * DebuggerMethodInfo::GetRuntimeModule()
1481 LIMITED_METHOD_CONTRACT;
1486 #endif // !DACCESS_COMPILE
1489 //---------------------------------------------------------------------------------------
1491 // Find the DebuggerJitInfo (DJI) for the given MethodDesc and native start address.
1492 // We need the native start address because generic methods may have multiple instances
1493 // of jitted code. This function does not create the DJI if it does not already exist.
1496 // pMD - the MD to lookup; must be non-NULL
1497 // addrNativeStartAddr - the native start address of jitted code
1500 // Returns the DJI corresponding to the specified MD and native start address.
1501 // NULL if the DJI is not found.
1504 DebuggerJitInfo * DebuggerMethodInfo::FindJitInfo(MethodDesc * pMD,
1505 TADDR addrNativeStartAddr)
1513 PRECONDITION(pMD != NULL);
1518 DebuggerJitInfo * pCheck = m_latestJitInfo;
1519 while (pCheck != NULL)
1521 if ( (pCheck->m_fd == dac_cast<PTR_MethodDesc>(pMD)) &&
1522 (pCheck->m_addrOfCode == addrNativeStartAddr) )
1527 pCheck = pCheck->m_prevJitInfo;
1534 #if !defined(DACCESS_COMPILE)
1537 * FindOrCreateInitAndAddJitInfo
1539 * This routine tries to find an existing DJI based on the method desc and start address, or allocates a new DJI, adding it to
1543 * fd - the method desc to find or create a DJI for.
1544 * startAddr - the start address to find or create the DJI for.
1547 * A pointer to the found or created DJI, or NULL.
1551 DebuggerJitInfo *DebuggerMethodInfo::FindOrCreateInitAndAddJitInfo(MethodDesc* fd, PCODE startAddr)
1561 _ASSERTE(fd != NULL);
1562 ARM_ONLY(_ASSERTE((startAddr & THUMB_CODE) == 1));
1564 // The debugger doesn't track Lightweight-codegen methods b/c they have no metadata.
1565 if (fd->IsDynamicMethod())
1570 if (startAddr == NULL)
1572 // This will grab the start address for the current code version.
1573 startAddr = g_pEEInterface->GetFunctionAddress(fd);
1574 if (startAddr == NULL)
1581 _ASSERTE(g_pEEInterface->GetNativeCodeMethodDesc(startAddr) == fd);
1584 // Check the lsit to see if we've already populated an entry for this JitInfo.
1585 // If we didn't have a JitInfo before, lazily create it now.
1586 // We don't care if we were prejitted or not.
1588 // We haven't got the lock yet so we'll repeat this lookup once
1589 // we've taken the lock.
1590 DebuggerJitInfo * pResult = FindJitInfo(fd, startAddr);
1591 if (pResult != NULL)
1596 // The DJI may already be populated in the cache, if so CreateInitAndAddJitInfo is a no-op and that is fine.
1597 // CreateInitAndAddJitInfo takes a lock and checks the list again, which makes this thread-safe.
1598 BOOL jitInfoWasCreated;
1599 return CreateInitAndAddJitInfo(fd, startAddr, &jitInfoWasCreated);
1602 // Create a DJI around a method-desc. The EE already has all the information we need for a DJI,
1603 // the DJI just serves as a cache of the information for the debugger.
1604 // Caller makes no guarantees about whether the DJI is already in the table. (Caller should avoid this if
1605 // it knows it's in the table, but b/c we can't expect caller to synchronize w/ the other threads).
1606 DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr, BOOL* jitInfoWasCreated)
1613 PRECONDITION(!g_pDebugger->HasDebuggerDataLock());
1617 _ASSERTE(fd != NULL);
1619 // May or may-not be jitted, that's why we passed in the start addr & size explicitly.
1620 _ASSERTE(startAddr != NULL);
1622 *jitInfoWasCreated = FALSE;
1624 // No support for light-weight codegen methods.
1625 if (fd->IsDynamicMethod())
1631 DebuggerJitInfo *dji = new (interopsafe) DebuggerJitInfo(this, fd);
1632 _ASSERTE(dji != NULL); // throws on oom error
1634 _ASSERTE(dji->m_methodInfo == this); // this should be set
1638 // Init may take locks that violate the debugger-data lock, so we can't init while we hold that lock.
1639 // But we can't init after we add it to the table and release the lock b/c another thread may pick
1640 // if up in the uninitialized state.
1641 // So we initialize a private copy of the DJI before we take the debugger-data lock.
1642 dji->Init(startAddr);
1644 dji->m_nextJitInfo = NULL;
1647 //<TODO>@TODO : _ASSERTE(EnC);</TODO>
1650 Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
1652 // We need to ensure that another thread didn't go in and add this exact same DJI?
1654 DebuggerJitInfo * pResult = FindJitInfo(dji->m_fd, (TADDR)dji->m_addrOfCode);
1655 if (pResult != NULL)
1658 _ASSERTE(pResult->m_sizeOfCode == dji->m_sizeOfCode);
1659 DeleteInteropSafe(dji);
1664 *jitInfoWasCreated = TRUE;
1668 // We know it's not in the table. Go add it!
1669 DebuggerJitInfo *djiPrev = m_latestJitInfo;
1671 LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: current head of dji list:0x%08x\n", djiPrev));
1673 if (djiPrev != NULL)
1675 dji->m_prevJitInfo = djiPrev;
1676 djiPrev->m_nextJitInfo = dji;
1678 m_latestJitInfo = dji;
1680 LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: DJI version 0x%04x for %s\n",
1681 GetCurrentEnCVersion(),
1682 dji->m_fd->m_pszDebugMethodName));
1686 m_latestJitInfo = dji;
1689 } // DebuggerDataLockHolder out of scope - release implied
1691 // We've now added a new DJI into the table and released the lock. Thus any other thread
1692 // can come and use our DJI. Good thing we inited the DJI _before_ adding it to the table.
1694 LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: new head of dji list:0x%08x\n", m_latestJitInfo));
1702 * This routine remove a DJI from the DMI's list and deletes the memory.
1705 * dji - The DJI to delete.
1712 void DebuggerMethodInfo::DeleteJitInfo(DebuggerJitInfo *dji)
1722 Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
1724 LOG((LF_CORDB,LL_INFO10000,"DMI:DJI: dji:0x%08x\n", dji));
1726 DebuggerJitInfo *djiPrev = dji->m_prevJitInfo;
1728 if (djiPrev != NULL)
1730 djiPrev->m_nextJitInfo = dji->m_nextJitInfo;
1733 if (dji->m_nextJitInfo != NULL)
1735 dji->m_nextJitInfo->m_prevJitInfo = djiPrev;
1740 // This DJI is the head of the list
1742 _ASSERTE(m_latestJitInfo == dji);
1744 m_latestJitInfo = djiPrev;
1749 DeleteInteropSafe(dji);
1751 // DebuggerDataLockHolder out of scope - release implied
1757 * This routine removes all the DJIs from the current DMI.
1767 void DebuggerMethodInfo::DeleteJitInfoList(void)
1777 Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
1779 while(m_latestJitInfo != NULL)
1781 DeleteJitInfo(m_latestJitInfo);
1784 // DebuggerDataLockHolder out of scope - release implied
1788 // Iterate through all existing DJIs. See header for expected usage.
1789 DebuggerMethodInfo::DJIIterator::DJIIterator()
1791 LIMITED_METHOD_CONTRACT;
1794 m_pLoaderModuleFilter = NULL;
1797 bool DebuggerMethodInfo::DJIIterator::IsAtEnd()
1799 LIMITED_METHOD_CONTRACT;
1801 return m_pCurrent == NULL;
1804 DebuggerJitInfo * DebuggerMethodInfo::DJIIterator::Current()
1806 LIMITED_METHOD_CONTRACT;
1811 void DebuggerMethodInfo::DJIIterator::Next(BOOL fFirst /*=FALSE*/)
1825 PREFIX_ASSUME(m_pCurrent != NULL); // IsAtEnd() should have caught this.
1826 m_pCurrent = m_pCurrent->m_prevJitInfo;
1829 // Check if we're at the end of the list, in which case we're done.
1830 for ( ; m_pCurrent != NULL; m_pCurrent = m_pCurrent->m_prevJitInfo)
1832 Module * pLoaderModule = m_pCurrent->m_pLoaderModule;
1834 // Obey the module filter if it's provided
1835 if ((m_pLoaderModuleFilter != NULL) && (m_pLoaderModuleFilter != pLoaderModule))
1838 //Obey the methodDesc filter if it is provided
1839 if ((m_pMethodDescFilter != NULL) && (m_pMethodDescFilter != m_pCurrent->m_fd))
1842 // Skip modules that are unloaded, but still hanging around. Note that we can't use DebuggerModule for this check
1843 // because of it is deleted pretty early during unloading, and we do not want to recreate it.
1844 if (pLoaderModule->GetLoaderAllocator()->IsUnloaded())
1852 /******************************************************************************
1853 * Return true iff this method is jitted
1854 ******************************************************************************/
1855 bool DebuggerMethodInfo::HasJitInfos()
1857 LIMITED_METHOD_CONTRACT;
1858 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1859 return (m_latestJitInfo != NULL);
1862 /******************************************************************************
1863 * Return true iff this has been EnCed since last time function was jitted.
1864 ******************************************************************************/
1865 bool DebuggerMethodInfo::HasMoreRecentEnCVersion()
1867 LIMITED_METHOD_CONTRACT;
1868 return ((m_latestJitInfo != NULL) &&
1869 (m_currentEnCVersion > m_latestJitInfo->m_encVersion));
1872 /******************************************************************************
1873 * Updated the instrumented-IL map
1874 ******************************************************************************/
1875 void DebuggerMethodInfo::SetInstrumentedILMap(COR_IL_MAP * pMap, SIZE_T cEntries)
1877 InstrumentedILOffsetMapping mapping;
1878 mapping.SetMappingInfo(cEntries, pMap);
1880 GetRuntimeModule()->SetInstrumentedILOffsetMapping(m_token, mapping);
1882 m_fHasInstrumentedILMap = true;
1885 /******************************************************************************
1886 * Get the JMC status for a given function.
1887 ******************************************************************************/
1888 bool DebuggerMethodInfo::IsJMCFunction()
1890 LIMITED_METHOD_CONTRACT;
1891 return m_fJMCStatus;
1894 /******************************************************************************
1895 * Set the JMC status to a given value
1896 ******************************************************************************/
1897 void DebuggerMethodInfo::SetJMCStatus(bool fStatus)
1907 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1909 // First check if this is a no-op.
1910 // Do this first b/c there may be some cases where we don't have a DebuggerModule
1911 // yet but are still calling SetJMCStatus(false), like if we detach before attach is complete.
1912 bool fOldStatus = IsJMCFunction();
1914 if (fOldStatus == fStatus)
1916 // if no change, then there's nothing to do.
1917 LOG((LF_CORDB,LL_EVERYTHING, "DMI::SetJMCStatus: %p, keeping old status, %d\n", this, fStatus));
1921 // For a perf-optimization, our Module needs to know if it has any user
1922 // code. If it doesn't, it shouldn't dispatch through the JMC probes.
1923 // So modules keep a count of # of JMC functions - if the count is 0, the
1924 // module can set is JMC probe flag to 0 and skip the JMC probes.
1925 Module * pRuntimeModule = this->GetRuntimeModule();
1927 // Update the module's count.
1930 LOG((LF_CORDB,LL_EVERYTHING, "DMI::SetJMCStatus: %p, changing to non-user code\n", this));
1931 _ASSERTE(pRuntimeModule->HasAnyJMCFunctions());
1932 pRuntimeModule->DecJMCFuncCount();
1936 LOG((LF_CORDB,LL_EVERYTHING, "DMI::SetJMCStatus: %p, changing to user code\n", this));
1937 pRuntimeModule->IncJMCFuncCount();
1938 _ASSERTE(pRuntimeModule->HasAnyJMCFunctions());
1941 m_fJMCStatus = fStatus;
1943 // We should update our module's JMC status...
1944 g_pDebugger->UpdateModuleJMCFlag(pRuntimeModule, DebuggerController::GetTotalMethodEnter() != 0);
1948 // Get an iterator that will go through ALL native code-blobs (DJI) in the specified
1949 // AppDomain, optionally filtered by loader module (if pLoaderModuleFilter != NULL).
1950 // This is EnC/ Generics / Prejit aware.
1951 void DebuggerMethodInfo::IterateAllDJIs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, MethodDesc * pMethodDescFilter, DebuggerMethodInfo::DJIIterator * pEnum)
1961 _ASSERTE(pEnum != NULL);
1962 _ASSERTE(pAppDomain != NULL || pMethodDescFilter != NULL);
1964 // Esnure we have DJIs for everything.
1965 CreateDJIsForNativeBlobs(pAppDomain, pLoaderModuleFilter, pMethodDescFilter);
1967 pEnum->m_pCurrent = m_latestJitInfo;
1968 pEnum->m_pLoaderModuleFilter = pLoaderModuleFilter;
1969 pEnum->m_pMethodDescFilter = pMethodDescFilter;
1971 // Advance to the first DJI that passes the filter
1975 //---------------------------------------------------------------------------------------
1977 // Bring the DJI cache up to date.
1980 // * pAppDomain - Create DJIs only for this AppDomain
1981 // * pLoaderModuleFilter - If non-NULL, create DJIs only for MethodDescs whose
1982 // loader module matches this one. (This can be different from m_module in the
1983 // case of generics defined in one module and instantiated in another). If
1984 // non-NULL, create DJIs for all modules in pAppDomain.
1985 // * pMethodDescFilter - If non-NULL, create DJIs only for this single MethodDesc.
1988 void DebuggerMethodInfo::CreateDJIsForNativeBlobs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, MethodDesc* pMethodDescFilter)
1998 // If we're not stopped and the module we're iterating over allows types to load,
1999 // then it's possible new native blobs are being created underneath us.
2000 _ASSERTE(g_pDebugger->IsStopped() ||
2001 ((pLoaderModuleFilter != NULL) && !pLoaderModuleFilter->IsReadyForTypeLoad()) ||
2002 pMethodDescFilter != NULL);
2004 if (pMethodDescFilter != NULL)
2006 CreateDJIsForMethodDesc(pMethodDescFilter);
2010 // @todo - we really only need to do this if the stop-counter goes up (else we know nothing new is added).
2011 // B/c of generics, it's possible that new instantiations of a method may have been jitted.
2012 // So just loop through all known instantiations and ensure that we have all the DJIs.
2013 // Note that this iterator won't show previous EnC versions, but we're already guaranteed to
2014 // have DJIs for every verision of a method that was EnCed.
2015 // This also handles the possibility of getting the same methoddesc back from the iterator.
2016 // It also lets EnC + generics play nice together (including if an generic method was EnC-ed)
2017 LoadedMethodDescIterator it(pAppDomain, m_module, m_token);
2018 CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
2019 while (it.Next(pDomainAssembly.This()))
2021 MethodDesc * pDesc = it.Current();
2022 if (!pDesc->HasNativeCode())
2027 Module * pLoaderModule = pDesc->GetLoaderModule();
2029 // Obey the module filter if it's provided
2030 if ((pLoaderModuleFilter != NULL) && (pLoaderModuleFilter != pLoaderModule))
2033 // Skip modules that are unloaded, but still hanging around. Note that we can't use DebuggerModule for this check
2034 // because of it is deleted pretty early during unloading, and we do not want to recreate it.
2035 if (pLoaderModule->GetLoaderAllocator()->IsUnloaded())
2038 CreateDJIsForMethodDesc(pDesc);
2044 //---------------------------------------------------------------------------------------
2046 // Bring the DJI cache up to date for jitted code instances of a particular MethodDesc.
2049 void DebuggerMethodInfo::CreateDJIsForMethodDesc(MethodDesc * pMethodDesc)
2060 // The debugger doesn't track Lightweight-codegen methods b/c they have no metadata.
2061 if (pMethodDesc->IsDynamicMethod())
2066 #ifdef FEATURE_CODE_VERSIONING
2067 CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
2068 // grab the code version lock to iterate available versions of the code
2070 CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
2071 NativeCodeVersionCollection nativeCodeVersions = pCodeVersionManager->GetNativeCodeVersions(pMethodDesc);
2073 for (NativeCodeVersionIterator itr = nativeCodeVersions.Begin(), end = nativeCodeVersions.End(); itr != end; itr++)
2075 // Some versions may not be compiled yet - skip those for now
2076 // if they compile later the JitCompiled callback will add a DJI to our cache at that time
2077 PCODE codeAddr = itr->GetNativeCode();
2080 // The DJI may already be populated in the cache, if so CreateInitAndAdd is
2081 // a no-op and that is fine.
2082 BOOL unusedDjiWasCreated;
2083 CreateInitAndAddJitInfo(pMethodDesc, codeAddr, &unusedDjiWasCreated);
2088 // We just ask for the DJI to ensure that it's lazily created.
2089 // This should only fail in an oom scenario.
2090 DebuggerJitInfo * djiTest = g_pDebugger->GetLatestJitInfoFromMethodDesc(pDesc);
2091 if (djiTest == NULL)
2093 // We're oom. Give up.
2103 * This routine returns the lastest DJI we have for a particular DMI.
2104 * DJIs are lazily created.
2109 * a possibly NULL pointer to a DJI.
2113 // For logging and other internal purposes, provide a non-initializing accessor.
2114 DebuggerJitInfo* DebuggerMethodInfo::GetLatestJitInfo_NoCreate()
2116 return m_latestJitInfo;
2120 DebuggerMethodInfoTable::DebuggerMethodInfoTable() : CHashTableAndData<CNewZeroData>(101)
2131 SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
2132 HRESULT hr = NewInit(101, sizeof(DebuggerMethodInfoEntry), 101);
2140 HRESULT DebuggerMethodInfoTable::AddMethodInfo(Module *pModule,
2142 DebuggerMethodInfo *mi)
2150 PRECONDITION(CheckPointer(pModule));
2151 PRECONDITION(CheckPointer(mi));
2155 LOG((LF_CORDB, LL_INFO1000, "DMIT::AMI Adding dmi:0x%x Mod:0x%x tok:"
2156 "0x%x nVer:0x%x\n", mi, pModule, token, mi->GetCurrentEnCVersion()));
2158 _ASSERTE(mi != NULL);
2160 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2162 HRESULT hr = OverwriteMethodInfo(pModule, token, mi, TRUE);
2166 DebuggerMethodInfoKey dmik;
2167 dmik.pModule = pModule;
2170 DebuggerMethodInfoEntry *dmie =
2171 (DebuggerMethodInfoEntry *) Add(HASH(&dmik));
2175 dmie->key.pModule = pModule;
2176 dmie->key.token = token;
2179 LOG((LF_CORDB, LL_INFO1000, "DMIT::AJI: mod:0x%x tok:0%x ",
2188 HRESULT DebuggerMethodInfoTable::OverwriteMethodInfo(Module *pModule,
2190 DebuggerMethodInfo *mi,
2198 PRECONDITION(CheckPointer(pModule));
2199 PRECONDITION(CheckPointer(mi));
2203 LOG((LF_CORDB, LL_INFO1000, "DMIT::OJI: dmi:0x%x mod:0x%x tok:0x%x\n", mi,
2206 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2208 DebuggerMethodInfoKey dmik;
2209 dmik.pModule = pModule;
2212 DebuggerMethodInfoEntry *entry
2213 = (DebuggerMethodInfoEntry *) Find(HASH(&dmik), KEY(&dmik));
2216 if ( (fOnlyIfNull &&
2217 entry->mi == NULL) ||
2222 LOG((LF_CORDB, LL_INFO1000, "DMIT::OJI: mod:0x%x tok:0x%x remap"
2223 "nVer:0x%x\n", pModule, token, entry->nVersionLastRemapped));
2231 // pModule is being destroyed - remove any entries that belong to it. Why?
2232 // (a) Correctness: the module can be reloaded at the same address,
2233 // which will cause accidental matches with our hashtable (indexed by
2234 // {Module*,mdMethodDef}
2235 // (b) Perf: don't waste the memory!
2236 void DebuggerMethodInfoTable::ClearMethodsOfModule(Module *pModule)
2238 WRAPPER_NO_CONTRACT;
2240 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2242 LOG((LF_CORDB, LL_INFO1000000, "CMOM:mod:0x%x (%S)\n", pModule
2243 ,pModule->GetDebugName()));
2247 DebuggerMethodInfoEntry *entry
2248 = (DebuggerMethodInfoEntry *) FindFirstEntry(&info);
2249 while(entry != NULL)
2251 Module *pMod = entry->key.pModule ;
2252 if (pMod == pModule)
2254 // This method actually got mitted, at least
2255 // once - remove all version info.
2256 while(entry->mi != NULL)
2258 DeleteEntryDMI(entry);
2261 Delete(HASH(&(entry->key)), (HASHENTRY*)entry);
2266 // Delete generic DJIs that have lifetime attached to this module
2268 DebuggerMethodInfo * dmi = entry->mi;
2271 DebuggerJitInfo * dji = dmi->GetLatestJitInfo_NoCreate();
2274 DebuggerJitInfo * djiPrev = dji->m_prevJitInfo;;
2276 if (dji->m_pLoaderModule == pModule)
2277 dmi->DeleteJitInfo(dji);
2282 dmi = dmi->m_prevMethodInfo;
2286 entry = (DebuggerMethodInfoEntry *) FindNextEntry(&info);
2290 void DebuggerMethodInfoTable::DeleteEntryDMI(DebuggerMethodInfoEntry *entry)
2297 CAN_TAKE_LOCK; // DeleteInteropSafe() eventually calls DebuggerMethodInfo::DeleteJitInfoList
2302 DebuggerMethodInfo *dmiPrev = entry->mi->m_prevMethodInfo;
2303 TRACE_FREE(entry->mi);
2304 DeleteInteropSafe(entry->mi);
2305 entry->mi = dmiPrev;
2306 if ( dmiPrev != NULL )
2307 dmiPrev->m_nextMethodInfo = NULL;
2310 #endif // #ifndef DACCESS_COMPILE
2312 DebuggerJitInfo *DebuggerJitInfo::GetJitInfoByAddress(const BYTE *pbAddr )
2322 DebuggerJitInfo *dji = this;
2325 LOG((LF_CORDB,LL_INFO10000,"DJI:GJIBA finding DJI "
2326 "corresponding to addr 0x%p, starting with 0x%p\n", pbAddr, dji));
2329 // If it's not NULL, but not in the range m_addrOfCode to end of function,
2330 // then get the previous one.
2331 while( dji != NULL &&
2332 !CodeRegionInfo::GetCodeRegionInfo(dji).IsMethodAddress(pbAddr))
2334 LOG((LF_CORDB,LL_INFO10000,"DJI:GJIBA: pbAddr 0x%p is not in code "
2335 "0x%p (size:0x%p)\n", pbAddr, dji->m_addrOfCode,
2336 dji->m_sizeOfCode));
2337 dji = dji->m_prevJitInfo;
2343 LOG((LF_CORDB,LL_INFO10000,"DJI:GJIBA couldn't find a DJI "
2344 "corresponding to addr 0x%p\n", pbAddr));
2350 PTR_DebuggerJitInfo DebuggerMethodInfo::GetLatestJitInfo(MethodDesc *mdesc)
2352 // dac checks ngen'ed image content first, so
2353 // only check for existing JIT info.
2354 #ifndef DACCESS_COMPILE
2360 CALLED_IN_DEBUGGERDATALOCK_HOLDER_SCOPE_MAY_GC_TRIGGERS_CONTRACT;
2361 PRECONDITION(!g_pDebugger->HasDebuggerDataLock());
2366 if (m_latestJitInfo && m_latestJitInfo->m_fd == mdesc && !m_latestJitInfo->m_fd->HasClassOrMethodInstantiation())
2367 return m_latestJitInfo;
2369 // This ensures that there is an entry in the DJI list for this particular MethodDesc.
2370 // in the case of generic code it may not be the first entry in the list.
2371 FindOrCreateInitAndAddJitInfo(mdesc, NULL /* startAddr */);
2373 #endif // #ifndef DACCESS_COMPILE
2375 return m_latestJitInfo;
2378 DebuggerMethodInfo *DebuggerMethodInfoTable::GetMethodInfo(Module *pModule, mdMethodDef token)
2380 WRAPPER_NO_CONTRACT;
2385 // @review. One of the BVTs causes this to be called before the table is initialized
2386 // In particular, the changes to BREAKPOINT_ADD mean that this table is now consulted
2387 // to determine if we have ever seen the method, rather than a call to LookupMethodDesc,
2388 // which would have just returned NULL. In general it seems OK to consult this table
2389 // when it is empty, so I've added this....
2393 DebuggerMethodInfoKey dmik;
2394 dmik.pModule = dac_cast<PTR_Module>(pModule);
2397 DebuggerMethodInfoEntry *entry = dac_cast<PTR_DebuggerMethodInfoEntry>(Find(HASH(&dmik), KEY(&dmik)));
2405 LOG((LF_CORDB, LL_INFO1000, "DMI::GMI: for methodDef 0x%x, got 0x%x prev:0x%x\n",
2406 token, entry->mi, (entry->mi?entry->mi->m_prevMethodInfo:0)));
2412 DebuggerMethodInfo *DebuggerMethodInfoTable::GetFirstMethodInfo(HASHFIND *info)
2414 CONTRACT(DebuggerMethodInfo*)
2419 PRECONDITION(CheckPointer(info));
2420 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2424 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2426 DebuggerMethodInfoEntry *entry = PTR_DebuggerMethodInfoEntry
2427 (PTR_HOST_TO_TADDR(FindFirstEntry(info)));
2434 DebuggerMethodInfo *DebuggerMethodInfoTable::GetNextMethodInfo(HASHFIND *info)
2436 CONTRACT(DebuggerMethodInfo*)
2441 PRECONDITION(CheckPointer(info));
2442 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2446 _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2448 DebuggerMethodInfoEntry *entry = PTR_DebuggerMethodInfoEntry
2449 (PTR_HOST_TO_TADDR(FindNextEntry(info)));
2451 // We may have incremented the version number
2452 // for methods that never got JITted, so we should
2453 // pretend like they don't exist here.
2454 while (entry != NULL &&
2457 entry = PTR_DebuggerMethodInfoEntry
2458 (PTR_HOST_TO_TADDR(FindNextEntry(info)));
2469 #ifdef DACCESS_COMPILE
2471 DebuggerMethodInfoEntry::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2475 // This structure is in an array in the hash
2476 // so the 'this' is implicitly enumerated by the
2477 // array enum in CHashTable.
2479 // For a MiniDumpNormal, what is needed for modules is already enumerated elsewhere.
2480 // Don't waste time doing it here an extra time. Also, this will add many MB extra into the dump.
2481 if ((key.pModule.IsValid()) &&
2482 CLRDATA_ENUM_MEM_MINI != flags
2483 && CLRDATA_ENUM_MEM_TRIAGE != flags)
2485 key.pModule->EnumMemoryRegions(flags, true);
2488 while (mi.IsValid())
2490 mi->EnumMemoryRegions(flags);
2491 mi = mi->m_prevMethodInfo;
2496 DebuggerMethodInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2501 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
2503 // Modules are enumerated already for minidumps, save the empty calls.
2504 if (m_module.IsValid())
2506 m_module->EnumMemoryRegions(flags, true);
2511 PTR_DebuggerJitInfo jitInfo = m_latestJitInfo;
2512 while (jitInfo.IsValid())
2514 jitInfo->EnumMemoryRegions(flags);
2515 jitInfo = jitInfo->m_prevJitInfo;
2520 DebuggerJitInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2525 if (m_methodInfo.IsValid())
2527 m_methodInfo->EnumMemoryRegions(flags);
2530 if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
2534 m_fd->EnumMemoryRegions(flags);
2537 DacEnumMemoryRegion(PTR_TO_TADDR(GetSequenceMap()),
2538 GetSequenceMapCount() * sizeof(DebuggerILToNativeMap));
2539 DacEnumMemoryRegion(PTR_TO_TADDR(GetVarNativeInfo()),
2540 GetVarNativeInfoCount() *
2541 sizeof(ICorDebugInfo::NativeVarInfo));
2546 void DebuggerMethodInfoTable::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2548 WRAPPER_NO_CONTRACT;
2551 CHashTableAndData<CNewZeroData>::EnumMemoryRegions(flags);
2553 for (ULONG i = 0; i < m_iEntries; i++)
2555 DebuggerMethodInfoEntry* entry =
2556 PTR_DebuggerMethodInfoEntry(PTR_HOST_TO_TADDR(EntryPtr(i)));
2557 entry->EnumMemoryRegions(flags);
2560 #endif // #ifdef DACCESS_COMPILE