Add missing semicolon
[platform/upstream/coreclr.git] / src / debug / ee / functioninfo.cpp
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 //*****************************************************************************
5
6 // 
7 // File: DebuggerModule.cpp
8 //
9 // Stuff for tracking DebuggerModules.
10 //
11 //*****************************************************************************
12
13 #include "stdafx.h"
14 #include "../inc/common.h"
15 #include "perflog.h"
16 #include "eeconfig.h" // This is here even for retail & free builds...
17 #include "vars.hpp"
18 #include <limits.h>
19 #include "ilformatter.h"
20 #include "debuginfostore.h"
21 #include "../../vm/methoditer.h"
22
23 #ifndef DACCESS_COMPILE
24
25 bool DbgIsSpecialILOffset(DWORD offset)
26 {
27     LIMITED_METHOD_CONTRACT;
28
29     return (offset == (ULONG) ICorDebugInfo::PROLOG ||
30             offset == (ULONG) ICorDebugInfo::EPILOG ||
31             offset == (ULONG) ICorDebugInfo::NO_MAPPING);
32 }
33
34 // Helper to use w/ the debug stores.
35 BYTE* InteropSafeNew(void * , size_t cBytes)
36 {
37     BYTE * p = new (interopsafe, nothrow) BYTE[cBytes];
38     return p;
39 }
40
41
42 //
43 // This is only fur internal debugging.
44 //
45 #ifdef LOGGING
46 static void _dumpVarNativeInfo(ICorDebugInfo::NativeVarInfo* vni)
47 {
48     WRAPPER_NO_CONTRACT;
49
50     LOG((LF_CORDB, LL_INFO1000000, "Var %02d: 0x%04x-0x%04x vlt=",
51             vni->varNumber,
52             vni->startOffset, vni->endOffset,
53             vni->loc.vlType));
54
55     switch (vni->loc.vlType)
56     {
57     case ICorDebugInfo::VLT_REG:
58         LOG((LF_CORDB, LL_INFO1000000, "REG reg=%d\n", vni->loc.vlReg.vlrReg));
59         break;
60
61     case ICorDebugInfo::VLT_REG_BYREF:
62         LOG((LF_CORDB, LL_INFO1000000, "REG_BYREF reg=%d\n", vni->loc.vlReg.vlrReg));
63         break;
64
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));
70         break;
71
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));
77         break;
78
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));
83         break;
84
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));
91         break;
92
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));
99         break;
100
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));
106         break;
107
108     case ICorDebugInfo::VLT_FPSTK:
109         LOG((LF_CORDB, LL_INFO1000000, "FPSTK reg=%d\n",
110              vni->loc.vlFPstk.vlfReg));
111         break;
112
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));
117         break;
118
119
120     default:
121         LOG((LF_CORDB, LL_INFO1000000, "???\n"));
122         break;
123     }
124 }
125 #endif
126
127 #if defined(WIN64EXCEPTIONS)
128 void DebuggerJitInfo::InitFuncletAddress()
129 {
130     CONTRACTL
131     {
132         SO_INTOLERANT;
133         NOTHROW;
134         GC_NOTRIGGER;
135     }
136     CONTRACTL_END;
137
138     m_funcletCount = (int)g_pEEInterface->GetFuncletStartOffsets((const BYTE*)m_addrOfCode, NULL, 0);
139
140     if (m_funcletCount == 0)
141     {
142         _ASSERTE(m_rgFunclet == NULL);
143         return;
144     }
145
146     m_rgFunclet = (DWORD*)(new (interopsafe, nothrow) DWORD[m_funcletCount]);
147
148     // All bets are off for stepping this method.
149     if (m_rgFunclet == NULL)
150     {
151         m_funcletCount = 0;
152         return;
153     }
154
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);
158 }
159
160 //
161 // DebuggerJitInfo::GetFuncletOffsetByIndex()
162 //
163 // Given a funclet index, return its starting offset.
164 //
165 // parameters:   index - index of the funclet
166 //
167 // return value: starting offset of the specified funclet, or -1 if the index is invalid
168 //
169 DWORD DebuggerJitInfo::GetFuncletOffsetByIndex(int index)
170 {
171     LIMITED_METHOD_CONTRACT;
172
173     if (index < 0 || index >= m_funcletCount)
174     {
175         return (-1);
176     }
177
178     return m_rgFunclet[index];
179 }
180
181 //
182 // DebuggerJitInfo::GetFuncletIndex()
183 //
184 // Given an offset or an absolute address, return the index of the funclet containing it.
185 //
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
188 //
189 // return value: the index of the funclet containing the specified offset or address,
190 //               or -1 if it's invalid
191 //
192 int DebuggerJitInfo::GetFuncletIndex(CORDB_ADDRESS offsetOrAddr, GetFuncletIndexMode mode)
193 {
194     WRAPPER_NO_CONTRACT;
195
196     DWORD offset = 0;
197     if (mode == GFIM_BYOFFSET)
198     {
199         offset = (DWORD)offsetOrAddr;
200     }
201
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.
204     // <TODO>
205     // What if there's an overflow?
206     // </TODO>
207     if (!m_codeRegionInfo.IsMethodAddress((const BYTE *)(mode == GFIM_BYOFFSET ? (size_t)m_codeRegionInfo.OffsetToAddress(offset) : offsetOrAddr)))
208     {
209         return PARENT_METHOD_INDEX;
210     }
211
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])) ) )
215     {
216         return PARENT_METHOD_INDEX;
217     }
218
219     for (int i = 0; i < m_funcletCount; i++)
220     {
221         if (i == (m_funcletCount - 1))
222         {
223             return i;
224         }
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])) ) )
227         {
228             return i;
229         }
230     }
231
232     UNREACHABLE();
233 }
234
235 #endif // WIN64EXCEPTIONS
236
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)                                                        \
243     if ((_wantFirst))                                                                             \
244         for ( ; (_map) > m_sequenceMap && (((_map)-1)->ilOffset == (_map)->ilOffset); (_map)--);  \
245     else                                                                                          \
246         for ( ; (_map) < m_sequenceMap + (m_sequenceMapCount-1) && (((_map)+1)->ilOffset == (_map)->ilOffset); (_map)++);
247 #else
248 #define ADJUST_MAP_ENTRY(_map, _wantFirst)
249 #endif // _WIN64
250
251 DebuggerJitInfo::DebuggerJitInfo(DebuggerMethodInfo *minfo, MethodDesc *fd) :
252     m_fd(fd),
253     m_pLoaderModule(fd->GetLoaderModule()),
254     m_jitComplete(false),
255 #ifdef EnC_SUPPORTED
256     m_encBreakpointsApplied(false),
257 #endif //EnC_SUPPORTED
258     m_methodInfo(minfo),
259     m_addrOfCode(NULL),
260     m_sizeOfCode(0), m_prevJitInfo(NULL), m_nextJitInfo(NULL),
261     m_lastIL(0),
262     m_sequenceMap(NULL),
263     m_sequenceMapCount(0),
264     m_callsiteMap(NULL),
265     m_callsiteMapCount(0),
266     m_sequenceMapSorted(false),
267     m_varNativeInfo(NULL), m_varNativeInfoCount(0),
268     m_fAttemptInit(false)
269 #if defined(WIN64EXCEPTIONS)
270     ,m_rgFunclet(NULL)
271     , m_funcletCount(0)
272 #endif // defined(WIN64EXCEPTIONS)
273 {
274     WRAPPER_NO_CONTRACT;
275
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());
282
283     _ASSERTE(minfo);
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));
287
288     // Debugger doesn't track LightWeight codegen methods.
289     // We should never even be creating a DJI for one.
290     _ASSERTE(!m_fd->IsDynamicMethod());
291 }
292     
293 DebuggerILToNativeMap *DebuggerJitInfo::MapILOffsetToMapEntry(SIZE_T offset, BOOL *exact, BOOL fWantFirst)
294 {
295     CONTRACTL
296     {
297         NOTHROW;
298         GC_NOTRIGGER;
299         MODE_ANY;
300         CAN_TAKE_LOCK;  // GetSequenceMapCount calls LazyInitBounds() which can eventually
301                         // call ExecutionManager::IncrementReader
302     }
303     CONTRACTL_END;
304
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);
310
311     //
312     // Binary search for matching map element.
313     //
314
315     DebuggerILToNativeMap *mMin = GetSequenceMap();
316     DebuggerILToNativeMap *mMax = mMin + GetSequenceMapCount();
317
318     _ASSERTE(m_sequenceMapSorted);
319     _ASSERTE( mMin < mMax ); //otherwise we have no code
320
321     if (exact)
322     {
323         *exact = FALSE;
324     }
325
326     if (mMin)
327     {
328         while (mMin + 1 < mMax)
329         {
330             _ASSERTE(mMin>=m_sequenceMap);
331             DebuggerILToNativeMap *mMid = mMin + ((mMax - mMin)>>1);
332             _ASSERTE(mMid>=m_sequenceMap);
333
334             if (offset == mMid->ilOffset)
335             {
336                 if (exact)
337                 {
338                     *exact = TRUE;
339                 }
340                 ADJUST_MAP_ENTRY(mMid, fWantFirst);
341                 return mMid;
342             }
343             else if (offset < mMid->ilOffset && mMid->ilOffset != (ULONG) ICorDebugInfo::PROLOG)
344             {
345                 mMax = mMid;
346             }
347             else
348             {
349                 mMin = mMid;
350             }
351         }
352
353         if (exact && offset == mMin->ilOffset)
354         {
355             *exact = TRUE;
356         }
357         ADJUST_MAP_ENTRY(mMin, fWantFirst);
358     }
359     return mMin;
360 }
361
362 void DebuggerJitInfo::InitILToNativeOffsetIterator(ILToNativeOffsetIterator &iterator, SIZE_T ilOffset)
363 {
364     WRAPPER_NO_CONTRACT;
365
366     iterator.Init(this, ilOffset);
367 }
368
369
370 DebuggerJitInfo::NativeOffset DebuggerJitInfo::MapILOffsetToNative(DebuggerJitInfo::ILOffset ilOffset)
371 {
372     CONTRACTL
373     {
374         SO_NOT_MAINLINE;
375         NOTHROW;
376         GC_NOTRIGGER;
377     }
378     CONTRACTL_END;
379
380     NativeOffset resultOffset;
381
382     DebuggerILToNativeMap *map = MapILOffsetToMapEntry(ilOffset.m_ilOffset, &(resultOffset.m_fExact));
383
384 #if defined(WIN64EXCEPTIONS)
385     // See if we want the map entry for the parent.
386     if (ilOffset.m_funcletIndex <= PARENT_METHOD_INDEX)
387     {
388 #endif // _WIN64
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));
392
393         resultOffset.m_nativeOffset = map->nativeStartOffset;
394
395 #if defined(WIN64EXCEPTIONS)
396     }
397     else
398     {
399         // funcletIndex is guaranteed to be >= 0 at this point.
400         if (ilOffset.m_funcletIndex > (m_funcletCount - 1))
401         {
402             resultOffset.m_fExact       = FALSE;
403             resultOffset.m_nativeOffset = ((SIZE_T)-1);
404         }
405         else
406         {
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))
412             {
413                 funcletEndOffset = GetFuncletOffsetByIndex(ilOffset.m_funcletIndex + 1);
414             }
415             else
416             {
417                 funcletEndOffset = (DWORD)m_sizeOfCode;
418             }
419
420             SIZE_T ilTargetOffset = map->ilOffset;
421
422             DebuggerILToNativeMap *mapEnd = GetSequenceMap() + GetSequenceMapCount();
423
424             for (; map < mapEnd && map->ilOffset == ilTargetOffset; map++)
425             {
426                 if ((map->nativeStartOffset >= funcletStartOffset) &&
427                     (map->nativeStartOffset < funcletEndOffset))
428                 {
429                     // This is the normal case where the start offset falls in
430                     // the range of the funclet.
431                     resultOffset.m_nativeOffset = map->nativeStartOffset;
432                     break;
433                 }
434             }
435
436             if (map == mapEnd || map->ilOffset != ilTargetOffset)
437             {
438                 resultOffset.m_fExact       = FALSE;
439                 resultOffset.m_nativeOffset = ((SIZE_T)-1);
440             }
441         }
442     }
443 #endif // WIN64EXCEPTIONS
444
445     return resultOffset;
446 }
447
448
449 DebuggerJitInfo::ILToNativeOffsetIterator::ILToNativeOffsetIterator()
450 {
451     LIMITED_METHOD_CONTRACT;
452
453     m_dji = NULL;
454     m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET;
455 #ifdef WIN64EXCEPTIONS
456     m_currentILOffset.m_funcletIndex = PARENT_METHOD_INDEX;
457 #endif
458 }
459
460 void DebuggerJitInfo::ILToNativeOffsetIterator::Init(DebuggerJitInfo* dji, SIZE_T ilOffset)
461 {
462     WRAPPER_NO_CONTRACT;
463
464     m_dji = dji;
465     m_currentILOffset.m_ilOffset = ilOffset;
466 #ifdef WIN64EXCEPTIONS
467     m_currentILOffset.m_funcletIndex = PARENT_METHOD_INDEX;
468 #endif
469
470     m_currentNativeOffset = m_dji->MapILOffsetToNative(m_currentILOffset);
471 }
472
473 bool DebuggerJitInfo::ILToNativeOffsetIterator::IsAtEnd()
474 {
475     LIMITED_METHOD_CONTRACT;
476
477     return (m_currentILOffset.m_ilOffset == INVALID_IL_OFFSET);
478 }
479
480 SIZE_T DebuggerJitInfo::ILToNativeOffsetIterator::Current(BOOL* pfExact)
481 {
482     LIMITED_METHOD_CONTRACT;
483
484     if (pfExact != NULL)
485     {
486         *pfExact = m_currentNativeOffset.m_fExact;
487     }
488     return m_currentNativeOffset.m_nativeOffset;
489 }
490
491 SIZE_T DebuggerJitInfo::ILToNativeOffsetIterator::CurrentAssertOnlyOne(BOOL* pfExact)
492 {
493     WRAPPER_NO_CONTRACT;
494
495     SIZE_T nativeOffset = Current(pfExact);
496
497     Next();
498     _ASSERTE(IsAtEnd());
499
500     return nativeOffset;
501 }
502
503 void DebuggerJitInfo::ILToNativeOffsetIterator::Next()
504 {
505 #if defined(WIN64EXCEPTIONS)
506     NativeOffset tmpNativeOffset;
507
508     for (m_currentILOffset.m_funcletIndex += 1;
509          m_currentILOffset.m_funcletIndex < m_dji->GetFuncletCount();
510          m_currentILOffset.m_funcletIndex++)
511     {
512         tmpNativeOffset = m_dji->MapILOffsetToNative(m_currentILOffset);
513         if (tmpNativeOffset.m_nativeOffset != ((SIZE_T)-1) &&
514             tmpNativeOffset.m_nativeOffset != m_currentNativeOffset.m_nativeOffset)
515         {
516             m_currentNativeOffset = tmpNativeOffset;
517             break;
518         }
519     }
520
521     if (m_currentILOffset.m_funcletIndex == m_dji->GetFuncletCount())
522     {
523         m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET;
524     }
525 #else  // !WIN64EXCEPTIONS
526     m_currentILOffset.m_ilOffset = INVALID_IL_OFFSET;
527 #endif // !WIN64EXCEPTIONS
528 }
529
530
531
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>
539
540 SIZE_T DebuggerJitInfo::MapSpecialToNative(CorDebugMappingResult mapping,
541                                            SIZE_T which,
542                                            BOOL *pfAccurate)
543 {
544     CONTRACTL
545     {
546         SO_NOT_MAINLINE;
547         NOTHROW;
548         GC_NOTRIGGER;
549         PRECONDITION(NULL != pfAccurate);
550     }
551     CONTRACTL_END;
552
553     LOG((LF_CORDB, LL_INFO10000, "DJI::MSTN map:0x%x which:0x%x\n", mapping, which));
554
555     bool fFound;
556     SIZE_T  cFound = 0;
557
558     DebuggerILToNativeMap *m = GetSequenceMap();
559     DebuggerILToNativeMap *mEnd = m + GetSequenceMapCount();
560     if (m)
561     {
562         while(m < mEnd)
563         {
564             _ASSERTE(m>=GetSequenceMap());
565
566             fFound = false;
567
568             if (DbgIsSpecialILOffset(m->ilOffset))
569                 cFound++;
570
571             if (cFound == which)
572             {
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)
579                         );
580
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;
585             }
586             m++;
587         }
588     }
589
590     LOG((LF_CORDB, LL_INFO10000, "DJI::MSTN No mapping found :(\n"));
591     (*pfAccurate) = FALSE;
592
593     return 0;
594 }
595
596 #if defined(WIN64EXCEPTIONS)
597 //
598 // DebuggerJitInfo::MapILOffsetToNativeForSetIP()
599 //
600 // This function maps an IL offset to a native offset, taking into account cloned finallys and nested EH clauses.
601 //
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
606 //
607 // return value: destination IP, in native offset
608 //
609 SIZE_T DebuggerJitInfo::MapILOffsetToNativeForSetIP(SIZE_T offsetILTo, int funcletIndexFrom,
610                                                     EHRangeTree* pEHRT, BOOL* pExact)
611 {
612     CONTRACTL
613     {
614         SO_NOT_MAINLINE;
615         NOTHROW;
616         GC_NOTRIGGER;
617         MODE_ANY;
618     }
619     CONTRACTL_END;
620
621     DebuggerILToNativeMap* pMap    = MapILOffsetToMapEntry(offsetILTo, pExact, TRUE);
622     DebuggerILToNativeMap* pMapEnd = GetSequenceMap() + GetSequenceMapCount();
623
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);
629
630     SIZE_T offsetNatTo = pMap->nativeStartOffset;
631
632     if (m_funcletCount == 0 ||
633         pEHRT == NULL       ||
634         FAILED(pEHRT->m_hrInit))
635     {
636         return offsetNatTo;
637     }
638
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);
646         pMapCur++)
647     {
648         int funcletIndexTo = GetFuncletIndex(pMapCur->nativeStartOffset, DebuggerJitInfo::GFIM_BYOFFSET);
649         if (funcletIndexFrom == funcletIndexTo)
650         {
651             return pMapCur->nativeStartOffset;
652         }
653     }
654
655     return offsetNatTo;
656 }
657 #endif // _WIN64
658
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,
672                                                 SIZE_T endOffset,
673                                                 DebuggerILToNativeMap **start,
674                                                 DebuggerILToNativeMap **end)
675 {
676     CONTRACTL
677     {
678         SO_NOT_MAINLINE;
679         NOTHROW;
680         GC_NOTRIGGER;
681     }
682     CONTRACTL_END;
683
684     LOG((LF_CORDB, LL_INFO1000000,
685          "DJI::MIRTMER: IL 0x%04x-0x%04x\n",
686          startOffset, endOffset));
687
688     if (GetSequenceMapCount() == 0)
689     {
690         *start = NULL;
691         *end = NULL;
692         return;
693     }
694
695     *start = MapILOffsetToMapEntry(startOffset);
696
697     //
698     // end points to the last range that endOffset maps to, not past
699     // the last range.
700     // We want to return the last IL, and exclude the epilog
701     if (endOffset == 0)
702     {
703         *end = GetSequenceMap() + GetSequenceMapCount() - 1;
704         _ASSERTE(*end>=m_sequenceMap);
705
706         while ( ((*end)->ilOffset == (ULONG) ICorDebugInfo::EPILOG||
707                 (*end)->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
708                && (*end) > m_sequenceMap)
709         {
710             (*end)--;
711             _ASSERTE(*end>=m_sequenceMap);
712
713         }
714     }
715     else
716         *end = MapILOffsetToMapEntry(endOffset - 1, NULL
717                                      WIN64_ARG(FALSE));
718
719     _ASSERTE(*end>=m_sequenceMap);
720
721
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,
726          (*start)->ilOffset,
727          (*start)->nativeStartOffset, (*start)->nativeEndOffset,
728          (*end)->ilOffset,
729          (*end)->nativeStartOffset, (*end)->nativeEndOffset));
730 }
731
732 // @dbgtodo Microsoft inspection: This function has been replicated in DacDbiStructures so 
733 // this version can be deleted when inspection is complete.
734
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,
750                                             DWORD *which,
751                                             BOOL skipPrologs)
752 {
753     CONTRACTL
754     {
755         SO_INTOLERANT;
756         NOTHROW;
757         GC_NOTRIGGER;
758         PRECONDITION(map != NULL);
759         PRECONDITION(which != NULL);
760     }
761     CONTRACTL_END;
762
763     DWORD nativeOffset = (DWORD)nativeOffsetToMap;
764
765     (*which) = 0;
766     DebuggerILToNativeMap *m = GetSequenceMap();
767     DebuggerILToNativeMap *mEnd = m + GetSequenceMapCount();
768
769     LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: nativeOffset = 0x%x\n", nativeOffset));
770
771     if (m)
772     {
773         while (m < mEnd)
774         {
775             _ASSERTE(m>=m_sequenceMap);
776
777 #ifdef LOGGING
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));
784             else
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));
786 #endif // LOGGING
787
788             if (m->ilOffset == (ULONG) ICorDebugInfo::PROLOG ||
789                 m->ilOffset == (ULONG) ICorDebugInfo::EPILOG ||
790                 m->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
791             {
792                 (*which)++;
793             }
794
795             if (nativeOffset >= m->nativeStartOffset
796                 && ((m->nativeEndOffset == 0 &&
797                     m->ilOffset != (ULONG) ICorDebugInfo::PROLOG)
798                      || nativeOffset < m->nativeEndOffset))
799             {
800                 ULONG ilOff = m->ilOffset;
801
802                 if( m->ilOffset == (ULONG) ICorDebugInfo::PROLOG )
803                 {
804                     if (skipPrologs && nativeOffset < m->nativeEndOffset)
805                     {
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;
809                         continue;
810                     }
811                     
812                     ilOff = 0;
813                     (*map) = MAPPING_PROLOG;
814                     LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI: MAPPING_PROLOG\n"));
815
816                 }
817                 else if (m->ilOffset == (ULONG) ICorDebugInfo::NO_MAPPING)
818                 {
819                     ilOff = 0;
820                     (*map) = MAPPING_UNMAPPED_ADDRESS ;
821                     LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_"
822                         "UNMAPPED_ADDRESS\n"));
823                 }
824                 else if( m->ilOffset == (ULONG) ICorDebugInfo::EPILOG )
825                 {
826                     ilOff = m_lastIL;
827                     (*map) = MAPPING_EPILOG;
828                     LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_EPILOG\n"));
829                 }
830                 else if (nativeOffset == m->nativeStartOffset)
831                 {
832                     (*map) = MAPPING_EXACT;
833                     LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_EXACT\n"));
834                 }
835                 else
836                 {
837                     (*map) = MAPPING_APPROXIMATE;
838                     LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:MAPPING_"
839                         "APPROXIMATE\n"));
840                 }
841
842                 return ilOff;
843             }
844             m++;
845         }
846     }
847
848     (*map) = MAPPING_NO_INFO;
849     LOG((LF_CORDB,LL_INFO10000,"DJI::MNOTI:NO_INFO\n"));
850     return 0;
851 }
852
853 /******************************************************************************
854  *
855  ******************************************************************************/
856 DebuggerJitInfo::~DebuggerJitInfo()
857 {
858     TRACE_FREE(m_sequenceMap);
859     if (m_sequenceMap != NULL)
860     {
861         DeleteInteropSafe(((BYTE *)m_sequenceMap));
862     }
863
864     TRACE_FREE(m_varNativeInfo);
865     if (m_varNativeInfo != NULL)
866     {
867         DeleteInteropSafe(m_varNativeInfo);
868     }
869
870 #if defined(WIN64EXCEPTIONS)
871     if (m_rgFunclet)
872     {
873         DeleteInteropSafe(m_rgFunclet);
874         m_rgFunclet = NULL;
875     }
876 #endif // WIN64EXCEPTIONS
877
878
879 #ifdef _DEBUG
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;
887 #endif
888
889
890     LOG((LF_CORDB,LL_EVERYTHING, "DJI::~DJI : deleted at 0x%p\n", this));
891 }
892
893 // Lazy initialize the Debugger-Jit-Info
894 void DebuggerJitInfo::LazyInitBounds()
895 {
896     CONTRACTL
897     {
898         SO_INTOLERANT;
899         NOTHROW;
900         GC_NOTRIGGER;
901         PRECONDITION(ThisMaybeHelperThread());
902         PRECONDITION(!g_pDebugger->HasDebuggerDataLock());
903     } CONTRACTL_END;
904
905     LOG((LF_CORDB, LL_EVERYTHING, "DJI::LazyInitBounds: this=0x%x m_fAttemptInit %s\n", this, m_fAttemptInit == true ? "true": "false"));
906
907     // Only attempt lazy-init once
908     if (m_fAttemptInit)
909     {
910         return;
911     }
912
913     EX_TRY
914     {
915         LOG((LF_CORDB, LL_EVERYTHING, "DJI::LazyInitBounds: this=0x%x Initing\n", this));
916
917         // Should have already been jitted
918         _ASSERTE(this->m_jitComplete);
919
920         MethodDesc * mdesc = this->m_fd;
921         DebugInfoRequest request;
922
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);
927
928         // Bounds info.
929         ULONG32 cMap = 0;
930         ICorDebugInfo::OffsetMapping *pMap = NULL;
931         ULONG32 cVars = 0;
932         ICorDebugInfo::NativeVarInfo *pVars = NULL;
933
934         BOOL fSuccess = DebugInfoManager::GetBoundariesAndVars(
935             request,
936             InteropSafeNew, NULL, // allocator
937             &cMap, &pMap,
938             &cVars, &pVars);
939
940         LOG((LF_CORDB,LL_EVERYTHING, "DJI::LazyInitBounds: this=0x%x GetBoundariesAndVars success=0x%x\n", this, fSuccess));
941
942         Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
943
944         if (!m_fAttemptInit)
945         {
946             if (fSuccess)
947             {
948                 this->SetBoundaries(cMap, pMap);
949                 this->SetVars(cVars, pVars);
950             }
951             m_fAttemptInit = true;
952         }
953         else
954         {
955             DeleteInteropSafe(pMap);
956             DeleteInteropSafe(pVars);
957         }
958         // DebuggerDataLockHolder out of scope - release implied
959     }
960     EX_CATCH
961     {
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.
965     }
966     EX_END_CATCH(SwallowAllExceptions)
967 }
968
969 /******************************************************************************
970  * SetVars() takes ownership of pVars
971  ******************************************************************************/
972 void DebuggerJitInfo::SetVars(ULONG32 cVars, ICorDebugInfo::NativeVarInfo *pVars)
973 {
974     LIMITED_METHOD_CONTRACT;
975
976     _ASSERTE(m_varNativeInfo == NULL);
977
978     m_varNativeInfo = pVars;
979     m_varNativeInfoCount = cVars;
980
981     LOG((LF_CORDB, LL_INFO1000000, "D::sV: var count is %d\n",
982          m_varNativeInfoCount));
983
984 #ifdef LOGGING
985     for (unsigned int i = 0; i < m_varNativeInfoCount; i++)
986     {
987         ICorDebugInfo::NativeVarInfo* vni = &(m_varNativeInfo[i]);
988         _dumpVarNativeInfo(vni);
989     }
990 #endif
991 }
992
993 CHECK DebuggerJitInfo::Check() const
994 {
995     LIMITED_METHOD_CONTRACT;
996
997     CHECK_OK;
998 }
999
1000 // Invariants for a DebuggerJitInfo
1001 // These should always be true at any well defined point.
1002 CHECK DebuggerJitInfo::Invariant() const
1003 {
1004     LIMITED_METHOD_CONTRACT;
1005     CHECK((m_sequenceMapCount == 0) == (m_sequenceMap == NULL));
1006     CHECK(m_methodInfo != NULL);
1007     CHECK(m_fd != NULL);
1008
1009     CHECK_OK;
1010 }
1011
1012
1013 #if !defined(DACCESS_COMPILE)
1014 /******************************************************************************
1015  * SetBoundaries() takes ownership of pMap
1016  ******************************************************************************/
1017 void DebuggerJitInfo::SetBoundaries(ULONG32 cMap, ICorDebugInfo::OffsetMapping *pMap)
1018 {
1019     CONTRACTL
1020     {
1021         SO_INTOLERANT;
1022         THROWS;
1023         GC_NOTRIGGER;
1024         PRECONDITION(CheckPointer(this));
1025     }
1026     CONTRACTL_END;
1027
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);
1031
1032     if (cMap == 0)
1033         return;
1034
1035     ULONG ilLast = 0;
1036 #ifdef _DEBUG
1037     // We assume that the map is sorted by native offset
1038     if (cMap > 1)
1039     {
1040         for(ICorDebugInfo::OffsetMapping * pEntry = pMap;
1041             pEntry < (pMap + cMap - 1);
1042             pEntry++)
1043         {
1044             _ASSERTE(pEntry->nativeOffset <= (pEntry+1)->nativeOffset);
1045         }
1046     }
1047 #endif //_DEBUG
1048
1049     //
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>
1053     //
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
1057
1058     m_sequenceMapCount = cMap;
1059
1060     DebuggerILToNativeMap *m = m_sequenceMap;
1061
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;
1067
1068     InstrumentedILOffsetMapping mapping = 
1069         m_methodInfo->GetRuntimeModule()->GetInstrumentedILOffsetMapping(m_methodInfo->m_token);
1070
1071     //
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++)
1079     {
1080         const ICorDebugInfo::OffsetMapping * const pMapEntry = &pMap[idxJitMap];
1081         _ASSERTE(m >= m_sequenceMap);
1082         _ASSERTE(m < m_sequenceMap + m_sequenceMapCount);
1083
1084         ilLast = max((int)ilLast, (int)pMapEntry->ilOffset);
1085
1086         // Simply copy everything over, since we translate to
1087         // CorDebugMappingResults immediately prior to handing
1088         // back to user...
1089         m->nativeStartOffset    = pMapEntry->nativeOffset;
1090         m->ilOffset             = pMapEntry->ilOffset;
1091         m->source               = pMapEntry->source;
1092
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.....
1096
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.
1099         // Ex, if map is:
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())
1105         {
1106             int ilThisOld = m_methodInfo->TranslateToInstIL(&mapping, 
1107                                                             pMapEntry->ilOffset, 
1108                                                             bInstrumentedToOriginal);
1109
1110             if (ilThisOld == ilPrevOld)
1111             {
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
1115                 continue;
1116             }
1117             m->ilOffset = ilThisOld;
1118             ilPrevOld = ilThisOld;
1119         }
1120         
1121         if (m > m_sequenceMap && (m->source & call_inst) != call_inst)
1122         {
1123             DebuggerILToNativeMap *last = m-1;
1124             if ((last->source & call_inst) == call_inst)
1125                 last = (last > m_sequenceMap) ? last - 1 : NULL;
1126                 
1127             if (last && (last->source & call_inst) != call_inst && m->ilOffset == last->ilOffset)
1128             {
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--;
1133                 continue;
1134             }
1135         }
1136         
1137
1138         // Move to next entry in the debugger's table
1139         m++;
1140     } // end for
1141
1142     DeleteInteropSafe(pMap);
1143
1144     _ASSERTE(m == m_sequenceMap + m_sequenceMapCount);
1145
1146     m_lastIL = ilLast;
1147
1148     // Set nativeEndOffset in debugger's il->native map
1149     // Do this before we resort by IL.
1150     unsigned int i;
1151     for(i = 0; i < m_sequenceMapCount - 1; i++)
1152     {
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)
1156             j++;
1157         
1158         m_sequenceMap[i].nativeEndOffset = m_sequenceMap[j].nativeStartOffset;
1159     }
1160
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);
1165
1166     // Now resort by IL.
1167     MapSortIL isort(m_sequenceMap, m_sequenceMapCount);
1168
1169     isort.Sort();
1170
1171     m_sequenceMapSorted = true;
1172     
1173     m_callsiteMapCount = m_sequenceMapCount;
1174     while (m_sequenceMapCount > 0 && (m_sequenceMap[m_sequenceMapCount-1].source & call_inst) == call_inst)
1175       m_sequenceMapCount--;
1176
1177     m_callsiteMap = m_sequenceMap + m_sequenceMapCount;
1178     m_callsiteMapCount -= m_sequenceMapCount;
1179     
1180     LOG((LF_CORDB, LL_INFO100000, "DJI::SetBoundaries: this=0x%x boundary count is %d (%d callsites)\n",
1181          this, m_sequenceMapCount, m_callsiteMapCount));
1182
1183 #ifdef LOGGING
1184     for (unsigned int count = 0; count < m_sequenceMapCount + m_callsiteMapCount; count++)
1185     {
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));
1204         else
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));
1213
1214         LOG((LF_CORDB, LL_INFO1000000, " Src:0x%x\n", m_sequenceMap[count].source));
1215
1216     }
1217 #endif //LOGGING
1218 }
1219 #endif // !DACCESS_COMPILE
1220
1221 // Init a DJI after it's jitted.
1222 void DebuggerJitInfo::Init(TADDR newAddress)
1223 {
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());
1227
1228     this->m_addrOfCode = (ULONG_PTR)PTR_TO_CORDB_ADDRESS((BYTE*) newAddress);
1229     this->m_jitComplete = true;
1230
1231     this->m_codeRegionInfo.InitializeFromStartAddress(PINSTRToPCODE((TADDR)this->m_addrOfCode));
1232     this->m_sizeOfCode =  this->m_codeRegionInfo.getSizeOfTotalCode();
1233
1234     this->m_encVersion = this->m_methodInfo->GetCurrentEnCVersion();
1235
1236 #if defined(WIN64EXCEPTIONS)
1237     this->InitFuncletAddress();
1238 #endif // WIN64EXCEPTIONS
1239
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()));
1253
1254 #if defined(LOGGING)
1255     for (unsigned int i = 0; i < this->GetSequenceMapCount(); i++)
1256     {
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));
1263     }
1264 #endif // LOGGING
1265
1266 }
1267
1268 /******************************************************************************
1269  *
1270  ******************************************************************************/
1271 ICorDebugInfo::SourceTypes DebuggerJitInfo::GetSrcTypeFromILOffset(SIZE_T ilOffset)
1272 {
1273     CONTRACTL
1274     {
1275         SO_NOT_MAINLINE;
1276         NOTHROW;
1277         GC_NOTRIGGER;
1278     }
1279     CONTRACTL_END;
1280
1281     BOOL exact = FALSE;
1282     DebuggerILToNativeMap *pMap = MapILOffsetToMapEntry(ilOffset, &exact);
1283
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,
1287         exact));
1288
1289     if (!exact)
1290     {
1291         return ICorDebugInfo::SOURCE_TYPE_INVALID;
1292     }
1293
1294     return pMap->source;
1295 }
1296
1297 /******************************************************************************
1298  *
1299  ******************************************************************************/
1300 DebuggerMethodInfo::~DebuggerMethodInfo()
1301 {
1302     CONTRACTL
1303     {
1304         SO_INTOLERANT;
1305         NOTHROW;
1306         GC_NOTRIGGER;
1307         DESTRUCTOR_CHECK;
1308     }
1309     CONTRACTL_END;
1310
1311     DeleteJitInfoList();
1312
1313     LOG((LF_CORDB,LL_EVERYTHING, "DMI::~DMI : deleted at 0x%p\n", this));
1314 }
1315
1316 // Translate between old & new offsets (w/ respect to Instrumented IL).
1317
1318 // Don't interpolate
1319 ULONG32 DebuggerMethodInfo::TranslateToInstIL(const InstrumentedILOffsetMapping * pMapping,
1320                                               ULONG32 offOrig, 
1321                                               bool fOrigToInst)
1322 {
1323     LIMITED_METHOD_CONTRACT;
1324
1325     SIZE_T iMap;
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))
1330     {
1331         return offOrig;
1332     }
1333
1334     ARRAY_PTR_COR_IL_MAP rgMap = pMapping->GetOffsets();
1335
1336     // This assumes:
1337     // - map is sorted in increasing order by both old & new
1338     // - round down.
1339     if (fOrigToInst)
1340     {
1341         // Translate: old --> new
1342
1343         // Treat it as prolog if offOrig is not in remapping range
1344         if ((offOrig < rgMap[0].oldOffset) || (offOrig == (ULONG32)ICorDebugInfo::PROLOG))
1345         {
1346             return (ULONG32)ICorDebugInfo::PROLOG;
1347         }
1348
1349         if (offOrig == (ULONG32)ICorDebugInfo::EPILOG)
1350         {
1351             return (ULONG32)ICorDebugInfo::EPILOG;
1352         }
1353
1354         if (offOrig == (ULONG32)ICorDebugInfo::NO_MAPPING)
1355         {
1356             return (ULONG32)ICorDebugInfo::NO_MAPPING;
1357         }
1358
1359         for(iMap = 1; iMap < cMap; iMap++)
1360         {
1361             if (offOrig < rgMap[iMap].oldOffset)
1362                 return rgMap[iMap-1].newOffset;
1363         }
1364
1365         return rgMap[iMap - 1].newOffset;
1366     }
1367     else
1368     {
1369         // Translate: new --> old
1370
1371         // Treat it as prolog if offOrig is not in remapping range
1372         if ((offOrig < rgMap[0].newOffset) || (offOrig == (ULONG32)ICorDebugInfo::PROLOG))
1373         {
1374             return (ULONG32)ICorDebugInfo::PROLOG;
1375         }
1376
1377         if (offOrig == (ULONG32)ICorDebugInfo::EPILOG)
1378         {
1379             return (ULONG32)ICorDebugInfo::EPILOG;
1380         }
1381
1382         if (offOrig == (ULONG32)ICorDebugInfo::NO_MAPPING)
1383         {
1384             return (ULONG32)ICorDebugInfo::NO_MAPPING;
1385         }
1386
1387         for(iMap = 1; iMap < cMap; iMap++)
1388         {
1389             if (offOrig < rgMap[iMap].newOffset)
1390                 return rgMap[iMap-1].oldOffset;
1391         }
1392
1393         return rgMap[iMap - 1].oldOffset;
1394     }
1395 }
1396
1397 /******************************************************************************
1398  * Constructor for DebuggerMethodInfo
1399  ******************************************************************************/
1400 DebuggerMethodInfo::DebuggerMethodInfo(Module *module, mdMethodDef token) :
1401         m_currentEnCVersion(CorDB_DEFAULT_ENC_FUNCTION_VERSION),
1402         m_module(module),
1403         m_token(token),
1404         m_prevMethodInfo(NULL),
1405         m_nextMethodInfo(NULL),
1406         m_latestJitInfo(NULL),
1407         m_fHasInstrumentedILMap(false)
1408 {
1409     CONTRACTL
1410     {
1411         SO_INTOLERANT;
1412         WRAPPER(THROWS);
1413         WRAPPER(GC_TRIGGERS);
1414         CONSTRUCTOR_CHECK;
1415     }
1416     CONTRACTL_END;
1417  
1418     LOG((LF_CORDB,LL_EVERYTHING, "DMI::DMI : created at 0x%p\n", this));
1419
1420     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1421
1422     DebuggerModule * pModule = GetPrimaryModule();
1423
1424     m_fJMCStatus = false;
1425
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)
1430     {
1431         // Use the accessor so that we keep the module's count properly updated.
1432         SetJMCStatus(pModule->GetRuntimeModule()->GetJMCStatus());
1433     }
1434  }
1435
1436
1437 /******************************************************************************
1438  * Get the primary debugger module for this DMI. This is 1:1 w/ an EE Module.
1439  ******************************************************************************/
1440 DebuggerModule* DebuggerMethodInfo::GetPrimaryModule()
1441 {
1442     CONTRACTL
1443     {
1444         SO_INTOLERANT;
1445         NOTHROW;
1446         GC_NOTRIGGER;
1447     }
1448     CONTRACTL_END;
1449
1450     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1451
1452     DebuggerModuleTable * pTable = g_pDebugger->GetModuleTable();
1453
1454     // If we're tracking debug info but no debugger's attached, then
1455     // we won't have a table for the modules yet.
1456     if (pTable == NULL)
1457         return NULL;
1458
1459     DebuggerModule * pModule = pTable->GetModule(GetRuntimeModule());
1460     if (pModule == NULL)
1461     {
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.
1466         return NULL;
1467     }
1468
1469     // Only give back primary modules...
1470     DebuggerModule * p2 = pModule->GetPrimaryModule();
1471     _ASSERTE(p2 != NULL);
1472
1473     return p2;
1474 }
1475
1476 /******************************************************************************
1477  * Get the runtime module for this DMI
1478  ******************************************************************************/
1479 Module * DebuggerMethodInfo::GetRuntimeModule()
1480 {
1481     LIMITED_METHOD_CONTRACT;
1482
1483     return m_module;
1484 }
1485
1486 #endif // !DACCESS_COMPILE
1487
1488
1489 //---------------------------------------------------------------------------------------
1490 //
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.
1494 //
1495 // Arguments:
1496 //    pMD                 - the MD to lookup; must be non-NULL 
1497 //    addrNativeStartAddr - the native start address of jitted code
1498 //
1499 // Return Value:
1500 //    Returns the DJI corresponding to the specified MD and native start address.
1501 //    NULL if the DJI is not found.
1502 //
1503
1504 DebuggerJitInfo * DebuggerMethodInfo::FindJitInfo(MethodDesc * pMD,
1505                                                   TADDR        addrNativeStartAddr)
1506 {
1507     CONTRACTL
1508     {
1509         SO_INTOLERANT;
1510         SUPPORTS_DAC;
1511         NOTHROW;
1512         GC_NOTRIGGER;
1513         PRECONDITION(pMD != NULL);
1514     }
1515     CONTRACTL_END;
1516
1517
1518     DebuggerJitInfo * pCheck = m_latestJitInfo;
1519     while (pCheck != NULL)
1520     {
1521         if ( (pCheck->m_fd == dac_cast<PTR_MethodDesc>(pMD)) && 
1522              (pCheck->m_addrOfCode == addrNativeStartAddr) )
1523         {
1524             return pCheck;
1525         }
1526
1527         pCheck = pCheck->m_prevJitInfo;
1528     }
1529
1530     return NULL;
1531 }
1532
1533
1534 #if !defined(DACCESS_COMPILE)
1535
1536 /*
1537  * FindOrCreateInitAndAddJitInfo
1538  *
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
1540  * the DMI.
1541  *
1542  * Parameters:
1543  *   fd - the method desc to find or create a DJI for.
1544  *   startAddr - the start address to find or create the DJI for.
1545  *
1546  * Returns
1547  *   A pointer to the found or created DJI, or NULL.
1548  *
1549  */
1550
1551 DebuggerJitInfo *DebuggerMethodInfo::FindOrCreateInitAndAddJitInfo(MethodDesc* fd, PCODE startAddr)
1552 {
1553     CONTRACTL
1554     {
1555         SO_INTOLERANT;
1556         THROWS;
1557         GC_NOTRIGGER;
1558     }
1559     CONTRACTL_END;
1560
1561     _ASSERTE(fd != NULL);
1562     ARM_ONLY(_ASSERTE((startAddr & THUMB_CODE) == 1));
1563
1564     // The debugger doesn't track Lightweight-codegen methods b/c they have no metadata.
1565     if (fd->IsDynamicMethod())
1566     {
1567         return NULL;
1568     }
1569
1570     if (startAddr == NULL)
1571     {
1572         // This will grab the start address for the current code version.
1573         startAddr = g_pEEInterface->GetFunctionAddress(fd);
1574         if (startAddr == NULL)
1575         {
1576             return NULL;
1577         }
1578     }
1579     else
1580     {
1581         _ASSERTE(g_pEEInterface->GetNativeCodeMethodDesc(startAddr) == fd);
1582     }
1583
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.
1587     //
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)
1592     {
1593         return pResult;
1594     }
1595
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);
1600 }
1601
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)
1607 {
1608     CONTRACTL
1609     {
1610         SO_INTOLERANT;
1611         THROWS;
1612         GC_NOTRIGGER;
1613         PRECONDITION(!g_pDebugger->HasDebuggerDataLock());
1614     }
1615     CONTRACTL_END;
1616
1617     _ASSERTE(fd != NULL);
1618
1619     // May or may-not be jitted, that's why we passed in the start addr & size explicitly.
1620     _ASSERTE(startAddr != NULL);
1621
1622     *jitInfoWasCreated = FALSE;
1623
1624     // No support for light-weight codegen methods.
1625     if (fd->IsDynamicMethod())
1626     {
1627         return NULL;
1628     }
1629
1630
1631     DebuggerJitInfo *dji = new (interopsafe) DebuggerJitInfo(this, fd);
1632     _ASSERTE(dji != NULL); // throws on oom error
1633
1634     _ASSERTE(dji->m_methodInfo == this); // this should be set
1635
1636     TRACE_ALLOC(dji);
1637
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);
1643
1644     dji->m_nextJitInfo = NULL;
1645
1646     //
1647     //<TODO>@TODO : _ASSERTE(EnC);</TODO>
1648     //
1649     {
1650         Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
1651
1652         // We need to ensure that another thread didn't go in and add this exact same DJI?
1653         {
1654             DebuggerJitInfo * pResult = FindJitInfo(dji->m_fd, (TADDR)dji->m_addrOfCode);
1655             if (pResult != NULL)
1656             {
1657                 // Found!
1658                 _ASSERTE(pResult->m_sizeOfCode == dji->m_sizeOfCode);
1659                 DeleteInteropSafe(dji);
1660                 return pResult;
1661             }
1662             else
1663             {
1664                 *jitInfoWasCreated = TRUE;
1665             }
1666         }
1667
1668         // We know it's not in the table. Go add it!
1669         DebuggerJitInfo *djiPrev = m_latestJitInfo;
1670
1671         LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: current head of dji list:0x%08x\n", djiPrev));
1672
1673         if (djiPrev != NULL)
1674         {
1675             dji->m_prevJitInfo = djiPrev;
1676             djiPrev->m_nextJitInfo = dji;
1677
1678             m_latestJitInfo = dji;
1679
1680             LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: DJI version 0x%04x for %s\n",
1681                  GetCurrentEnCVersion(),
1682                  dji->m_fd->m_pszDebugMethodName));
1683         }
1684         else
1685         {
1686             m_latestJitInfo = dji;
1687         }
1688
1689     } // DebuggerDataLockHolder out of scope - release implied
1690
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.
1693
1694     LOG((LF_CORDB,LL_INFO10000,"DMI:CAAJI: new head of dji list:0x%08x\n", m_latestJitInfo));
1695
1696     return dji;
1697 }
1698
1699 /*
1700  * DeleteJitInfo
1701  *
1702  * This routine remove a DJI from the DMI's list and deletes the memory.
1703  *
1704  * Parameters:
1705  *   dji - The DJI to delete.
1706  *
1707  * Returns
1708  *   None.
1709  *
1710  */
1711
1712 void DebuggerMethodInfo::DeleteJitInfo(DebuggerJitInfo *dji)
1713 {
1714     CONTRACTL
1715     {
1716         SO_INTOLERANT;
1717         NOTHROW;
1718         GC_NOTRIGGER;
1719     }
1720     CONTRACTL_END;
1721
1722     Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
1723
1724     LOG((LF_CORDB,LL_INFO10000,"DMI:DJI: dji:0x%08x\n", dji));
1725
1726     DebuggerJitInfo *djiPrev = dji->m_prevJitInfo;
1727
1728     if (djiPrev != NULL)
1729     {
1730         djiPrev->m_nextJitInfo = dji->m_nextJitInfo;
1731     }
1732
1733     if (dji->m_nextJitInfo != NULL)
1734     {
1735         dji->m_nextJitInfo->m_prevJitInfo = djiPrev;
1736     }
1737     else
1738     {
1739         //
1740         // This DJI is the head of the list
1741         //
1742         _ASSERTE(m_latestJitInfo == dji);
1743
1744         m_latestJitInfo = djiPrev;
1745     }
1746
1747     TRACE_FREE(dji);
1748
1749     DeleteInteropSafe(dji);
1750
1751     // DebuggerDataLockHolder out of scope - release implied
1752 }
1753
1754 /*
1755  * DeleteJitInfoList
1756  *
1757  * This routine removes all the DJIs from the current DMI.
1758  *
1759  * Parameters:
1760  *   None.
1761  *
1762  * Returns
1763  *   None.
1764  *
1765  */
1766
1767 void DebuggerMethodInfo::DeleteJitInfoList(void)
1768 {
1769     CONTRACTL
1770     {
1771         SO_INTOLERANT;
1772         NOTHROW;
1773         GC_NOTRIGGER;
1774     }
1775     CONTRACTL_END;
1776
1777     Debugger::DebuggerDataLockHolder debuggerDataLockHolder(g_pDebugger);
1778
1779     while(m_latestJitInfo != NULL)
1780     {
1781         DeleteJitInfo(m_latestJitInfo);
1782     }
1783
1784     // DebuggerDataLockHolder out of scope - release implied
1785 }
1786
1787
1788 // Iterate through all existing DJIs. See header for expected usage.
1789 DebuggerMethodInfo::DJIIterator::DJIIterator()
1790 {
1791     LIMITED_METHOD_CONTRACT;
1792
1793     m_pCurrent = NULL;
1794     m_pLoaderModuleFilter = NULL;
1795 }
1796
1797 bool DebuggerMethodInfo::DJIIterator::IsAtEnd()
1798 {
1799     LIMITED_METHOD_CONTRACT;
1800
1801     return m_pCurrent == NULL;
1802 }
1803
1804 DebuggerJitInfo * DebuggerMethodInfo::DJIIterator::Current()
1805 {
1806     LIMITED_METHOD_CONTRACT;
1807
1808     return m_pCurrent;
1809 }
1810
1811 void DebuggerMethodInfo::DJIIterator::Next(BOOL fFirst /*=FALSE*/)
1812 {
1813     CONTRACTL
1814     {
1815         NOTHROW;
1816         GC_NOTRIGGER;
1817         FORBID_FAULT;
1818         MODE_ANY;
1819         CANNOT_TAKE_LOCK;
1820     }
1821     CONTRACTL_END;
1822
1823     if (!fFirst)
1824     {
1825         PREFIX_ASSUME(m_pCurrent != NULL); // IsAtEnd() should have caught this.
1826         m_pCurrent = m_pCurrent->m_prevJitInfo;
1827     }
1828
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)
1831     {
1832         Module * pLoaderModule = m_pCurrent->m_pLoaderModule;
1833
1834         // Obey the module filter if it's provided
1835         if ((m_pLoaderModuleFilter != NULL) && (m_pLoaderModuleFilter != pLoaderModule))
1836             continue;
1837
1838         //Obey the methodDesc filter if it is provided
1839         if ((m_pMethodDescFilter != NULL) && (m_pMethodDescFilter != m_pCurrent->m_fd))
1840             continue;
1841
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())
1845             continue;
1846
1847         break;
1848     }
1849 }
1850
1851
1852 /******************************************************************************
1853  * Return true iff this method is jitted
1854  ******************************************************************************/
1855 bool DebuggerMethodInfo::HasJitInfos()
1856 {
1857     LIMITED_METHOD_CONTRACT;
1858     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1859     return (m_latestJitInfo != NULL);
1860 }
1861
1862 /******************************************************************************
1863  * Return true iff this has been EnCed since last time function was jitted.
1864  ******************************************************************************/
1865 bool DebuggerMethodInfo::HasMoreRecentEnCVersion()
1866 {
1867     LIMITED_METHOD_CONTRACT;
1868     return ((m_latestJitInfo != NULL) &&
1869             (m_currentEnCVersion > m_latestJitInfo->m_encVersion));
1870 }
1871
1872 /******************************************************************************
1873  * Updated the instrumented-IL map
1874  ******************************************************************************/
1875 void DebuggerMethodInfo::SetInstrumentedILMap(COR_IL_MAP * pMap, SIZE_T cEntries)
1876 {
1877     InstrumentedILOffsetMapping mapping;
1878     mapping.SetMappingInfo(cEntries, pMap);
1879
1880     GetRuntimeModule()->SetInstrumentedILOffsetMapping(m_token, mapping);
1881
1882     m_fHasInstrumentedILMap = true;
1883 }
1884
1885 /******************************************************************************
1886  * Get the JMC status for a given function.
1887  ******************************************************************************/
1888 bool DebuggerMethodInfo::IsJMCFunction()
1889 {
1890     LIMITED_METHOD_CONTRACT;
1891     return m_fJMCStatus;
1892 }
1893
1894 /******************************************************************************
1895  * Set the JMC status to a given value
1896  ******************************************************************************/
1897 void DebuggerMethodInfo::SetJMCStatus(bool fStatus)
1898 {
1899     CONTRACTL
1900     {
1901         SO_NOT_MAINLINE;
1902         NOTHROW;
1903         GC_NOTRIGGER;
1904     }
1905     CONTRACTL_END;
1906
1907     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
1908
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();
1913
1914     if (fOldStatus == fStatus)
1915     {
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));
1918         return;
1919     }
1920
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();
1926
1927     // Update the module's count.
1928     if (!fStatus)
1929     {
1930         LOG((LF_CORDB,LL_EVERYTHING, "DMI::SetJMCStatus: %p, changing to non-user code\n", this));
1931         _ASSERTE(pRuntimeModule->HasAnyJMCFunctions());
1932         pRuntimeModule->DecJMCFuncCount();
1933     }
1934     else
1935     {
1936         LOG((LF_CORDB,LL_EVERYTHING, "DMI::SetJMCStatus: %p, changing to user code\n", this));
1937         pRuntimeModule->IncJMCFuncCount();
1938         _ASSERTE(pRuntimeModule->HasAnyJMCFunctions());
1939     }
1940
1941     m_fJMCStatus = fStatus;
1942
1943     // We should update our module's JMC status...
1944     g_pDebugger->UpdateModuleJMCFlag(pRuntimeModule, DebuggerController::GetTotalMethodEnter() != 0);
1945
1946 }
1947
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)
1952 {
1953     CONTRACTL
1954     {
1955         SO_NOT_MAINLINE;
1956         THROWS;
1957         GC_NOTRIGGER;
1958     }
1959     CONTRACTL_END;
1960
1961     _ASSERTE(pEnum != NULL);
1962     _ASSERTE(pAppDomain != NULL || pMethodDescFilter != NULL);
1963
1964     // Esnure we have DJIs for everything.
1965     CreateDJIsForNativeBlobs(pAppDomain, pLoaderModuleFilter, pMethodDescFilter);
1966
1967     pEnum->m_pCurrent = m_latestJitInfo;
1968     pEnum->m_pLoaderModuleFilter = pLoaderModuleFilter;
1969     pEnum->m_pMethodDescFilter = pMethodDescFilter;
1970
1971     // Advance to the first DJI that passes the filter
1972     pEnum->Next(TRUE);
1973 }
1974
1975 //---------------------------------------------------------------------------------------
1976 //
1977 // Bring the DJI cache up to date.
1978 //
1979 // Arguments:
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.
1986 //
1987
1988 void DebuggerMethodInfo::CreateDJIsForNativeBlobs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, MethodDesc* pMethodDescFilter)
1989 {
1990     CONTRACTL
1991     {
1992         SO_NOT_MAINLINE;
1993         THROWS;
1994         GC_NOTRIGGER;
1995     }
1996     CONTRACTL_END;
1997
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);
2003
2004     if (pMethodDescFilter != NULL)
2005     {
2006         CreateDJIsForMethodDesc(pMethodDescFilter);
2007     }
2008     else
2009     {
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()))
2020         {
2021             MethodDesc * pDesc = it.Current();
2022             if (!pDesc->HasNativeCode())
2023             {
2024                 continue;
2025             }
2026
2027             Module * pLoaderModule = pDesc->GetLoaderModule();
2028
2029             // Obey the module filter if it's provided
2030             if ((pLoaderModuleFilter != NULL) && (pLoaderModuleFilter != pLoaderModule))
2031                 continue;
2032
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())
2036                 continue;
2037
2038             CreateDJIsForMethodDesc(pDesc);
2039         }
2040     }
2041 }
2042
2043
2044 //---------------------------------------------------------------------------------------
2045 //
2046 // Bring the DJI cache up to date for jitted code instances of a particular MethodDesc.
2047 //
2048 //
2049 void DebuggerMethodInfo::CreateDJIsForMethodDesc(MethodDesc * pMethodDesc)
2050 {
2051     CONTRACTL
2052     {
2053         SO_NOT_MAINLINE;
2054         THROWS;
2055         GC_NOTRIGGER;
2056     }
2057     CONTRACTL_END;
2058
2059
2060     // The debugger doesn't track Lightweight-codegen methods b/c they have no metadata.
2061     if (pMethodDesc->IsDynamicMethod())
2062     {
2063         return;
2064     }
2065
2066 #ifdef FEATURE_CODE_VERSIONING
2067     CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
2068     // grab the code version lock to iterate available versions of the code
2069     {
2070         CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
2071         NativeCodeVersionCollection nativeCodeVersions = pCodeVersionManager->GetNativeCodeVersions(pMethodDesc);
2072
2073         for (NativeCodeVersionIterator itr = nativeCodeVersions.Begin(), end = nativeCodeVersions.End(); itr != end; itr++)
2074         {
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();
2078             if (codeAddr)
2079             {
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);
2084             }
2085         }
2086     }
2087 #else
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)
2092     {
2093         // We're oom. Give up.
2094         ThrowOutOfMemory();
2095         return;
2096     }
2097 #endif
2098 }
2099
2100 /*
2101  * GetLatestJitInfo
2102  *
2103  * This routine returns the lastest DJI we have for a particular DMI.
2104  * DJIs are lazily created.
2105  * Parameters:
2106  *   None.
2107  *
2108  * Returns
2109  *   a possibly NULL pointer to a DJI.
2110  *
2111  */
2112
2113 // For logging and other internal purposes, provide a non-initializing accessor.
2114 DebuggerJitInfo* DebuggerMethodInfo::GetLatestJitInfo_NoCreate()
2115 {
2116     return m_latestJitInfo;
2117 }
2118
2119
2120 DebuggerMethodInfoTable::DebuggerMethodInfoTable() : CHashTableAndData<CNewZeroData>(101)
2121 {
2122     CONTRACTL
2123     {
2124         WRAPPER(THROWS);
2125         GC_NOTRIGGER;
2126
2127         CONSTRUCTOR_CHECK;
2128     }
2129     CONTRACTL_END;
2130
2131     SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE;
2132     HRESULT hr = NewInit(101, sizeof(DebuggerMethodInfoEntry), 101);
2133
2134     if (FAILED(hr))
2135     {
2136         ThrowWin32(hr);
2137     }
2138 }
2139
2140 HRESULT DebuggerMethodInfoTable::AddMethodInfo(Module *pModule,
2141                    mdMethodDef token,
2142                    DebuggerMethodInfo *mi)
2143 {
2144     CONTRACTL
2145     {
2146         THROWS;
2147         GC_NOTRIGGER;
2148
2149         INSTANCE_CHECK;
2150         PRECONDITION(CheckPointer(pModule));
2151         PRECONDITION(CheckPointer(mi));
2152     }
2153     CONTRACTL_END;
2154
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()));
2157
2158    _ASSERTE(mi != NULL);
2159
2160     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2161
2162     HRESULT hr = OverwriteMethodInfo(pModule, token, mi, TRUE);
2163     if (hr == S_OK)
2164         return hr;
2165
2166     DebuggerMethodInfoKey dmik;
2167     dmik.pModule = pModule;
2168     dmik.token = token;
2169
2170     DebuggerMethodInfoEntry *dmie =
2171         (DebuggerMethodInfoEntry *) Add(HASH(&dmik));
2172
2173     if (dmie != NULL)
2174     {
2175         dmie->key.pModule = pModule;
2176         dmie->key.token = token;
2177         dmie->mi = mi;
2178
2179         LOG((LF_CORDB, LL_INFO1000, "DMIT::AJI: mod:0x%x tok:0%x ",
2180             pModule, token));
2181         return S_OK;
2182     }
2183
2184     ThrowOutOfMemory();
2185     return S_OK;
2186 }
2187
2188 HRESULT DebuggerMethodInfoTable::OverwriteMethodInfo(Module *pModule,
2189                          mdMethodDef token,
2190                          DebuggerMethodInfo *mi,
2191                          BOOL fOnlyIfNull)
2192 {
2193     CONTRACTL
2194     {
2195         NOTHROW;
2196         GC_NOTRIGGER;
2197
2198         PRECONDITION(CheckPointer(pModule));
2199         PRECONDITION(CheckPointer(mi));
2200     }
2201     CONTRACTL_END;
2202
2203     LOG((LF_CORDB, LL_INFO1000, "DMIT::OJI: dmi:0x%x mod:0x%x tok:0x%x\n", mi,
2204         pModule, token));
2205
2206     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2207
2208     DebuggerMethodInfoKey dmik;
2209     dmik.pModule = pModule;
2210     dmik.token = token;
2211
2212     DebuggerMethodInfoEntry *entry
2213       = (DebuggerMethodInfoEntry *) Find(HASH(&dmik), KEY(&dmik));
2214     if (entry != NULL)
2215     {
2216         if ( (fOnlyIfNull &&
2217               entry->mi == NULL) ||
2218              !fOnlyIfNull)
2219         {
2220             entry->mi = mi;
2221
2222             LOG((LF_CORDB, LL_INFO1000, "DMIT::OJI: mod:0x%x tok:0x%x remap"
2223                 "nVer:0x%x\n", pModule, token, entry->nVersionLastRemapped));
2224             return S_OK;
2225         }
2226     }
2227
2228     return E_FAIL;
2229 }
2230
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)
2237 {
2238     WRAPPER_NO_CONTRACT;
2239
2240     _ASSERTE(g_pDebugger->HasDebuggerDataLock()); 
2241
2242     LOG((LF_CORDB, LL_INFO1000000, "CMOM:mod:0x%x (%S)\n", pModule
2243         ,pModule->GetDebugName()));
2244
2245     HASHFIND info;
2246
2247     DebuggerMethodInfoEntry *entry
2248       = (DebuggerMethodInfoEntry *) FindFirstEntry(&info);
2249     while(entry != NULL)
2250     {
2251         Module *pMod = entry->key.pModule ;
2252         if (pMod == pModule)
2253         {
2254             // This method actually got mitted, at least
2255             // once - remove all version info.
2256             while(entry->mi != NULL)
2257             {
2258                 DeleteEntryDMI(entry);
2259             }
2260
2261             Delete(HASH(&(entry->key)), (HASHENTRY*)entry);
2262         }
2263         else
2264         {
2265             //
2266             // Delete generic DJIs that have lifetime attached to this module
2267             //
2268             DebuggerMethodInfo * dmi = entry->mi;
2269             while (dmi != NULL)
2270             {
2271                 DebuggerJitInfo * dji = dmi->GetLatestJitInfo_NoCreate();
2272                 while (dji != NULL)
2273                 {
2274                     DebuggerJitInfo * djiPrev = dji->m_prevJitInfo;;
2275
2276                     if (dji->m_pLoaderModule == pModule)
2277                         dmi->DeleteJitInfo(dji);
2278
2279                     dji = djiPrev;
2280                 }
2281
2282                 dmi = dmi->m_prevMethodInfo;
2283             }
2284         }
2285
2286         entry = (DebuggerMethodInfoEntry *) FindNextEntry(&info);
2287     }
2288 }
2289
2290 void DebuggerMethodInfoTable::DeleteEntryDMI(DebuggerMethodInfoEntry *entry)
2291 {
2292     CONTRACTL
2293     {
2294         NOTHROW;
2295         GC_NOTRIGGER;
2296         MODE_ANY;
2297         CAN_TAKE_LOCK;      // DeleteInteropSafe() eventually calls DebuggerMethodInfo::DeleteJitInfoList
2298                             // which locks.
2299     }
2300     CONTRACTL_END;
2301
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;
2308 }
2309
2310 #endif // #ifndef DACCESS_COMPILE
2311
2312 DebuggerJitInfo *DebuggerJitInfo::GetJitInfoByAddress(const BYTE *pbAddr )
2313 {
2314     CONTRACTL
2315     {
2316         SO_INTOLERANT;
2317         NOTHROW;
2318         GC_NOTRIGGER;
2319     }
2320     CONTRACTL_END;
2321
2322     DebuggerJitInfo *dji = this;
2323
2324 #ifdef LOGGING
2325     LOG((LF_CORDB,LL_INFO10000,"DJI:GJIBA finding DJI "
2326             "corresponding to addr 0x%p, starting with 0x%p\n", pbAddr, dji));
2327 #endif //LOGGING
2328
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))
2333     {
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;
2338     }
2339
2340 #ifdef LOGGING
2341     if (dji == NULL)
2342     {
2343         LOG((LF_CORDB,LL_INFO10000,"DJI:GJIBA couldn't find a DJI "
2344             "corresponding to addr 0x%p\n", pbAddr));
2345     }
2346 #endif //LOGGING
2347     return dji;
2348 }
2349
2350 PTR_DebuggerJitInfo DebuggerMethodInfo::GetLatestJitInfo(MethodDesc *mdesc)
2351 {
2352     // dac checks ngen'ed image content first, so
2353     // only check for existing JIT info.
2354 #ifndef DACCESS_COMPILE
2355
2356     CONTRACTL
2357     {
2358         SO_INTOLERANT;
2359         THROWS;
2360         CALLED_IN_DEBUGGERDATALOCK_HOLDER_SCOPE_MAY_GC_TRIGGERS_CONTRACT;
2361         PRECONDITION(!g_pDebugger->HasDebuggerDataLock());
2362     }
2363     CONTRACTL_END;
2364
2365
2366     if (m_latestJitInfo && m_latestJitInfo->m_fd == mdesc && !m_latestJitInfo->m_fd->HasClassOrMethodInstantiation())
2367         return m_latestJitInfo;
2368
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 */);
2372
2373 #endif // #ifndef DACCESS_COMPILE
2374
2375     return m_latestJitInfo;
2376 }
2377
2378 DebuggerMethodInfo *DebuggerMethodInfoTable::GetMethodInfo(Module *pModule, mdMethodDef token)
2379 {
2380     WRAPPER_NO_CONTRACT;
2381     SUPPORTS_DAC;
2382
2383     //        CHECK_DMI_TABLE;
2384
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....
2390     if (this == NULL)
2391         return NULL;
2392
2393     DebuggerMethodInfoKey dmik;
2394     dmik.pModule = dac_cast<PTR_Module>(pModule);
2395     dmik.token = token;
2396
2397     DebuggerMethodInfoEntry *entry = dac_cast<PTR_DebuggerMethodInfoEntry>(Find(HASH(&dmik), KEY(&dmik)));
2398
2399     if (entry == NULL )
2400     {
2401         return NULL;
2402     }
2403     else
2404     {
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)));
2407         return entry->mi;
2408     }
2409 }
2410
2411
2412 DebuggerMethodInfo *DebuggerMethodInfoTable::GetFirstMethodInfo(HASHFIND *info)
2413 {
2414     CONTRACT(DebuggerMethodInfo*)
2415     {
2416         NOTHROW;
2417         GC_NOTRIGGER;
2418
2419         PRECONDITION(CheckPointer(info));
2420         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2421     }
2422     CONTRACT_END;
2423
2424     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2425
2426     DebuggerMethodInfoEntry *entry = PTR_DebuggerMethodInfoEntry
2427         (PTR_HOST_TO_TADDR(FindFirstEntry(info)));
2428     if (entry == NULL)
2429         RETURN NULL;
2430     else
2431         RETURN entry->mi;
2432 }
2433
2434 DebuggerMethodInfo *DebuggerMethodInfoTable::GetNextMethodInfo(HASHFIND *info)
2435 {
2436     CONTRACT(DebuggerMethodInfo*)
2437     {
2438         NOTHROW;
2439         GC_NOTRIGGER;
2440
2441         PRECONDITION(CheckPointer(info));
2442         POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
2443     }
2444     CONTRACT_END;
2445
2446     _ASSERTE(g_pDebugger->HasDebuggerDataLock());
2447
2448     DebuggerMethodInfoEntry *entry = PTR_DebuggerMethodInfoEntry
2449         (PTR_HOST_TO_TADDR(FindNextEntry(info)));
2450
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 &&
2455            entry->mi == NULL)
2456     {
2457         entry = PTR_DebuggerMethodInfoEntry
2458             (PTR_HOST_TO_TADDR(FindNextEntry(info)));
2459     }
2460
2461     if (entry == NULL)
2462         RETURN NULL;
2463     else
2464         RETURN entry->mi;
2465 }
2466
2467
2468
2469 #ifdef DACCESS_COMPILE
2470 void
2471 DebuggerMethodInfoEntry::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2472 {
2473     SUPPORTS_DAC; 
2474
2475     // This structure is in an array in the hash
2476     // so the 'this' is implicitly enumerated by the
2477     // array enum in CHashTable.
2478
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)
2484     {
2485         key.pModule->EnumMemoryRegions(flags, true);
2486     }
2487
2488     while (mi.IsValid())
2489     {
2490         mi->EnumMemoryRegions(flags);
2491         mi = mi->m_prevMethodInfo;
2492     }
2493 }
2494
2495 void
2496 DebuggerMethodInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2497 {
2498     DAC_ENUM_DTHIS();
2499     SUPPORTS_DAC;
2500
2501     if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
2502     {
2503         // Modules are enumerated already for minidumps, save the empty calls.
2504         if (m_module.IsValid())
2505         {
2506             m_module->EnumMemoryRegions(flags, true);
2507         }
2508
2509     }
2510
2511     PTR_DebuggerJitInfo jitInfo = m_latestJitInfo;
2512     while (jitInfo.IsValid())
2513     {
2514         jitInfo->EnumMemoryRegions(flags);
2515         jitInfo = jitInfo->m_prevJitInfo;
2516     }
2517 }
2518
2519 void
2520 DebuggerJitInfo::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2521 {
2522     DAC_ENUM_DTHIS();
2523     SUPPORTS_DAC;
2524
2525     if (m_methodInfo.IsValid())
2526     {
2527         m_methodInfo->EnumMemoryRegions(flags);
2528     }
2529
2530     if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
2531     {
2532         if (m_fd.IsValid())
2533         {
2534             m_fd->EnumMemoryRegions(flags);
2535         }
2536
2537         DacEnumMemoryRegion(PTR_TO_TADDR(GetSequenceMap()),
2538                             GetSequenceMapCount() * sizeof(DebuggerILToNativeMap));
2539         DacEnumMemoryRegion(PTR_TO_TADDR(GetVarNativeInfo()),
2540                             GetVarNativeInfoCount() *
2541                             sizeof(ICorDebugInfo::NativeVarInfo));
2542     }
2543 }
2544
2545
2546 void DebuggerMethodInfoTable::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2547 {
2548     WRAPPER_NO_CONTRACT;
2549
2550     DAC_ENUM_VTHIS();
2551     CHashTableAndData<CNewZeroData>::EnumMemoryRegions(flags);
2552
2553     for (ULONG i = 0; i < m_iEntries; i++)
2554     {
2555         DebuggerMethodInfoEntry* entry =
2556             PTR_DebuggerMethodInfoEntry(PTR_HOST_TO_TADDR(EntryPtr(i)));
2557         entry->EnumMemoryRegions(flags);
2558     }
2559 }
2560 #endif // #ifdef DACCESS_COMPILE