CrashServer: ship new library in installer
[TortoiseGit.git] / src / crashrpt / excprpt.cpp
blob5f17c1d9d2ee53e874db4e8a2c95cdb4ae6a1692
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // Module: excprpt.cpp
4 //
5 // Desc: See excprpt.h
6 //
7 // Copyright (c) 2003 Michael Carruth
8 //
9 ///////////////////////////////////////////////////////////////////////////////
12 #include "stdafx.h"
13 #include "excprpt.h"
14 #include "utility.h"
16 #include "StackTrace.h"
18 //////////////////////////////////////////////////////////////////////
19 // Construction/Destruction
20 //////////////////////////////////////////////////////////////////////
23 //-----------------------------------------------------------------------------
24 // CExceptionReport::CExceptionReport
26 //
28 CExceptionReport::CExceptionReport(PEXCEPTION_POINTERS ExceptionInfo, BSTR message)
30 m_excpInfo = ExceptionInfo;
31 m_message = message;
32 TCHAR szModName[_MAX_FNAME + 1];
33 GetModuleFileName(NULL, szModName, _MAX_FNAME);
34 m_sModule = szModName;
35 m_sCommandLine = GetCommandLine();
36 m_frameNumber = 0;
40 //-----------------------------------------------------------------------------
41 // CExceptionReport::getCrashFile
43 // Creates the dump file returning the file name
45 string CExceptionReport::getCrashFile()
47 TCHAR buf[MAX_PATH] = {0};
48 _stprintf_s(buf, MAX_PATH, _T("%s\\%s.dmp"), _tgetenv("TEMP"), CUtility::getAppName().c_str());
50 // Create the file
51 HANDLE hFile = CreateFile(
52 buf,
53 GENERIC_WRITE,
55 NULL,
56 CREATE_ALWAYS,
57 FILE_ATTRIBUTE_NORMAL,
58 NULL);
61 // Write the minidump to the file
63 if (hFile)
65 writeDumpFile(hFile, m_excpInfo, reinterpret_cast<void *>(this));
68 // Close file
69 CloseHandle(hFile);
71 return string(buf);
75 void CExceptionReport::writeDumpFile(HANDLE hFile, PEXCEPTION_POINTERS excpInfo, void *data)
77 if (excpInfo == NULL) {
78 // Generate exception to get proper context in dump
79 __try {
80 RaiseException(EXCEPTION_BREAKPOINT, 0, 0, NULL);
81 } __except(writeDumpFile(hFile, GetExceptionInformation(), data), EXCEPTION_CONTINUE_EXECUTION) {
83 } else {
84 MINIDUMP_EXCEPTION_INFORMATION eInfo;
85 eInfo.ThreadId = GetCurrentThreadId();
86 eInfo.ExceptionPointers = excpInfo;
87 eInfo.ClientPointers = FALSE;
89 MINIDUMP_CALLBACK_INFORMATION cbMiniDump;
90 cbMiniDump.CallbackRoutine = CExceptionReport::miniDumpCallback;
91 cbMiniDump.CallbackParam = data;
93 MiniDumpWriteDump(
94 GetCurrentProcess(),
95 GetCurrentProcessId(),
96 hFile,
97 MiniDumpWithIndirectlyReferencedMemory,
98 excpInfo ? &eInfo : NULL,
99 NULL,
100 &cbMiniDump);
104 //-----------------------------------------------------------------------------
105 // CExceptionReport::getCrashLog
107 // Creates the XML log file returning the name
109 string CExceptionReport::getCrashLog()
111 string sFile;
112 MSXML2::IXMLDOMDocument *pDoc = NULL;
113 MSXML2::IXMLDOMNode *root = NULL;
114 MSXML2::IXMLDOMNode *node = NULL;
115 MSXML2::IXMLDOMNode *newNode = NULL;
116 BSTR rootName = ::SysAllocString(L"Exception");
117 VARIANT v;
119 CoInitialize(NULL);
121 // Create an empty XML document
122 CHECKHR(CoCreateInstance(
123 MSXML2::CLSID_DOMDocument,
124 NULL,
125 CLSCTX_INPROC_SERVER,
126 MSXML2::IID_IXMLDOMDocument,
127 (void**)&pDoc));
129 // Create root node
130 root = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, rootName);
133 // Add exception record node
135 if (m_excpInfo)
137 node = CreateExceptionRecordNode(pDoc, m_excpInfo->ExceptionRecord);
138 CHECKHR(root->appendChild(node, &newNode));
139 // The XML Document should now own the node.
140 SAFERELEASE(node);
141 SAFERELEASE(newNode);
145 // Add optional message node
147 if (m_message != NULL) {
148 node = CreateMsgNode(pDoc, m_message);
149 CHECKHR(root->appendChild(node, &newNode));
150 // The XML Document should now own the node.
151 SAFERELEASE(node);
152 SAFERELEASE(newNode);
156 // Add processor node
158 node = CreateProcessorNode(pDoc);
159 CHECKHR(root->appendChild(node, &newNode));
160 // The XML Document should now own the node.
161 SAFERELEASE(node);
162 SAFERELEASE(newNode);
165 // Add OS node
167 node = CreateOSNode(pDoc);
168 CHECKHR(root->appendChild(node, &newNode));
169 // The XML Document should now own the node.
170 SAFERELEASE(node);
171 SAFERELEASE(newNode);
174 // Add modules node
176 node = CreateModulesNode(pDoc);
177 CHECKHR(root->appendChild(node, &newNode));
178 // The XML Document should now own the node.
179 SAFERELEASE(node);
180 SAFERELEASE(newNode);
183 // Add stack walkback node
185 node = CreateWalkbackNode(pDoc, m_excpInfo != NULL ? m_excpInfo->ContextRecord : NULL);
186 CHECKHR(root->appendChild(node, &newNode));
187 // The XML Document should now own the node.
188 SAFERELEASE(node);
189 SAFERELEASE(newNode);
192 // Add the root to the doc
193 CHECKHR(pDoc->appendChild(root, NULL));
196 // Create dat file name and save
198 TCHAR buf[MAX_PATH] = {0};
199 _tprintf_s(buf, _T("%s\\%s.xml"), getenv("TEMP"), CUtility::getAppName());
200 V_VT(&v) = VT_BSTR;
201 V_BSTR(&v) = CUtility::AllocSysString(buf);
202 pDoc->save(v);
203 SysFreeString(V_BSTR(&v));
205 CleanUp:
206 SAFERELEASE(pDoc);
207 SAFERELEASE(root);
208 SAFERELEASE(node);
209 SAFERELEASE(newNode);
210 SysFreeString(rootName);
212 CoUninitialize();
214 return sFile;
218 //-----------------------------------------------------------------------------
219 // CExceptionReport::getNumSymbolFiles
221 // Returns the number of symbols files found
223 int CExceptionReport::getNumSymbolFiles()
225 return m_symFiles.size();
229 //-----------------------------------------------------------------------------
230 // CExceptionReport::getSymbolFile
232 // Returns the symbol file name given an index
234 string CExceptionReport::getSymbolFile(int index)
236 string ret;
238 if (0 < index && index < (int)m_symFiles.size())
239 ret = m_symFiles[index];
241 return ret;
244 //-----------------------------------------------------------------------------
245 // CExceptionReport::CreateDOMNode
247 // Helper function
249 MSXML2::IXMLDOMNode*
250 CExceptionReport::CreateDOMNode(MSXML2::IXMLDOMDocument* pDoc,
251 int type,
252 BSTR bstrName)
254 MSXML2::IXMLDOMNode * node;
255 VARIANT vtype;
257 vtype.vt = VT_I4;
258 V_I4(&vtype) = (int)type;
260 pDoc->createNode(vtype, bstrName, NULL, &node);
261 return node;
264 //-----------------------------------------------------------------------------
265 // CreateExceptionSymbolAttributes
267 // Create attributes in the exception record with the symbolic info, if available
269 void CExceptionReport::CreateExceptionSymbolAttributes(DWORD_PTR /*address*/, const char * /*ImageName*/,
270 const char *FunctionName, DWORD_PTR functionDisp,
271 const char *Filename, DWORD LineNumber, DWORD lineDisp,
272 void *data)
274 string sAddr;
275 BSTR funcName = ::SysAllocString(L"FunctionName");
276 BSTR funcDispName = ::SysAllocString(L"FunctionDisplacement");
277 BSTR fileName = ::SysAllocString(L"Filename");
278 BSTR lineName = ::SysAllocString(L"LineNumber");
279 BSTR lineDispName = ::SysAllocString(L"LineDisplacement");
280 CExceptionReport *self = reinterpret_cast<CExceptionReport *>(data);
282 VARIANT v;
284 // don't need ImageName [module], as that is already done
285 if (FunctionName != NULL) {
286 V_VT(&v) = VT_BSTR;
287 V_BSTR(&v) = CUtility::AllocSysString(FunctionName);
288 self->m_exception_element->setAttribute(funcName, v);
289 // Recycle variant
290 SysFreeString(V_BSTR(&v));
291 TCHAR buf[MAX_PATH] = {0};
292 _tprintf_s(buf, offsetFormat, functionDisp);
293 V_VT(&v) = VT_BSTR;
294 V_BSTR(&v) = CUtility::AllocSysString(buf);
295 self->m_exception_element->setAttribute(funcDispName, v);
296 // Recycle variant
297 SysFreeString(V_BSTR(&v));
300 if (Filename != NULL) {
301 V_VT(&v) = VT_BSTR;
302 V_BSTR(&v) = CUtility::AllocSysString(Filename);
303 self->m_exception_element->setAttribute(fileName, v);
304 // Recycle variant
305 SysFreeString(V_BSTR(&v));
307 TCHAR buf[MAX_PATH] = {0};
308 _tprintf_s(buf, _T("%d"), LineNumber);
309 V_VT(&v) = VT_BSTR;
310 V_BSTR(&v) = CUtility::AllocSysString(buf);
311 self->m_exception_element->setAttribute(lineName, v);
312 // Recycle variant
313 SysFreeString(V_BSTR(&v));
315 _tprintf_s(buf, offsetFormat, lineDisp);
316 V_VT(&v) = VT_BSTR;
317 V_BSTR(&v) = CUtility::AllocSysString(buf);
318 self->m_exception_element->setAttribute(lineDispName, v);
319 // Recycle variant
320 SysFreeString(V_BSTR(&v));
322 ::SysFreeString(funcName);
323 ::SysFreeString(funcDispName);
324 ::SysFreeString(fileName);
325 ::SysFreeString(lineName);
326 ::SysFreeString(lineDispName);
329 //-----------------------------------------------------------------------------
330 // CExceptionReport::CreateExceptionRecordNode
334 MSXML2::IXMLDOMNode*
335 CExceptionReport::CreateExceptionRecordNode(MSXML2::IXMLDOMDocument* pDoc,
336 EXCEPTION_RECORD* pExceptionRecord)
338 MSXML2::IXMLDOMNode* pNode = NULL;
339 MSXML2::IXMLDOMElement* pElement = NULL;
340 BSTR nodeName = ::SysAllocString(L"ExceptionRecord");
341 BSTR modName = ::SysAllocString(L"ModuleName");
342 BSTR codeName = ::SysAllocString(L"ExceptionCode");
343 BSTR descName = ::SysAllocString(L"ExceptionDescription");
344 BSTR addrName = ::SysAllocString(L"ExceptionAddress");
345 BSTR commandlineName = ::SysAllocString(L"CommandLine");
347 VARIANT v;
348 string sAddr;
350 // Create exception record node
351 pNode = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, nodeName);
353 // Get element interface
354 CHECKHR(pNode->QueryInterface(MSXML2::IID_IXMLDOMElement, (void**)&pElement));
357 // Set module name attribute
359 V_VT(&v) = VT_BSTR;
360 V_BSTR(&v) = CUtility::AllocSysString(m_sModule);
361 pElement->setAttribute(modName, v);
362 // Recycle variant
363 SysFreeString(V_BSTR(&v));
366 // Set command line name attribute
368 V_VT(&v) = VT_BSTR;
369 V_BSTR(&v) = CUtility::AllocSysString(m_sCommandLine);
370 pElement->setAttribute(commandlineName, v);
371 // Recycle variant
372 SysFreeString(V_BSTR(&v));
375 // Set exception code
377 TCHAR buf[MAX_PATH] = {0};
378 _tprintf_s(buf, _T("%#x"), pExceptionRecord->ExceptionCode);
379 m_sException = buf;
380 V_VT(&v) = VT_BSTR;
381 V_BSTR(&v) = CUtility::AllocSysString(buf);
382 pElement->setAttribute(codeName, v);
383 // Recycle variant
384 SysFreeString(V_BSTR(&v));
387 // Set exception description
389 V_VT(&v) = VT_BSTR;
390 switch (pExceptionRecord->ExceptionCode)
392 case EXCEPTION_ACCESS_VIOLATION:
393 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_ACCESS_VIOLATION");
394 break;
395 case EXCEPTION_DATATYPE_MISALIGNMENT:
396 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_DATATYPE_MISALIGNMENT");
397 break;
398 case EXCEPTION_BREAKPOINT:
399 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_BREAKPOINT");
400 break;
401 case EXCEPTION_SINGLE_STEP:
402 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_SINGLE_STEP");
403 break;
404 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
405 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_ARRAY_BOUNDS_EXCEEDED");
406 break;
407 case EXCEPTION_FLT_DENORMAL_OPERAND:
408 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_FLT_DENORMAL_OPERAND");
409 break;
410 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
411 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_FLT_DIVIDE_BY_ZERO");
412 break;
413 case EXCEPTION_FLT_INEXACT_RESULT:
414 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_FLT_INEXACT_RESULT");
415 break;
416 case EXCEPTION_FLT_INVALID_OPERATION:
417 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_FLT_INVALID_OPERATION");
418 break;
419 case EXCEPTION_FLT_OVERFLOW:
420 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_FLT_OVERFLOW");
421 break;
422 case EXCEPTION_FLT_STACK_CHECK:
423 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_FLT_STACK_CHECK");
424 break;
425 case EXCEPTION_FLT_UNDERFLOW:
426 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_FLT_UNDERFLOW");
427 break;
428 case EXCEPTION_INT_DIVIDE_BY_ZERO:
429 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_INT_DIVIDE_BY_ZERO");
430 break;
431 case EXCEPTION_INT_OVERFLOW:
432 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_INT_OVERFLOW");
433 break;
434 case EXCEPTION_PRIV_INSTRUCTION:
435 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_PRIV_INSTRUCTION");
436 break;
437 case EXCEPTION_IN_PAGE_ERROR:
438 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_IN_PAGE_ERROR");
439 break;
440 case EXCEPTION_ILLEGAL_INSTRUCTION:
441 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_ILLEGAL_INSTRUCTION");
442 break;
443 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
444 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_NONCONTINUABLE_EXCEPTION");
445 break;
446 case EXCEPTION_STACK_OVERFLOW:
447 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_STACK_OVERFLOW");
448 break;
449 case EXCEPTION_INVALID_DISPOSITION:
450 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_INVALID_DISPOSITION");
451 break;
452 case EXCEPTION_GUARD_PAGE:
453 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_GUARD_PAGE");
454 break;
455 case EXCEPTION_INVALID_HANDLE:
456 V_BSTR(&v) = ::SysAllocString(L"EXCEPTION_INVALID_HANDLE");
457 break;
458 default:
459 V_BSTR(&v) = L"EXCEPTION_UNKNOWN";
460 break;
462 pElement->setAttribute(descName, v);
463 // Recycle variant
464 SysFreeString(V_BSTR(&v));
467 // Set exception address
469 _tprintf_s(buf, _T("%#x"), pExceptionRecord->ExceptionAddress);
470 m_sAddress = sAddr;
471 V_VT(&v) = VT_BSTR;
472 V_BSTR(&v) = CUtility::AllocSysString(buf);
473 pElement->setAttribute(addrName, v);
474 // Recycle variant
475 SysFreeString(V_BSTR(&v));
477 // Try to include symbolic information
478 m_exception_element = pElement;
479 AddressToSymbol(reinterpret_cast<DWORD_PTR>(pExceptionRecord->ExceptionAddress)-1,
480 CreateExceptionSymbolAttributes,
481 reinterpret_cast<void *>(this));
482 CleanUp:
483 ::SysFreeString(nodeName);
484 ::SysFreeString(modName);
485 ::SysFreeString(codeName);
486 ::SysFreeString(addrName);
487 SAFERELEASE(pElement);
489 return pNode;
492 //-----------------------------------------------------------------------------
493 // CExceptionReport::CreateProcessorNode
497 MSXML2::IXMLDOMNode*
498 CExceptionReport::CreateProcessorNode(MSXML2::IXMLDOMDocument* pDoc)
500 MSXML2::IXMLDOMNode* pNode = NULL;
501 MSXML2::IXMLDOMElement* pElement = NULL;
502 BSTR nodeName = ::SysAllocString(L"Processor");
503 BSTR archName = ::SysAllocString(L"Architecture");
504 BSTR levelName = ::SysAllocString(L"Level");
505 BSTR numberName = ::SysAllocString(L"NumberOfProcessors");
506 SYSTEM_INFO si;
507 VARIANT v;
509 // Create exception record node
510 pNode = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, nodeName);
512 // Get element interface
513 CHECKHR(pNode->QueryInterface(MSXML2::IID_IXMLDOMElement, (void**)&pElement));
516 // Get processor info
518 GetSystemInfo(&si);
521 // Set architecture
523 V_VT(&v) = VT_BSTR;
524 switch (si.wProcessorArchitecture)
526 case PROCESSOR_ARCHITECTURE_INTEL:
527 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_INTEL");
528 break;
529 case PROCESSOR_ARCHITECTURE_MIPS:
530 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_MIPS");
531 break;
532 case PROCESSOR_ARCHITECTURE_ALPHA:
533 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_ALPHA");
534 break;
535 case PROCESSOR_ARCHITECTURE_PPC:
536 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_PPC");
537 break;
538 case PROCESSOR_ARCHITECTURE_SHX:
539 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_SHX");
540 break;
541 case PROCESSOR_ARCHITECTURE_ARM:
542 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_ARM");
543 break;
544 case PROCESSOR_ARCHITECTURE_IA64:
545 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_IA64");
546 break;
547 case PROCESSOR_ARCHITECTURE_ALPHA64:
548 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_ALPHA64");
549 break;
550 case PROCESSOR_ARCHITECTURE_AMD64:
551 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_AMD64");
552 break;
553 case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
554 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_IA32_ON_WIN64");
555 break;
556 case PROCESSOR_ARCHITECTURE_UNKNOWN:
557 V_BSTR(&v) = ::SysAllocString(L"PROCESSOR_ARCHITECTURE_UNKNOWN");
558 break;
559 default:
560 V_BSTR(&v) = ::SysAllocString(L"Unknown");
562 pElement->setAttribute(archName, v);
563 // Recycle variant
564 SysFreeString(V_BSTR(&v));
567 // Set level
569 V_VT(&v) = VT_BSTR;
570 if (PROCESSOR_ARCHITECTURE_INTEL == si.wProcessorArchitecture)
572 switch (si.wProcessorLevel)
574 case 3:
575 V_BSTR(&v) = ::SysAllocString(L"Intel 30386");
576 break;
577 case 4:
578 V_BSTR(&v) = ::SysAllocString(L"Intel 80486");
579 break;
580 case 5:
581 V_BSTR(&v) = ::SysAllocString(L"Intel Pentium");
582 break;
583 case 6:
584 V_BSTR(&v) = ::SysAllocString(L"Intel Pentium Pro or Pentium II");
585 break;
586 default:
587 V_BSTR(&v) = ::SysAllocString(L"Unknown");
590 pElement->setAttribute(levelName, v);
591 // Recycle variant
592 SysFreeString(V_BSTR(&v));
595 // Set num of processors
597 V_VT(&v) = VT_I4;
598 V_I4(&v) = si.dwNumberOfProcessors;
599 pElement->setAttribute(numberName, v);
601 CleanUp:
602 ::SysFreeString(nodeName);
603 ::SysFreeString(archName);
604 ::SysFreeString(levelName);
605 ::SysFreeString(numberName);
606 SAFERELEASE(pElement);
608 return pNode;
611 //-----------------------------------------------------------------------------
612 // CExceptionReport::CreateOSNode
616 MSXML2::IXMLDOMNode*
617 CExceptionReport::CreateOSNode(MSXML2::IXMLDOMDocument* pDoc)
619 MSXML2::IXMLDOMNode* pNode = NULL;
620 MSXML2::IXMLDOMElement* pElement = NULL;
621 BSTR nodeName = ::SysAllocString(L"OperatingSystem");
622 BSTR majorName = ::SysAllocString(L"MajorVersion");
623 BSTR minorName = ::SysAllocString(L"MinorVersion");
624 BSTR buildName = ::SysAllocString(L"BuildNumber");
625 BSTR csdName = ::SysAllocString(L"CSDVersion");
626 OSVERSIONINFO oi;
627 VARIANT v;
629 // Create exception record node
630 pNode = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, nodeName);
632 // Get element interface
633 CHECKHR(pNode->QueryInterface(MSXML2::IID_IXMLDOMElement, (void**)&pElement));
636 // Get OS info
638 oi.dwOSVersionInfoSize = sizeof(oi);
639 GetVersionEx(&oi);
642 // Set major version
644 V_VT(&v) = VT_I4;
645 V_I4(&v) = oi.dwMajorVersion;
646 pElement->setAttribute(majorName, v);
649 // Set minor version
651 V_VT(&v) = VT_I4;
652 V_I4(&v) = oi.dwMinorVersion;
653 pElement->setAttribute(minorName, v);
656 // Set build version
658 V_VT(&v) = VT_I4;
659 V_I4(&v) = oi.dwBuildNumber;
660 pElement->setAttribute(buildName, v);
663 // Set CSD version
665 V_VT(&v) = VT_BSTR;
666 V_BSTR(&v) = CUtility::AllocSysString(oi.szCSDVersion);
667 pElement->setAttribute(csdName, v);
668 ::SysFreeString(V_BSTR(&v));
670 CleanUp:
671 ::SysFreeString(nodeName);
672 ::SysFreeString(majorName);
673 ::SysFreeString(minorName);
674 ::SysFreeString(buildName);
675 ::SysFreeString(csdName);
676 SAFERELEASE(pElement);
678 return pNode;
681 //-----------------------------------------------------------------------------
682 // CExceptionReport::CreateModulesNode
686 MSXML2::IXMLDOMNode*
687 CExceptionReport::CreateModulesNode(MSXML2::IXMLDOMDocument* pDoc)
689 MSXML2::IXMLDOMNode* pNode = NULL;
690 MSXML2::IXMLDOMNode* pNode2 = NULL;
691 MSXML2::IXMLDOMNode* pNewNode = NULL;
692 MSXML2::IXMLDOMElement* pElement = NULL;
693 MSXML2::IXMLDOMElement* pElement2= NULL;
694 BSTR nodeName = ::SysAllocString(L"Modules");
695 BSTR nodeName2 = ::SysAllocString(L"Module");
696 BSTR fullPath = ::SysAllocString(L"FullPath");
697 BSTR baseAddrName = ::SysAllocString(L"BaseAddress");
698 BSTR sizeName = ::SysAllocString(L"Size");
699 BSTR timeStampName = ::SysAllocString(L"TimeStamp");
700 BSTR fileVerName = ::SysAllocString(L"FileVersion");
701 BSTR prodVerName = ::SysAllocString(L"ProductVersion");
703 string sAddr;
704 VARIANT v;
707 // Create modules node
708 pNode = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, nodeName);
711 // Add module information (freeing storage as we go)
713 MINIDUMP_MODULE_CALLBACK item;
714 std::vector<MINIDUMP_MODULE_CALLBACK>::iterator iter;
715 for (iter = m_modules.begin(); iter != m_modules.end(); iter++)
717 item = *iter;
718 // Create module node
719 pNode2 = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, nodeName2);
721 // Get element interface
722 CHECKHR(pNode2->QueryInterface(MSXML2::IID_IXMLDOMElement, (void**)&pElement));
725 // Set full path
727 V_VT(&v) = VT_BSTR;
728 V_BSTR(&v) = SysAllocString(item.FullPath);
729 pElement->setAttribute(fullPath, v);
730 // Recycle variant
731 SysFreeString(V_BSTR(&v));
734 // Set base address
736 TCHAR buf[MAX_PATH] = {0};
737 _tprintf_s(buf, addressFormat, item.BaseOfImage);
738 V_VT(&v) = VT_BSTR;
739 V_BSTR(&v) = CUtility::AllocSysString(buf);
740 pElement->setAttribute(baseAddrName, v);
741 // Recycle variant
742 SysFreeString(V_BSTR(&v));
745 // Set module size
747 _tprintf_s(buf, sizeFormat, item.SizeOfImage);
748 V_VT(&v) = VT_BSTR;
749 V_BSTR(&v) = CUtility::AllocSysString(buf);
750 pElement->setAttribute(sizeName, v);
751 // Recycle variant
752 SysFreeString(V_BSTR(&v));
755 // Set timestamp
757 FILETIME ft = CUtility::getLastWriteFileTime(item.FullPath);
758 SYSTEMTIME st = {0};
760 FileTimeToSystemTime(&ft, &st);
762 _tprintf_s(buf, _T("%02u/%02u/%04u %02u:%02u:%02u"),
763 st.wMonth,
764 st.wDay,
765 st.wYear,
766 st.wHour,
767 st.wMinute,
768 st.wSecond);
770 V_VT(&v) = VT_BSTR;
771 V_BSTR(&v) = CUtility::AllocSysString(buf);
772 pElement->setAttribute(timeStampName, v);
773 // Recycle variant
774 SysFreeString(V_BSTR(&v));
777 // Set file version
779 _tprintf_s(buf,"%d.%d.%d.%d",
780 HIWORD(item.VersionInfo.dwFileVersionMS),
781 LOWORD(item.VersionInfo.dwFileVersionMS),
782 HIWORD(item.VersionInfo.dwFileVersionLS),
783 LOWORD(item.VersionInfo.dwFileVersionLS));
785 V_VT(&v) = VT_BSTR;
786 V_BSTR(&v) = CUtility::AllocSysString(buf);
787 pElement->setAttribute(fileVerName, v);
788 // Recycle variant
789 SysFreeString(V_BSTR(&v));
792 // Set product version
794 _tprintf_s(buf, "%d.%d.%d.%d",
795 HIWORD(item.VersionInfo.dwProductVersionMS),
796 LOWORD(item.VersionInfo.dwProductVersionMS),
797 HIWORD(item.VersionInfo.dwProductVersionLS),
798 LOWORD(item.VersionInfo.dwProductVersionLS));
800 V_VT(&v) = VT_BSTR;
801 V_BSTR(&v) = CUtility::AllocSysString(buf);
802 pElement->setAttribute(prodVerName, v);
803 // Recycle variant
804 SysFreeString(V_BSTR(&v));
807 // Append module to modules
809 pNode->appendChild(pNode2, &pNewNode);
810 // The XML Document should now own the node.
811 SAFERELEASE(pNode2);
812 SAFERELEASE(pElement2);
813 SAFERELEASE(pNewNode);
815 free(item.FullPath);
817 m_modules.clear();
819 CleanUp:
821 ::SysFreeString(nodeName);
822 ::SysFreeString(nodeName2);
823 ::SysFreeString(fullPath);
824 ::SysFreeString(baseAddrName);
825 ::SysFreeString(sizeName);
826 ::SysFreeString(timeStampName);
827 ::SysFreeString(fileVerName);
828 ::SysFreeString(prodVerName);
829 SAFERELEASE(pNode2);
830 SAFERELEASE(pNewNode);
831 SAFERELEASE(pElement);
832 SAFERELEASE(pElement2);
834 return pNode;
837 //-----------------------------------------------------------------------------
838 // CreateMsgNode
840 // Builds the application-defined message node
842 MSXML2::IXMLDOMNode *
843 CExceptionReport::CreateMsgNode(MSXML2::IXMLDOMDocument* pDoc, BSTR message)
845 MSXML2::IXMLDOMNode* pNode = NULL;
846 MSXML2::IXMLDOMElement* pElement = NULL;
847 BSTR nodeName = ::SysAllocString(L"ApplicationDescription");
849 // Create CrashDescription record node
850 pNode = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, nodeName);
852 // Get element interface
853 CHECKHR(pNode->QueryInterface(MSXML2::IID_IXMLDOMElement, (void**)&pElement));
855 pElement->put_text(message);
857 CleanUp:
858 ::SysFreeString(nodeName);
859 SAFERELEASE(pElement);
861 return pNode;
864 //-----------------------------------------------------------------------------
865 // CreateWalkbackEntryNode
867 // Create a single node in the stack walback
869 void
870 CExceptionReport::CreateWalkbackEntryNode(DWORD_PTR address, const char *ImageName,
871 const char *FunctionName, DWORD_PTR functionDisp,
872 const char *Filename, DWORD LineNumber, DWORD lineDisp,
873 void *data)
875 MSXML2::IXMLDOMNode* pNode = NULL;
876 MSXML2::IXMLDOMElement* pElement = NULL;
877 MSXML2::IXMLDOMNode* pNewNode = NULL;
878 string sAddr;
879 BSTR nodeName = ::SysAllocString(L"Frame");
880 BSTR frameName = ::SysAllocString(L"FrameNumber");
881 BSTR addrName = ::SysAllocString(L"ReturnAddress");
882 BSTR moduleName = ::SysAllocString(L"ModuleName");
883 BSTR funcName = ::SysAllocString(L"FunctionName");
884 BSTR funcDispName = ::SysAllocString(L"FunctionDisplacement");
885 BSTR fileName = ::SysAllocString(L"Filename");
886 BSTR lineName = ::SysAllocString(L"LineNumber");
887 BSTR lineDispName = ::SysAllocString(L"LineDisplacement");
888 CExceptionReport *self = reinterpret_cast<CExceptionReport *>(data);
890 // Create frame record node
891 pNode = self->CreateDOMNode(self->m_stack_doc, MSXML2::NODE_ELEMENT, nodeName);
893 // Get element interface
894 CHECKHR(pNode->QueryInterface(MSXML2::IID_IXMLDOMElement, (void**)&pElement));
897 VARIANT v;
899 self->m_frameNumber++;
900 TCHAR buf[MAX_PATH] = {0};
901 _tprintf_s(buf, _T("%d"), self->m_frameNumber);
903 V_VT(&v) = VT_BSTR;
904 V_BSTR(&v) = CUtility::AllocSysString(buf);
905 pElement->setAttribute(frameName, v);
906 // Recycle variant
907 SysFreeString(V_BSTR(&v));
909 _tprintf_s(buf, offsetFormat, address);
910 V_VT(&v) = VT_BSTR;
911 V_BSTR(&v) = CUtility::AllocSysString(buf);
912 pElement->setAttribute(addrName, v);
913 // Recycle variant
914 SysFreeString(V_BSTR(&v));
916 if (ImageName != NULL) {
917 V_VT(&v) = VT_BSTR;
918 V_BSTR(&v) = CUtility::AllocSysString(ImageName);
919 pElement->setAttribute(moduleName, v);
920 // Recycle variant
921 SysFreeString(V_BSTR(&v));
924 if (FunctionName != NULL) {
925 V_VT(&v) = VT_BSTR;
926 V_BSTR(&v) = CUtility::AllocSysString(FunctionName);
927 pElement->setAttribute(funcName, v);
928 // Recycle variant
929 SysFreeString(V_BSTR(&v));
930 _tprintf_s(buf, offsetFormat, functionDisp);
931 V_VT(&v) = VT_BSTR;
932 V_BSTR(&v) = CUtility::AllocSysString(buf);
933 pElement->setAttribute(funcDispName, v);
934 // Recycle variant
935 SysFreeString(V_BSTR(&v));
938 if (Filename != NULL) {
939 V_VT(&v) = VT_BSTR;
940 V_BSTR(&v) = CUtility::AllocSysString(Filename);
941 pElement->setAttribute(fileName, v);
942 // Recycle variant
943 SysFreeString(V_BSTR(&v));
945 _tprintf_s(buf, _T("%d"), LineNumber);
946 V_VT(&v) = VT_BSTR;
947 V_BSTR(&v) = CUtility::AllocSysString(buf);
948 pElement->setAttribute(lineName, v);
949 // Recycle variant
950 SysFreeString(V_BSTR(&v));
952 _tprintf_s(buf, offsetFormat, lineDisp);
953 V_VT(&v) = VT_BSTR;
954 V_BSTR(&v) = CUtility::AllocSysString(buf);
955 pElement->setAttribute(lineDispName, v);
956 // Recycle variant
957 SysFreeString(V_BSTR(&v));
959 // add to walkback element
961 self->m_stack_element->appendChild(pNode, &pNewNode);
962 SAFERELEASE(pNewNode);
963 // The XML Document should now own the node.
964 CleanUp:
965 SAFERELEASE(pNode);
966 SAFERELEASE(pElement);
967 ::SysFreeString(nodeName);
968 ::SysFreeString(frameName);
969 ::SysFreeString(addrName);
970 ::SysFreeString(moduleName);
971 ::SysFreeString(funcName);
972 ::SysFreeString(funcDispName);
973 ::SysFreeString(fileName);
974 ::SysFreeString(lineName);
975 ::SysFreeString(lineDispName);
978 //-----------------------------------------------------------------------------
979 // CreateWalkbackNode
981 // Builds the stack walkback list
983 MSXML2::IXMLDOMNode *
984 CExceptionReport::CreateWalkbackNode(MSXML2::IXMLDOMDocument* pDoc, CONTEXT *pContext)
986 MSXML2::IXMLDOMNode* pNode = NULL;
988 MSXML2::IXMLDOMElement* pElement = NULL;
989 BSTR nodeName = ::SysAllocString(L"CallStack");
991 // Create CallStack record node
992 pNode = CreateDOMNode(pDoc, MSXML2::NODE_ELEMENT, nodeName);
994 // Get element interface
995 CHECKHR(pNode->QueryInterface(MSXML2::IID_IXMLDOMElement, (void**)&pElement));
997 // create the trace
998 // set static variables for use by CreateWalkbackEntryNode
999 m_stack_element = pElement;
1000 m_stack_doc = pDoc;
1001 m_frameNumber = 0;
1002 // If no context is supplied, skip 1 frames:
1003 // 1 this function
1004 // ??
1005 DoStackTrace(pContext == NULL ? 1 : 0, 9999, CreateWalkbackEntryNode, pContext, this);
1007 CleanUp:
1008 ::SysFreeString(nodeName);
1009 SAFERELEASE(pElement);
1011 return pNode;
1014 //-----------------------------------------------------------------------------
1015 // CExceptionReport::miniDumpCallback
1017 // Mini dump module callback. Hit once for each module processed by
1018 // MiniDumpWriteDump. Builds a linked list of all module names which is
1019 // eventually used to create the <modules> node in the XML log file.
1021 BOOL CALLBACK
1022 CExceptionReport::miniDumpCallback(PVOID data,
1023 CONST PMINIDUMP_CALLBACK_INPUT CallbackInput,
1024 PMINIDUMP_CALLBACK_OUTPUT)
1026 CExceptionReport *self = reinterpret_cast<CExceptionReport*>(data);
1027 if (ModuleCallback == CallbackInput->CallbackType)
1029 MINIDUMP_MODULE_CALLBACK item;
1031 item = CallbackInput->Module;
1032 item.FullPath = _wcsdup(CallbackInput->Module.FullPath);
1033 self->m_modules.push_back(item);
1036 return TRUE;