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: UTIL.CPP
6//
7
8// ===========================================================================
9
10
11#include "common.h"
12#include "excep.h"
13#include "corhost.h"
14#include "eventtrace.h"
15#include "posterror.h"
16#include "eemessagebox.h"
17
18#include <shlobj.h>
19
20#include "dlwrap.h"
21
22#ifndef DACCESS_COMPILE
23
24// Helper function that encapsulates the parsing rules.
25//
26// Called first with *pdstout == NULL to figure out how many args there are
27// and the size of the required destination buffer.
28//
29// Called again with a nonnull *pdstout to fill in the actual buffer.
30//
31// Returns the # of arguments.
32static UINT ParseCommandLine(LPCWSTR psrc, __inout LPWSTR *pdstout)
33{
34 CONTRACTL
35 {
36 NOTHROW;
37 GC_NOTRIGGER;
38 FORBID_FAULT;
39 }
40 CONTRACTL_END
41
42 UINT argcount = 1; // discovery of arg0 is unconditional, below
43 LPWSTR pdst = *pdstout;
44 BOOL fDoWrite = (pdst != NULL);
45
46 BOOL fInQuotes;
47 int iSlash;
48
49 /* A quoted program name is handled here. The handling is much
50 simpler than for other arguments. Basically, whatever lies
51 between the leading double-quote and next one, or a terminal null
52 character is simply accepted. Fancier handling is not required
53 because the program name must be a legal NTFS/HPFS file name.
54 Note that the double-quote characters are not copied, nor do they
55 contribute to numchars.
56
57 This "simplification" is necessary for compatibility reasons even
58 though it leads to mishandling of certain cases. For example,
59 "c:\tests\"test.exe will result in an arg0 of c:\tests\ and an
60 arg1 of test.exe. In any rational world this is incorrect, but
61 we need to preserve compatibility.
62 */
63
64 LPCWSTR pStart = psrc;
65 BOOL skipQuote = FALSE;
66
67 if (*psrc == W('\"'))
68 {
69 // scan from just past the first double-quote through the next
70 // double-quote, or up to a null, whichever comes first
71 while ((*(++psrc) != W('\"')) && (*psrc != W('\0')))
72 continue;
73
74 skipQuote = TRUE;
75 }
76 else
77 {
78 /* Not a quoted program name */
79
80 while (!ISWWHITE(*psrc) && *psrc != W('\0'))
81 psrc++;
82 }
83
84 // We have now identified arg0 as pStart (or pStart+1 if we have a leading
85 // quote) through psrc-1 inclusive
86 if (skipQuote)
87 pStart++;
88 while (pStart < psrc)
89 {
90 if (fDoWrite)
91 *pdst = *pStart;
92
93 pStart++;
94 pdst++;
95 }
96
97 // And terminate it.
98 if (fDoWrite)
99 *pdst = W('\0');
100
101 pdst++;
102
103 // if we stopped on a double-quote when arg0 is quoted, skip over it
104 if (skipQuote && *psrc == W('\"'))
105 psrc++;
106
107 while ( *psrc != W('\0'))
108 {
109LEADINGWHITE:
110
111 // The outofarg state.
112 while (ISWWHITE(*psrc))
113 psrc++;
114
115 if (*psrc == W('\0'))
116 break;
117 else
118 if (*psrc == W('#'))
119 {
120 while (*psrc != W('\0') && *psrc != W('\n'))
121 psrc++; // skip to end of line
122
123 goto LEADINGWHITE;
124 }
125
126 argcount++;
127 fInQuotes = FALSE;
128
129 while ((!ISWWHITE(*psrc) || fInQuotes) && *psrc != W('\0'))
130 {
131 switch (*psrc)
132 {
133 case W('\\'):
134 iSlash = 0;
135 while (*psrc == W('\\'))
136 {
137 iSlash++;
138 psrc++;
139 }
140
141 if (*psrc == W('\"'))
142 {
143 for ( ; iSlash >= 2; iSlash -= 2)
144 {
145 if (fDoWrite)
146 *pdst = W('\\');
147
148 pdst++;
149 }
150
151 if (iSlash & 1)
152 {
153 if (fDoWrite)
154 *pdst = *psrc;
155
156 psrc++;
157 pdst++;
158 }
159 else
160 {
161 fInQuotes = !fInQuotes;
162 psrc++;
163 }
164 }
165 else
166 for ( ; iSlash > 0; iSlash--)
167 {
168 if (fDoWrite)
169 *pdst = W('\\');
170
171 pdst++;
172 }
173
174 break;
175
176 case W('\"'):
177 fInQuotes = !fInQuotes;
178 psrc++;
179 break;
180
181 default:
182 if (fDoWrite)
183 *pdst = *psrc;
184
185 psrc++;
186 pdst++;
187 }
188 }
189
190 if (fDoWrite)
191 *pdst = W('\0');
192
193 pdst++;
194 }
195
196
197 _ASSERTE(*psrc == W('\0'));
198 *pdstout = pdst;
199 return argcount;
200}
201
202
203// Function to parse apart a command line and return the
204// arguments just like argv and argc
205// This function is a little funky because of the pointer work
206// but it is neat because it allows the recipient of the char**
207// to only have to do a single delete []
208LPWSTR* CommandLineToArgvW(__in LPWSTR lpCmdLine, DWORD *pNumArgs)
209{
210
211 CONTRACTL
212 {
213 NOTHROW;
214 GC_NOTRIGGER;
215 INJECT_FAULT(return NULL;);
216 }
217 CONTRACTL_END
218
219 DWORD argcount = 0;
220 LPWSTR retval = NULL;
221 LPWSTR *pslot;
222 // First we need to find out how many strings there are in the command line
223 _ASSERTE(lpCmdLine);
224 _ASSERTE(pNumArgs);
225
226 LPWSTR pdst = NULL;
227 argcount = ParseCommandLine(lpCmdLine, &pdst);
228
229 // This check is because on WinCE the Application Name is not passed in as an argument to the app!
230 if (argcount == 0)
231 {
232 *pNumArgs = 0;
233 return NULL;
234 }
235
236 // Now we need alloc a buffer the size of the command line + the number of strings * DWORD
237 retval = new (nothrow) WCHAR[(argcount*sizeof(WCHAR*))/sizeof(WCHAR) + (pdst - (LPWSTR)NULL)];
238 if(!retval)
239 return NULL;
240
241 pdst = (LPWSTR)( argcount*sizeof(LPWSTR*) + (BYTE*)retval );
242 ParseCommandLine(lpCmdLine, &pdst);
243 pdst = (LPWSTR)( argcount*sizeof(LPWSTR*) + (BYTE*)retval );
244 pslot = (LPWSTR*)retval;
245 for (DWORD i = 0; i < argcount; i++)
246 {
247 *(pslot++) = pdst;
248 while (*pdst != W('\0'))
249 {
250 pdst++;
251 }
252 pdst++;
253 }
254
255
256
257 *pNumArgs = argcount;
258 return (LPWSTR*)retval;
259
260}
261
262
263
264
265//************************************************************************
266// CQuickHeap
267//
268// A fast non-multithread-safe heap for short term use.
269// Destroying the heap frees all blocks allocated from the heap.
270// Blocks cannot be freed individually.
271//
272// The heap uses COM+ exceptions to report errors.
273//
274// The heap does not use any internal synchronization so it is not
275// multithreadsafe.
276//************************************************************************
277CQuickHeap::CQuickHeap()
278{
279 LIMITED_METHOD_CONTRACT;
280
281 m_pFirstQuickBlock = NULL;
282 m_pFirstBigQuickBlock = NULL;
283 m_pNextFree = NULL;
284}
285
286CQuickHeap::~CQuickHeap()
287{
288 CONTRACTL
289 {
290 NOTHROW;
291 GC_NOTRIGGER;
292 FORBID_FAULT;
293 }
294 CONTRACTL_END
295
296 QuickBlock *pQuickBlock = m_pFirstQuickBlock;
297 while (pQuickBlock) {
298 QuickBlock *ptmp = pQuickBlock;
299 pQuickBlock = pQuickBlock->m_next;
300 delete [] (BYTE*)ptmp;
301 }
302
303 pQuickBlock = m_pFirstBigQuickBlock;
304 while (pQuickBlock) {
305 QuickBlock *ptmp = pQuickBlock;
306 pQuickBlock = pQuickBlock->m_next;
307 delete [] (BYTE*)ptmp;
308 }
309}
310
311LPVOID CQuickHeap::Alloc(UINT sz)
312{
313 CONTRACTL
314 {
315 THROWS;
316 GC_NOTRIGGER;
317 SO_TOLERANT; // So long as we cleanup the heap when we're done, all the memory goes with it
318 INJECT_FAULT(COMPlusThrowOM(););
319 } CONTRACTL_END;
320
321 sz = (sz+7) & ~7;
322
323 if ( sz > kBlockSize ) {
324
325 QuickBlock *pQuickBigBlock = (QuickBlock*) new BYTE[sz + sizeof(QuickBlock) - 1];
326 pQuickBigBlock->m_next = m_pFirstBigQuickBlock;
327 m_pFirstBigQuickBlock = pQuickBigBlock;
328
329 return pQuickBigBlock->m_bytes;
330
331
332 } else {
333 if (m_pNextFree == NULL || sz > (UINT)( &(m_pFirstQuickBlock->m_bytes[kBlockSize]) - m_pNextFree )) {
334 QuickBlock *pQuickBlock = (QuickBlock*) new BYTE[kBlockSize + sizeof(QuickBlock) - 1];
335 pQuickBlock->m_next = m_pFirstQuickBlock;
336 m_pFirstQuickBlock = pQuickBlock;
337 m_pNextFree = pQuickBlock->m_bytes;
338 }
339 LPVOID pv = m_pNextFree;
340 m_pNextFree += sz;
341 return pv;
342 }
343}
344
345//----------------------------------------------------------------------------
346// Output functions that avoid the crt's.
347//----------------------------------------------------------------------------
348
349static
350void NPrintToHandleA(HANDLE Handle, const char *pszString, size_t BytesToWrite)
351{
352 CONTRACTL
353 {
354 NOTHROW;
355 GC_NOTRIGGER;
356 FORBID_FAULT;
357 }
358 CONTRACTL_END
359
360 if (Handle == INVALID_HANDLE_VALUE || Handle == NULL)
361 return;
362
363 BOOL success;
364 DWORD dwBytesWritten;
365 const size_t maxWriteFileSize = 32767; // This is somewhat arbitrary limit, but 2**16-1 doesn't work
366
367 while (BytesToWrite > 0) {
368 DWORD dwChunkToWrite = (DWORD) min(BytesToWrite, maxWriteFileSize);
369 // No CharNextExA on CoreSystem, we just assume no multi-byte characters (this code path shouldn't be
370 // used in the production codepath for currently supported CoreSystem based products anyway).
371#ifndef FEATURE_CORESYSTEM
372 if (dwChunkToWrite < BytesToWrite) {
373 break;
374 // must go by char to find biggest string that will fit, taking DBCS chars into account
375 //dwChunkToWrite = 0;
376 //const char *charNext = pszString;
377 //while (dwChunkToWrite < maxWriteFileSize-2 && charNext) {
378 // charNext = CharNextExA(0, pszString+dwChunkToWrite, 0);
379 // dwChunkToWrite = (DWORD)(charNext - pszString);
380 //}
381 //if (dwChunkToWrite == 0)
382 // break;
383 }
384#endif // !FEATURE_CORESYSTEM
385
386 // Try to write to handle. If this is not a CUI app, then this is probably
387 // not going to work unless the dev took special pains to set their own console
388 // handle during CreateProcess. So try it, but don't yell if it doesn't work in
389 // that case. Also, if we redirect stdout to a pipe then the pipe breaks (ie, we
390 // write to something like the UNIX head command), don't complain.
391 success = WriteFile(Handle, pszString, dwChunkToWrite, &dwBytesWritten, NULL);
392 if (!success)
393 {
394#if defined(_DEBUG)
395 // This can happen if stdout is a closed pipe. This might not help
396 // much, but we'll have half a chance of seeing this.
397 OutputDebugStringA("CLR: Writing out an unhandled exception to stdout failed!\n");
398 OutputDebugStringA(pszString);
399#endif //_DEBUG
400
401 break;
402 }
403 else {
404 _ASSERTE(dwBytesWritten == dwChunkToWrite);
405 }
406 pszString = pszString + dwChunkToWrite;
407 BytesToWrite -= dwChunkToWrite;
408 }
409
410}
411
412static
413void PrintToHandleA(HANDLE Handle, const char *pszString)
414{
415 CONTRACTL
416 {
417 NOTHROW;
418 GC_NOTRIGGER;
419 FORBID_FAULT;
420 }
421 CONTRACTL_END
422
423 size_t len = strlen(pszString);
424 NPrintToHandleA(Handle, pszString, len);
425}
426
427void PrintToStdOutA(const char *pszString) {
428 CONTRACTL
429 {
430 NOTHROW;
431 GC_NOTRIGGER;
432 FORBID_FAULT;
433 }
434 CONTRACTL_END
435
436 HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
437 PrintToHandleA(Handle, pszString);
438}
439
440
441void PrintToStdOutW(const WCHAR *pwzString)
442{
443 CONTRACTL
444 {
445 THROWS;
446 GC_NOTRIGGER;
447 INJECT_FAULT(COMPlusThrowOM(););
448 }
449 CONTRACTL_END
450
451 MAKE_MULTIBYTE_FROMWIDE_BESTFIT(pStr, pwzString, GetConsoleOutputCP());
452
453 PrintToStdOutA(pStr);
454}
455
456void PrintToStdErrA(const char *pszString) {
457 CONTRACTL
458 {
459 NOTHROW;
460 GC_NOTRIGGER;
461 FORBID_FAULT;
462 }
463 CONTRACTL_END
464
465 HANDLE Handle = GetStdHandle(STD_ERROR_HANDLE);
466 PrintToHandleA(Handle, pszString);
467}
468
469
470void PrintToStdErrW(const WCHAR *pwzString)
471{
472 CONTRACTL
473 {
474 THROWS;
475 GC_NOTRIGGER;
476 INJECT_FAULT(COMPlusThrowOM(););
477 }
478 CONTRACTL_END
479
480 MAKE_MULTIBYTE_FROMWIDE_BESTFIT(pStr, pwzString, GetConsoleOutputCP());
481
482 PrintToStdErrA(pStr);
483}
484
485
486
487void NPrintToStdOutA(const char *pszString, size_t nbytes) {
488 CONTRACTL
489 {
490 NOTHROW;
491 GC_NOTRIGGER;
492 FORBID_FAULT;
493 }
494 CONTRACTL_END
495
496 HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
497 NPrintToHandleA(Handle, pszString, nbytes);
498}
499
500
501void NPrintToStdOutW(const WCHAR *pwzString, size_t nchars)
502{
503 CONTRACTL
504 {
505 THROWS;
506 GC_NOTRIGGER;
507 INJECT_FAULT(COMPlusThrowOM(););
508 }
509 CONTRACTL_END
510
511 LPSTR pStr;
512 MAKE_MULTIBYTE_FROMWIDEN_BESTFIT(pStr, pwzString, (int)nchars, nbytes, GetConsoleOutputCP());
513
514 NPrintToStdOutA(pStr, nbytes);
515}
516
517void NPrintToStdErrA(const char *pszString, size_t nbytes) {
518 CONTRACTL
519 {
520 NOTHROW;
521 GC_NOTRIGGER;
522 FORBID_FAULT;
523 }
524 CONTRACTL_END
525
526 HANDLE Handle = GetStdHandle(STD_ERROR_HANDLE);
527 NPrintToHandleA(Handle, pszString, nbytes);
528}
529
530
531void NPrintToStdErrW(const WCHAR *pwzString, size_t nchars)
532{
533 CONTRACTL
534 {
535 THROWS;
536 GC_NOTRIGGER;
537 INJECT_FAULT(COMPlusThrowOM(););
538 }
539 CONTRACTL_END
540
541 LPSTR pStr;
542
543 MAKE_MULTIBYTE_FROMWIDEN_BESTFIT(pStr, pwzString, (int)nchars, nbytes, GetConsoleOutputCP());
544
545 NPrintToStdErrA(pStr, nbytes);
546}
547//----------------------------------------------------------------------------
548
549
550
551
552
553//+--------------------------------------------------------------------------
554//
555// Function: VMDebugOutputA( . . . . )
556// VMDebugOutputW( . . . . )
557//
558// Synopsis: Output a message formatted in printf fashion to the debugger.
559// ANSI and wide character versions are both provided. Only
560// present in debug builds (i.e. when _DEBUG is defined).
561//
562// Arguments: [format] --- ANSI or Wide character format string
563// in printf/OutputDebugString-style format.
564//
565// [ ... ] --- Variable length argument list compatible
566// with the format string.
567//
568// Returns: Nothing.
569//
570// Notes: Has internal static sized character buffer of
571// width specified by the preprocessor constant DEBUGOUT_BUFSIZE.
572//
573//---------------------------------------------------------------------------
574#ifdef _DEBUG
575
576#define DEBUGOUT_BUFSIZE 1024
577
578void __cdecl VMDebugOutputA(__in LPSTR format, ...)
579{
580 STATIC_CONTRACT_NOTHROW;
581 STATIC_CONTRACT_GC_NOTRIGGER;
582 STATIC_CONTRACT_FORBID_FAULT;
583
584 va_list argPtr;
585 va_start(argPtr, format);
586
587 char szBuffer[DEBUGOUT_BUFSIZE];
588
589 if(vsprintf_s(szBuffer, DEBUGOUT_BUFSIZE-1, format, argPtr) > 0)
590 OutputDebugStringA(szBuffer);
591 va_end(argPtr);
592}
593
594void __cdecl VMDebugOutputW(__in LPWSTR format, ...)
595{
596 STATIC_CONTRACT_NOTHROW;
597 STATIC_CONTRACT_GC_NOTRIGGER;
598 STATIC_CONTRACT_FORBID_FAULT;
599 STATIC_CONTRACT_DEBUG_ONLY;
600
601 va_list argPtr;
602 va_start(argPtr, format);
603
604 WCHAR wszBuffer[DEBUGOUT_BUFSIZE];
605
606 if(vswprintf_s(wszBuffer, DEBUGOUT_BUFSIZE-2, format, argPtr) > 0)
607 WszOutputDebugString(wszBuffer);
608 va_end(argPtr);
609}
610
611#endif // #ifdef DACCESS_COMPILE
612
613//*****************************************************************************
614// Compare VarLoc's
615//*****************************************************************************
616
617bool operator ==(const ICorDebugInfo::VarLoc &varLoc1,
618 const ICorDebugInfo::VarLoc &varLoc2)
619{
620 STATIC_CONTRACT_NOTHROW;
621 STATIC_CONTRACT_GC_NOTRIGGER;
622 STATIC_CONTRACT_FORBID_FAULT;
623
624 if (varLoc1.vlType != varLoc2.vlType)
625 return false;
626
627 switch(varLoc1.vlType)
628 {
629 case ICorDebugInfo::VLT_REG:
630 case ICorDebugInfo::VLT_REG_BYREF:
631 return varLoc1.vlReg.vlrReg == varLoc2.vlReg.vlrReg;
632
633 case ICorDebugInfo::VLT_STK:
634 case ICorDebugInfo::VLT_STK_BYREF:
635 return varLoc1.vlStk.vlsBaseReg == varLoc2.vlStk.vlsBaseReg &&
636 varLoc1.vlStk.vlsOffset == varLoc2.vlStk.vlsOffset;
637
638 case ICorDebugInfo::VLT_REG_REG:
639 return varLoc1.vlRegReg.vlrrReg1 == varLoc2.vlRegReg.vlrrReg1 &&
640 varLoc1.vlRegReg.vlrrReg2 == varLoc2.vlRegReg.vlrrReg2;
641
642 case ICorDebugInfo::VLT_REG_STK:
643 return varLoc1.vlRegStk.vlrsReg == varLoc2.vlRegStk.vlrsReg &&
644 varLoc1.vlRegStk.vlrsStk.vlrssBaseReg == varLoc2.vlRegStk.vlrsStk.vlrssBaseReg &&
645 varLoc1.vlRegStk.vlrsStk.vlrssOffset == varLoc2.vlRegStk.vlrsStk.vlrssOffset;
646
647 case ICorDebugInfo::VLT_STK_REG:
648 return varLoc1.vlStkReg.vlsrStk.vlsrsBaseReg == varLoc2.vlStkReg.vlsrStk.vlsrsBaseReg &&
649 varLoc1.vlStkReg.vlsrStk.vlsrsOffset == varLoc2.vlStkReg.vlsrStk.vlsrsBaseReg &&
650 varLoc1.vlStkReg.vlsrReg == varLoc2.vlStkReg.vlsrReg;
651
652 case ICorDebugInfo::VLT_STK2:
653 return varLoc1.vlStk2.vls2BaseReg == varLoc2.vlStk2.vls2BaseReg &&
654 varLoc1.vlStk2.vls2Offset == varLoc2.vlStk2.vls2Offset;
655
656 case ICorDebugInfo::VLT_FPSTK:
657 return varLoc1.vlFPstk.vlfReg == varLoc2.vlFPstk.vlfReg;
658
659 default:
660 _ASSERTE(!"Bad vlType"); return false;
661 }
662}
663
664#endif // #ifndef DACCESS_COMPILE
665
666//*****************************************************************************
667// The following are used to read and write data given NativeVarInfo
668// for primitive types. For ValueClasses, FALSE will be returned.
669//*****************************************************************************
670
671SIZE_T GetRegOffsInCONTEXT(ICorDebugInfo::RegNum regNum)
672{
673 STATIC_CONTRACT_NOTHROW;
674 STATIC_CONTRACT_GC_NOTRIGGER;
675 STATIC_CONTRACT_FORBID_FAULT;
676
677#ifdef _TARGET_X86_
678 switch(regNum)
679 {
680 case ICorDebugInfo::REGNUM_EAX: return offsetof(T_CONTEXT,Eax);
681 case ICorDebugInfo::REGNUM_ECX: return offsetof(T_CONTEXT,Ecx);
682 case ICorDebugInfo::REGNUM_EDX: return offsetof(T_CONTEXT,Edx);
683 case ICorDebugInfo::REGNUM_EBX: return offsetof(T_CONTEXT,Ebx);
684 // TODO: Fix AMBIENT_SP handling.
685 // AMBIENT_SP It isn't necessarily the same value as ESP. We probably shouldn't try
686 // and handle REGNUM_AMBIENT_SP here, and instead update our callers (eg.
687 // GetNativeVarVal) to handle this case explicitly. This logic should also be
688 // merged with the parallel (but correct in this case) logic in mscordbi.
689 case ICorDebugInfo::REGNUM_ESP:
690 case ICorDebugInfo::REGNUM_AMBIENT_SP:
691 return offsetof(T_CONTEXT,Esp);
692 case ICorDebugInfo::REGNUM_EBP: return offsetof(T_CONTEXT,Ebp);
693 case ICorDebugInfo::REGNUM_ESI: return offsetof(T_CONTEXT,Esi);
694 case ICorDebugInfo::REGNUM_EDI: return offsetof(T_CONTEXT,Edi);
695 default: _ASSERTE(!"Bad regNum"); return (SIZE_T) -1;
696 }
697#elif defined(_TARGET_AMD64_)
698 switch(regNum)
699 {
700 case ICorDebugInfo::REGNUM_RAX: return offsetof(CONTEXT, Rax);
701 case ICorDebugInfo::REGNUM_RCX: return offsetof(CONTEXT, Rcx);
702 case ICorDebugInfo::REGNUM_RDX: return offsetof(CONTEXT, Rdx);
703 case ICorDebugInfo::REGNUM_RBX: return offsetof(CONTEXT, Rbx);
704 case ICorDebugInfo::REGNUM_RSP: return offsetof(CONTEXT, Rsp);
705 case ICorDebugInfo::REGNUM_RBP: return offsetof(CONTEXT, Rbp);
706 case ICorDebugInfo::REGNUM_RSI: return offsetof(CONTEXT, Rsi);
707 case ICorDebugInfo::REGNUM_RDI: return offsetof(CONTEXT, Rdi);
708 case ICorDebugInfo::REGNUM_R8: return offsetof(CONTEXT, R8);
709 case ICorDebugInfo::REGNUM_R9: return offsetof(CONTEXT, R9);
710 case ICorDebugInfo::REGNUM_R10: return offsetof(CONTEXT, R10);
711 case ICorDebugInfo::REGNUM_R11: return offsetof(CONTEXT, R11);
712 case ICorDebugInfo::REGNUM_R12: return offsetof(CONTEXT, R12);
713 case ICorDebugInfo::REGNUM_R13: return offsetof(CONTEXT, R13);
714 case ICorDebugInfo::REGNUM_R14: return offsetof(CONTEXT, R14);
715 case ICorDebugInfo::REGNUM_R15: return offsetof(CONTEXT, R15);
716 default: _ASSERTE(!"Bad regNum"); return (SIZE_T)(-1);
717 }
718#elif defined(_TARGET_ARM_)
719
720 switch(regNum)
721 {
722 case ICorDebugInfo::REGNUM_R0: return offsetof(T_CONTEXT, R0);
723 case ICorDebugInfo::REGNUM_R1: return offsetof(T_CONTEXT, R1);
724 case ICorDebugInfo::REGNUM_R2: return offsetof(T_CONTEXT, R2);
725 case ICorDebugInfo::REGNUM_R3: return offsetof(T_CONTEXT, R3);
726 case ICorDebugInfo::REGNUM_R4: return offsetof(T_CONTEXT, R4);
727 case ICorDebugInfo::REGNUM_R5: return offsetof(T_CONTEXT, R5);
728 case ICorDebugInfo::REGNUM_R6: return offsetof(T_CONTEXT, R6);
729 case ICorDebugInfo::REGNUM_R7: return offsetof(T_CONTEXT, R7);
730 case ICorDebugInfo::REGNUM_R8: return offsetof(T_CONTEXT, R8);
731 case ICorDebugInfo::REGNUM_R9: return offsetof(T_CONTEXT, R9);
732 case ICorDebugInfo::REGNUM_R10: return offsetof(T_CONTEXT, R10);
733 case ICorDebugInfo::REGNUM_R11: return offsetof(T_CONTEXT, R11);
734 case ICorDebugInfo::REGNUM_R12: return offsetof(T_CONTEXT, R12);
735 case ICorDebugInfo::REGNUM_SP: return offsetof(T_CONTEXT, Sp);
736 case ICorDebugInfo::REGNUM_PC: return offsetof(T_CONTEXT, Pc);
737 case ICorDebugInfo::REGNUM_LR: return offsetof(T_CONTEXT, Lr);
738 case ICorDebugInfo::REGNUM_AMBIENT_SP: return offsetof(T_CONTEXT, Sp);
739 default: _ASSERTE(!"Bad regNum"); return (SIZE_T)(-1);
740 }
741#elif defined(_TARGET_ARM64_)
742
743 switch(regNum)
744 {
745 case ICorDebugInfo::REGNUM_X0: return offsetof(T_CONTEXT, X0);
746 case ICorDebugInfo::REGNUM_X1: return offsetof(T_CONTEXT, X1);
747 case ICorDebugInfo::REGNUM_X2: return offsetof(T_CONTEXT, X2);
748 case ICorDebugInfo::REGNUM_X3: return offsetof(T_CONTEXT, X3);
749 case ICorDebugInfo::REGNUM_X4: return offsetof(T_CONTEXT, X4);
750 case ICorDebugInfo::REGNUM_X5: return offsetof(T_CONTEXT, X5);
751 case ICorDebugInfo::REGNUM_X6: return offsetof(T_CONTEXT, X6);
752 case ICorDebugInfo::REGNUM_X7: return offsetof(T_CONTEXT, X7);
753 case ICorDebugInfo::REGNUM_X8: return offsetof(T_CONTEXT, X8);
754 case ICorDebugInfo::REGNUM_X9: return offsetof(T_CONTEXT, X9);
755 case ICorDebugInfo::REGNUM_X10: return offsetof(T_CONTEXT, X10);
756 case ICorDebugInfo::REGNUM_X11: return offsetof(T_CONTEXT, X11);
757 case ICorDebugInfo::REGNUM_X12: return offsetof(T_CONTEXT, X12);
758 case ICorDebugInfo::REGNUM_X13: return offsetof(T_CONTEXT, X13);
759 case ICorDebugInfo::REGNUM_X14: return offsetof(T_CONTEXT, X14);
760 case ICorDebugInfo::REGNUM_X15: return offsetof(T_CONTEXT, X15);
761 case ICorDebugInfo::REGNUM_X16: return offsetof(T_CONTEXT, X16);
762 case ICorDebugInfo::REGNUM_X17: return offsetof(T_CONTEXT, X17);
763 case ICorDebugInfo::REGNUM_X18: return offsetof(T_CONTEXT, X18);
764 case ICorDebugInfo::REGNUM_X19: return offsetof(T_CONTEXT, X19);
765 case ICorDebugInfo::REGNUM_X20: return offsetof(T_CONTEXT, X20);
766 case ICorDebugInfo::REGNUM_X21: return offsetof(T_CONTEXT, X21);
767 case ICorDebugInfo::REGNUM_X22: return offsetof(T_CONTEXT, X22);
768 case ICorDebugInfo::REGNUM_X23: return offsetof(T_CONTEXT, X23);
769 case ICorDebugInfo::REGNUM_X24: return offsetof(T_CONTEXT, X24);
770 case ICorDebugInfo::REGNUM_X25: return offsetof(T_CONTEXT, X25);
771 case ICorDebugInfo::REGNUM_X26: return offsetof(T_CONTEXT, X26);
772 case ICorDebugInfo::REGNUM_X27: return offsetof(T_CONTEXT, X27);
773 case ICorDebugInfo::REGNUM_X28: return offsetof(T_CONTEXT, X28);
774 case ICorDebugInfo::REGNUM_FP: return offsetof(T_CONTEXT, Fp);
775 case ICorDebugInfo::REGNUM_LR: return offsetof(T_CONTEXT, Lr);
776 case ICorDebugInfo::REGNUM_SP: return offsetof(T_CONTEXT, Sp);
777 case ICorDebugInfo::REGNUM_PC: return offsetof(T_CONTEXT, Pc);
778 case ICorDebugInfo::REGNUM_AMBIENT_SP: return offsetof(T_CONTEXT, Sp);
779 default: _ASSERTE(!"Bad regNum"); return (SIZE_T)(-1);
780 }
781#else
782 PORTABILITY_ASSERT("GetRegOffsInCONTEXT is not implemented on this platform.");
783 return (SIZE_T) -1;
784#endif // _TARGET_X86_
785}
786
787SIZE_T DereferenceByRefVar(SIZE_T addr)
788{
789 STATIC_CONTRACT_WRAPPER;
790
791 SIZE_T result = NULL;
792
793#if defined(DACCESS_COMPILE)
794 HRESULT hr = DacReadAll(addr, &result, sizeof(result), false);
795 if (FAILED(hr))
796 {
797 result = NULL;
798 }
799
800#else // !DACCESS_COMPILE
801 EX_TRY
802 {
803 AVInRuntimeImplOkayHolder AVOkay;
804
805 result = *(SIZE_T*)addr;
806 }
807 EX_CATCH
808 {
809 }
810 EX_END_CATCH(SwallowAllExceptions);
811
812#endif // !DACCESS_COMPILE
813
814 return result;
815}
816
817// How are errors communicated to the caller?
818ULONG NativeVarLocations(const ICorDebugInfo::VarLoc & varLoc,
819 PT_CONTEXT pCtx,
820 ULONG numLocs,
821 NativeVarLocation* locs)
822{
823 STATIC_CONTRACT_NOTHROW;
824 STATIC_CONTRACT_GC_NOTRIGGER;
825 STATIC_CONTRACT_FORBID_FAULT;
826
827 _ASSERTE(numLocs >= MAX_NATIVE_VAR_LOCS);
828
829 bool fByRef = false;
830 switch(varLoc.vlType)
831 {
832 SIZE_T regOffs;
833 TADDR baseReg;
834
835 case ICorDebugInfo::VLT_REG_BYREF:
836 fByRef = true; // fall through
837 case ICorDebugInfo::VLT_REG:
838 regOffs = GetRegOffsInCONTEXT(varLoc.vlReg.vlrReg);
839 locs->addr = (ULONG64)(ULONG_PTR)pCtx + regOffs;
840 if (fByRef)
841 {
842 locs->addr = (ULONG64)DereferenceByRefVar((SIZE_T)locs->addr);
843 }
844 locs->size = sizeof(SIZE_T);
845 {
846 locs->contextReg = true;
847 }
848 return 1;
849
850 case ICorDebugInfo::VLT_STK_BYREF:
851 fByRef = true; // fall through
852 case ICorDebugInfo::VLT_STK:
853 regOffs = GetRegOffsInCONTEXT(varLoc.vlStk.vlsBaseReg);
854 baseReg = *(TADDR *)(regOffs + (BYTE*)pCtx);
855 locs->addr = baseReg + varLoc.vlStk.vlsOffset;
856 if (fByRef)
857 {
858 locs->addr = (ULONG64)DereferenceByRefVar((SIZE_T)locs->addr);
859 }
860 locs->size = sizeof(SIZE_T);
861 locs->contextReg = false;
862 return 1;
863
864 case ICorDebugInfo::VLT_REG_REG:
865 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg1);
866 locs->addr = (ULONG64)(ULONG_PTR)pCtx + regOffs;
867 locs->size = sizeof(SIZE_T);
868 locs->contextReg = true;
869 locs++;
870
871 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg2);
872 locs->addr = (ULONG64)(ULONG_PTR)pCtx + regOffs;
873 locs->size = sizeof(SIZE_T);
874 locs->contextReg = true;
875 return 2;
876
877 case ICorDebugInfo::VLT_REG_STK:
878 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsReg);
879 locs->addr = (ULONG64)(ULONG_PTR)pCtx + regOffs;
880 locs->size = sizeof(SIZE_T);
881 locs->contextReg = true;
882 locs++;
883
884 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsStk.vlrssBaseReg);
885 baseReg = *(TADDR *)(regOffs + (BYTE*)pCtx);
886 locs->addr = baseReg + varLoc.vlRegStk.vlrsStk.vlrssOffset;
887 locs->size = sizeof(SIZE_T);
888 locs->contextReg = false;
889 return 2;
890
891 case ICorDebugInfo::VLT_STK_REG:
892 regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrStk.vlsrsBaseReg);
893 baseReg = *(TADDR *)(regOffs + (BYTE*)pCtx);
894 locs->addr = baseReg + varLoc.vlStkReg.vlsrStk.vlsrsOffset;
895 locs->size = sizeof(SIZE_T);
896 locs->contextReg = false;
897 locs++;
898
899 regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrReg);
900 locs->addr = (ULONG64)(ULONG_PTR)pCtx + regOffs;
901 locs->size = sizeof(SIZE_T);
902 locs->contextReg = true;
903 return 2;
904
905 case ICorDebugInfo::VLT_STK2:
906 regOffs = GetRegOffsInCONTEXT(varLoc.vlStk2.vls2BaseReg);
907 baseReg = *(TADDR *)(regOffs + (BYTE*)pCtx);
908 locs->addr = baseReg + varLoc.vlStk2.vls2Offset;
909 locs->size = 2 * sizeof(SIZE_T);
910 locs->contextReg = false;
911 return 1;
912
913 case ICorDebugInfo::VLT_FPSTK:
914 _ASSERTE(!"NYI");
915 return 0;
916
917 default:
918 _ASSERTE(!"Bad locType");
919 return 0;
920 }
921}
922
923
924BOOL CompareFiles(HANDLE hFile1,HANDLE hFile2)
925{
926
927 STATIC_CONTRACT_THROWS;
928 STATIC_CONTRACT_GC_NOTRIGGER;
929 BY_HANDLE_FILE_INFORMATION fileinfo1;
930 BY_HANDLE_FILE_INFORMATION fileinfo2;
931 if (!GetFileInformationByHandle(hFile1,&fileinfo1) ||
932 !GetFileInformationByHandle(hFile2,&fileinfo2))
933 ThrowLastError();
934 return fileinfo1.nFileIndexLow == fileinfo2.nFileIndexLow &&
935 fileinfo1.nFileIndexHigh == fileinfo2.nFileIndexHigh &&
936 fileinfo1.dwVolumeSerialNumber==fileinfo2.dwVolumeSerialNumber;
937}
938
939
940#ifndef DACCESS_COMPILE
941
942// Returns the location at which the variable
943// begins. Returns NULL for register vars. For reg-stack
944// split, it'll return the addr of the stack part.
945// This also works for VLT_REG (a single register).
946SIZE_T *NativeVarStackAddr(const ICorDebugInfo::VarLoc & varLoc,
947 PCONTEXT pCtx)
948{
949 STATIC_CONTRACT_NOTHROW;
950 STATIC_CONTRACT_GC_NOTRIGGER;
951 STATIC_CONTRACT_FORBID_FAULT;
952
953 SIZE_T *dwAddr = NULL;
954
955 bool fByRef = false;
956 switch(varLoc.vlType)
957 {
958 SIZE_T regOffs;
959 const BYTE * baseReg;
960
961 case ICorDebugInfo::VLT_REG_BYREF:
962 fByRef = true; // fall through
963 case ICorDebugInfo::VLT_REG:
964 regOffs = GetRegOffsInCONTEXT(varLoc.vlReg.vlrReg);
965 dwAddr = (SIZE_T *)(regOffs + (BYTE*)pCtx);
966 if (fByRef)
967 {
968 dwAddr = (SIZE_T*)(*dwAddr);
969 }
970 LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_REG @ 0x%x (by ref = %d)\n", dwAddr, fByRef));
971 break;
972
973 case ICorDebugInfo::VLT_STK_BYREF:
974 fByRef = true; // fall through
975 case ICorDebugInfo::VLT_STK:
976 regOffs = GetRegOffsInCONTEXT(varLoc.vlStk.vlsBaseReg);
977 baseReg = (const BYTE *)*(SIZE_T *)(regOffs + (BYTE*)pCtx);
978 dwAddr = (SIZE_T *)(baseReg + varLoc.vlStk.vlsOffset);
979 if (fByRef)
980 {
981 dwAddr = (SIZE_T*)(*dwAddr);
982 }
983 LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_STK @ 0x%x (by ref = %d)\n", dwAddr, fByRef));
984 break;
985
986 case ICorDebugInfo::VLT_STK2:
987 // <TODO>@TODO : VLT_STK2 is overloaded to also mean VLT_STK_n.
988 // return FALSE if n > 2;</TODO>
989
990 regOffs = GetRegOffsInCONTEXT(varLoc.vlStk2.vls2BaseReg);
991 baseReg = (const BYTE *)*(SIZE_T *)(regOffs + (BYTE*)pCtx);
992 dwAddr = (SIZE_T *)(baseReg + varLoc.vlStk2.vls2Offset);
993 LOG((LF_CORDB, LL_INFO100, "NVSA: VLT_STK_2 @ 0x%x\n",dwAddr));
994 break;
995
996 case ICorDebugInfo::VLT_REG_STK:
997 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsStk.vlrssBaseReg);
998 baseReg = (const BYTE *)*(SIZE_T *)(regOffs + (BYTE*)pCtx);
999 dwAddr = (SIZE_T *)(baseReg + varLoc.vlRegStk.vlrsStk.vlrssOffset);
1000 LOG((LF_CORDB, LL_INFO100, "NVSA: REG_STK @ 0x%x\n",dwAddr));
1001 break;
1002
1003 case ICorDebugInfo::VLT_STK_REG:
1004 regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrStk.vlsrsBaseReg);
1005 baseReg = (const BYTE *)*(SIZE_T *)(regOffs + (BYTE*)pCtx);
1006 dwAddr = (SIZE_T *)(baseReg + varLoc.vlStkReg.vlsrStk.vlsrsOffset);
1007 LOG((LF_CORDB, LL_INFO100, "NVSA: STK_REG @ 0x%x\n",dwAddr));
1008 break;
1009
1010 case ICorDebugInfo::VLT_REG_REG:
1011 case ICorDebugInfo::VLT_FPSTK:
1012 _ASSERTE(!"NYI"); break;
1013
1014 default:
1015 _ASSERTE(!"Bad locType"); break;
1016 }
1017
1018 return dwAddr;
1019
1020}
1021
1022
1023#if defined(_WIN64)
1024void GetNativeVarValHelper(SIZE_T* dstAddrLow, SIZE_T* dstAddrHigh, SIZE_T* srcAddr, SIZE_T size)
1025{
1026 if (size == 1)
1027 *(BYTE*)dstAddrLow = *(BYTE*)srcAddr;
1028 else if (size == 2)
1029 *(USHORT*)dstAddrLow = *(USHORT*)srcAddr;
1030 else if (size == 4)
1031 *(ULONG*)dstAddrLow = *(ULONG*)srcAddr;
1032 else if (size == 8)
1033 *dstAddrLow = *srcAddr;
1034 else if (size == 16)
1035 {
1036 *dstAddrLow = *srcAddr;
1037 *dstAddrHigh = *(srcAddr+1);
1038 }
1039 else
1040 {
1041 _ASSERTE(!"util.cpp - unreachable code.\n");
1042 UNREACHABLE();
1043 }
1044}
1045#endif // _WIN64
1046
1047
1048bool GetNativeVarVal(const ICorDebugInfo::VarLoc & varLoc,
1049 PCONTEXT pCtx,
1050 SIZE_T * pVal1,
1051 SIZE_T * pVal2
1052 WIN64_ARG(SIZE_T cbSize))
1053{
1054
1055 STATIC_CONTRACT_NOTHROW;
1056 STATIC_CONTRACT_GC_NOTRIGGER;
1057 STATIC_CONTRACT_FORBID_FAULT;
1058
1059 switch(varLoc.vlType)
1060 {
1061#if !defined(_WIN64)
1062 SIZE_T regOffs;
1063
1064 case ICorDebugInfo::VLT_REG:
1065 *pVal1 = *NativeVarStackAddr(varLoc,pCtx);
1066 break;
1067
1068 case ICorDebugInfo::VLT_STK:
1069 *pVal1 = *NativeVarStackAddr(varLoc,pCtx);
1070 break;
1071
1072 case ICorDebugInfo::VLT_STK2:
1073 *pVal1 = *NativeVarStackAddr(varLoc,pCtx);
1074 *pVal2 = *(NativeVarStackAddr(varLoc,pCtx)+ 1);
1075 break;
1076
1077 case ICorDebugInfo::VLT_REG_REG:
1078 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg1);
1079 *pVal1 = *(SIZE_T *)(regOffs + (BYTE*)pCtx);
1080 LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_REG 1 @ 0x%x\n",
1081 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1082
1083 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg2);
1084 *pVal2 = *(SIZE_T *)(regOffs + (BYTE*)pCtx);
1085 LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_REG 2 @ 0x%x\n",
1086 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1087 break;
1088
1089 case ICorDebugInfo::VLT_REG_STK:
1090 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsReg);
1091 *pVal1 = *(SIZE_T *)(regOffs + (BYTE*)pCtx);
1092 LOG((LF_CORDB, LL_INFO100, "GNVV: STK_REG_STK reg @ 0x%x\n",
1093 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1094 *pVal2 = *NativeVarStackAddr(varLoc,pCtx);
1095 break;
1096
1097 case ICorDebugInfo::VLT_STK_REG:
1098 *pVal1 = *NativeVarStackAddr(varLoc,pCtx);
1099 regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrReg);
1100 *pVal2 = *(SIZE_T *)(regOffs + (BYTE*)pCtx);
1101 LOG((LF_CORDB, LL_INFO100, "GNVV: STK_STK_REG reg @ 0x%x\n",
1102 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1103 break;
1104
1105 case ICorDebugInfo::VLT_FPSTK:
1106 _ASSERTE(!"NYI"); break;
1107
1108#else // _WIN64
1109 case ICorDebugInfo::VLT_REG:
1110 case ICorDebugInfo::VLT_REG_FP:
1111 case ICorDebugInfo::VLT_STK:
1112 GetNativeVarValHelper(pVal1, pVal2, NativeVarStackAddr(varLoc, pCtx), cbSize);
1113 break;
1114
1115 case ICorDebugInfo::VLT_REG_BYREF: // fall through
1116 case ICorDebugInfo::VLT_STK_BYREF:
1117 _ASSERTE(!"GNVV: This function should not be called for value types");
1118 break;
1119
1120#endif // _WIN64
1121
1122 default:
1123 _ASSERTE(!"Bad locType"); break;
1124 }
1125
1126 return true;
1127}
1128
1129
1130#if defined(_WIN64)
1131void SetNativeVarValHelper(SIZE_T* dstAddr, SIZE_T valueLow, SIZE_T valueHigh, SIZE_T size)
1132{
1133 if (size == 1)
1134 *(BYTE*)dstAddr = (BYTE)valueLow;
1135 else if (size == 2)
1136 *(USHORT*)dstAddr = (USHORT)valueLow;
1137 else if (size == 4)
1138 *(ULONG*)dstAddr = (ULONG)valueLow;
1139 else if (size == 8)
1140 *dstAddr = valueLow;
1141 else if (size == 16)
1142 {
1143 *dstAddr = valueLow;
1144 *(dstAddr+1) = valueHigh;
1145 }
1146 else
1147 {
1148 _ASSERTE(!"util.cpp - unreachable code.\n");
1149 UNREACHABLE();
1150 }
1151}
1152#endif // _WIN64
1153
1154
1155bool SetNativeVarVal(const ICorDebugInfo::VarLoc & varLoc,
1156 PCONTEXT pCtx,
1157 SIZE_T val1,
1158 SIZE_T val2
1159 WIN64_ARG(SIZE_T cbSize))
1160{
1161 STATIC_CONTRACT_NOTHROW;
1162 STATIC_CONTRACT_GC_NOTRIGGER;
1163 STATIC_CONTRACT_FORBID_FAULT;
1164
1165 switch(varLoc.vlType)
1166 {
1167#if !defined(_WIN64)
1168 SIZE_T regOffs;
1169
1170 case ICorDebugInfo::VLT_REG:
1171 *NativeVarStackAddr(varLoc,pCtx) = val1;
1172 break;
1173
1174 case ICorDebugInfo::VLT_STK:
1175 *NativeVarStackAddr(varLoc,pCtx) = val1;
1176 break;
1177
1178 case ICorDebugInfo::VLT_STK2:
1179 *NativeVarStackAddr(varLoc,pCtx) = val1;
1180 *(NativeVarStackAddr(varLoc,pCtx)+ 1) = val2;
1181 break;
1182
1183 case ICorDebugInfo::VLT_REG_REG:
1184 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg1);
1185 *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val1;
1186 LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_REG 1 @ 0x%x\n",
1187 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1188
1189 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegReg.vlrrReg2);
1190 *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val2;
1191 LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_REG 2 @ 0x%x\n",
1192 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1193 break;
1194
1195 case ICorDebugInfo::VLT_REG_STK:
1196 regOffs = GetRegOffsInCONTEXT(varLoc.vlRegStk.vlrsReg);
1197 *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val1;
1198 LOG((LF_CORDB, LL_INFO100, "SNVV: STK_REG_STK reg @ 0x%x\n",
1199 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1200 *NativeVarStackAddr(varLoc,pCtx) = val2;
1201 break;
1202
1203 case ICorDebugInfo::VLT_STK_REG:
1204 *NativeVarStackAddr(varLoc,pCtx) = val1;
1205 regOffs = GetRegOffsInCONTEXT(varLoc.vlStkReg.vlsrReg);
1206 *(SIZE_T *)(regOffs + (BYTE*)pCtx) = val2;
1207 LOG((LF_CORDB, LL_INFO100, "SNVV: STK_STK_REG reg @ 0x%x\n",
1208 (SIZE_T *)(regOffs + (BYTE*)pCtx)));
1209 break;
1210
1211 case ICorDebugInfo::VLT_FPSTK:
1212 _ASSERTE(!"NYI"); break;
1213
1214#else // _WIN64
1215 case ICorDebugInfo::VLT_REG:
1216 case ICorDebugInfo::VLT_REG_FP:
1217 case ICorDebugInfo::VLT_STK:
1218 SetNativeVarValHelper(NativeVarStackAddr(varLoc, pCtx), val1, val2, cbSize);
1219 break;
1220
1221 case ICorDebugInfo::VLT_REG_BYREF: // fall through
1222 case ICorDebugInfo::VLT_STK_BYREF:
1223 _ASSERTE(!"GNVV: This function should not be called for value types");
1224 break;
1225
1226#endif // _WIN64
1227
1228 default:
1229 _ASSERTE(!"Bad locType"); break;
1230 }
1231
1232 return true;
1233}
1234
1235HRESULT VMPostError( // Returned error.
1236 HRESULT hrRpt, // Reported error.
1237 ...) // Error arguments.
1238{
1239 CONTRACTL
1240 {
1241 NOTHROW;
1242 GC_TRIGGERS;
1243 MODE_ANY;
1244 }
1245 CONTRACTL_END;
1246
1247 GCX_PREEMP();
1248
1249 va_list marker; // User text.
1250 va_start(marker, hrRpt);
1251 hrRpt = PostErrorVA(hrRpt, marker);
1252 va_end(marker);
1253
1254 return hrRpt;
1255}
1256
1257#ifndef CROSSGEN_COMPILE
1258void VMDumpCOMErrors(HRESULT hrErr)
1259{
1260 CONTRACTL
1261 {
1262 NOTHROW;
1263 GC_TRIGGERS;
1264 MODE_PREEMPTIVE;
1265 PRECONDITION(FAILED(hrErr));
1266 }
1267 CONTRACTL_END;
1268
1269 SafeComHolderPreemp<IErrorInfo> pIErr(NULL);// Error interface.
1270 BSTRHolder bstrDesc(NULL); // Description text.
1271
1272 // Try to get an error info object and display the message.
1273 if (SafeGetErrorInfo(&pIErr) == S_OK && pIErr->GetDescription(&bstrDesc) == S_OK)
1274 {
1275 EEMessageBoxCatastrophic(IDS_EE_GENERIC, IDS_FATAL_ERROR, (BSTR)bstrDesc);
1276 }
1277 else
1278 {
1279 // Just give out the failed hr return code.
1280 EEMessageBoxCatastrophic(IDS_COMPLUS_ERROR, IDS_FATAL_ERROR, hrErr);
1281 }
1282}
1283
1284//-----------------------------------------------------------------------------
1285#ifndef FEATURE_PAL
1286
1287// Wrap registry functions to use CQuickWSTR to allocate space. This does it
1288// in a stack friendly manner.
1289//-----------------------------------------------------------------------------
1290LONG UtilRegEnumKey(HKEY hKey, // handle to key to query
1291 DWORD dwIndex, // index of subkey to query
1292 CQuickWSTR* lpName) // buffer for subkey name
1293{
1294 CONTRACTL
1295 {
1296 NOTHROW;
1297 GC_NOTRIGGER;
1298 INJECT_FAULT(return ERROR_NOT_ENOUGH_MEMORY;);
1299 }
1300 CONTRACTL_END;
1301
1302 DWORD size = (DWORD)lpName->MaxSize();
1303 LONG result = WszRegEnumKeyEx(hKey,
1304 dwIndex,
1305 lpName->Ptr(),
1306 &size,
1307 NULL,
1308 NULL,
1309 NULL,
1310 NULL);
1311
1312 if (result == ERROR_SUCCESS || result == ERROR_MORE_DATA) {
1313
1314 // Grow or shrink buffer to correct size
1315 if (lpName->ReSizeNoThrow(size+1) != NOERROR)
1316 result = ERROR_NOT_ENOUGH_MEMORY;
1317
1318 if (result == ERROR_MORE_DATA) {
1319 size = (DWORD)lpName->MaxSize();
1320 result = WszRegEnumKeyEx(hKey,
1321 dwIndex,
1322 lpName->Ptr(),
1323 &size,
1324 NULL,
1325 NULL,
1326 NULL,
1327 NULL);
1328 }
1329 }
1330
1331 return result;
1332}
1333
1334LONG UtilRegQueryStringValueEx(HKEY hKey, // handle to key to query
1335 LPCWSTR lpValueName, // address of name of value to query
1336 LPDWORD lpReserved, // reserved
1337 LPDWORD lpType, // address of buffer for value type
1338 CQuickWSTR* lpData)// data buffer
1339{
1340 CONTRACTL
1341 {
1342 NOTHROW;
1343 GC_NOTRIGGER;
1344 INJECT_FAULT(return ERROR_NOT_ENOUGH_MEMORY;);
1345 }
1346 CONTRACTL_END;
1347
1348 DWORD size = (DWORD)lpData->MaxSize();
1349 LONG result = WszRegQueryValueEx(hKey,
1350 lpValueName,
1351 lpReserved,
1352 lpType,
1353 (LPBYTE) lpData->Ptr(),
1354 &size);
1355
1356 if (result == ERROR_SUCCESS || result == ERROR_MORE_DATA) {
1357
1358 // Grow or shrink buffer to correct size
1359 if (lpData->ReSizeNoThrow(size+1) != NOERROR)
1360 result = ERROR_NOT_ENOUGH_MEMORY;
1361
1362 if (result == ERROR_MORE_DATA) {
1363 size = (DWORD)lpData->MaxSize();
1364 result = WszRegQueryValueEx(hKey,
1365 lpValueName,
1366 lpReserved,
1367 lpType,
1368 (LPBYTE) lpData->Ptr(),
1369 &size);
1370 }
1371 }
1372
1373 return result;
1374}
1375
1376BOOL ReportEventCLR(
1377 WORD wType,
1378 WORD wCategory,
1379 DWORD dwEventID,
1380 PSID lpUserSid,
1381 SString * message)
1382{
1383 CONTRACTL {
1384 THROWS;
1385 GC_TRIGGERS;
1386 MODE_ANY;
1387 } CONTRACTL_END;
1388
1389 GCX_PREEMP();
1390
1391 SString buff;
1392 buff.Printf(W(".NET Runtime version %s - %s"), VER_FILEVERSION_STR_L, message->GetUnicode());
1393
1394 DWORD dwRetVal = ClrReportEvent(W(".NET Runtime"),
1395 wType, // event type
1396 wCategory, // category
1397 dwEventID, // event identifier
1398 lpUserSid, // user security identifier
1399 buff.GetUnicode()); // one substitution string
1400
1401 // Return BOOLEAN based upon return code
1402 return (dwRetVal == ERROR_SUCCESS)?TRUE:FALSE;
1403}
1404
1405// This function checks to see if GetLogicalProcessorInformation API is supported.
1406// On success, this function allocates a SLPI array, sets nEntries to number
1407// of elements in the SLPI array and returns a pointer to the SLPI array after filling it with information.
1408//
1409// Note: If successful, IsGLPISupported allocates memory for the SLPI array and expects the caller to
1410// free the memory once the caller is done using the information in the SLPI array.
1411//
1412// If the API is not supported or any failure, returns NULL
1413//
1414SYSTEM_LOGICAL_PROCESSOR_INFORMATION *IsGLPISupported( PDWORD nEntries )
1415{
1416 DWORD cbslpi = 0;
1417 DWORD dwNumElements = 0;
1418 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *pslpi = NULL;
1419
1420 // We setup the first call to GetLogicalProcessorInformation to fail so that we can obtain
1421 // the size of the buffer required to allocate for the SLPI array that is returned
1422
1423 if (!GetLogicalProcessorInformation(pslpi, &cbslpi) &&
1424 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1425 {
1426 // If we fail with anything other than an ERROR_INSUFFICIENT_BUFFER here, we punt with failure.
1427 return NULL;
1428 }
1429
1430 _ASSERTE(cbslpi);
1431
1432 // compute the number of SLPI entries required to hold the information returned from GLPI
1433
1434 dwNumElements = cbslpi / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
1435
1436 // allocate a buffer in the free heap to hold an array of SLPI entries from GLPI, number of elements in the array is dwNumElements
1437
1438 pslpi = new (nothrow) SYSTEM_LOGICAL_PROCESSOR_INFORMATION[ dwNumElements ];
1439
1440 if(pslpi == NULL)
1441 {
1442 // the memory allocation failed
1443 return NULL;
1444 }
1445
1446 // Make call to GetLogicalProcessorInformation. Returns array of SLPI structures
1447
1448 if (!GetLogicalProcessorInformation(pslpi, &cbslpi))
1449 {
1450 // GetLogicalProcessorInformation failed
1451 delete[] pslpi ; //Allocation was fine but the API call itself failed and so we are releasing the memory before the return NULL.
1452 return NULL ;
1453 }
1454
1455 // GetLogicalProcessorInformation successful, set nEntries to number of entries in the SLPI array
1456 *nEntries = dwNumElements;
1457
1458 return pslpi; // return pointer to SLPI array
1459
1460}//IsGLPISupported
1461
1462// This function returns the size of highest level cache on the physical chip. If it cannot
1463// determine the cachesize this function returns 0.
1464size_t GetLogicalProcessorCacheSizeFromOS()
1465{
1466 size_t cache_size = 0;
1467 DWORD nEntries = 0;
1468
1469 // Try to use GetLogicalProcessorInformation API and get a valid pointer to the SLPI array if successful. Returns NULL
1470 // if API not present or on failure.
1471
1472 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *pslpi = IsGLPISupported(&nEntries) ;
1473
1474 if (pslpi == NULL)
1475 {
1476 // GetLogicalProcessorInformation not supported or failed.
1477 goto Exit;
1478 }
1479
1480 // Crack the information. Iterate through all the SLPI array entries for all processors in system.
1481 // Will return the greatest of all the processor cache sizes or zero
1482 {
1483 size_t last_cache_size = 0;
1484
1485 for (DWORD i=0; i < nEntries; i++)
1486 {
1487 if (pslpi[i].Relationship == RelationCache)
1488 {
1489 last_cache_size = max(last_cache_size, pslpi[i].Cache.Size);
1490 }
1491 }
1492 cache_size = last_cache_size;
1493 }
1494Exit:
1495
1496 if(pslpi)
1497 delete[] pslpi; // release the memory allocated for the SLPI array.
1498
1499 return cache_size;
1500}
1501
1502#endif // !FEATURE_PAL
1503
1504// This function returns the number of logical processors on a given physical chip. If it cannot
1505// determine the number of logical cpus, or the machine is not populated uniformly with the same
1506// type of processors, this function returns 0.
1507
1508DWORD GetLogicalCpuCountFromOS()
1509{
1510 // No CONTRACT possible because GetLogicalCpuCount uses SEH
1511
1512 STATIC_CONTRACT_THROWS;
1513 STATIC_CONTRACT_GC_NOTRIGGER;
1514
1515 static DWORD val = 0;
1516 DWORD retVal = 0;
1517
1518#ifdef FEATURE_PAL
1519 retVal = PAL_GetLogicalCpuCountFromOS();
1520#else // FEATURE_PAL
1521
1522 DWORD nEntries = 0;
1523
1524 DWORD prevcount = 0;
1525 DWORD count = 1;
1526
1527 // Try to use GetLogicalProcessorInformation API and get a valid pointer to the SLPI array if successful. Returns NULL
1528 // if API not present or on failure.
1529 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *pslpi = IsGLPISupported(&nEntries) ;
1530
1531 if (pslpi == NULL)
1532 {
1533 // GetLogicalProcessorInformation no supported
1534 goto lDone;
1535 }
1536
1537 for (DWORD j = 0; j < nEntries; j++)
1538 {
1539 if (pslpi[j].Relationship == RelationProcessorCore)
1540 {
1541 // LTP_PC_SMT indicates HT or SMT
1542 if (pslpi[j].ProcessorCore.Flags == LTP_PC_SMT)
1543 {
1544 SIZE_T pmask = pslpi[j].ProcessorMask;
1545
1546 // Count the processors in the mask
1547 //
1548 // These are not the fastest bit counters. There may be processor intrinsics
1549 // (which would be best), but there are variants faster than these:
1550 // See http://en.wikipedia.org/wiki/Hamming_weight.
1551 // This is the naive implementation.
1552#if !_WIN64
1553 count = (pmask & 0x55555555) + ((pmask >> 1) & 0x55555555);
1554 count = (count & 0x33333333) + ((count >> 2) & 0x33333333);
1555 count = (count & 0x0F0F0F0F) + ((count >> 4) & 0x0F0F0F0F);
1556 count = (count & 0x00FF00FF) + ((count >> 8) & 0x00FF00FF);
1557 count = (count & 0x0000FFFF) + ((count >> 16)& 0x0000FFFF);
1558#else
1559 pmask = (pmask & 0x5555555555555555ull) + ((pmask >> 1) & 0x5555555555555555ull);
1560 pmask = (pmask & 0x3333333333333333ull) + ((pmask >> 2) & 0x3333333333333333ull);
1561 pmask = (pmask & 0x0f0f0f0f0f0f0f0full) + ((pmask >> 4) & 0x0f0f0f0f0f0f0f0full);
1562 pmask = (pmask & 0x00ff00ff00ff00ffull) + ((pmask >> 8) & 0x00ff00ff00ff00ffull);
1563 pmask = (pmask & 0x0000ffff0000ffffull) + ((pmask >> 16) & 0x0000ffff0000ffffull);
1564 pmask = (pmask & 0x00000000ffffffffull) + ((pmask >> 32) & 0x00000000ffffffffull);
1565 count = static_cast<DWORD>(pmask);
1566#endif // !_WIN64 else
1567 assert (count > 0);
1568
1569 if (prevcount)
1570 {
1571 if (count != prevcount)
1572 {
1573 retVal = 1; // masks are not symmetric
1574 goto lDone;
1575 }
1576 }
1577
1578 prevcount = count;
1579 }
1580 }
1581 }
1582
1583 retVal = count;
1584
1585lDone:
1586
1587 if(pslpi)
1588 {
1589 delete[] pslpi; // release the memory allocated for the SLPI array
1590 }
1591#endif // FEATURE_PAL
1592
1593 return retVal;
1594}
1595
1596#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
1597
1598#define CACHE_WAY_BITS 0xFFC00000 // number of cache WAYS-Associativity is returned in EBX[31:22] (10 bits) using cpuid function 4
1599#define CACHE_PARTITION_BITS 0x003FF000 // number of cache Physical Partitions is returned in EBX[21:12] (10 bits) using cpuid function 4
1600#define CACHE_LINESIZE_BITS 0x00000FFF // Linesize returned in EBX[11:0] (12 bits) using cpuid function 4
1601
1602// these are defined in src\VM\AMD64\asmhelpers.asm / cgenx86.cpp
1603extern "C" DWORD __stdcall getcpuid(DWORD arg1, unsigned char result[16]);
1604extern "C" DWORD __stdcall getextcpuid(DWORD arg1, DWORD arg2, unsigned char result[16]);
1605
1606// The following function uses a deterministic mechanism for enumerating/calculating the details of the cache hierarychy at runtime
1607// by using deterministic cache parameter leafs on Prescott and higher processors.
1608// If successful, this function returns the cache size in bytes of the highest level on-die cache. Returns 0 on failure.
1609
1610size_t GetIntelDeterministicCacheEnum()
1611{
1612 LIMITED_METHOD_CONTRACT;
1613 size_t retVal = 0;
1614 unsigned char buffer[16];
1615 size_t buflen = ARRAYSIZE(buffer);
1616
1617 DWORD maxCpuid = getextcpuid(0,0,buffer);
1618 DWORD dwBuffer[4];
1619 memcpy(dwBuffer, buffer, buflen);
1620
1621 if( (maxCpuid > 3) && (maxCpuid < 0x80000000) ) // Deterministic Cache Enum is Supported
1622 {
1623 DWORD dwCacheWays, dwCachePartitions, dwLineSize, dwSets;
1624 DWORD retEAX = 0;
1625 DWORD loopECX = 0;
1626 size_t maxSize = 0;
1627 size_t curSize = 0;
1628
1629 // Make First call to getextcpuid with loopECX=0. loopECX provides an index indicating which level to return information about.
1630 // The second parameter is input EAX=4, to specify we want deterministic cache parameter leaf information.
1631 // getextcpuid with EAX=4 should be executed with loopECX = 0,1, ... until retEAX [4:0] contains 00000b, indicating no more
1632 // cache levels are supported.
1633
1634 getextcpuid(loopECX, 4, buffer);
1635 memcpy(dwBuffer, buffer, buflen);
1636 retEAX = dwBuffer[0]; // get EAX
1637
1638 int i = 0;
1639 while(retEAX & 0x1f) // Crack cache enums and loop while EAX > 0
1640 {
1641
1642 dwCacheWays = (dwBuffer[1] & CACHE_WAY_BITS) >> 22;
1643 dwCachePartitions = (dwBuffer[1] & CACHE_PARTITION_BITS) >> 12;
1644 dwLineSize = dwBuffer[1] & CACHE_LINESIZE_BITS;
1645 dwSets = dwBuffer[2]; // ECX
1646
1647 curSize = (dwCacheWays+1)*(dwCachePartitions+1)*(dwLineSize+1)*(dwSets+1);
1648
1649 if (maxSize < curSize)
1650 maxSize = curSize;
1651
1652 loopECX++;
1653 getextcpuid(loopECX, 4, buffer);
1654 memcpy(dwBuffer, buffer, buflen);
1655 retEAX = dwBuffer[0] ; // get EAX[4:0];
1656 i++;
1657 if (i > 16) { // prevent infinite looping
1658 return 0;
1659 }
1660 }
1661 retVal = maxSize;
1662 }
1663 return retVal ;
1664}
1665
1666// The following function uses CPUID function 2 with descriptor values to determine the cache size. This requires a-priori
1667// knowledge of the descriptor values. This works on gallatin and prior processors (already released processors).
1668// If successful, this function returns the cache size in bytes of the highest level on-die cache. Returns 0 on failure.
1669
1670size_t GetIntelDescriptorValuesCache()
1671{
1672 LIMITED_METHOD_CONTRACT;
1673 size_t size = 0;
1674 size_t maxSize = 0;
1675 unsigned char buffer[16];
1676
1677 getextcpuid(0,2, buffer); // call CPUID with EAX function 2H to obtain cache descriptor values
1678
1679 for (int i = buffer[0]; --i >= 0; )
1680 {
1681 int j;
1682 for (j = 3; j < 16; j += 4)
1683 {
1684 // if the information in a register is marked invalid, set to null descriptors
1685 if (buffer[j] & 0x80)
1686 {
1687 buffer[j-3] = 0;
1688 buffer[j-2] = 0;
1689 buffer[j-1] = 0;
1690 buffer[j-0] = 0;
1691 }
1692 }
1693
1694 for (j = 1; j < 16; j++)
1695 {
1696 switch (buffer[j]) // need to add descriptor values for 8M and 12M when they become known
1697 {
1698 case 0x41:
1699 case 0x79:
1700 size = 128*1024;
1701 break;
1702
1703 case 0x42:
1704 case 0x7A:
1705 case 0x82:
1706 size = 256*1024;
1707 break;
1708
1709 case 0x22:
1710 case 0x43:
1711 case 0x7B:
1712 case 0x83:
1713 case 0x86:
1714 size = 512*1024;
1715 break;
1716
1717 case 0x23:
1718 case 0x44:
1719 case 0x7C:
1720 case 0x84:
1721 case 0x87:
1722 size = 1024*1024;
1723 break;
1724
1725 case 0x25:
1726 case 0x45:
1727 case 0x85:
1728 size = 2*1024*1024;
1729 break;
1730
1731 case 0x29:
1732 size = 4*1024*1024;
1733 break;
1734 }
1735 if (maxSize < size)
1736 maxSize = size;
1737 }
1738
1739 if (i > 0)
1740 getextcpuid(0,2, buffer);
1741 }
1742 return maxSize;
1743}
1744
1745
1746
1747#define NUM_LOGICAL_BITS 0x00FF0000 // EBX[23:16] Bit 16-23 in ebx contains the number of logical
1748 // processors per physical processor (using cpuid function 1)
1749#define INITIAL_APIC_ID_BITS 0xFF000000 // EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique
1750 // initial APIC ID for the processor this code is running on.
1751 // Default value = 0xff if HT is not supported
1752
1753// This function uses CPUID function 1 to return the number of logical processors on a given physical chip.
1754// It returns the number of logicals processors on a physical chip.
1755
1756DWORD GetLogicalCpuCountFallback()
1757{
1758 BYTE LogicalNum = 0;
1759 BYTE PhysicalNum = 0;
1760 DWORD lProcCounter = 0;
1761 unsigned char buffer[16];
1762
1763 DWORD* dwBuffer = (DWORD*)buffer;
1764 DWORD retVal = 1;
1765
1766 getextcpuid(0,1, buffer); //call CPUID with EAX=1
1767
1768 if (dwBuffer[3] & (1<<28)) // edx:bit 28 is HT bit
1769 {
1770 PhysicalNum = (BYTE) g_SystemInfo.dwNumberOfProcessors ; // total # of processors
1771 LogicalNum = (BYTE) ((dwBuffer[1] & NUM_LOGICAL_BITS) >> 16); // # of logical per physical
1772
1773 if(LogicalNum > 1)
1774 {
1775#ifdef FEATURE_CORESYSTEM
1776 // CoreSystem doesn't expose GetProcessAffinityMask or SetProcessAffinityMask or anything
1777 // functionally equivalent. Just assume 1:1 mapping if we get here (in reality we shouldn't since
1778 // all CoreSystems support GetLogicalProcessorInformation so GetLogicalCpuCountFromOS should have
1779 // taken care of everything.
1780 goto fDone;
1781#else // FEATURE_CORESYSTEM
1782 HANDLE hCurrentProcessHandle;
1783 DWORD_PTR dwProcessAffinity;
1784 DWORD_PTR dwSystemAffinity;
1785 DWORD_PTR dwAffinityMask;
1786
1787 // Calculate the appropriate shifts and mask based on the
1788 // number of logical processors.
1789
1790 BYTE i = 1, PHY_ID_MASK = 0xFF, PHY_ID_SHIFT = 0;
1791 while (i < LogicalNum)
1792 {
1793 i *= 2;
1794 PHY_ID_MASK <<= 1;
1795 PHY_ID_SHIFT++;
1796 }
1797 hCurrentProcessHandle = GetCurrentProcess();
1798
1799 GetProcessAffinityMask(hCurrentProcessHandle, &dwProcessAffinity, &dwSystemAffinity);
1800
1801 // Check if available process affinity mask is equal to the available system affinity mask
1802 // If the masks are equal, then all the processors the OS utilizes are available to the
1803 // application.
1804
1805 if (dwProcessAffinity != dwSystemAffinity)
1806 {
1807 retVal = 0;
1808 goto fDone;
1809 }
1810
1811 dwAffinityMask = 1;
1812
1813 // loop over all processors, running APIC ID retrieval code starting
1814 // with the first one by setting process affinity.
1815 while (dwAffinityMask != 0 && dwAffinityMask <= dwProcessAffinity)
1816 {
1817 // Check if this CPU is available
1818 if (dwAffinityMask & dwProcessAffinity)
1819 {
1820 if (SetProcessAffinityMask(hCurrentProcessHandle, dwAffinityMask))
1821 {
1822 BYTE APIC_ID, LOG_ID, PHY_ID;
1823 __SwitchToThread(0, CALLER_LIMITS_SPINNING); // Give OS time to switch CPU
1824
1825 getextcpuid(0,1, buffer); //call cpuid with EAX=1
1826
1827 APIC_ID = (dwBuffer[1] & INITIAL_APIC_ID_BITS) >> 24;
1828 LOG_ID = APIC_ID & ~PHY_ID_MASK;
1829 PHY_ID = APIC_ID >> PHY_ID_SHIFT;
1830 if (LOG_ID != 0)
1831 lProcCounter++;
1832 }
1833 }
1834 dwAffinityMask = dwAffinityMask << 1;
1835 }
1836 // Reset the processor affinity
1837
1838 SetProcessAffinityMask(hCurrentProcessHandle, dwProcessAffinity);
1839
1840 // Check if HT is enabled on all the processors
1841 if(lProcCounter > 0 && (lProcCounter == (DWORD)(PhysicalNum / LogicalNum)))
1842 {
1843 retVal = lProcCounter;
1844 goto fDone;
1845 }
1846#endif // FEATURE_CORESYSTEM
1847 }
1848 }
1849fDone:
1850
1851 return retVal;
1852}
1853
1854#endif // _TARGET_X86_ || _TARGET_AMD64_
1855
1856// fix this if/when AMD does multicore or SMT
1857size_t GetCacheSizePerLogicalCpu(BOOL bTrueSize)
1858{
1859 // No CONTRACT possible because GetCacheSizePerLogicalCpu uses SEH
1860
1861 STATIC_CONTRACT_NOTHROW;
1862 STATIC_CONTRACT_GC_NOTRIGGER;
1863
1864 static size_t maxSize;
1865 static size_t maxTrueSize;
1866
1867 if (maxSize)
1868 {
1869 // maxSize and maxTrueSize cached
1870 if (bTrueSize)
1871 {
1872 return maxTrueSize;
1873 }
1874 else
1875 {
1876 return maxSize;
1877 }
1878 }
1879
1880#if defined(_TARGET_AMD64_) || defined (_TARGET_X86_)
1881 DefaultCatchFilterParam param;
1882 param.pv = COMPLUS_EXCEPTION_EXECUTE_HANDLER;
1883
1884 PAL_TRY(DefaultCatchFilterParam *, pParam, &param)
1885 {
1886 unsigned char buffer[16];
1887 DWORD* dwBuffer = (DWORD*)buffer;
1888
1889 DWORD maxCpuId = getcpuid(0, buffer);
1890
1891 if (dwBuffer[1] == 'uneG')
1892 {
1893 if (dwBuffer[3] == 'Ieni')
1894 {
1895 if (dwBuffer[2] == 'letn')
1896 {
1897 /*
1898 //The following lines are commented because the OS API on Windows 2003 SP1 is not returning the Cache Relation information on x86.
1899 //Once the OS API (LH and above) is updated with this information, we should start using the OS API to get the cache enumeration by
1900 //uncommenting the lines below.
1901
1902 tempSize = GetLogicalProcessorCacheSizeFromOS(); //use OS API for cache enumeration on LH and above
1903 */
1904 size_t tempSize = 0;
1905 if (maxCpuId >= 2) // cpuid support for cache size determination is available
1906 {
1907 tempSize = GetIntelDeterministicCacheEnum(); // try to use use deterministic cache size enumeration
1908 if (!tempSize)
1909 { // deterministic enumeration failed, fallback to legacy enumeration using descriptor values
1910 tempSize = GetIntelDescriptorValuesCache();
1911 }
1912 }
1913
1914 // TODO: Currently GetLogicalCpuCountFromOS() and GetLogicalCpuCountFallback() are broken on
1915 // multi-core processor, but we never call into those two functions since we don't halve the
1916 // gen0size when it's prescott and above processor. We keep the old version here for earlier
1917 // generation system(Northwood based), perf data suggests on those systems, halve gen0 size
1918 // still boost the performance(ex:Biztalk boosts about 17%). So on earlier systems(Northwood)
1919 // based, we still go ahead and halve gen0 size. The logic in GetLogicalCpuCountFromOS()
1920 // and GetLogicalCpuCountFallback() works fine for those earlier generation systems.
1921 // If it's a Prescott and above processor or Multi-core, perf data suggests not to halve gen0
1922 // size at all gives us overall better performance.
1923 // This is going to be fixed with a new version in orcas time frame.
1924 if (maxCpuId >= 2 && !((maxCpuId > 3) && (maxCpuId < 0x80000000)))
1925 {
1926 DWORD logicalProcessorCount = GetLogicalCpuCountFromOS(); //try to obtain HT enumeration from OS API
1927
1928 if (!logicalProcessorCount)
1929 {
1930 logicalProcessorCount = GetLogicalCpuCountFallback(); // OS API failed, Fallback to HT enumeration using CPUID
1931 }
1932
1933 if (logicalProcessorCount)
1934 {
1935 tempSize = tempSize / logicalProcessorCount;
1936 }
1937 }
1938
1939 // update maxSize once with final value
1940 maxTrueSize = tempSize;
1941
1942#ifdef _WIN64
1943 if (maxCpuId >= 2)
1944 {
1945 // If we're running on a Prescott or greater core, EM64T tests
1946 // show that starting with a gen0 larger than LLC improves performance.
1947 // Thus, start with a gen0 size that is larger than the cache. The value of
1948 // 3 is a reasonable tradeoff between workingset and performance.
1949 maxSize = maxTrueSize * 3;
1950 }
1951 else
1952#endif
1953 {
1954 maxSize = maxTrueSize;
1955 }
1956 }
1957 }
1958 }
1959
1960 if (dwBuffer[1] == 'htuA') {
1961 if (dwBuffer[3] == 'itne') {
1962 if (dwBuffer[2] == 'DMAc') {
1963
1964 if (getcpuid(0x80000000, buffer) >= 0x80000006)
1965 {
1966 getcpuid(0x80000006, buffer);
1967
1968 DWORD dwL2CacheBits = dwBuffer[2];
1969 DWORD dwL3CacheBits = dwBuffer[3];
1970
1971 maxTrueSize = (size_t)((dwL2CacheBits >> 16) * 1024); // L2 cache size in ECX bits 31-16
1972
1973 getcpuid(0x1, buffer);
1974 DWORD dwBaseFamily = (dwBuffer[0] & (0xF << 8)) >> 8;
1975 DWORD dwExtFamily = (dwBuffer[0] & (0xFF << 20)) >> 20;
1976 DWORD dwFamily = dwBaseFamily >= 0xF ? dwBaseFamily + dwExtFamily : dwBaseFamily;
1977
1978 if (dwFamily >= 0x10)
1979 {
1980 BOOL bSkipAMDL3 = FALSE;
1981
1982 if (dwFamily == 0x10) // are we running on a Barcelona (Family 10h) processor?
1983 {
1984 // check model
1985 DWORD dwBaseModel = (dwBuffer[0] & (0xF << 4)) >> 4 ;
1986 DWORD dwExtModel = (dwBuffer[0] & (0xF << 16)) >> 16;
1987 DWORD dwModel = dwBaseFamily >= 0xF ? (dwExtModel << 4) | dwBaseModel : dwBaseModel;
1988
1989 switch (dwModel)
1990 {
1991 case 0x2:
1992 // 65nm parts do not benefit from larger Gen0
1993 bSkipAMDL3 = TRUE;
1994 break;
1995
1996 case 0x4:
1997 default:
1998 bSkipAMDL3 = FALSE;
1999 }
2000 }
2001
2002 if (!bSkipAMDL3)
2003 {
2004 // 45nm Greyhound parts (and future parts based on newer northbridge) benefit
2005 // from increased gen0 size, taking L3 into account
2006 getcpuid(0x80000008, buffer);
2007 DWORD dwNumberOfCores = (dwBuffer[2] & (0xFF)) + 1; // NC is in ECX bits 7-0
2008
2009 DWORD dwL3CacheSize = (size_t)((dwL3CacheBits >> 18) * 512 * 1024); // L3 size in EDX bits 31-18 * 512KB
2010 // L3 is shared between cores
2011 dwL3CacheSize = dwL3CacheSize / dwNumberOfCores;
2012 maxTrueSize += dwL3CacheSize; // due to exclusive caches, add L3 size (possibly zero) to L2
2013 // L1 is too small to worry about, so ignore it
2014 }
2015 }
2016
2017
2018 maxSize = maxTrueSize;
2019 }
2020 }
2021 }
2022 }
2023 }
2024 PAL_EXCEPT_FILTER(DefaultCatchFilter)
2025 {
2026 }
2027 PAL_ENDTRY
2028#else
2029 maxSize = maxTrueSize = GetLogicalProcessorCacheSizeFromOS() ; // Returns the size of the highest level processor cache
2030#endif
2031
2032#if defined(_TARGET_ARM64_)
2033 // Bigger gen0 size helps arm64 targets
2034 maxSize = maxTrueSize * 3;
2035#endif
2036
2037 // printf("GetCacheSizePerLogicalCpu returns %d, adjusted size %d\n", maxSize, maxTrueSize);
2038 if (bTrueSize)
2039 return maxTrueSize;
2040 else
2041 return maxSize;
2042}
2043
2044//---------------------------------------------------------------------
2045
2046#ifndef FEATURE_PAL
2047ThreadLocaleHolder::~ThreadLocaleHolder()
2048{
2049 SetThreadLocale(m_locale);
2050}
2051
2052HMODULE CLRGetModuleHandle(LPCWSTR lpModuleFileName)
2053{
2054 // Don't use dynamic contract: will override GetLastError value
2055 STATIC_CONTRACT_NOTHROW;
2056 STATIC_CONTRACT_GC_NOTRIGGER;
2057 STATIC_CONTRACT_FORBID_FAULT;
2058 STATIC_CONTRACT_SO_TOLERANT;
2059
2060 HMODULE hMod = WszGetModuleHandle(lpModuleFileName);
2061 return hMod;
2062}
2063
2064
2065HMODULE CLRGetCurrentModuleHandle()
2066{
2067 // Don't use dynamic contract: will override GetLastError value
2068 STATIC_CONTRACT_NOTHROW;
2069 STATIC_CONTRACT_GC_NOTRIGGER;
2070 STATIC_CONTRACT_FORBID_FAULT;
2071 STATIC_CONTRACT_SO_TOLERANT;
2072
2073 HMODULE hMod = WszGetModuleHandle(NULL);
2074 return hMod;
2075}
2076
2077
2078#endif // !FEATURE_PAL
2079
2080LPVOID EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes);
2081BOOL EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem);
2082void ShutdownRuntimeWithoutExiting(int exitCode);
2083BOOL IsRuntimeStarted(DWORD *pdwStartupFlags);
2084
2085void *GetCLRFunction(LPCSTR FunctionName)
2086{
2087
2088 void* func = NULL;
2089 BEGIN_ENTRYPOINT_VOIDRET;
2090
2091 LIMITED_METHOD_CONTRACT;
2092
2093 if (strcmp(FunctionName, "EEHeapAllocInProcessHeap") == 0)
2094 {
2095 func = (void*)EEHeapAllocInProcessHeap;
2096 }
2097 else if (strcmp(FunctionName, "EEHeapFreeInProcessHeap") == 0)
2098 {
2099 func = (void*)EEHeapFreeInProcessHeap;
2100 }
2101 else if (strcmp(FunctionName, "ShutdownRuntimeWithoutExiting") == 0)
2102 {
2103 func = (void*)ShutdownRuntimeWithoutExiting;
2104 }
2105 else if (strcmp(FunctionName, "IsRuntimeStarted") == 0)
2106 {
2107 func = (void*)IsRuntimeStarted;
2108 }
2109 else {
2110 _ASSERTE ("Unknown function name");
2111 func = NULL;
2112 }
2113 END_ENTRYPOINT_VOIDRET;
2114
2115 return func;
2116}
2117
2118#endif // CROSSGEN_COMPILE
2119
2120LPVOID
2121CLRMapViewOfFileEx(
2122 IN HANDLE hFileMappingObject,
2123 IN DWORD dwDesiredAccess,
2124 IN DWORD dwFileOffsetHigh,
2125 IN DWORD dwFileOffsetLow,
2126 IN SIZE_T dwNumberOfBytesToMap,
2127 IN LPVOID lpBaseAddress
2128 )
2129{
2130#ifdef _DEBUG
2131#ifdef _TARGET_X86_
2132
2133 char *tmp = new (nothrow) char;
2134 if (!tmp)
2135 {
2136 SetLastError(ERROR_OUTOFMEMORY);
2137 return NULL;
2138 }
2139 delete tmp;
2140
2141#endif // _TARGET_X86_
2142#endif // _DEBUG
2143
2144 LPVOID pv = MapViewOfFileEx(hFileMappingObject,dwDesiredAccess,dwFileOffsetHigh,dwFileOffsetLow,dwNumberOfBytesToMap,lpBaseAddress);
2145
2146
2147 if (!pv)
2148 {
2149 if(GetLastError()==ERROR_SUCCESS)
2150 SetLastError(ERROR_OUTOFMEMORY);
2151 return NULL;
2152 }
2153
2154#ifdef _DEBUG
2155#ifdef _TARGET_X86_
2156 if (pv && g_pConfig && g_pConfig->ShouldInjectFault(INJECTFAULT_MAPVIEWOFFILE))
2157 {
2158 MEMORY_BASIC_INFORMATION mbi;
2159 memset(&mbi, 0, sizeof(mbi));
2160 if (!ClrVirtualQuery(pv, &mbi, sizeof(mbi)))
2161 {
2162 if(GetLastError()==ERROR_SUCCESS)
2163 SetLastError(ERROR_OUTOFMEMORY);
2164 return NULL;
2165 }
2166 UnmapViewOfFile(pv);
2167 pv = ClrVirtualAlloc(lpBaseAddress, mbi.RegionSize, MEM_RESERVE, PAGE_NOACCESS);
2168 }
2169 else
2170#endif // _TARGET_X86_
2171#endif // _DEBUG
2172 {
2173 }
2174
2175 if (!pv && GetLastError()==ERROR_SUCCESS)
2176 SetLastError(ERROR_OUTOFMEMORY);
2177
2178 return pv;
2179}
2180
2181LPVOID
2182CLRMapViewOfFile(
2183 IN HANDLE hFileMappingObject,
2184 IN DWORD dwDesiredAccess,
2185 IN DWORD dwFileOffsetHigh,
2186 IN DWORD dwFileOffsetLow,
2187 IN SIZE_T dwNumberOfBytesToMap
2188 )
2189{
2190 WRAPPER_NO_CONTRACT;
2191 return CLRMapViewOfFileEx(hFileMappingObject,dwDesiredAccess,dwFileOffsetHigh,dwFileOffsetLow,dwNumberOfBytesToMap,NULL);
2192}
2193
2194
2195BOOL
2196CLRUnmapViewOfFile(
2197 IN LPVOID lpBaseAddress
2198 )
2199{
2200 STATIC_CONTRACT_ENTRY_POINT;
2201
2202#ifdef _DEBUG
2203#ifdef _TARGET_X86_
2204 if (g_pConfig && g_pConfig->ShouldInjectFault(INJECTFAULT_MAPVIEWOFFILE))
2205 {
2206 return ClrVirtualFree((LPVOID)lpBaseAddress, 0, MEM_RELEASE);
2207 }
2208 else
2209#endif // _TARGET_X86_
2210#endif // _DEBUG
2211 {
2212 BOOL result = UnmapViewOfFile(lpBaseAddress);
2213 if (result)
2214 {
2215 }
2216 return result;
2217 }
2218}
2219
2220
2221#ifndef CROSSGEN_COMPILE
2222
2223static HMODULE CLRLoadLibraryWorker(LPCWSTR lpLibFileName, DWORD *pLastError)
2224{
2225 // Don't use dynamic contract: will override GetLastError value
2226 STATIC_CONTRACT_NOTHROW;
2227 STATIC_CONTRACT_GC_TRIGGERS;
2228 STATIC_CONTRACT_FAULT;
2229 STATIC_CONTRACT_SO_TOLERANT;
2230
2231 HMODULE hMod;
2232 UINT last = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
2233 {
2234 INDEBUG(PEDecoder::ForceRelocForDLL(lpLibFileName));
2235 hMod = WszLoadLibrary(lpLibFileName);
2236 *pLastError = GetLastError();
2237 }
2238 SetErrorMode(last);
2239 return hMod;
2240}
2241
2242HMODULE CLRLoadLibrary(LPCWSTR lpLibFileName)
2243{
2244 // Don't use dynamic contract: will override GetLastError value
2245 STATIC_CONTRACT_NOTHROW;
2246 STATIC_CONTRACT_GC_TRIGGERS;
2247 STATIC_CONTRACT_FAULT;
2248
2249 DWORD dwLastError = 0;
2250 HMODULE hmod = 0;
2251
2252 // This method should be marked "throws" due to the probe here.
2253 STATIC_CONTRACT_VIOLATION(ThrowsViolation);
2254
2255 BEGIN_SO_TOLERANT_CODE(GetThread());
2256 hmod = CLRLoadLibraryWorker(lpLibFileName, &dwLastError);
2257 END_SO_TOLERANT_CODE;
2258
2259 SetLastError(dwLastError);
2260 return hmod;
2261}
2262
2263#ifndef FEATURE_PAL
2264
2265static HMODULE CLRLoadLibraryExWorker(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags, DWORD *pLastError)
2266
2267{
2268 // Don't use dynamic contract: will override GetLastError value
2269 STATIC_CONTRACT_NOTHROW;
2270 STATIC_CONTRACT_GC_TRIGGERS;
2271 STATIC_CONTRACT_FAULT;
2272 STATIC_CONTRACT_SO_TOLERANT;
2273
2274 HMODULE hMod;
2275 UINT last = SetErrorMode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
2276 {
2277 INDEBUG(PEDecoder::ForceRelocForDLL(lpLibFileName));
2278 hMod = WszLoadLibraryEx(lpLibFileName, hFile, dwFlags);
2279 *pLastError = GetLastError();
2280 }
2281 SetErrorMode(last);
2282 return hMod;
2283}
2284
2285HMODULE CLRLoadLibraryEx(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
2286{
2287 // Don't use dynamic contract: will override GetLastError value
2288
2289 // This will throw in the case of SO
2290 //STATIC_CONTRACT_NOTHROW;
2291 STATIC_CONTRACT_GC_TRIGGERS;
2292 STATIC_CONTRACT_FAULT;
2293
2294 DWORD lastError = ERROR_SUCCESS;
2295 HMODULE hmod = NULL;
2296
2297 BEGIN_SO_TOLERANT_CODE(GetThread());
2298 hmod = CLRLoadLibraryExWorker(lpLibFileName, hFile, dwFlags, &lastError);
2299 END_SO_TOLERANT_CODE;
2300
2301 SetLastError(lastError);
2302 return hmod;
2303}
2304
2305#endif // !FEATURE_PAL
2306
2307BOOL CLRFreeLibrary(HMODULE hModule)
2308{
2309 // Don't use dynamic contract: will override GetLastError value
2310 STATIC_CONTRACT_NOTHROW;
2311 STATIC_CONTRACT_GC_TRIGGERS;
2312 STATIC_CONTRACT_FORBID_FAULT;
2313 STATIC_CONTRACT_SO_TOLERANT;
2314
2315 return FreeLibrary(hModule);
2316}
2317
2318VOID CLRFreeLibraryAndExitThread(HMODULE hModule,DWORD dwExitCode)
2319{
2320 // Don't use dynamic contract: will override GetLastError value
2321 STATIC_CONTRACT_NOTHROW;
2322 STATIC_CONTRACT_GC_TRIGGERS;
2323 STATIC_CONTRACT_FORBID_FAULT;
2324 STATIC_CONTRACT_SO_TOLERANT;
2325
2326 // This is no-return
2327 FreeLibraryAndExitThread(hModule,dwExitCode);
2328}
2329
2330#endif // CROSSGEN_COMPILE
2331
2332#endif // #ifndef DACCESS_COMPILE
2333
2334GPTR_IMPL(JITNotification, g_pNotificationTable);
2335GVAL_IMPL(ULONG32, g_dacNotificationFlags);
2336
2337BOOL IsValidMethodCodeNotification(USHORT Notification)
2338{
2339 // If any bit is on other than that given by a valid combination of flags, no good.
2340 if (Notification & ~(
2341 CLRDATA_METHNOTIFY_NONE |
2342 CLRDATA_METHNOTIFY_GENERATED |
2343 CLRDATA_METHNOTIFY_DISCARDED))
2344 {
2345 return FALSE;
2346 }
2347
2348 return TRUE;
2349}
2350
2351JITNotifications::JITNotifications(JITNotification *jitTable)
2352{
2353 LIMITED_METHOD_CONTRACT;
2354 if (jitTable)
2355 {
2356 // Bookkeeping info is held in the first slot
2357 m_jitTable = jitTable + 1;
2358 }
2359 else
2360 {
2361 m_jitTable = NULL;
2362 }
2363}
2364
2365BOOL JITNotifications::FindItem(TADDR clrModule, mdToken token, UINT *indexOut)
2366{
2367 LIMITED_METHOD_CONTRACT;
2368 if (m_jitTable == NULL)
2369 {
2370 return FALSE;
2371 }
2372
2373 if (indexOut == NULL)
2374 {
2375 return FALSE;
2376 }
2377
2378 UINT Length = GetLength();
2379 for(UINT i=0; i < Length; i++)
2380 {
2381 JITNotification *pCurrent = m_jitTable + i;
2382 if (!pCurrent->IsFree() &&
2383 pCurrent->clrModule == clrModule &&
2384 pCurrent->methodToken == token)
2385 {
2386 *indexOut = i;
2387 return TRUE;
2388 }
2389 }
2390
2391 return FALSE;
2392}
2393
2394// if clrModule is NULL, all active notifications are changed to NType
2395BOOL JITNotifications::SetAllNotifications(TADDR clrModule,USHORT NType,BOOL *changedOut)
2396{
2397 if (m_jitTable == NULL)
2398 {
2399 return FALSE;
2400 }
2401
2402 if (changedOut == NULL)
2403 {
2404 return FALSE;
2405 }
2406
2407 *changedOut = FALSE;
2408
2409 UINT Length = GetLength();
2410 for(UINT i=0; i < Length; i++)
2411 {
2412 JITNotification *pCurrent = m_jitTable + i;
2413 if (!pCurrent->IsFree() &&
2414 ((clrModule == NULL) || (pCurrent->clrModule == clrModule))&&
2415 pCurrent->state != NType)
2416 {
2417 pCurrent->state = NType;
2418 *changedOut = TRUE;
2419 }
2420 }
2421
2422 if (*changedOut && NType == CLRDATA_METHNOTIFY_NONE)
2423 {
2424 // Need to recompute length if we removed notifications
2425 for (UINT iCurrent=Length; iCurrent > 0; iCurrent--)
2426 {
2427 JITNotification *pCurrent = m_jitTable + (iCurrent - 1);
2428 if (pCurrent->IsFree())
2429 {
2430 DecrementLength();
2431 }
2432 }
2433 }
2434 return TRUE;
2435}
2436
2437BOOL JITNotifications::SetNotification(TADDR clrModule, mdToken token, USHORT NType)
2438{
2439 UINT iIndex;
2440
2441 if (!IsActive())
2442 {
2443 return FALSE;
2444 }
2445
2446 if (clrModule == NULL)
2447 {
2448 return FALSE;
2449 }
2450
2451 if (NType == CLRDATA_METHNOTIFY_NONE)
2452 {
2453 // Remove an item if it exists
2454 if (FindItem(clrModule, token, &iIndex))
2455 {
2456 JITNotification *pItem = m_jitTable + iIndex;
2457 pItem->SetFree();
2458 _ASSERTE(iIndex < GetLength());
2459 // Update highest?
2460 if (iIndex == (GetLength()-1))
2461 {
2462 DecrementLength();
2463 }
2464 }
2465 return TRUE;
2466 }
2467
2468 if (FindItem(clrModule, token, &iIndex))
2469 {
2470 JITNotification *pItem = m_jitTable + iIndex;
2471 _ASSERTE(pItem->IsFree() == FALSE);
2472 pItem->state = NType;
2473 return TRUE;
2474 }
2475
2476 // Find first free item
2477 UINT iFirstFree = GetLength();
2478 for (UINT i = 0; i < iFirstFree; i++)
2479 {
2480 JITNotification *pCurrent = m_jitTable + i;
2481 if (pCurrent->state == CLRDATA_METHNOTIFY_NONE)
2482 {
2483 iFirstFree = i;
2484 break;
2485 }
2486 }
2487
2488 if (iFirstFree == GetLength() &&
2489 iFirstFree == GetTableSize())
2490 {
2491 // No more room
2492 return FALSE;
2493 }
2494
2495 JITNotification *pCurrent = m_jitTable + iFirstFree;
2496 pCurrent->SetState(clrModule, token, NType);
2497 if (iFirstFree == GetLength())
2498 {
2499 IncrementLength();
2500 }
2501
2502 return TRUE;
2503}
2504
2505UINT JITNotifications::GetLength()
2506{
2507 LIMITED_METHOD_CONTRACT;
2508 _ASSERTE(IsActive());
2509
2510 if (!IsActive())
2511 {
2512 return 0;
2513 }
2514
2515 return (UINT) (m_jitTable - 1)->methodToken;
2516}
2517
2518void JITNotifications::IncrementLength()
2519{
2520 _ASSERTE(IsActive());
2521
2522 if (!IsActive())
2523 {
2524 return;
2525 }
2526
2527 UINT *pShort = (UINT *) &((m_jitTable - 1)->methodToken);
2528 (*pShort)++;
2529}
2530
2531void JITNotifications::DecrementLength()
2532{
2533 _ASSERTE(IsActive());
2534
2535 if (!IsActive())
2536 {
2537 return;
2538 }
2539
2540 UINT *pShort = (UINT *) &((m_jitTable - 1)->methodToken);
2541 (*pShort)--;
2542}
2543
2544UINT JITNotifications::GetTableSize()
2545{
2546 _ASSERTE(IsActive());
2547
2548 if (!IsActive())
2549 {
2550 return 0;
2551 }
2552
2553 return ((UINT) (m_jitTable - 1)->clrModule);
2554}
2555
2556USHORT JITNotifications::Requested(TADDR clrModule, mdToken token)
2557{
2558 LIMITED_METHOD_CONTRACT;
2559 UINT iIndex;
2560 if (FindItem(clrModule, token, &iIndex))
2561 {
2562 JITNotification *pItem = m_jitTable + iIndex;
2563 _ASSERTE(pItem->IsFree() == FALSE);
2564 return pItem->state;
2565 }
2566
2567 return CLRDATA_METHNOTIFY_NONE;
2568}
2569
2570#ifdef DACCESS_COMPILE
2571
2572JITNotification *JITNotifications::InitializeNotificationTable(UINT TableSize)
2573{
2574 // We use the first entry in the table for recordkeeping info.
2575
2576 JITNotification *retTable = new (nothrow) JITNotification[TableSize+1];
2577 if (retTable)
2578 {
2579 // Set the length
2580 UINT *pUint = (UINT *) &(retTable->methodToken);
2581 *pUint = 0;
2582 // Set the table size
2583 pUint = (UINT *) &(retTable->clrModule);
2584 *pUint = TableSize;
2585 }
2586 return retTable;
2587}
2588
2589template <class NotificationClass>
2590BOOL UpdateOutOfProcTable(__GlobalPtr<NotificationClass*, DPTR(NotificationClass)> pHostTable, NotificationClass* copyFrom, UINT tableSize)
2591{
2592
2593 ClrSafeInt<ULONG32> allocSize = S_SIZE_T(sizeof(NotificationClass)) * ClrSafeInt<UINT>(tableSize);
2594 if (allocSize.IsOverflow())
2595 {
2596 return FALSE;
2597 }
2598
2599 if (dac_cast<TADDR>(pHostTable) == NULL)
2600 {
2601 // The table has not been initialized in the target. Allocate space for it and update the pointer
2602 // in the target so that we'll use this allocated memory from now on. Note that we never free this
2603 // memory, but this isn't a big deal because it's only a single allocation.
2604 TADDR Location;
2605
2606 if (DacAllocVirtual(0, allocSize.Value(),
2607 MEM_COMMIT, PAGE_READWRITE, false,
2608 &Location) != S_OK)
2609 {
2610 return FALSE;
2611 }
2612
2613 DPTR(DPTR(NotificationClass)) ppTable = &pHostTable;
2614 *ppTable = DPTR(NotificationClass)(Location);
2615 if (DacWriteHostInstance(ppTable,false) != S_OK)
2616 {
2617 return FALSE;
2618 }
2619 }
2620
2621 // We store recordkeeping info right before the m_jitTable pointer, that must be written as well.
2622 if (DacWriteAll(dac_cast<TADDR>(pHostTable), copyFrom,
2623 allocSize.Value(), false) != S_OK)
2624 {
2625 return FALSE;
2626 }
2627
2628 return TRUE;
2629}
2630
2631BOOL JITNotifications::UpdateOutOfProcTable()
2632{
2633 return ::UpdateOutOfProcTable<JITNotification>(g_pNotificationTable, m_jitTable - 1, GetTableSize() + 1);
2634}
2635#endif // DACCESS_COMPILE
2636
2637GPTR_IMPL(GcNotification, g_pGcNotificationTable);
2638
2639GcNotifications::GcNotifications(GcNotification *gcTable)
2640{
2641 LIMITED_METHOD_CONTRACT;
2642 if (gcTable)
2643 {
2644 // Bookkeeping info is held in the first slot
2645 m_gcTable = gcTable + 1;
2646 }
2647 else
2648 {
2649 m_gcTable = NULL;
2650 }
2651}
2652
2653BOOL GcNotifications::FindItem(GcEvtArgs ev_, UINT *indexOut)
2654{
2655 LIMITED_METHOD_CONTRACT;
2656 if (m_gcTable == NULL)
2657 {
2658 return FALSE;
2659 }
2660
2661 if (indexOut == NULL)
2662 {
2663 return FALSE;
2664 }
2665
2666 UINT length = Length();
2667 for (UINT i = 0; i < length; i++)
2668 {
2669 if (m_gcTable[i].IsMatch(ev_))
2670 {
2671 *indexOut = i;
2672 return TRUE;
2673 }
2674 }
2675
2676 return FALSE;
2677}
2678
2679
2680BOOL GcNotifications::SetNotification(GcEvtArgs ev)
2681{
2682 if (!IsActive())
2683 {
2684 return FALSE;
2685 }
2686
2687 if (ev.typ < 0 || ev.typ >= GC_EVENT_TYPE_MAX)
2688 {
2689 return FALSE;
2690 }
2691
2692 // build the "match" event
2693 GcEvtArgs evStar = { ev.typ };
2694 switch (ev.typ)
2695 {
2696 case GC_MARK_END:
2697 // specify mark event matching all generations
2698 evStar.condemnedGeneration = -1;
2699 break;
2700 default:
2701 break;
2702 }
2703
2704 // look for the entry that matches the evStar argument
2705 UINT idx;
2706 if (!FindItem(evStar, &idx))
2707 {
2708 // Find first free item
2709 UINT iFirstFree = Length();
2710 for (UINT i = 0; i < iFirstFree; i++)
2711 {
2712 GcNotification *pCurrent = m_gcTable + i;
2713 if (pCurrent->IsFree())
2714 {
2715 iFirstFree = i;
2716 break;
2717 }
2718 }
2719
2720 if (iFirstFree == Length() &&
2721 iFirstFree == GetTableSize())
2722 {
2723 // No more room
2724 return FALSE;
2725 }
2726
2727 // guarantee the free cell is zeroed out
2728 m_gcTable[iFirstFree].SetFree();
2729 idx = iFirstFree;
2730 }
2731
2732 // Now update the state
2733 m_gcTable[idx].ev.typ = ev.typ;
2734 switch (ev.typ)
2735 {
2736 case GC_MARK_END:
2737 if (ev.condemnedGeneration == 0)
2738 {
2739 m_gcTable[idx].SetFree();
2740 }
2741 else
2742 {
2743 m_gcTable[idx].ev.condemnedGeneration |= ev.condemnedGeneration;
2744 }
2745 break;
2746 default:
2747 break;
2748 }
2749
2750 // and if needed, update the array's length
2751 if (idx == Length())
2752 {
2753 IncrementLength();
2754 }
2755
2756 return TRUE;
2757}
2758
2759GARY_IMPL(size_t, g_clrNotificationArguments, MAX_CLR_NOTIFICATION_ARGS);
2760
2761#ifdef DACCESS_COMPILE
2762
2763GcNotification *GcNotifications::InitializeNotificationTable(UINT TableSize)
2764{
2765 // We use the first entry in the table for recordkeeping info.
2766
2767 GcNotification *retTable = new (nothrow) GcNotification[TableSize+1];
2768 if (retTable)
2769 {
2770 // Set the length
2771 UINT *pUint = (UINT *) &(retTable[0].ev.typ);
2772 *pUint = 0;
2773 // Set the table size
2774 ++pUint;
2775 *pUint = TableSize;
2776 }
2777 return retTable;
2778}
2779
2780BOOL GcNotifications::UpdateOutOfProcTable()
2781{
2782 return ::UpdateOutOfProcTable<GcNotification>(g_pGcNotificationTable, m_gcTable - 1, GetTableSize() + 1);
2783}
2784
2785#else // DACCESS_COMPILE
2786
2787static CrstStatic g_clrNotificationCrst;
2788
2789void DACRaiseException(TADDR *args, UINT argCount)
2790{
2791 STATIC_CONTRACT_NOTHROW;
2792 STATIC_CONTRACT_GC_NOTRIGGER;
2793 STATIC_CONTRACT_MODE_ANY;
2794 STATIC_CONTRACT_SO_TOLERANT;
2795
2796 struct Param
2797 {
2798 TADDR *args;
2799 UINT argCount;
2800 } param;
2801 param.args = args;
2802 param.argCount = argCount;
2803
2804 PAL_TRY(Param *, pParam, &param)
2805 {
2806 RaiseException(CLRDATA_NOTIFY_EXCEPTION, 0, pParam->argCount, (ULONG_PTR *)pParam->args);
2807 }
2808 PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2809 {
2810 }
2811 PAL_ENDTRY
2812}
2813
2814void DACNotifyExceptionHelper(TADDR *args, UINT argCount)
2815{
2816 CONTRACTL
2817 {
2818 NOTHROW;
2819 GC_NOTRIGGER;
2820 SO_INTOLERANT;
2821 MODE_ANY;
2822 }
2823 CONTRACTL_END;
2824
2825 _ASSERTE(argCount <= MAX_CLR_NOTIFICATION_ARGS);
2826
2827 if (IsDebuggerPresent() && !CORDebuggerAttached())
2828 {
2829 CrstHolder lh(&g_clrNotificationCrst);
2830
2831 for (UINT i = 0; i < argCount; i++)
2832 {
2833 g_clrNotificationArguments[i] = args[i];
2834 }
2835
2836 DACRaiseException(args, argCount);
2837
2838 g_clrNotificationArguments[0] = NULL;
2839 }
2840}
2841
2842void InitializeClrNotifications()
2843{
2844 g_clrNotificationCrst.Init(CrstClrNotification, CRST_UNSAFE_ANYMODE);
2845 g_clrNotificationArguments[0] = NULL;
2846}
2847
2848// <TODO> FIX IN BETA 2
2849//
2850// g_dacNotificationFlags is only modified by the DAC and therefore the
2851// optmizer can assume that it will always be its default value and has
2852// been seen to eliminate the code in DoModuleLoadNotification,
2853// etc... such that DAC notifications are no longer sent.
2854//
2855// TODO: fix this in Beta 2
2856// the RIGHT fix is to make g_dacNotificationFlags volatile, but currently
2857// we don't have DAC macros to do that. Additionally, there are a number
2858// of other places we should look at DAC definitions to determine if they
2859// should be also declared volatile.
2860//
2861// for now we just turn off optimization for these guys
2862#ifdef _MSC_VER
2863#pragma warning(push)
2864#pragma warning(disable: 4748)
2865#pragma optimize("", off)
2866#endif // _MSC_VER
2867
2868#if defined(FEATURE_GDBJIT)
2869#include "gdbjit.h"
2870#endif // FEATURE_GDBJIT
2871
2872// called from the runtime
2873void DACNotify::DoJITNotification(MethodDesc *MethodDescPtr, TADDR NativeCodeLocation)
2874{
2875 CONTRACTL
2876 {
2877 NOTHROW;
2878 GC_NOTRIGGER;
2879 SO_INTOLERANT;
2880 MODE_PREEMPTIVE;
2881 }
2882 CONTRACTL_END;
2883
2884 TADDR Args[3] = { JIT_NOTIFICATION2, (TADDR) MethodDescPtr, NativeCodeLocation };
2885 DACNotifyExceptionHelper(Args, 3);
2886}
2887
2888void DACNotify::DoJITPitchingNotification(MethodDesc *MethodDescPtr)
2889{
2890 CONTRACTL
2891 {
2892 NOTHROW;
2893 GC_NOTRIGGER;
2894 SO_INTOLERANT;
2895 MODE_PREEMPTIVE;
2896 }
2897 CONTRACTL_END;
2898
2899#if defined(FEATURE_GDBJIT) && defined(FEATURE_PAL) && !defined(CROSSGEN_COMPILE)
2900 NotifyGdb::MethodPitched(MethodDescPtr);
2901#endif
2902 TADDR Args[2] = { JIT_PITCHING_NOTIFICATION, (TADDR) MethodDescPtr };
2903 DACNotifyExceptionHelper(Args, 2);
2904}
2905
2906void DACNotify::DoModuleLoadNotification(Module *ModulePtr)
2907{
2908 CONTRACTL
2909 {
2910 NOTHROW;
2911 GC_NOTRIGGER;
2912 SO_INTOLERANT;
2913 MODE_PREEMPTIVE;
2914 }
2915 CONTRACTL_END;
2916
2917 if ((g_dacNotificationFlags & CLRDATA_NOTIFY_ON_MODULE_LOAD) != 0)
2918 {
2919 TADDR Args[2] = { MODULE_LOAD_NOTIFICATION, (TADDR) ModulePtr};
2920 DACNotifyExceptionHelper(Args, 2);
2921 }
2922}
2923
2924void DACNotify::DoModuleUnloadNotification(Module *ModulePtr)
2925{
2926 CONTRACTL
2927 {
2928 NOTHROW;
2929 GC_NOTRIGGER;
2930 SO_INTOLERANT;
2931 MODE_PREEMPTIVE;
2932 }
2933 CONTRACTL_END;
2934
2935 if ((g_dacNotificationFlags & CLRDATA_NOTIFY_ON_MODULE_UNLOAD) != 0)
2936 {
2937 TADDR Args[2] = { MODULE_UNLOAD_NOTIFICATION, (TADDR) ModulePtr};
2938 DACNotifyExceptionHelper(Args, 2);
2939 }
2940}
2941
2942void DACNotify::DoExceptionNotification(Thread* ThreadPtr)
2943{
2944 CONTRACTL
2945 {
2946 NOTHROW;
2947 GC_NOTRIGGER;
2948 SO_INTOLERANT;
2949 MODE_PREEMPTIVE;
2950 }
2951 CONTRACTL_END;
2952
2953 if ((g_dacNotificationFlags & CLRDATA_NOTIFY_ON_EXCEPTION) != 0)
2954 {
2955 TADDR Args[2] = { EXCEPTION_NOTIFICATION, (TADDR) ThreadPtr};
2956 DACNotifyExceptionHelper(Args, 2);
2957 }
2958}
2959
2960void DACNotify::DoGCNotification(const GcEvtArgs& args)
2961{
2962 CONTRACTL
2963 {
2964 NOTHROW;
2965 GC_NOTRIGGER;
2966 SO_INTOLERANT;
2967 MODE_COOPERATIVE;
2968 }
2969 CONTRACTL_END;
2970
2971 if (args.typ == GC_MARK_END)
2972 {
2973 TADDR Args[3] = { GC_NOTIFICATION, (TADDR) args.typ, args.condemnedGeneration };
2974 DACNotifyExceptionHelper(Args, 3);
2975 }
2976}
2977
2978void DACNotify::DoExceptionCatcherEnterNotification(MethodDesc *MethodDescPtr, DWORD nativeOffset)
2979{
2980 CONTRACTL
2981 {
2982 NOTHROW;
2983 GC_NOTRIGGER;
2984 SO_INTOLERANT;
2985 MODE_COOPERATIVE;
2986 }
2987 CONTRACTL_END;
2988
2989 if ((g_dacNotificationFlags & CLRDATA_NOTIFY_ON_EXCEPTION_CATCH_ENTER) != 0)
2990 {
2991 TADDR Args[3] = { CATCH_ENTER_NOTIFICATION, (TADDR) MethodDescPtr, (TADDR)nativeOffset };
2992 DACNotifyExceptionHelper(Args, 3);
2993 }
2994}
2995
2996#ifdef _MSC_VER
2997#pragma optimize("", on)
2998#pragma warning(pop)
2999#endif // _MSC_VER
3000// </TODO>
3001
3002#endif // DACCESS_COMPILE
3003
3004// called from the DAC
3005int DACNotify::GetType(TADDR Args[])
3006{
3007 // Type is an enum, and will thus fit into an int.
3008 return static_cast<int>(Args[0]);
3009}
3010
3011BOOL DACNotify::ParseJITNotification(TADDR Args[], TADDR& MethodDescPtr, TADDR& NativeCodeLocation)
3012{
3013 _ASSERTE(Args[0] == JIT_NOTIFICATION2);
3014 if (Args[0] != JIT_NOTIFICATION2)
3015 {
3016 return FALSE;
3017 }
3018
3019 MethodDescPtr = Args[1];
3020 NativeCodeLocation = Args[2];
3021
3022 return TRUE;
3023}
3024
3025BOOL DACNotify::ParseJITPitchingNotification(TADDR Args[], TADDR& MethodDescPtr)
3026{
3027 _ASSERTE(Args[0] == JIT_PITCHING_NOTIFICATION);
3028 if (Args[0] != JIT_PITCHING_NOTIFICATION)
3029 {
3030 return FALSE;
3031 }
3032
3033 MethodDescPtr = Args[1];
3034
3035 return TRUE;
3036}
3037
3038BOOL DACNotify::ParseModuleLoadNotification(TADDR Args[], TADDR& Module)
3039{
3040 _ASSERTE(Args[0] == MODULE_LOAD_NOTIFICATION);
3041 if (Args[0] != MODULE_LOAD_NOTIFICATION)
3042 {
3043 return FALSE;
3044 }
3045
3046 Module = Args[1];
3047
3048 return TRUE;
3049}
3050
3051BOOL DACNotify::ParseModuleUnloadNotification(TADDR Args[], TADDR& Module)
3052{
3053 _ASSERTE(Args[0] == MODULE_UNLOAD_NOTIFICATION);
3054 if (Args[0] != MODULE_UNLOAD_NOTIFICATION)
3055 {
3056 return FALSE;
3057 }
3058
3059 Module = Args[1];
3060
3061 return TRUE;
3062}
3063
3064BOOL DACNotify::ParseExceptionNotification(TADDR Args[], TADDR& ThreadPtr)
3065{
3066 _ASSERTE(Args[0] == EXCEPTION_NOTIFICATION);
3067 if (Args[0] != EXCEPTION_NOTIFICATION)
3068 {
3069 return FALSE;
3070 }
3071
3072 ThreadPtr = Args[1];
3073
3074 return TRUE;
3075}
3076
3077
3078BOOL DACNotify::ParseGCNotification(TADDR Args[], GcEvtArgs& args)
3079{
3080 _ASSERTE(Args[0] == GC_NOTIFICATION);
3081 if (Args[0] != GC_NOTIFICATION)
3082 {
3083 return FALSE;
3084 }
3085
3086 BOOL bRet = FALSE;
3087
3088 args.typ = (GcEvt_t) Args[1];
3089 switch (args.typ)
3090 {
3091 case GC_MARK_END:
3092 {
3093 // The condemnedGeneration is an int.
3094 args.condemnedGeneration = static_cast<int>(Args[2]);
3095 bRet = TRUE;
3096 break;
3097 }
3098 default:
3099 bRet = FALSE;
3100 break;
3101 }
3102
3103 return bRet;
3104}
3105
3106BOOL DACNotify::ParseExceptionCatcherEnterNotification(TADDR Args[], TADDR& MethodDescPtr, DWORD& nativeOffset)
3107{
3108 _ASSERTE(Args[0] == CATCH_ENTER_NOTIFICATION);
3109 if (Args[0] != CATCH_ENTER_NOTIFICATION)
3110 {
3111 return FALSE;
3112 }
3113
3114 MethodDescPtr = Args[1];
3115 nativeOffset = (DWORD) Args[2];
3116 return TRUE;
3117}
3118
3119
3120#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
3121
3122
3123#if defined(_DEBUG) && !defined(FEATURE_PAL)
3124
3125typedef USHORT
3126(__stdcall *PFNRtlCaptureStackBackTrace)(
3127 IN ULONG FramesToSkip,
3128 IN ULONG FramesToCapture,
3129 OUT PVOID * BackTrace,
3130 OUT PULONG BackTraceHash);
3131
3132static PFNRtlCaptureStackBackTrace s_RtlCaptureStackBackTrace = NULL;
3133
3134WORD UtilCaptureStackBackTrace(
3135 ULONG FramesToSkip,
3136 ULONG FramesToCapture,
3137 PVOID * BackTrace,
3138 OUT PULONG BackTraceHash)
3139{
3140 WRAPPER_NO_CONTRACT;
3141
3142#ifdef _DEBUG
3143 Thread* t = GetThread();
3144 if (t != NULL) {
3145 // the thread should not have a hijack set up or we can't walk the stack.
3146 _ASSERTE(!(t->m_State & Thread::TS_Hijacked));
3147 }
3148#endif
3149
3150 if(!s_RtlCaptureStackBackTrace)
3151 {
3152 // Don't need to worry about race conditions here since it will be the same value
3153 HMODULE hModNtdll = GetModuleHandleA("ntdll.dll");
3154 s_RtlCaptureStackBackTrace = reinterpret_cast<PFNRtlCaptureStackBackTrace>(
3155 GetProcAddress(hModNtdll, "RtlCaptureStackBackTrace"));
3156 }
3157 if (!s_RtlCaptureStackBackTrace) {
3158 return 0;
3159 }
3160 ULONG hash;
3161 if (BackTraceHash == NULL) {
3162 BackTraceHash = &hash;
3163 }
3164 return s_RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture, BackTrace, BackTraceHash);
3165}
3166
3167#endif // #if _DEBUG && !FEATURE_PAL
3168
3169
3170#ifdef _DEBUG
3171DisableDelayLoadCheckForOleaut32::DisableDelayLoadCheckForOleaut32()
3172{
3173 GetThread()->SetThreadStateNC(Thread::TSNC_DisableOleaut32Check);
3174}
3175
3176DisableDelayLoadCheckForOleaut32::~DisableDelayLoadCheckForOleaut32()
3177{
3178 GetThread()->ResetThreadStateNC(Thread::TSNC_DisableOleaut32Check);
3179}
3180
3181BOOL DelayLoadOleaut32CheckDisabled()
3182{
3183 Thread *pThread = GetThread();
3184 if (pThread && pThread->HasThreadStateNC(Thread::TSNC_DisableOleaut32Check))
3185 {
3186 return TRUE;
3187 }
3188
3189 return FALSE;
3190}
3191#endif
3192
3193BOOL EnableARM()
3194{
3195#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
3196 CONTRACTL
3197 {
3198 NOTHROW;
3199 // TODO: this should really be GC_TRIGGERS so we wouldn't need the
3200 // CONTRACT_VIOLATION below but the hosting API that calls this
3201 // can be called on a COOP thread and it has a GC_NOTRIGGER contract.
3202 // We should use the AD unload thread to call this function on.
3203 GC_NOTRIGGER;
3204 SO_TOLERANT;
3205 }
3206 CONTRACTL_END;
3207
3208 BOOL fARMEnabled = g_fEnableARM;
3209
3210 if (!fARMEnabled)
3211 {
3212 if (ThreadStore::s_pThreadStore)
3213 {
3214 // We need to establish the baselines for the CPU usage counting.
3215 Thread *pThread = NULL;
3216 CONTRACT_VIOLATION(GCViolation);
3217
3218 // I am returning TRUE here so the caller will NOT enable
3219 // ARM - if we can't take the thread store lock, something
3220 // is already kind of messed up so no need to proceed with
3221 // enabling ARM.
3222 BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return TRUE);
3223 // Take the thread store lock while we enumerate threads.
3224 ThreadStoreLockHolder tsl ;
3225
3226 while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL)
3227 {
3228 if (pThread->IsUnstarted() || pThread->IsDead())
3229 continue;
3230 pThread->QueryThreadProcessorUsage();
3231 }
3232
3233 END_SO_INTOLERANT_CODE;
3234 }
3235 g_fEnableARM = TRUE;
3236 }
3237
3238 return fARMEnabled;
3239#else // FEATURE_APPDOMAIN_RESOURCE_MONITORING
3240 return FALSE;
3241#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
3242}
3243
3244#endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE
3245
3246
3247static BOOL TrustMeIAmSafe(void *pLock)
3248{
3249 LIMITED_METHOD_CONTRACT;
3250 return TRUE;
3251}
3252
3253LockOwner g_lockTrustMeIAmThreadSafe = { NULL, TrustMeIAmSafe };
3254
3255
3256DangerousNonHostedSpinLock g_randomLock;
3257CLRRandom g_random;
3258
3259
3260int GetRandomInt(int maxVal)
3261{
3262#ifndef CROSSGEN_COMPILE
3263 // Use the thread-local Random instance if possible
3264 Thread* pThread = GetThread();
3265 if (pThread)
3266 return pThread->GetRandom()->Next(maxVal);
3267#endif
3268
3269 // No Thread object - need to fall back to the global generator.
3270 // In DAC builds we don't need the lock (DAC is single-threaded) and can't get it anyway (DNHSL isn't supported)
3271#ifndef DACCESS_COMPILE
3272 DangerousNonHostedSpinLockHolder lh(&g_randomLock);
3273#endif
3274 if (!g_random.IsInitialized())
3275 g_random.Init();
3276 return g_random.Next(maxVal);
3277}
3278
3279// These wrap the SString:L:CompareCaseInsenstive function in a way that makes it
3280// easy to fix code that uses _stricmp. _stricmp should be avoided as it uses the current
3281// C-runtime locale rather than the invariance culture.
3282//
3283// Note that unlike the real _stricmp, these functions unavoidably have a throws/gc_triggers/inject_fault
3284// contract. So if need a case-insensitive comparison in a place where you can't tolerate this contract,
3285// you've got a problem.
3286int __cdecl stricmpUTF8(const char* szStr1, const char* szStr2)
3287{
3288 CONTRACTL
3289 {
3290 THROWS;
3291 GC_TRIGGERS;
3292 INJECT_FAULT(COMPlusThrowOM());
3293 }
3294 CONTRACTL_END
3295
3296 SString sStr1 (SString::Utf8, szStr1);
3297 SString sStr2 (SString::Utf8, szStr2);
3298 return sStr1.CompareCaseInsensitive(sStr2);
3299
3300}
3301
3302#ifndef DACCESS_COMPILE
3303//
3304// Casing Table Helpers for use in the EE.
3305//
3306
3307// // Convert szIn to lower case in the Invariant locale.
3308INT32 InternalCasingHelper::InvariantToLower(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn)
3309{
3310 CONTRACTL {
3311 THROWS;
3312 GC_TRIGGERS;
3313 MODE_ANY;
3314 INJECT_FAULT(COMPlusThrowOM());
3315 } CONTRACTL_END
3316
3317 return InvariantToLowerHelper(szOut, cMaxBytes, szIn, TRUE /*fAllowThrow*/);
3318}
3319
3320// Convert szIn to lower case in the Invariant locale.
3321INT32 InternalCasingHelper::InvariantToLowerNoThrow(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn)
3322{
3323 CONTRACTL {
3324 NOTHROW;
3325 GC_NOTRIGGER;
3326 MODE_ANY;
3327 INJECT_FAULT(return 0;);
3328 } CONTRACTL_END
3329
3330
3331 return InvariantToLowerHelper(szOut, cMaxBytes, szIn, FALSE /*fAllowThrow*/);
3332}
3333
3334// Convert szIn to lower case in the Invariant locale.
3335INT32 InternalCasingHelper::InvariantToLowerHelper(__out_bcount_opt(cMaxBytes) LPUTF8 szOut, int cMaxBytes, __in_z LPCUTF8 szIn, BOOL fAllowThrow)
3336{
3337
3338 CONTRACTL {
3339 // This fcn can trigger a lazy load of the TextInfo class.
3340 if (fAllowThrow) THROWS; else NOTHROW;
3341 if (fAllowThrow) GC_TRIGGERS; else GC_NOTRIGGER;
3342 if (fAllowThrow) {INJECT_FAULT(COMPlusThrowOM());} else {INJECT_FAULT(return 0);}
3343 MODE_ANY;
3344
3345 PRECONDITION((cMaxBytes == 0) || CheckPointer(szOut));
3346 PRECONDITION(CheckPointer(szIn));
3347 } CONTRACTL_END
3348
3349 int inLength = (int)(strlen(szIn)+1);
3350 INT32 result = 0;
3351
3352 LPCUTF8 szInSave = szIn;
3353 LPUTF8 szOutSave = szOut;
3354 BOOL bFoundHighChars=FALSE;
3355 //Compute our end point.
3356 LPCUTF8 szEnd;
3357 INT32 wideCopyLen;
3358
3359 CQuickBytes qbOut;
3360 LPWSTR szWideOut;
3361
3362 if (cMaxBytes != 0 && szOut == NULL) {
3363 if (fAllowThrow) {
3364 COMPlusThrowHR(ERROR_INVALID_PARAMETER);
3365 }
3366 SetLastError(ERROR_INVALID_PARAMETER);
3367 result = 0;
3368 goto Exit;
3369 }
3370
3371 if (cMaxBytes) {
3372 szEnd = szOut + min(inLength, cMaxBytes);
3373 //Walk the string copying the characters. Change the case on
3374 //any character between A-Z.
3375 for (; szOut<szEnd; szOut++, szIn++) {
3376 if (*szIn>='A' && *szIn<='Z') {
3377 *szOut = *szIn | 0x20;
3378 }
3379 else {
3380 if (((UINT32)(*szIn))>((UINT32)0x80)) {
3381 bFoundHighChars = TRUE;
3382 break;
3383 }
3384 *szOut = *szIn;
3385 }
3386 }
3387
3388 if (!bFoundHighChars) {
3389 //If we copied everything, tell them how many bytes we copied,
3390 //and arrange it so that the original position of the string + the returned
3391 //length gives us the position of the null (useful if we're appending).
3392 if (--inLength > cMaxBytes) {
3393 if (fAllowThrow) {
3394 COMPlusThrowHR(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
3395 }
3396 SetLastError(ERROR_INSUFFICIENT_BUFFER);
3397 result = 0;
3398 goto Exit;
3399 }
3400
3401 result = inLength;
3402 goto Exit;
3403 }
3404 }
3405 else {
3406 szEnd = szIn + inLength;
3407 for (; szIn<szEnd; szIn++) {
3408 if (((UINT32)(*szIn))>((UINT32)0x80)) {
3409 bFoundHighChars = TRUE;
3410 break;
3411 }
3412 }
3413
3414 if (!bFoundHighChars) {
3415 result = inLength;
3416 goto Exit;
3417 }
3418 }
3419
3420 szOut = szOutSave;
3421
3422#ifndef FEATURE_PAL
3423
3424 //convert the UTF8 to Unicode
3425 //MAKE_WIDEPTR_FROMUTF8(szInWide, szInSave);
3426
3427 int __lszInWide;
3428 LPWSTR szInWide;
3429 __lszInWide = WszMultiByteToWideChar(CP_UTF8, 0, szInSave, -1, 0, 0);
3430 if (__lszInWide > MAKE_MAX_LENGTH)
3431 RaiseException(EXCEPTION_INT_OVERFLOW, EXCEPTION_NONCONTINUABLE, 0, 0);
3432 szInWide = (LPWSTR) alloca(__lszInWide*sizeof(WCHAR));
3433 if (szInWide == NULL) {
3434 if (fAllowThrow) {
3435 COMPlusThrowOM();
3436 } else {
3437 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3438 result = 0;
3439 goto Exit;
3440 }
3441 }
3442 if (0==WszMultiByteToWideChar(CP_UTF8, 0, szInSave, -1, szInWide, __lszInWide)) {
3443 RaiseException(ERROR_NO_UNICODE_TRANSLATION, EXCEPTION_NONCONTINUABLE, 0, 0);
3444 }
3445
3446
3447 wideCopyLen = (INT32)wcslen(szInWide)+1;
3448 if (fAllowThrow) {
3449 szWideOut = (LPWSTR)qbOut.AllocThrows(wideCopyLen * sizeof(WCHAR));
3450 }
3451 else {
3452 szWideOut = (LPWSTR)qbOut.AllocNoThrow(wideCopyLen * sizeof(WCHAR));
3453 if (!szWideOut) {
3454 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3455 result = 0;
3456 goto Exit;
3457 }
3458 }
3459
3460 //Do the casing operation
3461 ::LCMapStringEx(W(""), LCMAP_LOWERCASE, szInWide, wideCopyLen, szWideOut, wideCopyLen, NULL, NULL, 0);
3462
3463 //Convert the Unicode back to UTF8
3464 result = WszWideCharToMultiByte(CP_UTF8, 0, szWideOut, wideCopyLen, szOut, cMaxBytes, NULL, NULL);
3465
3466 if ((result == 0) && fAllowThrow) {
3467 COMPlusThrowWin32();
3468 }
3469
3470#endif // !FEATURE_PAL
3471
3472Exit:
3473 return result;
3474}
3475
3476//
3477//
3478// COMCharacter and Helper functions
3479//
3480//
3481
3482#ifndef FEATURE_PAL
3483/*============================GetCharacterInfoHelper============================
3484**Determines character type info (digit, whitespace, etc) for the given char.
3485**Args: c is the character on which to operate.
3486** CharInfoType is one of CT_CTYPE1, CT_CTYPE2, CT_CTYPE3 and specifies the type
3487** of information being requested.
3488**Returns: The bitmask returned by GetStringTypeEx. The caller needs to know
3489** how to interpret this.
3490**Exceptions: ArgumentException if GetStringTypeEx fails.
3491==============================================================================*/
3492INT32 GetCharacterInfoHelper(WCHAR c, INT32 CharInfoType)
3493{
3494 WRAPPER_NO_CONTRACT;
3495
3496 unsigned short result=0;
3497 if (!GetStringTypeEx(LOCALE_USER_DEFAULT, CharInfoType, &(c), 1, &result)) {
3498 _ASSERTE(!"This should not happen, verify the arguments passed to GetStringTypeEx()");
3499 }
3500 return(INT32)result;
3501}
3502#endif // !FEATURE_PAL
3503
3504/*==============================nativeIsWhiteSpace==============================
3505**The locally available version of IsWhiteSpace. Designed to be called by other
3506**native methods. The work is mostly done by GetCharacterInfoHelper
3507**Args: c -- the character to check.
3508**Returns: true if c is whitespace, false otherwise.
3509**Exceptions: Only those thrown by GetCharacterInfoHelper.
3510==============================================================================*/
3511BOOL COMCharacter::nativeIsWhiteSpace(WCHAR c)
3512{
3513 WRAPPER_NO_CONTRACT;
3514
3515#ifndef FEATURE_PAL
3516 if (c <= (WCHAR) 0x7F) // common case
3517 {
3518 BOOL result = (c == ' ') || (c == '\r') || (c == '\n') || (c == '\t') || (c == '\f') || (c == (WCHAR) 0x0B);
3519
3520 ASSERT(result == ((GetCharacterInfoHelper(c, CT_CTYPE1) & C1_SPACE)!=0));
3521
3522 return result;
3523 }
3524
3525 // GetCharacterInfoHelper costs around 160 instructions
3526 return((GetCharacterInfoHelper(c, CT_CTYPE1) & C1_SPACE)!=0);
3527#else // !FEATURE_PAL
3528 return iswspace(c);
3529#endif // !FEATURE_PAL
3530}
3531
3532/*================================nativeIsDigit=================================
3533**The locally available version of IsDigit. Designed to be called by other
3534**native methods. The work is mostly done by GetCharacterInfoHelper
3535**Args: c -- the character to check.
3536**Returns: true if c is whitespace, false otherwise.
3537**Exceptions: Only those thrown by GetCharacterInfoHelper.
3538==============================================================================*/
3539BOOL COMCharacter::nativeIsDigit(WCHAR c)
3540{
3541 WRAPPER_NO_CONTRACT;
3542#ifndef FEATURE_PAL
3543 return((GetCharacterInfoHelper(c, CT_CTYPE1) & C1_DIGIT)!=0);
3544#else // !FEATURE_PAL
3545 return iswdigit(c);
3546#endif // !FEATURE_PAL
3547}
3548
3549BOOL RuntimeFileNotFound(HRESULT hr)
3550{
3551 LIMITED_METHOD_CONTRACT;
3552 return Assembly::FileNotFound(hr);
3553}
3554
3555#ifndef FEATURE_PAL
3556HRESULT GetFileVersion( // S_OK or error
3557 LPCWSTR wszFilePath, // Path to the executable.
3558 ULARGE_INTEGER* pFileVersion) // Put file version here.
3559{
3560 CONTRACTL
3561 {
3562 NOTHROW;
3563 GC_NOTRIGGER;
3564 MODE_ANY;
3565 }
3566 CONTRACTL_END;
3567
3568 //
3569 // Note that this code is equivalent to FusionGetFileVersionInfo, found in fusion\asmcache\asmcache.cpp
3570 //
3571
3572 // Avoid confusion.
3573 pFileVersion->QuadPart = 0;
3574
3575 DWORD ret;
3576
3577 DWORD dwHandle = 0;
3578 DWORD bufSize = GetFileVersionInfoSizeW(wszFilePath, &dwHandle);
3579 if (!bufSize)
3580 {
3581 return HRESULT_FROM_GetLastErrorNA();
3582 }
3583
3584 // Allocate the buffer for the version info structure
3585 // _alloca() can't return NULL -- raises STATUS_STACK_OVERFLOW.
3586 BYTE* pVersionInfoBuffer = reinterpret_cast< BYTE* >(_alloca(bufSize));
3587
3588 ret = GetFileVersionInfoW(wszFilePath, dwHandle, bufSize, pVersionInfoBuffer);
3589 if (!ret)
3590 {
3591 return HRESULT_FROM_GetLastErrorNA();
3592 }
3593
3594 // Extract the actual File Version number that we care about.
3595 UINT versionInfoSize = 0;
3596 VS_FIXEDFILEINFO* pVSFileInfo;
3597 ret = VerQueryValueW(pVersionInfoBuffer, W("\\"),
3598 reinterpret_cast< void **>(&pVSFileInfo), &versionInfoSize);
3599 if (!ret || versionInfoSize == 0)
3600 {
3601 return HRESULT_FROM_GetLastErrorNA();
3602 }
3603
3604 pFileVersion->HighPart = pVSFileInfo->dwFileVersionMS;
3605 pFileVersion->LowPart = pVSFileInfo->dwFileVersionLS;
3606
3607 return S_OK;
3608}
3609#endif // !FEATURE_PAL
3610
3611#endif // !DACCESS_COMPILE
3612