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 | |
26 | DacTableInfo g_dacTableInfo; |
27 | DacGlobals g_dacGlobals; |
28 | |
29 | struct 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 | |
39 | const 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 | |
48 | DacHostVtPtrs g_dacHostVtPtrs; |
49 | |
50 | HRESULT |
51 | DacGetHostVtPtrs(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 | |
64 | bool |
65 | DacExceptionFilter(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 | |
96 | void __cdecl |
97 | DacWarning(__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 | |
109 | void |
110 | DacNotImpl(void) |
111 | { |
112 | EX_THROW(HRException, (E_NOTIMPL)); |
113 | } |
114 | |
115 | void |
116 | DacError(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. |
123 | void DECLSPEC_NORETURN |
124 | DacError_NoRet(HRESULT err) |
125 | { |
126 | EX_THROW(HRException, (err)); |
127 | } |
128 | |
129 | TADDR |
130 | DacGlobalBase(void) |
131 | { |
132 | if (!g_dacImpl) |
133 | { |
134 | DacError(E_UNEXPECTED); |
135 | UNREACHABLE(); |
136 | } |
137 | |
138 | return g_dacImpl->m_globalBase; |
139 | } |
140 | |
141 | HRESULT |
142 | DacReadAll(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 | |
195 | HRESULT |
196 | DacWriteAll(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 | |
221 | static 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 | |
248 | HRESULT |
249 | DacVirtualUnwind(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. |
290 | HRESULT |
291 | DacAllocVirtual(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. |
329 | HRESULT |
330 | DacFreeVirtual(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 | |
358 | PVOID |
359 | DacInstantiateTypeByAddressHelper(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 | |
487 | PVOID DacInstantiateTypeByAddress(TADDR addr, ULONG32 size, bool throwEx) |
488 | { |
489 | return DacInstantiateTypeByAddressHelper(addr, size, throwEx, true); |
490 | } |
491 | |
492 | PVOID DacInstantiateTypeByAddressNoReport(TADDR addr, ULONG32 size, bool throwEx) |
493 | { |
494 | return DacInstantiateTypeByAddressHelper(addr, size, throwEx, false); |
495 | } |
496 | |
497 | |
498 | PVOID |
499 | DacInstantiateClassByVTable(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 | |
668 | PSTR |
669 | DacInstantiateStringA(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 | |
800 | PWSTR |
801 | DacInstantiateStringW(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 | |
932 | TADDR |
933 | DacGetTargetAddrForHostAddr(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). |
997 | TADDR |
998 | DacGetTargetAddrForHostInteriorAddr(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 | |
1136 | PWSTR 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 | |
1155 | TADDR |
1156 | DacGetTargetVtForHostVt(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 | // |
1204 | bool 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 | // |
1223 | bool 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 | |
1234 | HRESULT |
1235 | DacWriteHostInstance(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 | |
1253 | bool |
1254 | DacHostPtrHasEnumMark(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 | |
1268 | bool |
1269 | DacHasMethodDescBeenEnumerated(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 | |
1282 | bool |
1283 | DacSetMethodDescEnumerated(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. |
1298 | IMDInternalImport* |
1299 | DacGetMDImport(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 | |
1310 | IMDInternalImport* |
1311 | DacGetMDImport(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 | |
1322 | COR_ILMETHOD* |
1323 | DacGetIlMethod(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 |
1342 | void |
1343 | DacMdCacheAddEEName(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 | } |
1353 | bool |
1354 | DacMdCacheGetEEName(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 | |
1367 | PVOID |
1368 | DacAllocHostOnlyInstance(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. |
1398 | bool 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 | // |
1427 | void 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 | |
1498 | HRESULT 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 | |