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