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// File: dacfn.cpp
6//
7
8//
9// Dac function implementations.
10//
11//*****************************************************************************
12
13#include "stdafx.h"
14
15#include <encee.h>
16#ifdef FEATURE_PREJIT
17#include "compile.h"
18#endif // FEATURE_PREJIT
19#include <virtualcallstub.h>
20#include "peimagelayout.inl"
21
22#include "gcinterface.h"
23#include "gcinterface.dac.h"
24
25
26DacTableInfo g_dacTableInfo;
27DacGlobals g_dacGlobals;
28
29struct DacHostVtPtrs
30{
31#define VPTR_CLASS(name) PVOID name;
32#define VPTR_MULTI_CLASS(name, keyBase) PVOID name##__##keyBase;
33#include <vptr_list.h>
34#undef VPTR_CLASS
35#undef VPTR_MULTI_CLASS
36};
37
38
39const WCHAR *g_dacVtStrings[] =
40{
41#define VPTR_CLASS(name) W(#name),
42#define VPTR_MULTI_CLASS(name, keyBase) W(#name),
43#include <vptr_list.h>
44#undef VPTR_CLASS
45#undef VPTR_MULTI_CLASS
46};
47
48DacHostVtPtrs g_dacHostVtPtrs;
49
50HRESULT
51DacGetHostVtPtrs(void)
52{
53#define VPTR_CLASS(name) \
54 g_dacHostVtPtrs.name = name::VPtrHostVTable();
55#define VPTR_MULTI_CLASS(name, keyBase) \
56 g_dacHostVtPtrs.name##__##keyBase = name::VPtrHostVTable();
57#include <vptr_list.h>
58#undef VPTR_CLASS
59#undef VPTR_MULTI_CLASS
60
61 return S_OK;
62}
63
64bool
65DacExceptionFilter(Exception* ex, ClrDataAccess* access,
66 HRESULT* status)
67{
68 SUPPORTS_DAC_HOST_ONLY;
69
70 // The DAC support functions throw HRExceptions and
71 // the underlying code can throw the normal set of
72 // CLR exceptions. Handle any exception
73 // other than an unexpected SEH exception.
74 // If we're not debugging, handle SEH exceptions also
75 // so that dac absorbs all exceptions by default.
76 if ((access && access->m_debugMode) &&
77 ex->IsType(SEHException::GetType()))
78 {
79 // Indicate this exception should be rethrown.
80 return FALSE;
81 }
82
83 // Indicate this exception is handled.
84 // XXX Microsoft - The C++-based EH has broken the ability
85 // to get proper SEH results. Make sure that the
86 // error returned is actually an error code as
87 // often it's just zero.
88 *status = ex->GetHR();
89 if (!FAILED(*status))
90 {
91 *status = E_FAIL;
92 }
93 return TRUE;
94}
95
96void __cdecl
97DacWarning(__in char* format, ...)
98{
99 char text[256];
100 va_list args;
101
102 va_start(args, format);
103 _vsnprintf_s(text, sizeof(text), _TRUNCATE, format, args);
104 text[sizeof(text) - 1] = 0;
105 va_end(args);
106 OutputDebugStringA(text);
107}
108
109void
110DacNotImpl(void)
111{
112 EX_THROW(HRException, (E_NOTIMPL));
113}
114
115void
116DacError(HRESULT err)
117{
118 EX_THROW(HRException, (err));
119}
120
121// Ideally DacNoImpl and DacError would be marked no-return, but that will require changing a bunch of existing
122// code to avoid "unreachable code" warnings.
123void DECLSPEC_NORETURN
124DacError_NoRet(HRESULT err)
125{
126 EX_THROW(HRException, (err));
127}
128
129TADDR
130DacGlobalBase(void)
131{
132 if (!g_dacImpl)
133 {
134 DacError(E_UNEXPECTED);
135 UNREACHABLE();
136 }
137
138 return g_dacImpl->m_globalBase;
139}
140
141HRESULT
142DacReadAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx)
143{
144 if (!g_dacImpl)
145 {
146 DacError(E_UNEXPECTED);
147 UNREACHABLE();
148 }
149
150 ClrSafeInt<TADDR> end = ClrSafeInt<TADDR>(addr) + ClrSafeInt<TADDR>(size);
151 if( end.IsOverflow() )
152 {
153 // Overflow - corrupt data
154 DacError(CORDBG_E_TARGET_INCONSISTENT);
155 }
156
157 HRESULT status;
158 ULONG32 returned;
159
160#if defined(DAC_MEASURE_PERF)
161 unsigned __int64 nStart, nEnd;
162 nStart = GetCycleCount();
163#endif // #if defined(DAC_MEASURE_PERF)
164
165 status = g_dacImpl->m_pTarget->
166 ReadVirtual(addr, (PBYTE)buffer, size, &returned);
167
168#if defined(DAC_MEASURE_PERF)
169 nEnd = GetCycleCount();
170 g_nReadVirtualTotalTime += nEnd - nStart;
171#endif // #if defined(DAC_MEASURE_PERF)
172
173 if (status != S_OK)
174 {
175 // Regardless of what status is, it's very important for dump debugging to
176 // always return CORDBG_E_READVIRTUAL_FAILURE.
177 if (throwEx)
178 {
179 DacError(CORDBG_E_READVIRTUAL_FAILURE);
180 }
181 return CORDBG_E_READVIRTUAL_FAILURE;
182 }
183 if (returned != size)
184 {
185 if (throwEx)
186 {
187 DacError(HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY));
188 }
189 return HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
190 }
191
192 return S_OK;
193}
194
195HRESULT
196DacWriteAll(TADDR addr, PVOID buffer, ULONG32 size, bool throwEx)
197{
198 if (!g_dacImpl)
199 {
200 DacError(E_UNEXPECTED);
201 UNREACHABLE();
202 }
203
204 HRESULT status;
205
206 status = g_dacImpl->m_pMutableTarget->WriteVirtual(addr, (PBYTE)buffer, size);
207 if (status != S_OK)
208 {
209 if (throwEx)
210 {
211 DacError(status);
212 }
213 return status;
214 }
215
216 return S_OK;
217}
218
219#ifdef FEATURE_PAL
220
221static BOOL DacReadAllAdapter(PVOID address, PVOID buffer, SIZE_T size)
222{
223 DAC_INSTANCE* inst = g_dacImpl->m_instances.Find((TADDR)address);
224 if (inst == nullptr || inst->size < size)
225 {
226 inst = g_dacImpl->m_instances.Alloc((TADDR)address, size, DAC_PAL);
227 if (inst == nullptr)
228 {
229 return FALSE;
230 }
231 inst->noReport = 0;
232 HRESULT hr = DacReadAll((TADDR)address, inst + 1, size, false);
233 if (FAILED(hr))
234 {
235 g_dacImpl->m_instances.ReturnAlloc(inst);
236 return FALSE;
237 }
238 if (!g_dacImpl->m_instances.Add(inst))
239 {
240 g_dacImpl->m_instances.ReturnAlloc(inst);
241 return FALSE;
242 }
243 }
244 memcpy(buffer, inst + 1, size);
245 return TRUE;
246}
247
248HRESULT
249DacVirtualUnwind(DWORD threadId, PT_CONTEXT context, PT_KNONVOLATILE_CONTEXT_POINTERS contextPointers)
250{
251 if (!g_dacImpl)
252 {
253 DacError(E_UNEXPECTED);
254 UNREACHABLE();
255 }
256
257 // The DAC code doesn't use these context pointers but zero them out to be safe.
258 if (contextPointers != NULL)
259 {
260 memset(contextPointers, 0, sizeof(T_KNONVOLATILE_CONTEXT_POINTERS));
261 }
262
263 HRESULT hr = S_OK;
264
265#ifdef FEATURE_DATATARGET4
266 ReleaseHolder<ICorDebugDataTarget4> dt;
267 hr = g_dacImpl->m_pTarget->QueryInterface(IID_ICorDebugDataTarget4, (void **)&dt);
268 if (SUCCEEDED(hr))
269 {
270 hr = dt->VirtualUnwind(threadId, sizeof(CONTEXT), (BYTE*)context);
271 }
272 else
273#endif
274 {
275 SIZE_T baseAddress = DacGlobalBase();
276 if (baseAddress == 0 || !PAL_VirtualUnwindOutOfProc(context, contextPointers, baseAddress, DacReadAllAdapter))
277 {
278 hr = E_FAIL;
279 }
280 }
281
282 return hr;
283}
284
285#endif // FEATURE_PAL
286
287// DacAllocVirtual - Allocate memory from the target process
288// Note: this is only available to clients supporting the legacy
289// ICLRDataTarget2 interface. It's currently used by SOS for notification tables.
290HRESULT
291DacAllocVirtual(TADDR addr, ULONG32 size,
292 ULONG32 typeFlags, ULONG32 protectFlags,
293 bool throwEx, TADDR* mem)
294{
295 if (!g_dacImpl)
296 {
297 DacError(E_UNEXPECTED);
298 UNREACHABLE();
299 }
300
301 ICLRDataTarget2 * pTarget2 = g_dacImpl->GetLegacyTarget2();
302 if (pTarget2 == NULL)
303 {
304 DacError(E_NOTIMPL);
305 UNREACHABLE();
306 }
307
308 CLRDATA_ADDRESS cdaMem;
309 HRESULT status = pTarget2->AllocVirtual(
310 TO_CDADDR(addr), size, typeFlags, protectFlags, &cdaMem);
311 if (status != S_OK)
312 {
313 if (throwEx)
314 {
315 DacError(status);
316 UNREACHABLE();
317 }
318
319 return status;
320 }
321
322 *mem = CLRDATA_ADDRESS_TO_TADDR(cdaMem);
323 return S_OK;
324}
325
326// DacFreeVirtual - Free memory from the target process
327// Note: this is only available to clients supporting the legacy
328// ICLRDataTarget2 interface. This is not currently used.
329HRESULT
330DacFreeVirtual(TADDR mem, ULONG32 size, ULONG32 typeFlags,
331 bool throwEx)
332{
333 if (!g_dacImpl)
334 {
335 DacError(E_UNEXPECTED);
336 UNREACHABLE();
337 }
338
339 ICLRDataTarget2 * pTarget2 = g_dacImpl->GetLegacyTarget2();
340 if (pTarget2 == NULL)
341 {
342 DacError(E_NOTIMPL);
343 UNREACHABLE();
344 }
345
346 HRESULT status = pTarget2->FreeVirtual(
347 TO_CDADDR(mem), size, typeFlags);
348
349 if (status != S_OK && throwEx)
350 {
351 DacError(status);
352 UNREACHABLE();
353 }
354
355 return status;
356}
357
358PVOID
359DacInstantiateTypeByAddressHelper(TADDR addr, ULONG32 size, bool throwEx, bool fReport)
360{
361#ifdef _PREFIX_
362
363 // Dac accesses are not interesting for PREfix and cause a lot of PREfix noise
364 // so we just return the unmodified pointer for our PREFIX builds
365 return (PVOID)addr;
366
367#else // !_PREFIX_
368
369 if (!g_dacImpl)
370 {
371 DacError(E_UNEXPECTED);
372 UNREACHABLE();
373 }
374
375 // Preserve special pointer values.
376 if (!addr || addr == (TADDR)-1)
377 {
378 return (PVOID)addr;
379 }
380
381 // DacInstanceManager::Alloc will assert (with a non-obvious message) on 0-size instances.
382 // Fail sooner and more obviously here.
383 _ASSERTE_MSG( size > 0, "DAC coding error: instance size cannot be 0" );
384
385 // Do not attempt to allocate more than 64megs for one object instance. While we should
386 // never even come close to this size, in cases of heap corruption or bogus data passed
387 // into the dac, we can allocate huge amounts of data if we are unlucky. This santiy
388 // checks the size to ensure we don't allocate gigs of data.
389 if (size > 0x4000000)
390 {
391 if (throwEx)
392 {
393 DacError(E_OUTOFMEMORY);
394 }
395 return NULL;
396 }
397
398 //
399 // Check the cache for an existing DPTR instance.
400 // It's possible that a previous access may have been
401 // smaller than the current access, so we have to
402 // allow an existing instance to be superseded.
403 //
404
405 DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr);
406 DAC_INSTANCE* oldInst = NULL;
407 if (inst)
408 {
409 // If the existing instance is large enough we
410 // can reuse it, otherwise we need to promote.
411 // We cannot promote a VPTR as the VPTR data
412 // has been updated with a host vtable and we
413 // don't want to lose that. This shouldn't
414 // happen anyway.
415 if (inst->size >= size)
416 {
417 return inst + 1;
418 }
419 else
420 {
421 // Existing instance is too small and must
422 // be superseded.
423 if (inst->usage == DAC_VPTR)
424 {
425 // The same address has already been marshalled as a VPTR, now we're trying to marshal as a
426 // DPTR. This is not allowed.
427 _ASSERTE_MSG(false, "DAC coding error: DPTR/VPTR usage conflict");
428 DacError(E_INVALIDARG);
429 UNREACHABLE();
430 }
431
432 // Promote the larger instance into the hash
433 // in place of the smaller, but keep the
434 // smaller instance around in case code still
435 // has a pointer to it. But ensure that we can
436 // create the larger instance and add it to the
437 // hash table before removing the old one.
438 oldInst = inst;
439 }
440 }
441
442 inst = g_dacImpl->m_instances.Alloc(addr, size, DAC_DPTR);
443 if (!inst)
444 {
445 DacError(E_OUTOFMEMORY);
446 UNREACHABLE();
447 }
448
449 if (fReport == false)
450 {
451 // mark the bit if necessary
452 inst->noReport = 1;
453 }
454 else
455 {
456 // clear the bit
457 inst->noReport = 0;
458 }
459 HRESULT status = DacReadAll(addr, inst + 1, size, false);
460 if (status != S_OK)
461 {
462 g_dacImpl->m_instances.ReturnAlloc(inst);
463 if (throwEx)
464 {
465 DacError(status);
466 }
467 return NULL;
468 }
469
470 if (!g_dacImpl->m_instances.Add(inst))
471 {
472 g_dacImpl->m_instances.ReturnAlloc(inst);
473 DacError(E_OUTOFMEMORY);
474 UNREACHABLE();
475 }
476
477 if (oldInst)
478 {
479 g_dacImpl->m_instances.Supersede(oldInst);
480 }
481
482 return inst + 1;
483
484#endif // !_PREFIX_
485}
486
487PVOID DacInstantiateTypeByAddress(TADDR addr, ULONG32 size, bool throwEx)
488{
489 return DacInstantiateTypeByAddressHelper(addr, size, throwEx, true);
490}
491
492PVOID DacInstantiateTypeByAddressNoReport(TADDR addr, ULONG32 size, bool throwEx)
493{
494 return DacInstantiateTypeByAddressHelper(addr, size, throwEx, false);
495}
496
497
498PVOID
499DacInstantiateClassByVTable(TADDR addr, ULONG32 minSize, bool throwEx)
500{
501#ifdef _PREFIX_
502
503 // Dac accesses are not interesting for PREfix and cause a lot of PREfix noise
504 // so we just return the unmodified pointer for our PREFIX builds
505 return (PVOID)addr;
506
507#else // !_PREFIX_
508
509 if (!g_dacImpl)
510 {
511 DacError(E_UNEXPECTED);
512 UNREACHABLE();
513 }
514
515 // Preserve special pointer values.
516 if (!addr || addr == (TADDR)-1)
517 {
518 return (PVOID)addr;
519 }
520
521 // Do not attempt to allocate more than 64megs for one object instance. While we should
522 // never even come close to this size, in cases of heap corruption or bogus data passed
523 // into the dac, we can allocate huge amounts of data if we are unlucky. This santiy
524 // checks the size to ensure we don't allocate gigs of data.
525 if (minSize > 0x4000000)
526 {
527 if (throwEx)
528 {
529 DacError(E_OUTOFMEMORY);
530 }
531 return NULL;
532 }
533
534 //
535 // Check the cache for an existing VPTR instance.
536 // If there is an instance we assume that it's
537 // the right object.
538 //
539
540 DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr);
541 DAC_INSTANCE* oldInst = NULL;
542 if (inst)
543 {
544 // If the existing instance is a VPTR we can
545 // reuse it, otherwise we need to promote.
546 if (inst->usage == DAC_VPTR)
547 {
548 // Sanity check that the object we're returning is big enough to fill the PTR type it's being
549 // accessed with. For more information, see the similar check below for the case when the
550 // object isn't already cached
551 _ASSERTE_MSG(inst->size >= minSize, "DAC coding error: Attempt to instantiate a VPTR from an object that is too small");
552
553 return inst + 1;
554 }
555 else
556 {
557 // Existing instance is not a match and must
558 // be superseded.
559 // Promote the new instance into the hash
560 // in place of the old, but keep the
561 // old instance around in case code still
562 // has a pointer to it. But ensure that we can
563 // create the larger instance and add it to the
564 // hash table before removing the old one.
565 oldInst = inst;
566 }
567 }
568
569 HRESULT status;
570 TADDR vtAddr;
571 ULONG32 size;
572 PVOID hostVtPtr;
573
574 // Read the vtable pointer to get the actual
575 // implementation class identity.
576 if ((status = DacReadAll(addr, &vtAddr, sizeof(vtAddr), throwEx)) != S_OK)
577 {
578 return NULL;
579 }
580
581 //
582 // Instantiate the right class, using the vtable as
583 // class identity.
584 //
585
586#define VPTR_CLASS(name) \
587 if (vtAddr == g_dacImpl->m_globalBase + \
588 g_dacGlobals.name##__vtAddr) \
589 { \
590 size = sizeof(name); \
591 hostVtPtr = g_dacHostVtPtrs.name; \
592 } \
593 else
594#define VPTR_MULTI_CLASS(name, keyBase) \
595 if (vtAddr == g_dacImpl->m_globalBase + \
596 g_dacGlobals.name##__##keyBase##__mvtAddr) \
597 { \
598 size = sizeof(name); \
599 hostVtPtr = g_dacHostVtPtrs.name##__##keyBase; \
600 } \
601 else
602#include <vptr_list.h>
603#undef VPTR_CLASS
604#undef VPTR_MULTI_CLASS
605
606 {
607 // Can't identify the vtable pointer.
608 if (throwEx)
609 {
610 _ASSERTE_MSG(false,"DAC coding error: Unrecognized vtable pointer in VPTR marshalling code");
611 DacError(E_INVALIDARG);
612 }
613 return NULL;
614 }
615
616 // Sanity check that the object we're returning is big enough to fill the PTR type it's being
617 // accessed with.
618 // If this is not true, it means the type being marshalled isn't a sub-type (or the same type)
619 // as the PTR type it's being used as. For example, trying to marshal an instance of a SystemDomain
620 // object into a PTR_AppDomain will cause this ASSERT to fire (because both SystemDomain and AppDomain
621 // derived from BaseDomain, and SystemDomain is smaller than AppDomain).
622 _ASSERTE_MSG(size >= minSize, "DAC coding error: Attempt to instantiate a VPTR from an object that is too small");
623
624 inst = g_dacImpl->m_instances.Alloc(addr, size, DAC_VPTR);
625 if (!inst)
626 {
627 DacError(E_OUTOFMEMORY);
628 UNREACHABLE();
629 }
630
631 // Copy the object contents into the host instance. Note that this assumes the host and target
632 // have the same exact layout. Specifically, it assumes the host and target vtable pointers are
633 // the same size.
634 if ((status = DacReadAll(addr, inst + 1, size, false)) != S_OK)
635 {
636 g_dacImpl->m_instances.ReturnAlloc(inst);
637 if (throwEx)
638 {
639 DacError(status);
640 }
641 return NULL;
642 }
643
644 // We now have a proper target object with a target
645 // vtable. We need to patch the vtable to the appropriate
646 // host vtable so that the virtual functions can be
647 // called in the host process.
648 *(PVOID*)(inst + 1) = hostVtPtr;
649
650 if (!g_dacImpl->m_instances.Add(inst))
651 {
652 g_dacImpl->m_instances.ReturnAlloc(inst);
653 DacError(E_OUTOFMEMORY);
654 UNREACHABLE();
655 }
656
657 if (oldInst)
658 {
659 g_dacImpl->m_instances.Supersede(oldInst);
660 }
661 return inst + 1;
662
663#endif // !_PREFIX_
664}
665
666#define LOCAL_STR_BUF 256
667
668PSTR
669DacInstantiateStringA(TADDR addr, ULONG32 maxChars, bool throwEx)
670{
671#ifdef _PREFIX_
672
673 // Dac accesses are not interesting for PREfix and cause a lot of PREfix noise
674 // so we just return the unmodified pointer for our PREFIX builds
675 return (PSTR)addr;
676
677#else // !_PREFIX_
678
679 HRESULT status;
680
681 if (!g_dacImpl)
682 {
683 DacError(E_UNEXPECTED);
684 UNREACHABLE();
685 }
686
687 // Preserve special pointer values.
688 if (!addr || addr == (TADDR)-1)
689 {
690 return (PSTR)addr;
691 }
692
693
694 // Do not attempt to allocate more than 64megs for a string. While we should
695 // never even come close to this size, in cases of heap corruption or bogus data passed
696 // into the dac, we can allocate huge amounts of data if we are unlucky. This santiy
697 // checks the size to ensure we don't allocate gigs of data.
698 if (maxChars > 0x4000000)
699 {
700 if (throwEx)
701 {
702 DacError(E_OUTOFMEMORY);
703 }
704 return NULL;
705 }
706
707 //
708 // Look for an existing string instance.
709 //
710
711 DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr);
712 if (inst && inst->usage == DAC_STRA)
713 {
714 return (PSTR)(inst + 1);
715 }
716
717 //
718 // Determine the length of the string
719 // by iteratively reading blocks and scanning them
720 // for a terminator.
721 //
722
723 char buf[LOCAL_STR_BUF];
724 TADDR scanAddr = addr;
725 ULONG32 curBytes = 0;
726 ULONG32 returned;
727
728 for (;;)
729 {
730 status = g_dacImpl->m_pTarget->
731 ReadVirtual(scanAddr, (PBYTE)buf, sizeof(buf),
732 &returned);
733 if (status != S_OK)
734 {
735 // We hit invalid memory before finding a terminator.
736 if (throwEx)
737 {
738 DacError(CORDBG_E_READVIRTUAL_FAILURE);
739 }
740 return NULL;
741 }
742
743 PSTR scan = (PSTR)buf;
744 PSTR scanEnd = scan + (returned / sizeof(*scan));
745 while (scan < scanEnd)
746 {
747 if (!*scan)
748 {
749 break;
750 }
751
752 scan++;
753 }
754
755 if (!*scan)
756 {
757 // Found a terminator.
758 scanAddr += ((scan + 1) - buf) * sizeof(*scan);
759 break;
760 }
761
762 // Ignore any partial character reads. The character
763 // will be reread on the next loop if necessary.
764 returned &= ~(sizeof(buf[0]) - 1);
765
766 // The assumption is that a memory read cannot wrap
767 // around the address space, thus if we have read to
768 // the top of memory scanAddr cannot wrap farther
769 // than to zero.
770 curBytes += returned;
771 scanAddr += returned;
772
773 if (!scanAddr ||
774 (curBytes + sizeof(buf[0]) - 1) / sizeof(buf[0]) >= maxChars)
775 {
776 // Wrapped around the top of memory or
777 // we didn't find a terminator within the given bound.
778 if (throwEx)
779 {
780 DacError(E_INVALIDARG);
781 }
782 return NULL;
783 }
784 }
785
786 // Now that we know the length we can create a
787 // host copy of the string.
788 PSTR retVal = (PSTR)
789 DacInstantiateTypeByAddress(addr, (ULONG32)(scanAddr - addr), throwEx);
790 if (retVal &&
791 (inst = g_dacImpl->m_instances.Find(addr)))
792 {
793 inst->usage = DAC_STRA;
794 }
795 return retVal;
796
797#endif // !_PREFIX_
798}
799
800PWSTR
801DacInstantiateStringW(TADDR addr, ULONG32 maxChars, bool throwEx)
802{
803#ifdef _PREFIX_
804
805 // Dac accesses are not interesting for PREfix and cause a lot of PREfix noise
806 // so we just return the unmodified pointer for our PREFIX builds
807 return (PWSTR)addr;
808
809#else // !_PREFIX_
810
811 HRESULT status;
812
813 if (!g_dacImpl)
814 {
815 DacError(E_UNEXPECTED);
816 UNREACHABLE();
817 }
818
819 // Preserve special pointer values.
820 if (!addr || addr == (TADDR)-1)
821 {
822 return (PWSTR)addr;
823 }
824
825 // Do not attempt to allocate more than 64megs for a string. While we should
826 // never even come close to this size, in cases of heap corruption or bogus data passed
827 // into the dac, we can allocate huge amounts of data if we are unlucky. This santiy
828 // checks the size to ensure we don't allocate gigs of data.
829 if (maxChars > 0x4000000)
830 {
831 if (throwEx)
832 {
833 DacError(E_OUTOFMEMORY);
834 }
835 return NULL;
836 }
837
838
839 //
840 // Look for an existing string instance.
841 //
842
843 DAC_INSTANCE* inst = g_dacImpl->m_instances.Find(addr);
844 if (inst && inst->usage == DAC_STRW)
845 {
846 return (PWSTR)(inst + 1);
847 }
848
849 //
850 // Determine the length of the string
851 // by iteratively reading blocks and scanning them
852 // for a terminator.
853 //
854
855 WCHAR buf[LOCAL_STR_BUF];
856 TADDR scanAddr = addr;
857 ULONG32 curBytes = 0;
858 ULONG32 returned;
859
860 for (;;)
861 {
862 status = g_dacImpl->m_pTarget->
863 ReadVirtual(scanAddr, (PBYTE)buf, sizeof(buf),
864 &returned);
865 if (status != S_OK)
866 {
867 // We hit invalid memory before finding a terminator.
868 if (throwEx)
869 {
870 DacError(CORDBG_E_READVIRTUAL_FAILURE);
871 }
872 return NULL;
873 }
874
875 PWSTR scan = (PWSTR)buf;
876 PWSTR scanEnd = scan + (returned / sizeof(*scan));
877 while (scan < scanEnd)
878 {
879 if (!*scan)
880 {
881 break;
882 }
883
884 scan++;
885 }
886
887 if (!*scan)
888 {
889 // Found a terminator.
890 scanAddr += ((scan + 1) - buf) * sizeof(*scan);
891 break;
892 }
893
894 // Ignore any partial character reads. The character
895 // will be reread on the next loop if necessary.
896 returned &= ~(sizeof(buf[0]) - 1);
897
898 // The assumption is that a memory read cannot wrap
899 // around the address space, thus if we have read to
900 // the top of memory scanAddr cannot wrap farther
901 // than to zero.
902 curBytes += returned;
903 scanAddr += returned;
904
905 if (!scanAddr ||
906 (curBytes + sizeof(buf[0]) - 1) / sizeof(buf[0]) >= maxChars)
907 {
908 // Wrapped around the top of memory or
909 // we didn't find a terminator within the given bound.
910 if (throwEx)
911 {
912 DacError(E_INVALIDARG);
913 }
914 return NULL;
915 }
916 }
917
918 // Now that we know the length we can create a
919 // host copy of the string.
920 PWSTR retVal = (PWSTR)
921 DacInstantiateTypeByAddress(addr, (ULONG32)(scanAddr - addr), throwEx);
922 if (retVal &&
923 (inst = g_dacImpl->m_instances.Find(addr)))
924 {
925 inst->usage = DAC_STRW;
926 }
927 return retVal;
928
929#endif // !_PREFIX_
930}
931
932TADDR
933DacGetTargetAddrForHostAddr(LPCVOID ptr, bool throwEx)
934{
935#ifdef _PREFIX_
936
937 // Dac accesses are not interesting for PREfix and cause a lot of PREfix noise
938 // so we just return the unmodified pointer for our PREFIX builds
939 return (TADDR) ptr;
940
941#else // !_PREFIX_
942
943 // Preserve special pointer values.
944 if (ptr == NULL || ((TADDR) ptr == (TADDR)-1))
945 {
946 return 0;
947 }
948 else
949 {
950 TADDR addr = 0;
951 HRESULT status = E_FAIL;
952
953 EX_TRY
954 {
955 DAC_INSTANCE* inst = (DAC_INSTANCE*)ptr - 1;
956 if (inst->sig == DAC_INSTANCE_SIG)
957 {
958 addr = inst->addr;
959 status = S_OK;
960 }
961 else
962 {
963 status = E_INVALIDARG;
964 }
965 }
966 EX_CATCH
967 {
968 status = E_INVALIDARG;
969 }
970 EX_END_CATCH(SwallowAllExceptions)
971
972 if (status != S_OK)
973 {
974 if (g_dacImpl && g_dacImpl->m_debugMode)
975 {
976 DebugBreak();
977 }
978
979 if (throwEx)
980 {
981 // This means a pointer was supplied which doesn't actually point to the beginning of
982 // a marshalled DAC instance.
983 _ASSERTE_MSG(false, "DAC coding error: Attempt to get target address from a host pointer "
984 "which is not an instance marshalled by DAC!");
985 DacError(status);
986 }
987 }
988
989 return addr;
990 }
991
992#endif // !_PREFIX_
993}
994
995// Similar to DacGetTargetAddrForHostAddr above except that ptr can represent any pointer within a host data
996// structure marshalled from the target (rather than just a pointer to the first field).
997TADDR
998DacGetTargetAddrForHostInteriorAddr(LPCVOID ptr, bool throwEx)
999{
1000 // Our algorithm for locating the containing DAC instance will search backwards through memory in
1001 // DAC_INSTANCE_ALIGN increments looking for a valid header. The following constant determines how many of
1002 // these iterations we'll perform before deciding the caller made a mistake and didn't marshal the
1003 // containing instance from the target to the host properly. Lower values will determine the maximum
1004 // offset from the start of a marshalled structure at which an interior pointer can appear. Higher values
1005 // will bound the amount of time it takes to report an error in the case where code has been incorrectly
1006 // DAC-ized.
1007 const DWORD kMaxSearchIterations = 100;
1008
1009#ifdef _PREFIX_
1010
1011 // Dac accesses are not interesting for PREfix and cause a lot of PREfix noise
1012 // so we just return the unmodified pointer for our PREFIX builds
1013 return (TADDR) ptr;
1014
1015#else // !_PREFIX_
1016
1017 // Preserve special pointer values.
1018 if (ptr == NULL || ((TADDR) ptr == (TADDR)-1))
1019 {
1020 return 0;
1021 }
1022 else
1023 {
1024 TADDR addr = 0;
1025 HRESULT status = E_FAIL;
1026
1027 EX_TRY
1028 {
1029 // We're going to search backwards through memory from the pointer looking for a valid DAC
1030 // instance header. Initialize this search pointer to the first legal value it could hold.
1031 // Intuitively this would be ptr - sizeof(DAC_INSTANCE), but DAC_INSTANCE headers are further
1032 // constrained to lie on DAC_INSTANCE_ALIGN boundaries. DAC_INSTANCE_ALIGN is large (16 bytes) due
1033 // to the need to keep the marshalled structure also aligned for any possible need, so we gain
1034 // considerable performance from only needing to test for DAC_INSTANCE headers at
1035 // DAC_INSTANCE_ALIGN aligned addresses.
1036 DAC_INSTANCE * inst = (DAC_INSTANCE*)(((ULONG_PTR)ptr - sizeof(DAC_INSTANCE)) & ~(DAC_INSTANCE_ALIGN - 1));
1037
1038 // When code is DAC'ized correctly then our search algorithm is guaranteed to terminate safely
1039 // before reading memory that doesn't belong to the containing DAC instance. Since people do make
1040 // mistakes we want to limit how long and far we search however. The counter below will let us
1041 // assert if we've likely tried to locate an interior host pointer in a non-marshalled structure.
1042 DWORD cIterations = 0;
1043
1044 bool tryAgain = false;
1045
1046 // Scan backwards in memory looking for a DAC_INSTANCE header.
1047 while (true)
1048 {
1049 // Step back DAC_INSTANCE_ALIGN bytes at a time (the initialization of inst above guarantees
1050 // we start with an aligned pointer value. Stop every time our potential DAC_INSTANCE header
1051 // has a correct signature value.
1052 while (tryAgain || inst->sig != DAC_INSTANCE_SIG)
1053 {
1054 tryAgain = false;
1055 inst = (DAC_INSTANCE*)((BYTE*)inst - DAC_INSTANCE_ALIGN);
1056
1057 // If we've searched a lot of memory (currently 100 * 16 == 1600 bytes) without success,
1058 // then assume this is due to an issue DAC-izing code (if you really do have a field within a
1059 // DAC marshalled structure whose offset is >1600 bytes then feel free to update the
1060 // constant at the start of this method).
1061 if (++cIterations > kMaxSearchIterations)
1062 {
1063 status = E_INVALIDARG;
1064 break;
1065 }
1066 }
1067
1068 // Fall through to a DAC error if we searched too long without finding a header candidate.
1069 if (status == E_INVALIDARG)
1070 break;
1071
1072 // Validate our candidate header by looking up the target address it claims to map in the
1073 // instance hash. The entry should both exist and correspond exactly to our candidate instance
1074 // pointer.
1075 // TODO: but what if the same memory was marshalled more than once (eg. once as a DPTR, once as a VPTR)?
1076 if (inst == g_dacImpl->m_instances.Find(inst->addr))
1077 {
1078 // We've found a valid DAC instance. Now validate that the marshalled structure it
1079 // represents really does enclose the pointer we're asking about. If not, someone hasn't
1080 // marshalled a containing structure before trying to map a pointer within that structure
1081 // (we've just gone and found the previous, unrelated marshalled structure in host memory).
1082 BYTE * parent = (BYTE*)(inst + 1);
1083 if (((BYTE*)ptr + sizeof(LPCVOID)) <= (parent + inst->size))
1084 {
1085 // Everything checks out: we've found a DAC instance header and its address range
1086 // encompasses the pointer we're interested in. Compute the corresponding target
1087 // address by taking into account the offset of the interior pointer into its
1088 // enclosing structure.
1089 addr = inst->addr + ((BYTE*)ptr - parent);
1090 status = S_OK;
1091 }
1092 else
1093 {
1094 // We found a valid DAC instance but it doesn't cover the address range containing our
1095 // input pointer. Fall though to report an erroring DAC-izing code.
1096 status = E_INVALIDARG;
1097 }
1098 break;
1099 }
1100 else
1101 {
1102 // This must not really be a match, perhaps a coincidence?
1103 // Keep searching
1104 tryAgain = true;
1105 }
1106 }
1107 }
1108 EX_CATCH
1109 {
1110 status = E_INVALIDARG;
1111 }
1112 EX_END_CATCH(SwallowAllExceptions)
1113
1114 if (status != S_OK)
1115 {
1116 if (g_dacImpl && g_dacImpl->m_debugMode)
1117 {
1118 DebugBreak();
1119 }
1120
1121 if (throwEx)
1122 {
1123 // This means a pointer was supplied which doesn't actually point to somewhere in a marshalled
1124 // DAC instance.
1125 _ASSERTE_MSG(false, "DAC coding error: Attempt to get target address from a host interior "
1126 "pointer which is not an instance marshalled by DAC!");
1127 DacError(status);
1128 }
1129 }
1130
1131 return addr;
1132 }
1133#endif // !_PREFIX_
1134}
1135
1136PWSTR DacGetVtNameW(TADDR targetVtable)
1137{
1138 PWSTR pszRet = NULL;
1139
1140 ULONG *targ = &g_dacGlobals.Thread__vtAddr;
1141 ULONG *targStart = targ;
1142 for (ULONG i = 0; i < sizeof(g_dacHostVtPtrs) / sizeof(PVOID); i++)
1143 {
1144 if (targetVtable == (*targ + DacGlobalBase()))
1145 {
1146 pszRet = (PWSTR) *(g_dacVtStrings + (targ - targStart));
1147 break;
1148 }
1149
1150 targ++;
1151 }
1152 return pszRet;
1153}
1154
1155TADDR
1156DacGetTargetVtForHostVt(LPCVOID vtHost, bool throwEx)
1157{
1158 PVOID* host;
1159 ULONG* targ;
1160 ULONG i;
1161
1162 // The host vtable table exactly parallels the
1163 // target vtable table, so just iterate to a match
1164 // return the matching entry.
1165 host = &g_dacHostVtPtrs.Thread;
1166 targ = &g_dacGlobals.Thread__vtAddr;
1167 for (i = 0; i < sizeof(g_dacHostVtPtrs) / sizeof(PVOID); i++)
1168 {
1169 if (*host == vtHost)
1170 {
1171 return *targ + DacGlobalBase();
1172 }
1173
1174 host++;
1175 targ++;
1176 }
1177
1178 if (throwEx)
1179 {
1180 DacError(E_INVALIDARG);
1181 }
1182 return 0;
1183}
1184
1185//
1186// DacEnumMemoryRegion - report a region of memory to the dump generation code
1187//
1188// Parameters:
1189// addr - target address of the beginning of the memory region
1190// size - number of bytes to report
1191// fExpectSuccess - whether or not ASSERTs should be raised if some memory in this region
1192// is found to be unreadable. Generally we should only report readable
1193// memory (unless the target is corrupt, in which case we expect asserts
1194// if target consistency checking is enabled). Reporting memory that
1195// isn't fully readable often indicates an issue that could cause much worse
1196// problems (loss of dump data, long/infinite loops in dump generation),
1197// so we want to try and catch any such usage. Ocassionally we can't say
1198// for sure how much of the reported region will be readable (eg. for the
1199// LoaderHeap, we only know the length of the allocated address space, not
1200// the size of the commit region for every block). In these special cases,
1201// we pass false to indicate that we're happy reporting up to the first
1202// unreadable byte. This should be avoided if at all possible.
1203//
1204bool DacEnumMemoryRegion(TADDR addr, TSIZE_T size, bool fExpectSuccess /*=true*/)
1205{
1206 if (!g_dacImpl)
1207 {
1208 DacError(E_UNEXPECTED);
1209 UNREACHABLE();
1210 }
1211
1212 return g_dacImpl->ReportMem(addr, size, fExpectSuccess);
1213}
1214
1215//
1216// DacUpdateMemoryRegion - updates/poisons a region of memory of generated dump
1217//
1218// Parameters:
1219// addr - target address of the beginning of the memory region
1220// bufferSize - number of bytes to update/poison
1221// buffer - data to be written at given target address
1222//
1223bool DacUpdateMemoryRegion(TADDR addr, TSIZE_T bufferSize, BYTE* buffer)
1224{
1225 if (!g_dacImpl)
1226 {
1227 DacError(E_UNEXPECTED);
1228 UNREACHABLE();
1229 }
1230
1231 return g_dacImpl->DacUpdateMemoryRegion(addr, bufferSize, buffer);
1232}
1233
1234HRESULT
1235DacWriteHostInstance(PVOID host, bool throwEx)
1236{
1237 if (!g_dacImpl)
1238 {
1239 DacError(E_UNEXPECTED);
1240 UNREACHABLE();
1241 }
1242
1243 TADDR addr = DacGetTargetAddrForHostAddr(host, throwEx);
1244 if (!addr)
1245 {
1246 return S_OK;
1247 }
1248
1249 DAC_INSTANCE* inst = (DAC_INSTANCE*)host - 1;
1250 return g_dacImpl->m_instances.Write(inst, throwEx);
1251}
1252
1253bool
1254DacHostPtrHasEnumMark(LPCVOID host)
1255{
1256 if (!DacGetTargetAddrForHostAddr(host, false))
1257 {
1258 // Make it easy to ignore invalid pointers when enumerating.
1259 return true;
1260 }
1261
1262 DAC_INSTANCE* inst = ((DAC_INSTANCE*)host) - 1;
1263 bool marked = inst->enumMem ? true : false;
1264 inst->enumMem = true;
1265 return marked;
1266}
1267
1268bool
1269DacHasMethodDescBeenEnumerated(LPCVOID pMD)
1270{
1271 if (!DacGetTargetAddrForHostAddr(pMD, false))
1272 {
1273 // Make it easy to ignore invalid pointers when enumerating.
1274 return true;
1275 }
1276
1277 DAC_INSTANCE* inst = ((DAC_INSTANCE*) pMD) - 1;
1278 bool MDEnumed = inst->MDEnumed ? true : false;
1279 return MDEnumed;
1280}
1281
1282bool
1283DacSetMethodDescEnumerated(LPCVOID pMD)
1284{
1285 if (!DacGetTargetAddrForHostAddr(pMD, false))
1286 {
1287 // Make it easy to ignore invalid pointers when enumerating.
1288 return true;
1289 }
1290
1291 DAC_INSTANCE* inst = ((DAC_INSTANCE*) pMD) - 1;
1292 bool MDEnumed = inst->MDEnumed ? true : false;
1293 inst->MDEnumed = true;
1294 return MDEnumed;
1295}
1296
1297// This gets called from DAC-ized code in the VM.
1298IMDInternalImport*
1299DacGetMDImport(const PEFile* peFile, bool throwEx)
1300{
1301 if (!g_dacImpl)
1302 {
1303 DacError(E_UNEXPECTED);
1304 UNREACHABLE();
1305 }
1306
1307 return g_dacImpl->GetMDImport(peFile, throwEx);
1308}
1309
1310IMDInternalImport*
1311DacGetMDImport(const ReflectionModule* reflectionModule, bool throwEx)
1312{
1313 if (!g_dacImpl)
1314 {
1315 DacError(E_UNEXPECTED);
1316 UNREACHABLE();
1317 }
1318
1319 return g_dacImpl->GetMDImport(reflectionModule, throwEx);
1320}
1321
1322COR_ILMETHOD*
1323DacGetIlMethod(TADDR methAddr)
1324{
1325 ULONG32 methodSize = static_cast<ULONG32>(PEDecoder::ComputeILMethodSize(methAddr));
1326
1327 // Sometimes when reading from dumps and inspect NGEN images, but we end up reading metadata from IL image
1328 // the method RVA could not match and we could read from a random address that will translate in inconsistent
1329 // IL code header. If we see the size of the code bigger than 64 Megs we are probably reading a bad IL code header.
1330 // For details see issue DevDiv 273199.
1331 if (methodSize > 0x4000000)
1332 {
1333 DacError(CORDBG_E_TARGET_INCONSISTENT);
1334 UNREACHABLE();
1335 }
1336 return (COR_ILMETHOD*)
1337 DacInstantiateTypeByAddress(methAddr, methodSize,
1338 true);
1339}
1340
1341#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1342void
1343DacMdCacheAddEEName(TADDR taEE, const SString& ssEEName)
1344{
1345 if (!g_dacImpl)
1346 {
1347 DacError(E_UNEXPECTED);
1348 UNREACHABLE();
1349 }
1350
1351 g_dacImpl->MdCacheAddEEName(taEE, ssEEName);
1352}
1353bool
1354DacMdCacheGetEEName(TADDR taEE, SString & eeName)
1355{
1356 if (!g_dacImpl)
1357 {
1358 DacError(E_UNEXPECTED);
1359 UNREACHABLE();
1360 }
1361
1362 return g_dacImpl->MdCacheGetEEName(taEE, eeName);
1363}
1364
1365#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
1366
1367PVOID
1368DacAllocHostOnlyInstance(ULONG32 size, bool throwEx)
1369{
1370 SUPPORTS_DAC_HOST_ONLY;
1371 if (!g_dacImpl)
1372 {
1373 DacError(E_UNEXPECTED);
1374 UNREACHABLE();
1375 }
1376
1377 DAC_INSTANCE* inst = g_dacImpl->m_instances.Alloc(0, size, DAC_DPTR);
1378 if (!inst)
1379 {
1380 DacError(E_OUTOFMEMORY);
1381 UNREACHABLE();
1382 }
1383
1384 g_dacImpl->m_instances.AddSuperseded(inst);
1385
1386 return inst + 1;
1387}
1388
1389//
1390// Queries whether ASSERTs should be raised when inconsistencies in the target are detected
1391//
1392// Return Value:
1393// true if ASSERTs should be raised in DACized code.
1394// false if ASSERTs should be ignored.
1395//
1396// Notes:
1397// See code:ClrDataAccess::TargetConsistencyAssertsEnabled for details.
1398bool DacTargetConsistencyAssertsEnabled()
1399{
1400 if (!g_dacImpl)
1401 {
1402 // No ClrDataAccess instance available (maybe we're still initializing). Any asserts when this is
1403 // the case should only be host-asserts (i.e. always bugs), and so we should just return true.
1404 return true;
1405 }
1406
1407 return g_dacImpl->TargetConsistencyAssertsEnabled();
1408}
1409
1410//
1411// DacEnumCodeForStackwalk
1412// This is a helper function to enumerate the instructions around a call site to aid heuristics
1413// used by debugger stack walkers.
1414//
1415// Arguments:
1416// taCallEnd - target address of the instruction just after the call instruction for the stack
1417// frame we want to examine(i.e. the return address for the next frame).
1418//
1419// Note that this is shared by our two stackwalks during minidump generation,
1420// code:Thread::EnumMemoryRegionsWorker and code:ClrDataAccess::EnumMemWalkStackHelper. Ideally
1421// we'd only have one stackwalk, but we currently have two different APIs for stackwalking
1422// (CLR StackFrameIterator and IXCLRDataStackWalk), and we must ensure that the memory needed
1423// for either is captured in a minidump. Eventually, all clients should get moved over to the
1424// arrowhead debugging architecture, at which time we can rip out all the IXCLRData APIs, and
1425// so this logic could just be private to the EnumMem code for Thread.
1426//
1427void DacEnumCodeForStackwalk(TADDR taCallEnd)
1428{
1429 if (taCallEnd == 0)
1430 return;
1431 //
1432 // x86 stack walkers often end up having to guess
1433 // about what's a return address on the stack.
1434 // Doing so involves looking at the code at the
1435 // possible call site and seeing if it could
1436 // reach the callee. Save enough code and around
1437 // the call site to allow this with a dump.
1438 //
1439 // For whatever reason 64-bit platforms require us to save
1440 // the instructions around the call sites on the stack as well.
1441 // Otherwise we cannnot show the stack in a minidump.
1442 //
1443 // Note that everything we do here is a heuristic that won't always work in general.
1444 // Eg., part of the 2xMAX_INSTRUCTION_LENGTH range might not be mapped (we could be
1445 // right on a page boundary). More seriously, X86 is not necessarily parsable in reverse
1446 // (eg. there could be a segment-override prefix in front of the call instruction that
1447 // we miss). So we'll dump what we can and ignore any failures. Ideally we'd better
1448 // quantify exactly what debuggers need and why, and try and avoid these ugly heuristics.
1449 // It seems like these heuristics are too tightly coupled to the implementation details
1450 // of some specific debugger stackwalking algorithm.
1451 //
1452 DacEnumMemoryRegion(taCallEnd - MAX_INSTRUCTION_LENGTH, MAX_INSTRUCTION_LENGTH * 2, false);
1453
1454#if defined(_TARGET_X86_)
1455 // If it was an indirect call we also need to save the data indirected through.
1456 // Note that this only handles absolute indirect calls (ModR/M byte of 0x15), all the other forms of
1457 // indirect calls are register-relative, and so we'd have to do a much more complicated decoding based
1458 // on the register context. Regardless, it seems like this is fundamentally error-prone because it's
1459 // aways possible that the call instruction was not 6 bytes long, and we could have some other instructions
1460 // that happen to match the pattern we're looking for.
1461 PTR_BYTE callCode = PTR_BYTE(taCallEnd - 6);
1462 PTR_BYTE callMrm = PTR_BYTE(taCallEnd - 5);
1463 PTR_TADDR callInd = PTR_TADDR(taCallEnd - 4);
1464 if (callCode.IsValid() &&
1465 (*callCode == 0xff) &&
1466 callMrm.IsValid() &&
1467 (*callMrm == 0x15) &&
1468 callInd.IsValid())
1469 {
1470 DacEnumMemoryRegion(*callInd, sizeof(TADDR), false);
1471 }
1472#endif // #ifdef _TARGET_X86_
1473}
1474
1475// ----------------------------------------------------------------------------
1476// DacReplacePatches
1477//
1478// Description:
1479// Given the address and the size of a memory range which is stored in the buffer, replace all the patches
1480// in the buffer with the real opcodes. This is especially important on X64 where the unwinder needs to
1481// disassemble the native instructions.
1482//
1483// Arguments:
1484// * range - the address and the size of the memory range
1485// * pBuffer - the buffer containting the memory range
1486//
1487// Return Value:
1488// Return S_OK if everything succeeds.
1489//
1490// Assumptions:
1491// * The debuggee has to be stopped.
1492//
1493// Notes:
1494// * @dbgtodo ICDProcess - When we DACize code:CordbProcess::ReadMemory,
1495// we should change it to use this function.
1496//
1497
1498HRESULT DacReplacePatchesInHostMemory(MemoryRange range, PVOID pBuffer)
1499{
1500 SUPPORTS_DAC;
1501
1502 // If the patch table is invalid, then there is no patch to replace.
1503 if (!DebuggerController::GetPatchTableValid())
1504 {
1505 return S_OK;
1506 }
1507
1508 HASHFIND info;
1509
1510 DebuggerPatchTable * pTable = DebuggerController::GetPatchTable();
1511 DebuggerControllerPatch * pPatch = pTable->GetFirstPatch(&info);
1512
1513 // <PERF>
1514 // The unwinder needs to read the stack very often to restore pushed registers, retrieve the
1515 // return addres, etc. However, stack addresses should never be patched.
1516 // One way to optimize this code is to pass the stack base and the stack limit of the thread to this
1517 // function and use those two values to filter out stack addresses.
1518 //
1519 // Another thing we can do is instead of enumerating the patches, we could enumerate the address.
1520 // This is more efficient when we have a large number of patches and a small memory range. Perhaps
1521 // we could do a hybrid approach, i.e. use the size of the range and the number of patches to dynamically
1522 // determine which enumeration is more efficient.
1523 // </PERF>
1524 while (pPatch != NULL)
1525 {
1526 CORDB_ADDRESS patchAddress = (CORDB_ADDRESS)dac_cast<TADDR>(pPatch->address);
1527
1528 if (patchAddress != NULL)
1529 {
1530 PRD_TYPE opcode = pPatch->opcode;
1531
1532 CORDB_ADDRESS address = (CORDB_ADDRESS)(dac_cast<TADDR>(range.StartAddress()));
1533 SIZE_T cbSize = range.Size();
1534
1535 // Check if the address of the patch is in the specified memory range.
1536 if (IsPatchInRequestedRange(address, cbSize, patchAddress))
1537 {
1538 // Replace the patch in the buffer with the original opcode.
1539 CORDbgSetInstructionEx(reinterpret_cast<PBYTE>(pBuffer), address, patchAddress, opcode, cbSize);
1540 }
1541 }
1542
1543 pPatch = pTable->GetNextPatch(&info);
1544 }
1545
1546 return S_OK;
1547}
1548