11d56de66b5fcbe1e701b969ea824ba876e21577
[platform/upstream/coreclr.git] / src / vm / dwbucketmanager.hpp
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 //
6 // FILE: dwbucketmanager.hpp
7 //
8 // This file contains the manager types for differents types of Watson buckets
9 // and various helper types.
10 //
11
12 // 
13
14 //
15 // ============================================================================
16
17 #ifndef DWBUCKETMANAGER_HPP
18 #define DWBUCKETMANAGER_HPP
19
20 #ifdef FEATURE_WINDOWSPHONE
21 #include "corhost.h"
22 #endif
23
24 // this will be used as an index into g_WerEventTraits
25 enum WatsonBucketType
26 {
27     CLR20r3 = 0,
28     MoCrash,
29 #ifdef FEATURE_WINDOWSPHONE
30     WinPhoneCrash,
31 #endif
32     // insert new types above this line
33     EndOfWerBucketTypes
34 };
35
36 const DWORD kInvalidParamsCount = 0xffffffff;
37
38 struct WerEventTypeTraits
39 {
40     const LPCWSTR EventName;
41     const DWORD CountParams;
42     INDEBUG(const WatsonBucketType BucketType);
43     
44     WerEventTypeTraits(LPCWSTR name, DWORD params DEBUG_ARG(WatsonBucketType type))
45         : EventName(name), CountParams(params) DEBUG_ARG(BucketType(type))
46     {
47         _ASSERTE(params < kInvalidParamsCount);
48     }
49 };
50
51 const WerEventTypeTraits g_WerEventTraits[] =
52 {
53     WerEventTypeTraits(W("CLR20r3"), 9 DEBUG_ARG(CLR20r3)),
54     WerEventTypeTraits(W("MoAppCrash"), 9 DEBUG_ARG(MoCrash))
55 #ifdef FEATURE_WINDOWSPHONE
56     // unfortunately Apollo uses the same event name
57     ,WerEventTypeTraits(W("CLR20r3"), 9 DEBUG_ARG(WinPhoneCrash))
58 #endif
59 };
60
61 DWORD GetCountBucketParamsForEvent(LPCWSTR wzEventName)
62 {
63     CONTRACTL
64     {
65         NOTHROW;
66         GC_NOTRIGGER;
67         MODE_ANY;
68         SUPPORTS_DAC;
69     }
70     CONTRACTL_END;
71
72     if (wzEventName == NULL)
73     {
74         _ASSERTE(!"missing event name when retrieving bucket params count");
75         return 10;
76     }
77     
78     DWORD countParams = kInvalidParamsCount;
79     for (int index = 0; index < EndOfWerBucketTypes; ++index)
80     {
81         if (wcscmp(wzEventName, g_WerEventTraits[index].EventName) == 0)
82         {
83             _ASSERTE(index == g_WerEventTraits[index].BucketType);
84             countParams = g_WerEventTraits[index].CountParams;
85             break;
86         }
87     }
88
89     if (countParams == kInvalidParamsCount)
90     {
91         _ASSERTE(!"unknown event name when retrieving bucket params count");
92         countParams = 10;
93     }
94     
95     return countParams;
96 }
97
98 #ifndef DACCESS_COMPILE
99
100 #include "dwreport.h"
101 #include <msodwwrap.h>
102 #include "dbginterface.h"
103 #include <sha1.h>
104
105 #ifdef FEATURE_APPX
106 #include "appxutil.h"
107 #endif
108
109 //------------------------------------------------------------------------------
110 // Description
111 //   Converts an array of bytes to a string of base32 encoded characters.
112 //
113 // Constructor
114 //   pData   -- The bytes to be converted.
115 //   nData   -- Count of bytes to be converted.
116 //
117 // Convert
118 //   pOut    -- Put converted bytes here.
119 //   nOut    -- Max number of characters to put
120 //
121 //  returns  -- Number of characters put.
122 //
123 // Notes
124 //   Five bytes of input produces 8 characters of output.
125 //------------------------------------------------------------------------------
126 class BytesToBase32
127 {
128 private:
129     // Five doesn't go into 8 very well, so we will wind up with 8 characters per
130     //  five bytes of input.  Specifically, a block of 5 bytes will be formatted
131     //  like this:
132     //      7  6  5  4  3  2  1  0 <-- bit #
133     //   0  1  1  1  1  1  2  2  2
134     //   1  2  2  3  3  3  3  3  4    <-- which character does the bit go to?
135     //   2  4  4  4  4  5  5  5  5
136     //   3  5  6  6  6  6  6  7  7
137     //   4  7  7  7  8  8  8  8  8
138     // This structure defines 2 masks and 3 shift values per 5-bit value.
139     //  The first mask is the mask from the first byte.  The first two
140     //  shifts are a left- OR a right- shift for the bits obtained via that mask.
141     //  If there is a second mask, that is to get bits from the next byte,
142     //  shifted right by the second shift value.  Finally, there is a bit to
143     //  indicate that the scanner should advance to the next byte.
144     // Referring to the table above, the decoder values for the first 5-bit
145     //  value will be:
146     //    m1 : 0xf8   - mask
147     //    l1 : 0      - no left shift
148     //    r1 : 3      - right shift 3 bits
149     //    m2 : 0      - no second mask
150     //    r2 : 0      - no second right shift
151     //    skip : 0    - don't skip to next byte (still 3 more bits, for the second 5-bits.
152     struct decoder_
153     {
154         unsigned int m1 : 8;    // Mask 1
155         unsigned int l1 : 4;    // Left shift 1
156         unsigned int r1 : 4;    // Right shift 2
157         unsigned int m2 : 8;    // Mask 2
158         unsigned int r2 : 4;    // Right shift 2
159         unsigned int skip:4;    // Skip to next input byte
160     };
161
162     static const decoder_ decoder[8]; // Array of decoder specs.
163     static const WCHAR base32[33];    // Array of 33 characters: A-Z, 0-5, =
164
165     BYTE    *pData;             // Pointer to data.
166     int     nData;              // Total bytes of data.
167
168     BYTE    *pEnd;
169
170     int     nWhich;             // Where in the sequence of 8 5-bit datums?
171
172 public:
173     BytesToBase32(BYTE *p, int n) : pData(p), nData(n), nWhich(0) { LIMITED_METHOD_CONTRACT; pEnd = pData + nData; }
174
175     WCHAR GetNextChar();
176     BOOL  MoreChars() { LIMITED_METHOD_CONTRACT; return pData < pEnd; }
177
178     int Convert(__inout_ecount(nOut) LPWSTR pOut, int nOut);
179 };
180
181 // This table tells how to pick out 5-bits at a time (8 times) from 5-bytes of data.
182 const BytesToBase32::decoder_ BytesToBase32::decoder[8] =
183 {  //  m1 l1 r1    m2 r2 skip
184     {0xf8, 0, 3, 0x00, 0, 0},
185     {0x07, 2, 0, 0xc0, 6, 1},
186     {0x3e, 0, 1, 0x00, 0, 0},
187     {0x01, 4, 0, 0xf0, 4, 1},
188     {0x0f, 1, 0, 0x80, 7, 1},
189     {0x7c, 0, 2, 0x00, 0, 0},
190     {0x03, 3, 0, 0xe0, 5, 1},
191     {0x1f, 0, 0, 0x00, 0, 1},
192 };
193
194 // Array of characters with which to encode.
195 const WCHAR BytesToBase32::base32[33] = {'A','B','C','D','E','F','G','H','I','J','K','L', 'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6'};
196
197 //------------------------------------------------------------------------------
198 // Description
199 //   Converts 5-bits to a character; fundamental base32 encoding.
200 //
201 // Parameters
202 //   none
203 //
204 // Returns
205 //   The next 5-bits, converted to a character.  Also advances the
206 //    character pointer.  When no characters remain to be converted,
207 //    returns W('6')
208 //
209 //------------------------------------------------------------------------------
210 WCHAR BytesToBase32::GetNextChar()
211 {
212     LIMITED_METHOD_CONTRACT;
213
214     unsigned int result = 0;
215
216     _ASSERTE(pData <= pEnd);
217     _ASSERTE(nWhich >= 0 && nWhich < lengthof(decoder));
218
219     // If out of data, return signal value, > any valid char.
220     if (pData == pEnd)
221         return base32[lengthof(base32)-1];
222
223 #if defined(_DEBUG)
224     if (decoder[nWhich].l1)
225     {   // There is a l1 shift.
226         _ASSERTE(decoder[nWhich].m1);       // There should be a m1 mask
227         _ASSERTE(decoder[nWhich].r1 == 0);  // There should not be a r1 shift
228         _ASSERTE(decoder[nWhich].m2);       // There shoulbe a m2 mask to fill in the rest of the bits.
229         _ASSERTE(decoder[nWhich].r2);       // m2 bits never start in the right place; there must be a shift
230         // The masks, shifted, and or'd together should equal 0x1f, 5-bits.
231         _ASSERTE( ( (decoder[nWhich].m1 << decoder[nWhich].l1) | (decoder[nWhich].m2 >> decoder[nWhich].r2)) == 0x1f);
232     }
233     else
234     {   // There is no l1 shift.
235         _ASSERTE(decoder[nWhich].m2 == 0);  // There should not be any m2 bits
236         _ASSERTE( (decoder[nWhich].m1 >> decoder[nWhich].r1) == 0x1f);  // The m1 bits, shifted should be 0x1f, 5-bits.
237     }
238 #endif
239
240     // Mask off the bits.
241     result = *pData & decoder[nWhich].m1;
242
243     // Shift left or right as needed.
244     if (decoder[nWhich].l1)
245     {   // Shift up to make space for low-order bits from next byte.
246         result = result << decoder[nWhich].l1;
247     }
248     else
249     if (decoder[nWhich].r1)
250     {   // Shift down into position.  There should be no more bits from next byte.
251         result = result >> decoder[nWhich].r1;
252     }
253
254     // Skip to next byte if appropriate.
255     if (decoder[nWhich].skip)
256         ++pData;
257
258     // Grab more bits if specified, and more are available.
259     if (pData < pEnd && decoder[nWhich].m2)
260     {   // All second-byte data are shifted right, so just mask and shift.
261         result |= ( (*pData & decoder[nWhich].m2) >> decoder[nWhich].r2);
262     }
263
264     // Advance the 'state machine' -- which 5-bits from an 8-byte block.
265     if (++nWhich == lengthof(decoder))
266         nWhich = 0;
267
268     // Sanity check on value.
269     _ASSERTE(result < lengthof(base32));
270
271     return base32[result];
272 } // WCHAR BytesToBase32::GetNextChar()
273
274 //------------------------------------------------------------------------------
275 // Description
276 //   Performs the conversion of a buffer to base32.
277 //
278 // Parameters
279 //   pOut     -- Buffer to receive the characters.
280 //   nOut     -- Maximum characters to write to the buffer.
281 //
282 // Returns
283 //   the number of characters copied to the output buffer.
284 //
285 //------------------------------------------------------------------------------
286 int BytesToBase32::Convert(
287     __inout_ecount(nOut) LPWSTR pOut,
288     int nOut)
289 {
290     WRAPPER_NO_CONTRACT;
291
292     int         nWritten = 0;           // Count of bytes written to output.
293
294     // Stop when the buffer is full, or the bytes are fully converted.
295     while (nOut > 0 && MoreChars())
296     {
297         *pOut = GetNextChar();
298         ++pOut;
299         --nOut;
300         ++nWritten;
301     }
302
303     return nWritten;
304 } // int BytesToBase32::Convert()
305
306 // this abstract class provides base functionality for populating a bucket parameter in the GMB with some data.
307 // the actual mapping of ordinal parameter to data type (eg parameter 1 is app name) is handled in subclasses
308 // of this type.  see GetBucketParamsManager() for retrieving a bucket params manager.
309 class BaseBucketParamsManager
310 {
311 private:
312     GenericModeBlock* m_pGmb;
313     TypeOfReportedError m_tore;
314     Thread* m_pThread;
315     OBJECTREF* m_pException;
316     INDEBUG(size_t m_countParamsLogged);
317     MethodDesc* m_pFaultingMD;
318     PCODE m_faultingPc;
319     
320     // misc helper functions
321     DWORD GetILOffset();
322     bool GetFileVersionInfoForModule(Module* pModule, USHORT& major, USHORT& minor, USHORT& build, USHORT& revision);
323     bool IsCodeContractsFrame(MethodDesc* pMD);
324     void FindFaultingMethodInfo();
325     OBJECTREF GetRealExceptionObject();
326     WCHAR* GetParamBufferForIndex(BucketParameterIndex paramIndex);
327     int CopyStringToBucket(__out_ecount(targetMaxLength) LPWSTR pTargetParam, int targetMaxLength, __in_z LPCWSTR pSource, bool cannonicalize = false);
328     void LogParam(__in_z LPCWSTR paramValue, BucketParameterIndex paramIndex);
329     
330 protected:
331     ~BaseBucketParamsManager();
332
333     typedef void (BaseBucketParamsManager::*DataPopulatorFunction)(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
334     void PopulateBucketParameter(BucketParameterIndex paramIndex, DataPopulatorFunction pFnDataPopulator, int maxLength);
335
336     void PopulateEventName(LPCWSTR eventTypeName);
337     // functions for retrieving data to go into various bucket parameters
338     void GetAppName(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
339     void GetAppVersion(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
340     void GetAppTimeStamp(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
341     void GetModuleName(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
342     void GetModuleVersion(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
343     void GetModuleTimeStamp(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
344     void GetMethodDef(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
345     void GetIlOffset(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
346     void GetExceptionName(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
347     void GetPackageMoniker(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
348     void GetPRAID(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
349     void GetIlRva(__out_ecount(maxLength) WCHAR* targetParam, int maxLength);
350
351 public:
352     BaseBucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE initialFaultingPc, Thread* pFaultingThread, OBJECTREF* pThrownException);
353
354     // function that consumers should call to populate the GMB
355     virtual void PopulateBucketParameters() = 0;
356 };
357
358 BaseBucketParamsManager::BaseBucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE initialFaultingPc, Thread* pFaultingThread, OBJECTREF* pThrownException)
359     : m_pFaultingMD(NULL), m_faultingPc(initialFaultingPc), m_pGmb(pGenericModeBlock), m_tore(typeOfError), m_pThread(pFaultingThread), m_pException(pThrownException)
360 {
361     CONTRACTL
362     {
363         NOTHROW;
364         GC_NOTRIGGER;
365         MODE_ANY;
366     }
367     CONTRACTL_END;
368
369     _ASSERTE(m_pGmb);
370     INDEBUG(m_countParamsLogged = 0);
371     
372     ZeroMemory(pGenericModeBlock, sizeof(GenericModeBlock));
373
374     EECodeInfo codeInfo(initialFaultingPc);
375     if (codeInfo.IsValid())
376     {
377         m_pFaultingMD = codeInfo.GetMethodDesc();
378
379         if (m_pFaultingMD)
380             FindFaultingMethodInfo();
381     }
382 }
383
384 BaseBucketParamsManager::~BaseBucketParamsManager()
385 {
386     LIMITED_METHOD_CONTRACT;
387     
388     _ASSERTE(m_countParamsLogged == GetCountBucketParamsForEvent(m_pGmb->wzEventTypeName));
389 }
390
391 void BaseBucketParamsManager::PopulateEventName(LPCWSTR eventTypeName)
392 {
393     CONTRACTL
394     {
395         NOTHROW;
396         GC_NOTRIGGER;
397         MODE_ANY;
398     }
399     CONTRACTL_END;
400
401     wcsncpy_s(m_pGmb->wzEventTypeName, DW_MAX_BUCKETPARAM_CWC, eventTypeName, _TRUNCATE);
402
403     _ASSERTE(GetCountBucketParamsForEvent(eventTypeName));
404     LOG((LF_EH, LL_INFO10, "Event     : %S\n", m_pGmb->wzEventTypeName));
405 }
406
407 WCHAR* BaseBucketParamsManager::GetParamBufferForIndex(BucketParameterIndex paramIndex)
408 {
409     CONTRACTL
410     {
411         NOTHROW;
412         GC_NOTRIGGER;
413         MODE_ANY;
414     }
415     CONTRACTL_END;
416
417     _ASSERTE(paramIndex < InvalidBucketParamIndex);
418     switch (paramIndex)
419     {
420         case Parameter1:
421             return m_pGmb->wzP1;
422         case Parameter2:
423             return m_pGmb->wzP2;
424         case Parameter3:
425             return m_pGmb->wzP3;
426         case Parameter4:
427             return m_pGmb->wzP4;
428         case Parameter5:
429             return m_pGmb->wzP5;
430         case Parameter6:
431             return m_pGmb->wzP6;
432         case Parameter7:
433             return m_pGmb->wzP7;
434         case Parameter8:
435             return m_pGmb->wzP8;
436         case Parameter9:
437             return m_pGmb->wzP9;
438         default:
439         {
440             _ASSERTE(!"bad paramIndex");
441             // this is a back-stop to prevent returning NULL and having to have
442             // callers check for it.  we should never get here though anyways.
443             return m_pGmb->wzP10;
444         }
445     }
446 }
447
448 void BaseBucketParamsManager::PopulateBucketParameter(BucketParameterIndex paramIndex, DataPopulatorFunction pFnDataPopulator, int maxLength)
449 {
450     CONTRACTL
451     {
452         NOTHROW;
453         GC_NOTRIGGER;
454         MODE_ANY;
455     }
456     CONTRACTL_END;
457
458     _ASSERTE(paramIndex < InvalidBucketParamIndex);
459     WCHAR* targetParam = GetParamBufferForIndex(paramIndex);
460
461     // verify that we haven't already written data to this param
462     _ASSERTE(targetParam && targetParam[0] == W('\0'));
463 #ifdef FEATURE_WINDOWSPHONE
464     WCHAR const* overrideParam = g_CLRErrorReportingManager.GetBucketParamOverride(paramIndex);
465     if (overrideParam != NULL)
466     {
467         CopyStringToBucket(targetParam, maxLength, overrideParam, false);
468     }
469     else
470 #endif // FEATURE_WINDOWSPHONE
471     {
472         (this->*pFnDataPopulator)(targetParam, maxLength);
473     }
474
475     LogParam(targetParam, paramIndex);
476 }
477
478 void BaseBucketParamsManager::GetAppName(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
479 {
480     CONTRACTL
481     {
482         NOTHROW;
483         GC_NOTRIGGER;
484         MODE_ANY;
485     }
486     CONTRACTL_END;
487
488     HMODULE hModule = WszGetModuleHandle(NULL);
489     WCHAR appPath[MAX_LONGPATH];
490     DWORD cchAppPath = NumItems(appPath);
491
492     if (GetCurrentModuleFileName(appPath, &cchAppPath) == S_OK)
493     {
494         CopyStringToBucket(targetParam, maxLength, appPath);
495     }
496     else
497     {
498         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
499     }
500 }
501
502 void BaseBucketParamsManager::GetAppVersion(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
503 {
504     CONTRACTL
505     {
506         NOTHROW;
507         GC_NOTRIGGER;
508         MODE_ANY;
509     }
510     CONTRACTL_END;
511
512     HMODULE hModule = WszGetModuleHandle(NULL);
513     WCHAR appPath[MAX_LONGPATH];
514     DWORD cchAppPath = NumItems(appPath);
515
516     WCHAR verBuf[23];
517     USHORT major, minor, build, revision;
518
519     if ((GetCurrentModuleFileName(appPath, &cchAppPath) == S_OK) && SUCCEEDED(DwGetFileVersionInfo(appPath, major, minor, build, revision)))
520     {
521         _snwprintf_s(targetParam,
522             maxLength,
523             _TRUNCATE,
524             W("%d.%d.%d.%d"),
525             major, minor, build, revision);
526     }
527     else if (DwGetAssemblyVersion(appPath, verBuf, NumItems(verBuf)) != 0)
528     {
529         wcscpy_s(targetParam, maxLength, verBuf);
530     }
531     else
532     {
533         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
534     }
535 }
536
537 void BaseBucketParamsManager::GetAppTimeStamp(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
538 {
539     CONTRACTL
540     {
541         NOTHROW;
542         GC_NOTRIGGER;
543         MODE_ANY;
544     }
545     CONTRACTL_END;
546
547     EX_TRY
548     {
549         CONTRACT_VIOLATION(GCViolation);
550
551         HMODULE hModule = WszGetModuleHandle(NULL);
552         PEDecoder pe(hModule);
553
554         ULONG ulTimeStamp = pe.GetTimeDateStamp();
555
556         _snwprintf_s(targetParam,
557                     maxLength,
558                     _TRUNCATE,
559                     W("%x"),
560                     ulTimeStamp);
561     }
562     EX_CATCH
563     {
564         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
565     }
566     EX_END_CATCH(SwallowAllExceptions)
567 }
568
569 void BaseBucketParamsManager::GetModuleName(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
570 {
571     CONTRACTL
572     {
573         NOTHROW;
574         GC_NOTRIGGER;
575         MODE_ANY;
576     }
577     CONTRACTL_END;
578
579     Module* pModule = NULL;
580
581     if (m_pFaultingMD != NULL)
582         pModule = m_pFaultingMD->GetModule();
583
584     bool failed = false;
585
586     if (pModule)
587     {
588         // Get the assembly name, and determine its length, including terminating NULL.
589         Assembly* pAssembly = pModule->GetAssembly();
590         LPCUTF8 utf8AssemblyName = pAssembly->GetSimpleName();
591         const int assemblyNameLength = WszMultiByteToWideChar(CP_UTF8, 0, utf8AssemblyName, -1, NULL, 0);
592
593         // full name and length.  minor assumption that this is not multi-module.
594         WCHAR *fullName = NULL;
595         int fullNameLength = assemblyNameLength;
596
597         if (pModule->IsManifest())
598         {
599             // Single-module assembly; allocate a buffer and convert assembly name.
600             fullName = reinterpret_cast< WCHAR* >(_alloca(sizeof(WCHAR)*(fullNameLength)));
601             WszMultiByteToWideChar(CP_UTF8, 0, utf8AssemblyName, -1, fullName, fullNameLength);
602         }
603         else
604         {   //  This is a non-manifest module, which means it is a multi-module assembly.
605             //  Construct a name like 'assembly+module'.
606
607             // Get the module name, and determine its length, including terminating NULL.
608             LPCUTF8 utf8ModuleName = pModule->GetSimpleName();
609             const int moduleNameLength = WszMultiByteToWideChar(CP_UTF8, 0, utf8ModuleName, -1, NULL, 0);
610
611             //  Full name length is assembly name length + module name length + 1 char for '+'.
612             //  However, both assemblyNameLength and moduleNameLength include space for terminating NULL,
613             //  but of course only one NULL is needed, so the final length is just the sum of the two lengths.
614             if (!ClrSafeInt<int>::addition(assemblyNameLength, moduleNameLength, fullNameLength))
615             {
616                 failed = true;
617             }
618             else
619             {
620                 // Allocate a buffer with proper prefast checks.
621                 int AllocLen;
622                 if (!ClrSafeInt<int>::multiply(sizeof(WCHAR), fullNameLength, AllocLen))
623                 {
624                     failed = true;
625                 }
626                 else
627                 {
628                     fullName = reinterpret_cast< WCHAR* >(_alloca(AllocLen));
629
630                     // Convert the assembly name.
631                     WszMultiByteToWideChar(CP_UTF8, 0, utf8AssemblyName, -1, fullName, assemblyNameLength);
632
633                     // replace NULL with '+'
634                     _ASSERTE(fullName[assemblyNameLength-1] == 0);
635                     fullName[assemblyNameLength-1] = W('+');
636
637                     // Convert the module name after the '+'
638                     WszMultiByteToWideChar(CP_UTF8, 0, utf8ModuleName,-1, &fullName[assemblyNameLength], moduleNameLength);
639                 }
640             }
641         }
642
643         if (!failed)
644         {
645             // Make sure NULL termination is right.
646             _ASSERTE(fullName[fullNameLength - 1] == 0);
647
648             // Copy name in, with possible truncation or hashing.
649             CopyStringToBucket(targetParam, maxLength, fullName);
650         }
651     }
652
653     if (!pModule || failed)
654     {
655         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
656     }
657 }
658
659 void BaseBucketParamsManager::GetModuleVersion(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
660 {
661     CONTRACTL
662     {
663         NOTHROW;
664         GC_NOTRIGGER;
665         MODE_ANY;
666     }
667     CONTRACTL_END;
668
669     Module* pModule = NULL;
670
671     if (m_pFaultingMD != NULL)
672         pModule = m_pFaultingMD->GetModule();
673
674     bool failed = false;
675
676     // @TODO: what if the it is in-memory module? It can have the version info.
677     // But we will not retrieve it right.
678     if (pModule)
679     {
680         USHORT major = 0, minor = 0, build = 0, revision = 0;
681
682         bool gotFileVersion = GetFileVersionInfoForModule(pModule, major, minor, build, revision);
683
684         // if we failed to get a version and this isn't the manifest module then try that
685         if (!gotFileVersion && !pModule->IsManifest())
686         {
687             pModule = pModule->GetAssembly()->GetManifestModule();
688             if (pModule)
689                 gotFileVersion = GetFileVersionInfoForModule(pModule, major, minor, build, revision);
690         }
691
692         if (!gotFileVersion)
693         {
694             // if we didn't get a file version then fall back to assembly version (typical for in-memory modules)
695             if (FAILED(pModule->GetAssembly()->GetVersion(&major, &minor, &build, &revision)))
696                 failed = true;
697         }
698
699         if (!failed)
700         {
701             _snwprintf_s(targetParam,
702                        maxLength,
703                        _TRUNCATE,
704                        W("%d.%d.%d.%d"),
705                        major, minor, build, revision);
706         }
707     }
708     
709     if (!pModule || failed)
710     {
711         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
712     }
713 }
714
715 void BaseBucketParamsManager::GetModuleTimeStamp(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
716 {
717     CONTRACTL
718     {
719         NOTHROW;
720         GC_NOTRIGGER;
721         MODE_ANY;
722     }
723     CONTRACTL_END;
724
725     Module* pModule = NULL;
726
727     if (m_pFaultingMD != NULL)
728         pModule = m_pFaultingMD->GetModule();
729
730     bool failed = false;
731
732     if (pModule)
733     {
734         EX_TRY
735         {
736             // We only store the IL timestamp in the native image for the 
737             // manifest module.  We should consider fixing this for Orcas.
738             PTR_PEFile pFile = pModule->GetAssembly()->GetManifestModule()->GetFile();
739
740             // for dynamic modules use 0 as the time stamp
741             ULONG ulTimeStamp = 0;
742
743             if (!pFile->IsDynamic())
744             {
745                 ulTimeStamp = pFile->GetILImageTimeDateStamp();
746                 _ASSERTE(ulTimeStamp != 0);
747             }
748
749             _snwprintf_s(targetParam,
750                    maxLength,
751                    _TRUNCATE,
752                    W("%x"),
753                    ulTimeStamp);
754         }
755         EX_CATCH
756         {
757             failed = true;
758         }
759         EX_END_CATCH(SwallowAllExceptions)
760     }
761     
762     if (!pModule || failed)
763     {
764         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
765     }
766 }
767
768 void BaseBucketParamsManager::GetMethodDef(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
769 {
770     CONTRACTL
771     {
772         NOTHROW;
773         GC_NOTRIGGER;
774         MODE_ANY;
775     }
776     CONTRACTL_END;
777
778     if (m_pFaultingMD)
779     {
780         mdMethodDef methodDef = m_pFaultingMD->GetMemberDef();
781         _snwprintf_s(targetParam,
782                    maxLength,
783                    _TRUNCATE,
784                    W("%x"),
785                    RidFromToken(methodDef));
786     }
787     else
788     {
789         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
790     }
791 }
792
793 void BaseBucketParamsManager::GetIlOffset(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
794 {
795     CONTRACTL
796     {
797         NOTHROW;
798         GC_NOTRIGGER;
799         MODE_ANY;
800     }
801     CONTRACTL_END;
802
803     DWORD ilOffset = GetILOffset();
804
805     _snwprintf_s(targetParam,
806                 maxLength,
807                 _TRUNCATE,
808                 W("%x"),
809                 ilOffset);
810 }
811
812 void BaseBucketParamsManager::GetExceptionName(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
813 {
814     CONTRACTL
815     {
816         NOTHROW;
817         GC_NOTRIGGER;
818         MODE_ANY;
819     }
820     CONTRACTL_END;
821
822     if (m_tore.GetType() != TypeOfReportedError::StackOverflowException)
823     {
824         // At this point we have to switch to cooperative mode, because we need an OBJECTREF.
825         GCX_COOP();
826
827         OBJECTREF throwable = GetRealExceptionObject();
828
829         LPCWSTR pExceptionName = NULL;
830
831         if (throwable == NULL)
832         {
833             // Don't have an exception object.  Make up something reasonable.
834             switch (m_tore.GetType())
835             {
836             case TypeOfReportedError::NativeThreadUnhandledException:
837             case TypeOfReportedError::UnhandledException:
838                 pExceptionName = W("Exception");
839                 break;
840             case TypeOfReportedError::FatalError:
841                 pExceptionName = W("FatalError");
842                 break;
843             case TypeOfReportedError::UserBreakpoint:
844                 pExceptionName = W("Debugger.Break");
845                 break;
846             case TypeOfReportedError::NativeBreakpoint:
847                 pExceptionName = W("Breakpoint");
848                 break;
849             default:
850                 _ASSERTE(!"Unexpected TypeOfReportedError");
851                 break;
852             }
853         }
854         else
855         {
856             MethodTable* pMT = OBJECTREFToObject(throwable)->GetMethodTable();
857             DefineFullyQualifiedNameForClassWOnStack();
858
859             EX_TRY
860             {
861                 pExceptionName = GetFullyQualifiedNameForClassNestedAwareW(pMT);
862             }
863             EX_CATCH
864             {
865             }
866             EX_END_CATCH(SwallowAllExceptions);
867         }
868
869         _ASSERTE(pExceptionName);
870
871         // Copy name in, with possible truncation or hashing.
872         CopyStringToBucket(targetParam, maxLength, pExceptionName);
873     }
874     else // StackOverflowException
875     {
876         // During StackOverflowException processing we may be under ThreadStore lock and cannot spawn a managed thread (otherwise deadlock).
877         // So we avoid using any managed heap objects and switching to GC_COOP.
878         CopyStringToBucket(targetParam, maxLength, W("System.StackOverflowException"));
879     }
880 }
881
882 void BaseBucketParamsManager::GetPackageMoniker(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
883 {
884     CONTRACTL
885     {
886         NOTHROW;
887         GC_NOTRIGGER;
888         MODE_ANY;
889     }
890     CONTRACTL_END;
891
892 #ifndef FEATURE_CORECLR
893     bool success = false;
894     EX_TRY
895     {
896         wcsncpy_s(targetParam, maxLength, AppX::GetHeadPackageMoniker(), _TRUNCATE);
897         success = true;
898     }
899     EX_CATCH
900     {
901     }
902     EX_END_CATCH(SwallowAllExceptions);
903
904     if (!success)
905     {
906         // should this ever legitimately fail??
907         _ASSERTE(!"failed to get package moniker for watson");
908         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
909     }
910 #else
911     _ASSERTE(!"AppX support NYI for CoreCLR");
912 #endif // FEATURE_CORECLR
913 }
914
915 void BaseBucketParamsManager::GetPRAID(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
916 {
917     CONTRACTL
918     {
919         NOTHROW;
920         GC_NOTRIGGER;
921         MODE_ANY;
922     }
923     CONTRACTL_END;
924
925 #ifndef FEATURE_CORECLR
926     LPCWSTR pPraid = NULL;
927     if (SUCCEEDED(AppX::GetApplicationId(pPraid)))
928     {
929         _snwprintf_s(targetParam,
930                     maxLength,
931                     _TRUNCATE,
932                     W("praid:%s"),
933                     pPraid);
934     }
935     else
936     {
937         // should this ever legitimately fail??
938         _ASSERTE(!"failed to get PRAID for watson");
939         wcsncpy_s(targetParam, maxLength, W("missing"), _TRUNCATE);
940     }
941 #else
942     _ASSERTE(!"PRAID support NYI for CoreCLR");
943 #endif
944 }
945
946 void BaseBucketParamsManager::GetIlRva(__out_ecount(maxLength) WCHAR* targetParam, int maxLength)
947 {
948     CONTRACTL
949     {
950         NOTHROW;
951         GC_NOTRIGGER;
952         MODE_ANY;
953     }
954     CONTRACTL_END;
955
956     DWORD ilOffset = GetILOffset();
957
958     if (ilOffset == MAXDWORD)
959         ilOffset = 0;
960
961     if (m_pFaultingMD)
962         ilOffset += m_pFaultingMD->GetRVA();
963
964     _snwprintf_s(targetParam,
965                 maxLength,
966                 _TRUNCATE,
967                 W("%x"),
968                 ilOffset);
969 }
970
971 // helper functions
972
973 DWORD BaseBucketParamsManager::GetILOffset()
974 {
975     CONTRACTL
976     {
977         NOTHROW;
978         GC_NOTRIGGER;
979         MODE_ANY;
980     }
981     CONTRACTL_END;
982
983     DWORD nativeOffset = 0;
984     DWORD ilOffset = MAXDWORD;
985
986     EECodeInfo codeInfo(m_faultingPc);
987     if (codeInfo.IsValid())
988     {
989         nativeOffset = codeInfo.GetRelOffset();
990         _ASSERTE(m_pFaultingMD == codeInfo.GetMethodDesc());
991     }
992
993     if (m_pFaultingMD)
994     {
995         EX_TRY
996         {
997             CONTRACT_VIOLATION(GCViolation);
998             _ASSERTE(g_pDebugInterface != NULL);
999             g_pDebugInterface->GetILOffsetFromNative(
1000                                 m_pFaultingMD,
1001                                 (const BYTE *)m_faultingPc,
1002                                 nativeOffset,
1003                                 &ilOffset);
1004         }
1005         EX_CATCH
1006         {
1007             // Swallow the exception, and just use MAXDWORD.
1008         }
1009         EX_END_CATCH(SwallowAllExceptions)
1010     }
1011
1012     return ilOffset;
1013 }
1014
1015 // attempts to get file version information for the specified module.
1016 // returns true on success and all out params will contain data.
1017 // on failure the out params are not touched.
1018 // assumes that pModule is not NULL!!
1019 bool BaseBucketParamsManager::GetFileVersionInfoForModule(Module* pModule, USHORT& major, USHORT& minor, USHORT& build, USHORT& revision)
1020 {
1021     CONTRACTL
1022     {
1023         NOTHROW;
1024         GC_NOTRIGGER;
1025         MODE_ANY;
1026         PRECONDITION(pModule != NULL);
1027     }
1028     CONTRACTL_END;
1029
1030     bool succeeded = false;
1031
1032     PEFile* pFile = pModule->GetFile();
1033     if (pFile)
1034     {
1035         // if we have a native imaged loaded for this module then get the version information from that.
1036         if (pFile->IsNativeLoaded())
1037         {
1038             PEImage* pNativeImage = pFile->GetPersistentNativeImage();
1039
1040             if (pNativeImage)
1041             {
1042                 LPCWSTR niPath = pNativeImage->GetPath().GetUnicode();
1043                 if (niPath != NULL && niPath != SString::Empty() && SUCCEEDED(DwGetFileVersionInfo(niPath, major, minor, build, revision)))
1044                 {
1045                     succeeded = true;
1046                 }
1047             }
1048         }
1049
1050         // if we failed to get the version info from the native image then fall back to the IL image.
1051         if (!succeeded)
1052         {
1053             LPCWSTR modulePath = pFile->GetPath().GetUnicode();
1054             if (modulePath != NULL && modulePath != SString::Empty() && SUCCEEDED(DwGetFileVersionInfo(modulePath, major, minor, build, revision)))
1055             {
1056                 succeeded = true;
1057             }
1058         }
1059     }
1060
1061     return succeeded;
1062 }
1063
1064 // attempts to determine if the specified MethodDesc is one of the code contracts methods.
1065 // this is defined as any method on the System.Diagnostics.Contracts.__ContractsRuntime type.
1066 bool BaseBucketParamsManager::IsCodeContractsFrame(MethodDesc* pMD)
1067 {
1068     CONTRACTL
1069     {
1070         NOTHROW;
1071         GC_NOTRIGGER;
1072         MODE_ANY;
1073         PRECONDITION(pMD != NULL);
1074     }
1075     CONTRACTL_END;
1076
1077     if (!pMD)
1078         return false;
1079
1080     MethodTable* pMT = pMD->GetMethodTable_NoLogging();
1081     LPCUTF8 pszNamespace = NULL;
1082     LPCUTF8 pszName = NULL;
1083     pszName = pMT->GetFullyQualifiedNameInfo(&pszNamespace);
1084
1085     if (!pszName || !pszNamespace)
1086         return false;
1087
1088     LPCUTF8 pszContractsNamespace = "System.Diagnostics.Contracts";
1089     LPCUTF8 pszContractsRuntimeType = "__ContractsRuntime";
1090
1091     if (strcmp(pszNamespace, pszContractsNamespace) == 0 &&
1092         strcmp(pszName, pszContractsRuntimeType) == 0)
1093         return true;
1094
1095     return false;
1096 }
1097
1098 // code contract failures will have several frames on the stack which are part of the code contracts infrastructure.
1099 // as such we don't want to blame any of these frames since they're just propagating the fault from the user's code.
1100 // the purpose of this function is to identify if the current faulting frame is part of the code contract infrastructure
1101 // and if it is to traverse the stack trace in the exception object until the first frame which isn't code contracts stuff.
1102 void BaseBucketParamsManager::FindFaultingMethodInfo()
1103 {
1104     CONTRACTL
1105     {
1106         NOTHROW;
1107         GC_NOTRIGGER;
1108         MODE_ANY;
1109         PRECONDITION(m_pFaultingMD != NULL);
1110     }
1111     CONTRACTL_END;
1112
1113     // check if this frame is part of the code contracts infrastructure
1114     if (IsCodeContractsFrame(m_pFaultingMD))
1115     {
1116         // it is so we need to do more searching to find the correct faulting MethodDesc.
1117         // iterate over each frame in the stack trace object until we find the first
1118         // frame that isn't part of the code contracts goop.
1119         GCX_COOP();
1120
1121         OBJECTREF throwable = GetRealExceptionObject();
1122
1123         if (throwable != NULL)
1124         {
1125             StackTraceArray traceData;
1126             EXCEPTIONREF(throwable)->GetStackTrace(traceData);
1127
1128             GCPROTECT_BEGIN(traceData);
1129
1130             size_t numElements = traceData.Size();
1131
1132             ContractFailureKind kind = GetContractFailureKind(throwable);
1133
1134             // skip frame 0 since we already know it's part of code contracts
1135             for (size_t index = 1; index < numElements; ++index)
1136             {
1137                 StackTraceElement const& cur = traceData[index];
1138
1139                 MethodDesc* pMD = cur.pFunc;
1140                 _ASSERTE(pMD);
1141
1142                 if (!IsCodeContractsFrame(pMD))
1143                 {
1144                     // we want the next frame for preconditions however if we don't have it for some
1145                     // reason then just use this frame (better than defaulting to the code contracts goop)
1146                     if ((kind == CONTRACT_FAILURE_PRECONDITION) && (index + 1 < numElements))
1147                     {
1148                         _ASSERTE(!IsCodeContractsFrame(traceData[index + 1].pFunc));
1149                         continue;
1150                     }
1151
1152                     m_pFaultingMD = pMD;
1153                     m_faultingPc = cur.ip;
1154                     break;
1155                 }
1156             }
1157
1158             GCPROTECT_END();
1159         }
1160     }
1161 }
1162
1163 // gets the "real" exception object.  it might be m_pException or the exception object on the thread
1164 OBJECTREF BaseBucketParamsManager::GetRealExceptionObject()
1165 {
1166     CONTRACTL
1167     {
1168         NOTHROW;
1169         GC_NOTRIGGER;
1170         MODE_COOPERATIVE;
1171     }
1172     CONTRACTL_END;
1173
1174     OBJECTREF throwable = NULL;
1175
1176     if (m_pException != NULL)
1177     {
1178         _ASSERTE(IsProtectedByGCFrame(m_pException));
1179         throwable = *m_pException;
1180     }
1181     else if (m_tore.IsException())
1182     {
1183         // If it is an exception, see if there is a Throwable object.
1184         if (m_pThread != NULL)
1185         {
1186             throwable = m_pThread->GetThrowable();
1187
1188             // If the "Throwable" is null, try the "LastThrownObject"
1189             if (throwable == NULL)
1190                 throwable = m_pThread->LastThrownObject();
1191         }
1192     }
1193
1194     return throwable;
1195 }
1196
1197 //------------------------------------------------------------------------------
1198 // Description
1199 //   Copies a string to a Watson bucket parameter.  If the offered string is
1200 //   longer than the maxLen, the string will be shortened.
1201 //
1202 // Parameters
1203 //   pTargetParam     -- the destination buffer.
1204 //   targetMaxLength  -- the max length of the parameter.
1205 //   pSource          -- the input string.
1206 //   cannonicalize    -- if true, cannonicalize the filename (tolower)
1207 //
1208 // Returns
1209 //   the number of characters copied to the output buffer.  zero indicates an
1210 //     error.
1211 //
1212 // Notes
1213 //   The truncation algorithm is this:
1214 //    - if the value contains non-ascii characters, divide the maxLen by 4,
1215 //      due to restrictions in Watson bucketing rules
1216 //    - if the value fits, just copy it as-is
1217 //    - if the value doesn't fit, strip any trailing ".dll", ".exe", ".netmodule",
1218 //      or "Exception"
1219 //    - if the value still doesn't fit, take a SHA1 hash of the source, and
1220 //      encode in base32.
1221 //    - if the value may require hashing, the maxlen should be at least 32,
1222 //      because that is what a SHA1 hash coded in base32 will require.
1223 //    - the maxlen does not include the terminating nul.
1224 //------------------------------------------------------------------------------
1225 int BaseBucketParamsManager::CopyStringToBucket(__out_ecount(targetMaxLength) LPWSTR pTargetParam, int targetMaxLength, __in_z LPCWSTR pSource, bool cannonicalize)
1226 {
1227     CONTRACTL
1228     {
1229         NOTHROW;
1230         GC_NOTRIGGER;
1231         MODE_ANY;
1232     }
1233     CONTRACTL_END;
1234
1235     // Array of suffixes to truncate if necessary.
1236     static const LPCWSTR truncations[] =
1237     {
1238         W("Exception"),
1239         W(".dll"),
1240         W(".exe"),
1241         W(".netmodule"),
1242         0
1243     };
1244
1245     int srcLen = static_cast<int>(wcslen(pSource));
1246
1247     // If the source contains unicode characters, they'll be encoded at 4 chars per char.
1248     int targLen = ContainsUnicodeChars(pSource) ? targetMaxLength / 4 : targetMaxLength;
1249
1250     // If the string is too long, see if there is a suffix that can be trimmed.
1251     if (srcLen > targLen)
1252     {
1253         for (int i = 0; truncations[i]; ++i)
1254         {
1255             // how long is this suffix?
1256             int slen = static_cast<int>(wcslen(truncations[i]));
1257
1258             // Could the string have this suffix?
1259             if (slen < srcLen)
1260             {
1261                 // maybe -- check.
1262                 if (SString::_wcsicmp(&pSource[srcLen - slen], truncations[i]) == 0)
1263                 {
1264                     // yes, the string does have this suffix.  drop it.
1265                     srcLen -= slen;
1266                     break;
1267                 }
1268             }
1269         }
1270     }
1271
1272     // If the (possibly truncated) value fits, copy it and return.
1273     if (srcLen <= targLen)
1274     {
1275         wcsncpy_s(pTargetParam, DW_MAX_BUCKETPARAM_CWC, pSource, srcLen);
1276
1277         if (cannonicalize)
1278         {
1279             // cannonicalize filenames so that the same exceptions tend to the same buckets.
1280             _wcslwr_s(pTargetParam, DW_MAX_BUCKETPARAM_CWC);
1281         }
1282         return srcLen;
1283     }
1284
1285     // String didn't fit, so hash it.
1286     SHA1Hash hash;
1287     hash.AddData(reinterpret_cast<BYTE*>(const_cast<LPWSTR>(pSource)), (static_cast<int>(wcslen(pSource))) * sizeof(WCHAR));
1288
1289     // Encode in base32.  The hash is a fixed size; we'll accept up to maxLen characters of the encoding.
1290     BytesToBase32 b32(hash.GetHash(), SHA1_HASH_SIZE);
1291     targLen = b32.Convert(pTargetParam, targetMaxLength);
1292     pTargetParam[targLen] = W('\0');
1293
1294     return targLen;
1295 }
1296
1297 void BaseBucketParamsManager::LogParam(__in_z LPCWSTR paramValue, BucketParameterIndex paramIndex)
1298 {
1299 #ifdef _DEBUG
1300     LIMITED_METHOD_CONTRACT;
1301
1302     _ASSERTE(paramIndex < InvalidBucketParamIndex);
1303     // the BucketParameterIndex enum starts at 0 however we refer to Watson 
1304     // bucket params with 1-based indices so we add one to paramIndex.
1305     LOG((LF_EH, LL_INFO10, "       p %d: %S\n", paramIndex + 1, paramValue));
1306     ++m_countParamsLogged;
1307 #endif
1308 }
1309
1310 // specific manager classes for the various watson bucket types that the CLR reports.
1311 // each type is responsible for populating the GMB according to the event type schema.
1312 // to add support for a new schema simply inherit from the BaseBucketParamsManager and
1313 // in the PopulateBucketParameters() function fill out the GMB as required.  then update
1314 // function GetBucketParamsManager() (and a few depedent functions) to return the new
1315 // type as required.
1316
1317 class CLR20r3BucketParamsManager : public BaseBucketParamsManager
1318 {
1319 public:   
1320     CLR20r3BucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE faultingPC, Thread* pFaultingThread, OBJECTREF* pThrownException);
1321     ~CLR20r3BucketParamsManager();
1322
1323     virtual void PopulateBucketParameters();
1324 };
1325
1326 CLR20r3BucketParamsManager::CLR20r3BucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE faultingPC, Thread* pFaultingThread, OBJECTREF* pThrownException)
1327     : BaseBucketParamsManager(pGenericModeBlock, typeOfError, faultingPC, pFaultingThread, pThrownException)
1328 {
1329     CONTRACTL
1330     {
1331         NOTHROW;
1332         GC_NOTRIGGER;
1333         MODE_ANY;
1334     }
1335     CONTRACTL_END;
1336 }
1337
1338 CLR20r3BucketParamsManager::~CLR20r3BucketParamsManager()
1339 {
1340     LIMITED_METHOD_CONTRACT;
1341 }
1342
1343 void CLR20r3BucketParamsManager::PopulateBucketParameters()
1344 {
1345     CONTRACTL
1346     {
1347         NOTHROW;
1348         GC_NOTRIGGER;
1349         MODE_ANY;
1350     }
1351     CONTRACTL_END;
1352
1353     PopulateEventName(g_WerEventTraits[CLR20r3].EventName);
1354
1355     // the "+ 1" is to explicitly indicate which fields need to specify space for NULL
1356     PopulateBucketParameter(Parameter1, &CLR20r3BucketParamsManager::GetAppName, 32);
1357     PopulateBucketParameter(Parameter2, &CLR20r3BucketParamsManager::GetAppVersion, 23 + 1);
1358     PopulateBucketParameter(Parameter3, &CLR20r3BucketParamsManager::GetAppTimeStamp, 8 + 1);
1359     PopulateBucketParameter(Parameter4, &CLR20r3BucketParamsManager::GetModuleName, 64);
1360     PopulateBucketParameter(Parameter5, &CLR20r3BucketParamsManager::GetModuleVersion, 23 + 1);
1361     PopulateBucketParameter(Parameter6, &CLR20r3BucketParamsManager::GetModuleTimeStamp, 8 + 1);
1362     PopulateBucketParameter(Parameter7, &CLR20r3BucketParamsManager::GetMethodDef, 6 + 1);
1363     PopulateBucketParameter(Parameter8, &CLR20r3BucketParamsManager::GetIlOffset, 8 + 1);
1364     PopulateBucketParameter(Parameter9, &CLR20r3BucketParamsManager::GetExceptionName, 32);
1365 }
1366
1367 class MoCrashBucketParamsManager : public BaseBucketParamsManager
1368 {
1369 public:
1370     MoCrashBucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE faultingPC, Thread* pFaultingThread, OBJECTREF* pThrownException);
1371     ~MoCrashBucketParamsManager();
1372
1373     virtual void PopulateBucketParameters();
1374 };
1375
1376 MoCrashBucketParamsManager::MoCrashBucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE faultingPC, Thread* pFaultingThread, OBJECTREF* pThrownException)
1377     : BaseBucketParamsManager(pGenericModeBlock, typeOfError, faultingPC, pFaultingThread, pThrownException)
1378 {
1379     CONTRACTL
1380     {
1381         NOTHROW;
1382         GC_NOTRIGGER;
1383         MODE_ANY;
1384     }
1385     CONTRACTL_END;
1386 }
1387
1388 MoCrashBucketParamsManager::~MoCrashBucketParamsManager()
1389 {
1390     LIMITED_METHOD_CONTRACT;
1391 }
1392
1393 void MoCrashBucketParamsManager::PopulateBucketParameters()
1394 {
1395     CONTRACTL
1396     {
1397         NOTHROW;
1398         GC_NOTRIGGER;
1399         MODE_ANY;
1400     }
1401     CONTRACTL_END;
1402
1403     PopulateEventName(g_WerEventTraits[MoCrash].EventName);
1404
1405     // DW_MAX_BUCKETPARAM_CWC - 1 to ensure space for NULL
1406     PopulateBucketParameter(Parameter1, &MoCrashBucketParamsManager::GetPackageMoniker, DW_MAX_BUCKETPARAM_CWC - 1);
1407     PopulateBucketParameter(Parameter2, &MoCrashBucketParamsManager::GetPRAID, DW_MAX_BUCKETPARAM_CWC - 1);
1408     PopulateBucketParameter(Parameter3, &MoCrashBucketParamsManager::GetAppVersion, DW_MAX_BUCKETPARAM_CWC - 1);
1409     PopulateBucketParameter(Parameter4, &MoCrashBucketParamsManager::GetAppTimeStamp, DW_MAX_BUCKETPARAM_CWC - 1);
1410     PopulateBucketParameter(Parameter5, &MoCrashBucketParamsManager::GetModuleName, DW_MAX_BUCKETPARAM_CWC - 1);
1411     PopulateBucketParameter(Parameter6, &MoCrashBucketParamsManager::GetModuleVersion, DW_MAX_BUCKETPARAM_CWC - 1);
1412     PopulateBucketParameter(Parameter7, &MoCrashBucketParamsManager::GetModuleTimeStamp, DW_MAX_BUCKETPARAM_CWC - 1);
1413     PopulateBucketParameter(Parameter8, &MoCrashBucketParamsManager::GetExceptionName, DW_MAX_BUCKETPARAM_CWC - 1);
1414     PopulateBucketParameter(Parameter9, &MoCrashBucketParamsManager::GetIlRva, DW_MAX_BUCKETPARAM_CWC - 1);
1415 }
1416
1417 #ifdef FEATURE_WINDOWSPHONE
1418 class WinPhoneBucketParamsManager : public BaseBucketParamsManager
1419 {
1420 public:   
1421     WinPhoneBucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE faultingPC, Thread* pFaultingThread, OBJECTREF* pThrownException);
1422     ~WinPhoneBucketParamsManager();
1423
1424     virtual void PopulateBucketParameters();
1425 };
1426
1427 WinPhoneBucketParamsManager::WinPhoneBucketParamsManager(GenericModeBlock* pGenericModeBlock, TypeOfReportedError typeOfError, PCODE faultingPC, Thread* pFaultingThread, OBJECTREF* pThrownException)
1428     : BaseBucketParamsManager(pGenericModeBlock, typeOfError, faultingPC, pFaultingThread, pThrownException)
1429 {
1430     CONTRACTL
1431     {
1432         NOTHROW;
1433         GC_NOTRIGGER;
1434         MODE_ANY;
1435     }
1436     CONTRACTL_END;
1437 }
1438
1439 WinPhoneBucketParamsManager::~WinPhoneBucketParamsManager()
1440 {
1441     LIMITED_METHOD_CONTRACT;
1442 }
1443
1444 void WinPhoneBucketParamsManager::PopulateBucketParameters()
1445 {
1446     CONTRACTL
1447     {
1448         NOTHROW;
1449         GC_NOTRIGGER;
1450         MODE_ANY;
1451     }
1452     CONTRACTL_END;
1453
1454     PopulateEventName(g_WerEventTraits[WinPhoneCrash].EventName);
1455
1456     // the "+ 1" is to explicitly indicate which fields need to specify space for NULL
1457     PopulateBucketParameter(Parameter1, &WinPhoneBucketParamsManager::GetAppName, DW_MAX_BUCKETPARAM_CWC - 1);
1458     PopulateBucketParameter(Parameter2, &WinPhoneBucketParamsManager::GetAppVersion, 23 + 1);
1459     PopulateBucketParameter(Parameter3, &WinPhoneBucketParamsManager::GetAppTimeStamp, 8 + 1);
1460     PopulateBucketParameter(Parameter4, &WinPhoneBucketParamsManager::GetModuleName, DW_MAX_BUCKETPARAM_CWC - 1);
1461     PopulateBucketParameter(Parameter5, &WinPhoneBucketParamsManager::GetModuleVersion, 23 + 1);
1462     PopulateBucketParameter(Parameter6, &WinPhoneBucketParamsManager::GetModuleTimeStamp, 8 + 1);
1463     PopulateBucketParameter(Parameter7, &WinPhoneBucketParamsManager::GetMethodDef, 6 + 1);
1464     PopulateBucketParameter(Parameter8, &WinPhoneBucketParamsManager::GetIlOffset, 8 + 1);
1465     PopulateBucketParameter(Parameter9, &WinPhoneBucketParamsManager::GetExceptionName, DW_MAX_BUCKETPARAM_CWC - 1);
1466 }
1467 #endif // FEATURE_WINDOWSPHONE
1468
1469 WatsonBucketType GetWatsonBucketType()
1470 {
1471     CONTRACTL
1472     {
1473         NOTHROW;
1474         GC_NOTRIGGER;
1475         MODE_ANY;
1476         SUPPORTS_DAC;
1477     }
1478     CONTRACTL_END;
1479
1480 #if defined(FEATURE_APPX) && !defined(FEATURE_CORECLR)
1481     if (AppX::IsAppXProcess() && !AppX::IsAppXNGen())
1482         return MoCrash;
1483     else
1484 #endif // FEATURE_APPX
1485
1486 #ifdef FEATURE_WINDOWSPHONE
1487         return WinPhoneCrash;
1488 #else
1489         return CLR20r3;
1490 #endif // FEATURE_WINDOWSPHONE
1491 }
1492
1493 #endif // DACCESS_COMPILE
1494
1495 #endif // DWBUCKETMANAGER_HPP