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: stack.cpp
6//
7
8//
9// CLRData stack walking.
10//
11//*****************************************************************************
12
13#include "stdafx.h"
14
15//----------------------------------------------------------------------------
16//
17// ClrDataStackWalk.
18//
19//----------------------------------------------------------------------------
20
21ClrDataStackWalk::ClrDataStackWalk(ClrDataAccess* dac,
22 Thread* thread,
23 ULONG32 flags)
24{
25 m_dac = dac;
26 m_dac->AddRef();
27 m_instanceAge = m_dac->m_instanceAge;
28 m_thread = thread;
29 m_walkFlags = flags;
30 m_refs = 1;
31 m_stackPrev = 0;
32
33 INDEBUG( m_framesUnwound = 0; )
34}
35
36ClrDataStackWalk::~ClrDataStackWalk(void)
37{
38 m_dac->Release();
39}
40
41STDMETHODIMP
42ClrDataStackWalk::QueryInterface(THIS_
43 IN REFIID interfaceId,
44 OUT PVOID* iface)
45{
46 if (IsEqualIID(interfaceId, IID_IUnknown) ||
47 IsEqualIID(interfaceId, __uuidof(IXCLRDataStackWalk)))
48 {
49 AddRef();
50 *iface = static_cast<IUnknown*>
51 (static_cast<IXCLRDataStackWalk*>(this));
52 return S_OK;
53 }
54 else
55 {
56 *iface = NULL;
57 return E_NOINTERFACE;
58 }
59}
60
61STDMETHODIMP_(ULONG)
62ClrDataStackWalk::AddRef(THIS)
63{
64 return InterlockedIncrement(&m_refs);
65}
66
67STDMETHODIMP_(ULONG)
68ClrDataStackWalk::Release(THIS)
69{
70 SUPPORTS_DAC_HOST_ONLY;
71 LONG newRefs = InterlockedDecrement(&m_refs);
72 if (newRefs == 0)
73 {
74 delete this;
75 }
76 return newRefs;
77}
78
79HRESULT STDMETHODCALLTYPE
80ClrDataStackWalk::GetContext(
81 /* [in] */ ULONG32 contextFlags,
82 /* [in] */ ULONG32 contextBufSize,
83 /* [out] */ ULONG32 *contextSize,
84 /* [size_is][out] */ BYTE contextBuf[ ])
85{
86 HRESULT status;
87
88 if (contextSize)
89 {
90 *contextSize = ContextSizeForFlags(contextFlags);
91 }
92
93 if (!CheckContextSizeForFlags(contextBufSize, contextFlags))
94 {
95 return E_INVALIDARG;
96 }
97
98 DAC_ENTER_SUB(m_dac);
99
100 EX_TRY
101 {
102 if (!m_frameIter.IsValid())
103 {
104 status = S_FALSE;
105 }
106 else
107 {
108 *(PT_CONTEXT)contextBuf = m_context;
109 UpdateContextFromRegDisp(&m_regDisp, (PT_CONTEXT)contextBuf);
110 status = S_OK;
111 }
112 }
113 EX_CATCH
114 {
115 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
116 {
117 EX_RETHROW;
118 }
119 }
120 EX_END_CATCH(SwallowAllExceptions)
121
122 DAC_LEAVE();
123 return status;
124}
125
126HRESULT STDMETHODCALLTYPE
127ClrDataStackWalk::SetContext(
128 /* [in] */ ULONG32 contextSize,
129 /* [size_is][in] */ BYTE context[ ])
130{
131 return SetContext2(m_frameIter.m_crawl.IsActiveFrame() ?
132 CLRDATA_STACK_SET_CURRENT_CONTEXT :
133 CLRDATA_STACK_SET_UNWIND_CONTEXT,
134 contextSize, context);
135}
136
137HRESULT STDMETHODCALLTYPE
138ClrDataStackWalk::SetContext2(
139 /* [in] */ ULONG32 flags,
140 /* [in] */ ULONG32 contextSize,
141 /* [size_is][in] */ BYTE context[ ])
142{
143 HRESULT status;
144
145 if ((flags & ~(CLRDATA_STACK_SET_CURRENT_CONTEXT |
146 CLRDATA_STACK_SET_UNWIND_CONTEXT)) != 0 ||
147 !CheckContextSizeForBuffer(contextSize, context))
148 {
149 return E_INVALIDARG;
150 }
151
152 DAC_ENTER_SUB(m_dac);
153
154 EX_TRY
155 {
156 // Copy the context to local state so
157 // that its lifetime extends beyond this call.
158 m_context = *(PT_CONTEXT)context;
159 m_thread->FillRegDisplay(&m_regDisp, &m_context);
160 m_frameIter.ResetRegDisp(&m_regDisp, (flags & CLRDATA_STACK_SET_CURRENT_CONTEXT) != 0);
161 m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
162 FilterFrames();
163 status = S_OK;
164 }
165 EX_CATCH
166 {
167 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
168 {
169 EX_RETHROW;
170 }
171 }
172 EX_END_CATCH(SwallowAllExceptions)
173
174 DAC_LEAVE();
175 return status;
176}
177
178HRESULT STDMETHODCALLTYPE
179ClrDataStackWalk::Next(void)
180{
181 HRESULT status = E_FAIL;
182
183 INDEBUG( static const int kFrameToReturnForever = 56; )
184
185 DAC_ENTER_SUB(m_dac);
186
187 EX_TRY
188 {
189 if (!m_frameIter.IsValid())
190 {
191 status = S_FALSE;
192 }
193 else
194#if defined(_DEBUG)
195 // m_framesUnwound is not incremented unless the special config value is set below in this function.
196 if (m_framesUnwound < kFrameToReturnForever)
197#endif // defined(_DEBUG)
198 {
199 // Default the previous stack value.
200 m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
201 StackWalkAction action = m_frameIter.Next();
202 switch(action)
203 {
204 case SWA_CONTINUE:
205 // We sucessfully unwound a frame so update
206 // the previous stack pointer before going into
207 // filtering to get the amount of stack skipped
208 // by the filtering.
209 m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
210 FilterFrames();
211 status = m_frameIter.IsValid() ? S_OK : S_FALSE;
212 break;
213 case SWA_ABORT:
214 status = S_FALSE;
215 break;
216 default:
217 status = E_FAIL;
218 break;
219 }
220 }
221
222#if defined(_DEBUG)
223 // Test hook: when testing on debug builds, we want an easy way to test that the target
224 // stack behaves as if it's smashed in a particular way. It would be very difficult to create
225 // a test that carefully broke the stack in a way that would force the stackwalker to report
226 // success on the same frame forever, and have that corruption be reliable over time. However, it's
227 // pretty easy for us to control the number of frames on the stack for tests that use this specific
228 // internal flag.
229 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DumpGeneration_IntentionallyCorruptDataFromTarget))
230 {
231 if (m_framesUnwound >= kFrameToReturnForever)
232 {
233 status = S_OK;
234 }
235 else
236 {
237 m_framesUnwound++;
238 }
239 }
240#endif // defined(_DEBUG)
241 }
242 EX_CATCH
243 {
244 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
245 {
246 EX_RETHROW;
247 }
248 }
249 EX_END_CATCH(SwallowAllExceptions)
250
251 DAC_LEAVE();
252 return status;
253}
254
255HRESULT STDMETHODCALLTYPE
256ClrDataStackWalk::GetStackSizeSkipped(
257 /* [out] */ ULONG64 *stackSizeSkipped)
258{
259 HRESULT status;
260
261 DAC_ENTER_SUB(m_dac);
262
263 EX_TRY
264 {
265 if (m_stackPrev)
266 {
267 *stackSizeSkipped =
268 (TADDR)GetRegdisplaySP(&m_regDisp) - m_stackPrev;
269 status = S_OK;
270 }
271 else
272 {
273 status = S_FALSE;
274 }
275 }
276 EX_CATCH
277 {
278 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
279 {
280 EX_RETHROW;
281 }
282 }
283 EX_END_CATCH(SwallowAllExceptions)
284
285 DAC_LEAVE();
286 return status;
287}
288
289HRESULT STDMETHODCALLTYPE
290ClrDataStackWalk::GetFrameType(
291 /* [out] */ CLRDataSimpleFrameType *simpleType,
292 /* [out] */ CLRDataDetailedFrameType *detailedType)
293{
294 HRESULT status;
295
296 DAC_ENTER_SUB(m_dac);
297
298 EX_TRY
299 {
300 if (m_frameIter.IsValid())
301 {
302 RawGetFrameType(simpleType, detailedType);
303 status = S_OK;
304 }
305 else
306 {
307 status = S_FALSE;
308 }
309 }
310 EX_CATCH
311 {
312 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
313 {
314 EX_RETHROW;
315 }
316 }
317 EX_END_CATCH(SwallowAllExceptions)
318
319 DAC_LEAVE();
320 return status;
321}
322
323HRESULT STDMETHODCALLTYPE
324ClrDataStackWalk::GetFrame(
325 /* [out] */ IXCLRDataFrame **frame)
326{
327 HRESULT status;
328
329 DAC_ENTER_SUB(m_dac);
330
331 EX_TRY
332 {
333 ClrDataFrame* dataFrame = NULL;
334 if (!m_frameIter.IsValid())
335 {
336 status = E_INVALIDARG;
337 goto Exit;
338 }
339
340 CLRDataSimpleFrameType simpleType;
341 CLRDataDetailedFrameType detailedType;
342
343 RawGetFrameType(&simpleType, &detailedType);
344 dataFrame =
345 new (nothrow) ClrDataFrame(m_dac, simpleType, detailedType,
346 m_frameIter.m_crawl.GetAppDomain(),
347 m_frameIter.m_crawl.GetFunction());
348 if (!dataFrame)
349 {
350 status = E_OUTOFMEMORY;
351 goto Exit;
352 }
353
354 dataFrame->m_context = m_context;
355 UpdateContextFromRegDisp(&m_regDisp, &dataFrame->m_context);
356 m_thread->FillRegDisplay(&dataFrame->m_regDisp,
357 &dataFrame->m_context);
358
359 *frame = static_cast<IXCLRDataFrame*>(dataFrame);
360 status = S_OK;
361
362 Exit: ;
363 }
364 EX_CATCH
365 {
366 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
367 {
368 EX_RETHROW;
369 }
370 }
371 EX_END_CATCH(SwallowAllExceptions)
372
373 DAC_LEAVE();
374 return status;
375}
376
377HRESULT STDMETHODCALLTYPE
378ClrDataStackWalk::Request(
379 /* [in] */ ULONG32 reqCode,
380 /* [in] */ ULONG32 inBufferSize,
381 /* [size_is][in] */ BYTE *inBuffer,
382 /* [in] */ ULONG32 outBufferSize,
383 /* [size_is][out] */ BYTE *outBuffer)
384{
385 HRESULT status;
386
387 DAC_ENTER_SUB(m_dac);
388
389 EX_TRY
390 {
391 switch(reqCode)
392 {
393 case CLRDATA_REQUEST_REVISION:
394 if (inBufferSize != 0 ||
395 inBuffer ||
396 outBufferSize != sizeof(ULONG32))
397 {
398 status = E_INVALIDARG;
399 }
400 else
401 {
402 *(ULONG32*)outBuffer = 1;
403 status = S_OK;
404 }
405 break;
406
407 case CLRDATA_STACK_WALK_REQUEST_SET_FIRST_FRAME:
408 // This code should be removed once the Windows debuggers stop using the old DAC API.
409 if ((inBufferSize != sizeof(ULONG32)) ||
410 (outBufferSize != 0))
411 {
412 status = E_INVALIDARG;
413 break;
414 }
415
416 m_frameIter.SetIsFirstFrame(*(ULONG32 UNALIGNED *)inBuffer != 0);
417 status = S_OK;
418 break;
419
420 case DACSTACKPRIV_REQUEST_FRAME_DATA:
421 if ((inBufferSize != 0) ||
422 (inBuffer != NULL) ||
423 (outBufferSize != sizeof(DacpFrameData)))
424 {
425 status = E_INVALIDARG;
426 break;
427 }
428 if (!m_frameIter.IsValid())
429 {
430 status = E_INVALIDARG;
431 break;
432 }
433
434 DacpFrameData* frameData;
435
436 frameData = (DacpFrameData*)outBuffer;
437 frameData->frameAddr =
438 TO_CDADDR(PTR_HOST_TO_TADDR(m_frameIter.m_crawl.GetFrame()));
439 status = S_OK;
440 break;
441
442 default:
443 status = E_INVALIDARG;
444 break;
445 }
446 }
447 EX_CATCH
448 {
449 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
450 {
451 EX_RETHROW;
452 }
453 }
454 EX_END_CATCH(SwallowAllExceptions)
455
456 DAC_LEAVE();
457 return status;
458}
459
460HRESULT
461ClrDataStackWalk::Init(void)
462{
463 if (m_thread->IsUnstarted())
464 {
465 return E_FAIL;
466 }
467
468 if (m_thread->GetFilterContext())
469 {
470 m_context = *m_thread->GetFilterContext();
471 }
472 else
473 {
474 DacGetThreadContext(m_thread, &m_context);
475 }
476 m_thread->FillRegDisplay(&m_regDisp, &m_context);
477
478 m_stackPrev = (TADDR)GetRegdisplaySP(&m_regDisp);
479
480 ULONG32 iterFlags = NOTIFY_ON_NO_FRAME_TRANSITIONS;
481
482 // If the filter is only allowing method frames
483 // turn on the appropriate iterator flag.
484 if ((m_walkFlags & SIMPFRAME_ALL) ==
485 CLRDATA_SIMPFRAME_MANAGED_METHOD)
486 {
487 iterFlags |= FUNCTIONSONLY;
488 }
489
490 m_frameIter.Init(m_thread, NULL, &m_regDisp, iterFlags);
491 if (m_frameIter.GetFrameState() == StackFrameIterator::SFITER_UNINITIALIZED)
492 {
493 return E_FAIL;
494 }
495 FilterFrames();
496
497 return S_OK;
498}
499
500void
501ClrDataStackWalk::FilterFrames(void)
502{
503 //
504 // Advance to a state compatible with the
505 // current filtering flags.
506 //
507
508 while (m_frameIter.IsValid())
509 {
510 switch(m_frameIter.GetFrameState())
511 {
512 case StackFrameIterator::SFITER_FRAMELESS_METHOD:
513 if (m_walkFlags & CLRDATA_SIMPFRAME_MANAGED_METHOD)
514 {
515 return;
516 }
517 break;
518 case StackFrameIterator::SFITER_FRAME_FUNCTION:
519 case StackFrameIterator::SFITER_SKIPPED_FRAME_FUNCTION:
520 case StackFrameIterator::SFITER_NO_FRAME_TRANSITION:
521 if (m_walkFlags & CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE)
522 {
523 return;
524 }
525 break;
526 default:
527 break;
528 }
529
530 m_frameIter.Next();
531 }
532}
533
534void
535ClrDataStackWalk::RawGetFrameType(
536 /* [out] */ CLRDataSimpleFrameType* simpleType,
537 /* [out] */ CLRDataDetailedFrameType* detailedType)
538{
539 if (simpleType)
540 {
541 switch(m_frameIter.GetFrameState())
542 {
543 case StackFrameIterator::SFITER_FRAMELESS_METHOD:
544 *simpleType = CLRDATA_SIMPFRAME_MANAGED_METHOD;
545 break;
546 case StackFrameIterator::SFITER_FRAME_FUNCTION:
547 case StackFrameIterator::SFITER_SKIPPED_FRAME_FUNCTION:
548 *simpleType = CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE;
549 break;
550 default:
551 *simpleType = CLRDATA_SIMPFRAME_UNRECOGNIZED;
552 break;
553 }
554 }
555
556 if (detailedType)
557 {
558 if (m_frameIter.m_crawl.GetFrame() && m_frameIter.m_crawl.GetFrame()->GetFrameAttribs() & Frame::FRAME_ATTR_EXCEPTION)
559 *detailedType = CLRDATA_DETFRAME_EXCEPTION_FILTER;
560 else
561 *detailedType = CLRDATA_DETFRAME_UNRECOGNIZED;
562 }
563}
564
565//----------------------------------------------------------------------------
566//
567// ClrDataFrame.
568//
569//----------------------------------------------------------------------------
570
571ClrDataFrame::ClrDataFrame(ClrDataAccess* dac,
572 CLRDataSimpleFrameType simpleType,
573 CLRDataDetailedFrameType detailedType,
574 AppDomain* appDomain,
575 MethodDesc* methodDesc)
576{
577 m_dac = dac;
578 m_dac->AddRef();
579 m_instanceAge = m_dac->m_instanceAge;
580 m_simpleType = simpleType;
581 m_detailedType = detailedType;
582 m_appDomain = appDomain;
583 m_methodDesc = methodDesc;
584 m_refs = 1;
585 m_methodSig = NULL;
586 m_localSig = NULL;
587}
588
589ClrDataFrame::~ClrDataFrame(void)
590{
591 delete m_methodSig;
592 delete m_localSig;
593 m_dac->Release();
594}
595
596STDMETHODIMP
597ClrDataFrame::QueryInterface(THIS_
598 IN REFIID interfaceId,
599 OUT PVOID* iface)
600{
601 if (IsEqualIID(interfaceId, IID_IUnknown) ||
602 IsEqualIID(interfaceId, __uuidof(IXCLRDataFrame)))
603 {
604 AddRef();
605 *iface = static_cast<IUnknown*>
606 (static_cast<IXCLRDataFrame*>(this));
607 return S_OK;
608 }
609 else if (IsEqualIID(interfaceId, __uuidof(IXCLRDataFrame2)))
610 {
611 AddRef();
612 *iface = static_cast<IUnknown*>
613 (static_cast<IXCLRDataFrame2*>(this));
614 return S_OK;
615 }
616 else
617 {
618 *iface = NULL;
619 return E_NOINTERFACE;
620 }
621}
622
623STDMETHODIMP_(ULONG)
624ClrDataFrame::AddRef(THIS)
625{
626 return InterlockedIncrement(&m_refs);
627}
628
629STDMETHODIMP_(ULONG)
630ClrDataFrame::Release(THIS)
631{
632 SUPPORTS_DAC_HOST_ONLY;
633 LONG newRefs = InterlockedDecrement(&m_refs);
634 if (newRefs == 0)
635 {
636 delete this;
637 }
638 return newRefs;
639}
640
641HRESULT STDMETHODCALLTYPE
642ClrDataFrame::GetContext(
643 /* [in] */ ULONG32 contextFlags,
644 /* [in] */ ULONG32 contextBufSize,
645 /* [out] */ ULONG32 *contextSize,
646 /* [size_is][out] */ BYTE contextBuf[ ])
647{
648 HRESULT status;
649
650 if (contextSize)
651 {
652 *contextSize = ContextSizeForFlags(contextFlags);
653 }
654
655 if (!CheckContextSizeForFlags(contextBufSize, contextFlags))
656 {
657 return E_INVALIDARG;
658 }
659
660 DAC_ENTER_SUB(m_dac);
661
662 EX_TRY
663 {
664 *(PT_CONTEXT)contextBuf = m_context;
665 status = S_OK;
666 }
667 EX_CATCH
668 {
669 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
670 {
671 EX_RETHROW;
672 }
673 }
674 EX_END_CATCH(SwallowAllExceptions)
675
676 DAC_LEAVE();
677 return status;
678}
679
680HRESULT STDMETHODCALLTYPE
681ClrDataFrame::GetFrameType(
682 /* [out] */ CLRDataSimpleFrameType *simpleType,
683 /* [out] */ CLRDataDetailedFrameType *detailedType)
684{
685 HRESULT status;
686
687 DAC_ENTER_SUB(m_dac);
688
689 EX_TRY
690 {
691 *simpleType = m_simpleType;
692 *detailedType = m_detailedType;
693 status = S_OK;
694 }
695 EX_CATCH
696 {
697 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
698 {
699 EX_RETHROW;
700 }
701 }
702 EX_END_CATCH(SwallowAllExceptions)
703
704 DAC_LEAVE();
705 return status;
706}
707
708HRESULT STDMETHODCALLTYPE
709ClrDataFrame::GetAppDomain(
710 /* [out] */ IXCLRDataAppDomain **appDomain)
711{
712 HRESULT status;
713
714 DAC_ENTER_SUB(m_dac);
715
716 EX_TRY
717 {
718 if (m_appDomain)
719 {
720 ClrDataAppDomain* dataAppDomain =
721 new (nothrow) ClrDataAppDomain(m_dac, m_appDomain);
722 if (!dataAppDomain)
723 {
724 status = E_OUTOFMEMORY;
725 }
726 else
727 {
728 *appDomain = static_cast<IXCLRDataAppDomain*>(dataAppDomain);
729 status = S_OK;
730 }
731 }
732 else
733 {
734 *appDomain = NULL;
735 status = S_FALSE;
736 }
737 }
738 EX_CATCH
739 {
740 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
741 {
742 EX_RETHROW;
743 }
744 }
745 EX_END_CATCH(SwallowAllExceptions)
746
747 DAC_LEAVE();
748 return status;
749}
750
751HRESULT STDMETHODCALLTYPE
752ClrDataFrame::GetNumArguments(
753 /* [out] */ ULONG32 *numArgs)
754{
755 HRESULT status;
756
757 DAC_ENTER_SUB(m_dac);
758
759 EX_TRY
760 {
761 if (!m_methodDesc)
762 {
763 status = E_NOINTERFACE;
764 }
765 else
766 {
767 MetaSig* sig;
768
769 status = GetMethodSig(&sig, numArgs);
770 }
771 }
772 EX_CATCH
773 {
774 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
775 {
776 EX_RETHROW;
777 }
778 }
779 EX_END_CATCH(SwallowAllExceptions)
780
781 DAC_LEAVE();
782 return status;
783}
784
785HRESULT STDMETHODCALLTYPE
786ClrDataFrame::GetArgumentByIndex(
787 /* [in] */ ULONG32 index,
788 /* [out] */ IXCLRDataValue **arg,
789 /* [in] */ ULONG32 bufLen,
790 /* [out] */ ULONG32 *nameLen,
791 /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ])
792{
793 HRESULT status;
794
795 DAC_ENTER_SUB(m_dac);
796
797 EX_TRY
798 {
799 if (nameLen)
800 {
801 *nameLen = 0;
802 }
803
804 if (!m_methodDesc)
805 {
806 status = E_NOINTERFACE;
807 goto Exit;
808 }
809
810 MetaSig* sig;
811 ULONG32 numArgs;
812
813 if (FAILED(status = GetMethodSig(&sig, &numArgs)))
814 {
815 goto Exit;
816 }
817
818 if (index >= numArgs)
819 {
820 status = E_INVALIDARG;
821 goto Exit;
822 }
823
824 if ((bufLen && name) || nameLen)
825 {
826 if (index == 0 && sig->HasThis())
827 {
828 if (nameLen)
829 {
830 *nameLen = 5;
831 }
832
833 StringCchCopy(name, bufLen, W("this"));
834 }
835 else
836 {
837 if (!m_methodDesc->IsNoMetadata())
838 {
839 IMDInternalImport* mdImport = m_methodDesc->GetMDImport();
840 mdParamDef paramToken;
841 LPCSTR paramName;
842 USHORT seq;
843 DWORD attr;
844
845 // Param indexing is 1-based.
846 ULONG32 mdIndex = index + 1;
847
848 // 'this' doesn't show up in the signature but
849 // is present in the dac API indexing so adjust the
850 // index down for methods with 'this'.
851 if (sig->HasThis())
852 {
853 mdIndex--;
854 }
855
856 status = mdImport->FindParamOfMethod(
857 m_methodDesc->GetMemberDef(),
858 mdIndex,
859 &paramToken);
860 if (status == S_OK)
861 {
862 status = mdImport->GetParamDefProps(
863 paramToken,
864 &seq,
865 &attr,
866 &paramName);
867 if ((status == S_OK) && (paramName != NULL))
868 {
869 if ((status = ConvertUtf8(paramName,
870 bufLen, nameLen, name)) != S_OK)
871 {
872 goto Exit;
873 }
874 }
875 }
876 }
877 else
878 {
879 if (nameLen)
880 {
881 *nameLen = 1;
882 }
883
884 name[0] = 0;
885 }
886 }
887 }
888
889 status = ValueFromDebugInfo(sig, true, index, index, arg);
890
891 Exit: ;
892 }
893 EX_CATCH
894 {
895 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
896 {
897 EX_RETHROW;
898 }
899 }
900 EX_END_CATCH(SwallowAllExceptions)
901
902 DAC_LEAVE();
903 return status;
904}
905
906HRESULT STDMETHODCALLTYPE
907ClrDataFrame::GetNumLocalVariables(
908 /* [out] */ ULONG32 *numLocals)
909{
910 HRESULT status;
911
912 DAC_ENTER_SUB(m_dac);
913
914 EX_TRY
915 {
916 if (!m_methodDesc)
917 {
918 status = E_NOINTERFACE;
919 }
920 else
921 {
922 MetaSig* sig;
923
924 status = GetLocalSig(&sig, numLocals);
925 }
926 }
927 EX_CATCH
928 {
929 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
930 {
931 EX_RETHROW;
932 }
933 }
934 EX_END_CATCH(SwallowAllExceptions)
935
936 DAC_LEAVE();
937 return status;
938}
939
940HRESULT STDMETHODCALLTYPE
941ClrDataFrame::GetLocalVariableByIndex(
942 /* [in] */ ULONG32 index,
943 /* [out] */ IXCLRDataValue **localVariable,
944 /* [in] */ ULONG32 bufLen,
945 /* [out] */ ULONG32 *nameLen,
946 /* [size_is][out] */ __out_ecount_part(bufLen, *nameLen) WCHAR name[ ])
947{
948 HRESULT status;
949
950 DAC_ENTER_SUB(m_dac);
951
952 EX_TRY
953 {
954 if (!m_methodDesc)
955 {
956 status = E_NOINTERFACE;
957 goto Exit;
958 }
959
960 MetaSig* sig;
961 ULONG32 numLocals;
962
963 if (FAILED(status = GetLocalSig(&sig, &numLocals)))
964 {
965 goto Exit;
966 }
967
968 if (index >= numLocals)
969 {
970 status = E_INVALIDARG;
971 goto Exit;
972 }
973
974 MetaSig* argSig;
975 ULONG32 numArgs;
976
977 if (FAILED(status = GetMethodSig(&argSig, &numArgs)))
978 {
979 goto Exit;
980 }
981
982 // Can't get names for locals in the Whidbey runtime.
983 if (bufLen && name)
984 {
985 if (nameLen)
986 {
987 *nameLen = 1;
988 }
989
990 name[0] = 0;
991 }
992
993 // The locals are indexed immediately following the arguments
994 // in the NativeVarInfos.
995 status = ValueFromDebugInfo(sig, false, index, index + numArgs,
996 localVariable);
997
998 Exit: ;
999 }
1000 EX_CATCH
1001 {
1002 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
1003 {
1004 EX_RETHROW;
1005 }
1006 }
1007 EX_END_CATCH(SwallowAllExceptions)
1008
1009 DAC_LEAVE();
1010 return status;
1011}
1012
1013HRESULT STDMETHODCALLTYPE
1014ClrDataFrame::GetNumTypeArguments(
1015 /* [out] */ ULONG32 *numTypeArgs)
1016{
1017 HRESULT status;
1018
1019 DAC_ENTER_SUB(m_dac);
1020
1021 EX_TRY
1022 {
1023 // XXX Microsoft.
1024 status = E_NOTIMPL;
1025 }
1026 EX_CATCH
1027 {
1028 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
1029 {
1030 EX_RETHROW;
1031 }
1032 }
1033 EX_END_CATCH(SwallowAllExceptions)
1034
1035 DAC_LEAVE();
1036 return status;
1037}
1038
1039HRESULT STDMETHODCALLTYPE
1040ClrDataFrame::GetTypeArgumentByIndex(
1041 /* [in] */ ULONG32 index,
1042 /* [out] */ IXCLRDataTypeInstance **typeArg)
1043{
1044 HRESULT status;
1045
1046 DAC_ENTER_SUB(m_dac);
1047
1048 EX_TRY
1049 {
1050 // XXX Microsoft.
1051 status = E_NOTIMPL;
1052 }
1053 EX_CATCH
1054 {
1055 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
1056 {
1057 EX_RETHROW;
1058 }
1059 }
1060 EX_END_CATCH(SwallowAllExceptions)
1061
1062 DAC_LEAVE();
1063 return status;
1064}
1065
1066
1067HRESULT STDMETHODCALLTYPE
1068ClrDataFrame::GetExactGenericArgsToken(
1069 /* [out] */ IXCLRDataValue ** genericToken)
1070{
1071 HRESULT status;
1072
1073 DAC_ENTER_SUB(m_dac);
1074
1075 EX_TRY
1076 {
1077 if (!m_methodDesc)
1078 {
1079 status = E_NOINTERFACE;
1080 goto Exit;
1081 }
1082
1083 MetaSig* sig;
1084 ULONG32 numLocals;
1085
1086 if (FAILED(status = GetLocalSig(&sig, &numLocals)))
1087 {
1088 goto Exit;
1089 }
1090
1091 // The locals are indexed immediately following the arguments
1092 // in the NativeVarInfos.
1093 status = ValueFromDebugInfo(sig, false, 1, (DWORD)ICorDebugInfo::TYPECTXT_ILNUM,
1094 genericToken);
1095 Exit: ;
1096 }
1097 EX_CATCH
1098 {
1099 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
1100 {
1101 EX_RETHROW;
1102 }
1103 }
1104 EX_END_CATCH(SwallowAllExceptions)
1105
1106 DAC_LEAVE();
1107 return status;
1108}
1109
1110HRESULT STDMETHODCALLTYPE
1111ClrDataFrame::GetCodeName(
1112 /* [in] */ ULONG32 flags,
1113 /* [in] */ ULONG32 bufLen,
1114 /* [out] */ ULONG32 *symbolLen,
1115 /* [size_is][out] */ __out_ecount_opt(bufLen) WCHAR symbolBuf[ ])
1116{
1117 HRESULT status = E_FAIL;
1118
1119 DAC_ENTER_SUB(m_dac);
1120
1121 EX_TRY
1122 {
1123 TADDR pcAddr = PCODEToPINSTR(GetControlPC(&m_regDisp));
1124 status = m_dac->
1125 RawGetMethodName(TO_CDADDR(pcAddr), flags,
1126 bufLen, symbolLen, symbolBuf,
1127 NULL);
1128 }
1129 EX_CATCH
1130 {
1131 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
1132 {
1133 EX_RETHROW;
1134 }
1135 }
1136 EX_END_CATCH(SwallowAllExceptions)
1137
1138 DAC_LEAVE();
1139
1140 return status;
1141}
1142
1143HRESULT STDMETHODCALLTYPE
1144ClrDataFrame::GetMethodInstance(
1145 /* [out] */ IXCLRDataMethodInstance **method)
1146{
1147 HRESULT status;
1148
1149 DAC_ENTER_SUB(m_dac);
1150
1151 EX_TRY
1152 {
1153 if (!m_methodDesc)
1154 {
1155 status = E_NOINTERFACE;
1156 }
1157 else
1158 {
1159 ClrDataMethodInstance* dataMethod =
1160 new (nothrow) ClrDataMethodInstance(m_dac,
1161 m_appDomain,
1162 m_methodDesc);
1163 *method = static_cast<IXCLRDataMethodInstance*>(dataMethod);
1164 status = dataMethod ? S_OK : E_OUTOFMEMORY;
1165 }
1166 }
1167 EX_CATCH
1168 {
1169 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
1170 {
1171 EX_RETHROW;
1172 }
1173 }
1174 EX_END_CATCH(SwallowAllExceptions)
1175
1176 DAC_LEAVE();
1177 return status;
1178}
1179
1180HRESULT STDMETHODCALLTYPE
1181ClrDataFrame::Request(
1182 /* [in] */ ULONG32 reqCode,
1183 /* [in] */ ULONG32 inBufferSize,
1184 /* [size_is][in] */ BYTE *inBuffer,
1185 /* [in] */ ULONG32 outBufferSize,
1186 /* [size_is][out] */ BYTE *outBuffer)
1187{
1188 HRESULT status;
1189
1190 DAC_ENTER_SUB(m_dac);
1191
1192 EX_TRY
1193 {
1194 switch(reqCode)
1195 {
1196 case CLRDATA_REQUEST_REVISION:
1197 if (inBufferSize != 0 ||
1198 inBuffer ||
1199 outBufferSize != sizeof(ULONG32))
1200 {
1201 status = E_INVALIDARG;
1202 }
1203 else
1204 {
1205 *(ULONG32*)outBuffer = 1;
1206 status = S_OK;
1207 }
1208 break;
1209
1210 default:
1211 status = E_INVALIDARG;
1212 break;
1213 }
1214 }
1215 EX_CATCH
1216 {
1217 if (!DacExceptionFilter(GET_EXCEPTION(), m_dac, &status))
1218 {
1219 EX_RETHROW;
1220 }
1221 }
1222 EX_END_CATCH(SwallowAllExceptions)
1223
1224 DAC_LEAVE();
1225 return status;
1226}
1227
1228HRESULT
1229ClrDataFrame::GetMethodSig(MetaSig** sig,
1230 ULONG32* count)
1231{
1232 if (!m_methodSig)
1233 {
1234 m_methodSig = new (nothrow) MetaSig(m_methodDesc);
1235 if (!m_methodSig)
1236 {
1237 return E_OUTOFMEMORY;
1238 }
1239 }
1240
1241 *sig = m_methodSig;
1242 *count = m_methodSig->NumFixedArgs() +
1243 (m_methodSig->HasThis() ? 1 : 0);
1244 return *count ? S_OK : S_FALSE;
1245}
1246
1247HRESULT
1248ClrDataFrame::GetLocalSig(MetaSig** sig,
1249 ULONG32* count)
1250{
1251 HRESULT hr;
1252 if (!m_localSig)
1253 {
1254 // It turns out we cannot really get rid of this check. Dynamic methods
1255 // (including IL stubs) do not have their local sig's available after JIT time.
1256 if (!m_methodDesc->IsIL())
1257 {
1258 *sig = NULL;
1259 *count = 0;
1260 return E_FAIL;
1261 }
1262
1263 COR_ILMETHOD_DECODER methodDecoder(m_methodDesc->GetILHeader());
1264 mdSignature localSig = methodDecoder.GetLocalVarSigTok() ?
1265 methodDecoder.GetLocalVarSigTok() : mdSignatureNil;
1266 if (localSig == mdSignatureNil)
1267 {
1268 *sig = NULL;
1269 *count = 0;
1270 return E_FAIL;
1271 }
1272
1273 ULONG tokenSigLen;
1274 PCCOR_SIGNATURE tokenSig;
1275 IfFailRet(m_methodDesc->GetModule()->GetMDImport()->GetSigFromToken(
1276 localSig,
1277 &tokenSigLen,
1278 &tokenSig));
1279
1280 SigTypeContext typeContext(m_methodDesc, TypeHandle());
1281 m_localSig = new (nothrow)
1282 MetaSig(tokenSig,
1283 tokenSigLen,
1284 m_methodDesc->GetModule(),
1285 &typeContext,
1286 MetaSig::sigLocalVars);
1287 if (!m_localSig)
1288 {
1289 return E_OUTOFMEMORY;
1290 }
1291 }
1292
1293 *sig = m_localSig;
1294 *count = m_localSig->NumFixedArgs();
1295 return S_OK;
1296}
1297
1298HRESULT
1299ClrDataFrame::ValueFromDebugInfo(MetaSig* sig,
1300 bool isArg,
1301 DWORD sigIndex,
1302 DWORD varInfoSlot,
1303 IXCLRDataValue** _value)
1304{
1305 HRESULT status;
1306 ULONG32 numVarInfo;
1307 NewHolder<ICorDebugInfo::NativeVarInfo> varInfo(NULL);
1308 ULONG32 codeOffset;
1309 ULONG32 valueFlags;
1310 ULONG32 i;
1311
1312 TADDR ip = PCODEToPINSTR(GetControlPC(&m_regDisp));
1313 if ((status = m_dac->GetMethodVarInfo(m_methodDesc,
1314 ip,
1315 &numVarInfo,
1316 &varInfo,
1317 &codeOffset)) != S_OK)
1318 {
1319 // We have signature info indicating that there
1320 // are values, but couldn't find any location info.
1321 // Optimized routines may have eliminated all
1322 // traditional variable locations, so just treat
1323 // this as a no-location case just like not being
1324 // able to find a matching lifetime.
1325 numVarInfo = 0;
1326 }
1327
1328 for (i = 0; i < numVarInfo; i++)
1329 {
1330 if (varInfo[i].startOffset <= codeOffset &&
1331 varInfo[i].endOffset >= codeOffset &&
1332 varInfo[i].varNumber == varInfoSlot &&
1333 varInfo[i].loc.vlType != ICorDebugInfo::VLT_INVALID)
1334 {
1335 break;
1336 }
1337 }
1338
1339 ULONG64 baseAddr;
1340 NativeVarLocation locs[MAX_NATIVE_VAR_LOCS];
1341 ULONG32 numLocs;
1342
1343 if (i >= numVarInfo)
1344 {
1345 numLocs = 0;
1346 }
1347 else
1348 {
1349 numLocs = NativeVarLocations(varInfo[i].loc, &m_context,
1350 NumItems(locs), locs);
1351 }
1352
1353 if (numLocs == 1 && !locs[0].contextReg)
1354 {
1355 baseAddr = TO_CDADDR(locs[0].addr);
1356 }
1357 else
1358 {
1359 baseAddr = 0;
1360 }
1361
1362 TypeHandle argType;
1363
1364 sig->Reset();
1365 if (isArg && sigIndex == 0 && sig->HasThis())
1366 {
1367 argType = TypeHandle(m_methodDesc->GetMethodTable());
1368 valueFlags = CLRDATA_VALUE_IS_REFERENCE;
1369 }
1370 else
1371 {
1372 // 'this' doesn't show up in the signature but
1373 // is present in the indexing so adjust the
1374 // index down for methods with 'this'.
1375 if (isArg && sig->HasThis())
1376 {
1377
1378 sigIndex--;
1379 }
1380
1381 do
1382 {
1383 sig->NextArg();
1384 }
1385 while (sigIndex-- > 0);
1386
1387 // == FailIfNotLoaded
1388 // Will also return null if type is not restored
1389 argType = sig->GetLastTypeHandleThrowing(ClassLoader::DontLoadTypes);
1390 if (argType.IsNull())
1391 {
1392 // XXX Microsoft - Sometimes types can't be looked
1393 // up and this at least allows the value to be used,
1394 // but is it the right behavior?
1395 argType = TypeHandle(MscorlibBinder::GetElementType(ELEMENT_TYPE_U8));
1396 valueFlags = 0;
1397 }
1398 else
1399 {
1400 valueFlags = GetTypeFieldValueFlags(argType, NULL, 0, false);
1401
1402 // If this is a primitive variable and the actual size is smaller than what we have been told,
1403 // then lower the size so that we won't read in trash memory (e.g. reading 4 bytes for a short).
1404 if ((valueFlags & CLRDATA_VALUE_IS_PRIMITIVE) != 0)
1405 {
1406 if (numLocs == 1)
1407 {
1408 UINT actualSize = argType.GetSize();
1409 if (actualSize < locs[0].size)
1410 {
1411 locs[0].size = actualSize;
1412 }
1413 }
1414 }
1415 }
1416 }
1417
1418 ClrDataValue* value = new (nothrow)
1419 ClrDataValue(m_dac,
1420 m_appDomain,
1421 NULL,
1422 valueFlags,
1423 argType,
1424 baseAddr,
1425 numLocs,
1426 locs);
1427 if (!value)
1428 {
1429 return E_OUTOFMEMORY;
1430 }
1431
1432 *_value = value;
1433 return S_OK;
1434}
1435