PageRenderTime 69ms CodeModel.GetById 13ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/processing/crashrptprobe/MinidumpReader.cpp

http://crashrpt.googlecode.com/
C++ | 879 lines | 654 code | 118 blank | 107 comment | 63 complexity | 9c69896e0de2e60298c019a5109d1aff MD5 | raw file
  1/************************************************************************************* 
  2This file is a part of CrashRpt library.
  3Copyright (c) 2003-2013 The CrashRpt project authors. All Rights Reserved.
  4
  5Use of this source code is governed by a BSD-style license
  6that can be found in the License.txt file in the root of the source
  7tree. All contributing project authors may
  8be found in the Authors.txt file in the root of the source tree.
  9***************************************************************************************/
 10
 11#include "stdafx.h"
 12#include "MinidumpReader.h"
 13#include <assert.h>
 14#include "Utility.h"
 15#include "strconv.h"
 16#include "md5.h"
 17
 18CMiniDumpReader* g_pMiniDumpReader = NULL;
 19
 20// Callback function prototypes
 21
 22BOOL CALLBACK ReadProcessMemoryProc64(
 23                                      HANDLE hProcess,
 24                                      DWORD64 lpBaseAddress,
 25                                      PVOID lpBuffer,
 26                                      DWORD nSize,
 27                                      LPDWORD lpNumberOfBytesRead);
 28
 29PVOID CALLBACK FunctionTableAccessProc64(
 30    HANDLE hProcess,
 31    DWORD64 AddrBase);
 32
 33DWORD64 CALLBACK GetModuleBaseProc64(
 34                                     HANDLE hProcess,
 35                                     DWORD64 Address);
 36
 37BOOL CALLBACK SymRegisterCallbackProc64(
 38                                        HANDLE hProcess,
 39                                        ULONG ActionCode,
 40                                        ULONG64 CallbackData,
 41                                        ULONG64 UserContext
 42                                        );
 43
 44CMiniDumpReader::CMiniDumpReader()
 45{
 46    m_bLoaded = FALSE;
 47    m_bReadSysInfoStream = FALSE;
 48    m_bReadExceptionStream = FALSE;
 49    m_bReadModuleListStream = FALSE;
 50    m_bReadMemoryListStream = FALSE;
 51    m_bReadThreadListStream = FALSE;
 52    m_hFileMiniDump = INVALID_HANDLE_VALUE;
 53    m_hFileMapping = NULL;
 54    m_pMiniDumpStartPtr = NULL;  
 55}
 56
 57CMiniDumpReader::~CMiniDumpReader()
 58{
 59    Close();
 60}
 61
 62int CMiniDumpReader::Open(CString sFileName, CString sSymSearchPath)
 63{  
 64    static DWORD dwProcessID = 0;
 65
 66    if(m_bLoaded)
 67    {
 68		// Already loaded
 69        return 0;
 70    }
 71
 72    m_sFileName = sFileName;
 73    m_sSymSearchPath = sSymSearchPath;
 74
 75    m_hFileMiniDump = CreateFile(
 76        sFileName, 
 77        FILE_GENERIC_READ, 
 78        0, 
 79        NULL, 
 80        OPEN_EXISTING, 
 81        NULL, 
 82        NULL);
 83
 84    if(m_hFileMiniDump==INVALID_HANDLE_VALUE)
 85    {
 86        Close();
 87        return 1;
 88    }
 89
 90    m_hFileMapping = CreateFileMapping(
 91        m_hFileMiniDump, 
 92        NULL, 
 93        PAGE_READONLY, 
 94        0, 
 95        0, 
 96        0);
 97
 98    if(m_hFileMapping==NULL)
 99    {
100        Close();
101        return 2;
102    }
103
104    m_pMiniDumpStartPtr = MapViewOfFile(
105        m_hFileMapping, 
106        FILE_MAP_READ, 
107        0, 
108        0, 
109        0);
110
111    if(m_pMiniDumpStartPtr==NULL)
112    {    
113        Close();
114        return 3;
115    }
116
117    m_DumpData.m_hProcess = (HANDLE)(++dwProcessID);  
118
119    DWORD dwOptions = 0;
120    //dwOptions |= SYMOPT_DEFERRED_LOADS; // Symbols are not loaded until a reference is made requiring the symbols be loaded.
121    dwOptions |= SYMOPT_EXACT_SYMBOLS; // Do not load an unmatched .pdb file. 
122    dwOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; // Do not display system dialog boxes when there is a media failure such as no media in a drive.
123    dwOptions |= SYMOPT_UNDNAME; // All symbols are presented in undecorated form.   
124    SymSetOptions(dwOptions);
125
126    strconv_t strconv;
127    BOOL bSymInit = SymInitializeW(
128        m_DumpData.m_hProcess,
129        strconv.t2w(sSymSearchPath), 
130        FALSE);
131
132    if(!bSymInit)
133    {
134        m_DumpData.m_hProcess = NULL;
135        Close();
136        return 5;
137    }
138
139    /*SymRegisterCallbackW64(
140    m_DumpData.m_hProcess, 
141    SymRegisterCallbackProc64,
142    (ULONG64)this);*/
143
144    m_bReadSysInfoStream = !ReadSysInfoStream();  
145    m_bReadModuleListStream = !ReadModuleListStream();
146    m_bReadThreadListStream = !ReadThreadListStream();
147    m_bReadMemoryListStream = !ReadMemoryListStream();    
148    m_bReadExceptionStream = !ReadExceptionStream();    
149
150    m_bLoaded = true;
151    return 0;
152}
153
154//BOOL CALLBACK SymRegisterCallbackProc64(
155//  HANDLE hProcess,
156//  ULONG ActionCode,
157//  ULONG64 CallbackData,
158//  ULONG64 UserContext
159//)
160//{
161//  UNREFERENCED_PARAMETER(hProcess);
162//  CMiniDumpReader* pMdmpReader = (CMiniDumpReader*)UserContext;
163//
164//  switch(ActionCode)
165//  {
166//  case CBA_DEBUG_INFO:
167//    {
168//      LPCTSTR szMessage = (LPCTSTR)CallbackData;
169//      pMdmpReader->m_DumpData.m_LoadLog.push_back(szMessage);
170//    } 
171//    return TRUE;   
172//  case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
173//    {
174//      // Ignore      
175//    } 
176//    return FALSE;    
177//  case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
178//    {
179//      IMAGEHLP_DEFERRED_SYMBOL_LOADW64* pLoadInfo = 
180//        (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)CallbackData;
181//      CString sMessage;
182//      sMessage.Format(_T("Completed loading symbols for %s."), pLoadInfo->FileName);
183//      //pMdmpReader->m_DumpData.m_LoadLog.push_back(sMessage);
184//    }
185//    return TRUE;
186//  case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
187//    {
188//      IMAGEHLP_DEFERRED_SYMBOL_LOADW64* pLoadInfo = 
189//        (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)CallbackData;
190//      CString sMessage;
191//      sMessage.Format(_T("Failed to loaded symbols for %s."), pLoadInfo->FileName);
192//      pMdmpReader->m_DumpData.m_LoadLog.push_back(sMessage);
193//    }
194//    return TRUE;
195//  case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
196//    {
197//      IMAGEHLP_DEFERRED_SYMBOL_LOADW64* pLoadInfo = 
198//        (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)CallbackData;
199//      CString sMessage;
200//      sMessage.Format(_T("Partially loaded symbols for %s."), pLoadInfo->FileName);
201//      pMdmpReader->m_DumpData.m_LoadLog.push_back(sMessage);
202//    }
203//    return TRUE;
204//  case CBA_DEFERRED_SYMBOL_LOAD_START:
205//    {
206//      IMAGEHLP_DEFERRED_SYMBOL_LOADW64* pLoadInfo = 
207//        (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)CallbackData;
208//      CString sMessage;
209//      sMessage.Format(_T("Started loading symbols for %s."), pLoadInfo->FileName);
210//      //pMdmpReader->m_DumpData.m_LoadLog.push_back(sMessage);
211//    }
212//    return TRUE;
213//  }
214//
215//  return FALSE;
216//}
217
218void CMiniDumpReader::Close()
219{
220    UnmapViewOfFile(m_pMiniDumpStartPtr);
221
222    if(m_hFileMapping!=NULL)
223    {
224        CloseHandle(m_hFileMapping);
225    }
226
227    if(m_hFileMiniDump!=INVALID_HANDLE_VALUE)
228    {
229        CloseHandle(m_hFileMiniDump);
230		m_hFileMiniDump = INVALID_HANDLE_VALUE;
231    }
232
233    m_pMiniDumpStartPtr = NULL;
234
235    if(m_DumpData.m_hProcess!=NULL)
236    {
237        SymCleanup(m_DumpData.m_hProcess);
238    }
239}
240
241BOOL CMiniDumpReader::CheckDbgHelpApiVersion()
242{
243    // Set valid dbghelp API version
244    API_VERSION CompiledApiVer;
245    CompiledApiVer.MajorVersion = 6;
246    CompiledApiVer.MinorVersion = 1;
247    CompiledApiVer.Revision = 11;    
248    CompiledApiVer.Reserved = 0;
249    LPAPI_VERSION pActualApiVer = ImagehlpApiVersionEx(&CompiledApiVer);    
250    if(CompiledApiVer.MajorVersion!=pActualApiVer->MajorVersion ||
251        CompiledApiVer.MinorVersion!=pActualApiVer->MinorVersion ||
252        CompiledApiVer.Revision!=pActualApiVer->Revision)
253    {     
254        return FALSE; // Not exact version of dbghelp.dll! Expected v6.11.
255    }
256
257    return TRUE;
258}
259
260// Extracts a UNICODE string stored in minidump file by its relative address
261CString CMiniDumpReader::GetMinidumpString(LPVOID start_addr, RVA rva)
262{
263    MINIDUMP_STRING* pms = (MINIDUMP_STRING*)((LPBYTE)start_addr+rva);
264    //CString sModule = CString(pms->Buffer, pms->Length);
265    CString sModule = pms->Buffer;  
266    return sModule;
267}
268
269int CMiniDumpReader::ReadSysInfoStream()
270{
271    LPVOID pStreamStart = NULL;
272    ULONG uStreamSize = 0;
273    MINIDUMP_DIRECTORY* pmd = NULL;
274    BOOL bRead = FALSE;
275
276    bRead = MiniDumpReadDumpStream(m_pMiniDumpStartPtr, SystemInfoStream, 
277        &pmd, &pStreamStart, &uStreamSize);
278
279    if(bRead)
280    {
281        MINIDUMP_SYSTEM_INFO* pSysInfo = (MINIDUMP_SYSTEM_INFO*)pStreamStart;
282
283        m_DumpData.m_uProcessorArchitecture = pSysInfo->ProcessorArchitecture;
284        m_DumpData.m_uchNumberOfProcessors = pSysInfo->NumberOfProcessors;
285        m_DumpData.m_uchProductType = pSysInfo->ProductType;
286        m_DumpData.m_ulVerMajor = pSysInfo->MajorVersion;
287        m_DumpData.m_ulVerMinor = pSysInfo->MinorVersion;
288        m_DumpData.m_ulVerBuild = pSysInfo->BuildNumber;
289        m_DumpData.m_sCSDVer = GetMinidumpString(m_pMiniDumpStartPtr, pSysInfo->CSDVersionRva);
290
291        // Clean up
292        pStreamStart = NULL;
293        uStreamSize = 0;    
294        pmd = NULL;
295    }
296    else 
297    {
298        return 1;    
299    }
300
301    return 0;
302}
303
304int CMiniDumpReader::ReadExceptionStream()
305{
306    LPVOID pStreamStart = NULL;
307    ULONG uStreamSize = 0;
308    MINIDUMP_DIRECTORY* pmd = NULL;
309    BOOL bRead = FALSE;
310
311    bRead = MiniDumpReadDumpStream(
312        m_pMiniDumpStartPtr, 
313        ExceptionStream, 
314        &pmd, 
315        &pStreamStart, 
316        &uStreamSize);
317
318    if(bRead)
319    {
320        MINIDUMP_EXCEPTION_STREAM* pExceptionStream = (MINIDUMP_EXCEPTION_STREAM*)pStreamStart;
321        if(pExceptionStream!=NULL && 
322            uStreamSize>=sizeof(MINIDUMP_EXCEPTION_STREAM))
323        {
324            m_DumpData.m_uExceptionThreadId = pExceptionStream->ThreadId;
325            m_DumpData.m_uExceptionCode = pExceptionStream->ExceptionRecord.ExceptionCode;
326            m_DumpData.m_uExceptionAddress = pExceptionStream->ExceptionRecord.ExceptionAddress;          
327            m_DumpData.m_pExceptionThreadContext = 
328                (CONTEXT*)(((LPBYTE)m_pMiniDumpStartPtr)+pExceptionStream->ThreadContext.Rva);      
329
330            CString sMsg;
331            int nExcModuleRowID = GetModuleRowIdByAddress(m_DumpData.m_uExceptionAddress);
332            if(nExcModuleRowID>=0)
333            {
334                sMsg.Format(_T("Unhandled exception at 0x%I64x in %s: 0x%x : %s"),
335                    m_DumpData.m_uExceptionAddress,
336                    m_DumpData.m_Modules[nExcModuleRowID].m_sModuleName,
337                    m_DumpData.m_uExceptionCode,
338                    _T("Exception description.")
339                    );
340            }
341            else
342            {
343
344            }
345            m_DumpData.m_LoadLog.push_back(sMsg);
346        }    
347    }
348    else
349    {
350        CString sMsg;
351        sMsg = _T("No exception information found in minidump.");
352        m_DumpData.m_LoadLog.push_back(sMsg);
353        return 1;
354    }
355
356    return 0;
357}
358
359int CMiniDumpReader::ReadModuleListStream()
360{
361    LPVOID pStreamStart = NULL;
362    ULONG uStreamSize = 0;
363    MINIDUMP_DIRECTORY* pmd = NULL;
364    BOOL bRead = FALSE;
365    strconv_t strconv;
366
367    bRead = MiniDumpReadDumpStream(
368        m_pMiniDumpStartPtr, 
369        ModuleListStream, 
370        &pmd, 
371        &pStreamStart, 
372        &uStreamSize);
373
374    if(bRead)
375    {
376        MINIDUMP_MODULE_LIST* pModuleStream = (MINIDUMP_MODULE_LIST*)pStreamStart;
377        if(pModuleStream!=NULL)
378        {
379            ULONG32 uNumberOfModules = pModuleStream->NumberOfModules;
380            ULONG32 i;
381            for(i=0; i<uNumberOfModules; i++)
382            {
383                MINIDUMP_MODULE* pModule = 
384                    (MINIDUMP_MODULE*)((LPBYTE)pModuleStream->Modules+i*sizeof(MINIDUMP_MODULE));
385
386                CString sModuleName = GetMinidumpString(m_pMiniDumpStartPtr, pModule->ModuleNameRva);               
387                LPCWSTR szModuleName = strconv.t2w(sModuleName);
388                DWORD64 dwBaseAddr = pModule->BaseOfImage;
389                DWORD64 dwImageSize = pModule->SizeOfImage;
390
391                CString sShortModuleName = sModuleName;
392                int pos = -1;
393                pos = sModuleName.ReverseFind('\\');
394                if(pos>=0)
395                    sShortModuleName = sShortModuleName.Mid(pos+1);          
396
397                /*DWORD64 dwLoadResult = */SymLoadModuleExW(
398                    m_DumpData.m_hProcess,
399                    NULL,
400                    (PWSTR)szModuleName,
401                    NULL,
402                    dwBaseAddr,
403                    (DWORD)dwImageSize,
404                    NULL,
405                    0);         
406
407                IMAGEHLP_MODULE64 modinfo;
408                memset(&modinfo, 0, sizeof(IMAGEHLP_MODULE64));
409                modinfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
410                BOOL bModuleInfo = SymGetModuleInfo64(m_DumpData.m_hProcess,
411                    dwBaseAddr, 
412                    &modinfo);
413                MdmpModule m;
414                if(!bModuleInfo)
415                {          
416                    m.m_bImageUnmatched = TRUE;
417                    m.m_bNoSymbolInfo = TRUE;
418                    m.m_bPdbUnmatched = TRUE;
419                    m.m_pVersionInfo = NULL;
420                    m.m_sImageName = sModuleName;
421                    m.m_sModuleName = sShortModuleName;
422                    m.m_uBaseAddr = dwBaseAddr;
423                    m.m_uImageSize = dwImageSize;          
424                }
425                else
426                {          
427                    m.m_uBaseAddr = modinfo.BaseOfImage;
428                    m.m_uImageSize = modinfo.ImageSize;        
429                    m.m_sModuleName = sShortModuleName;
430                    m.m_sImageName = modinfo.ImageName;
431                    m.m_sLoadedImageName = modinfo.LoadedImageName;
432                    m.m_sLoadedPdbName = modinfo.LoadedPdbName;
433                    m.m_pVersionInfo = &pModule->VersionInfo;
434                    m.m_bPdbUnmatched = modinfo.PdbUnmatched;          
435                    BOOL bTimeStampMatched = pModule->TimeDateStamp == modinfo.TimeDateStamp;
436                    m.m_bImageUnmatched = !bTimeStampMatched;
437                    m.m_bNoSymbolInfo = !modinfo.GlobalSymbols;
438                }        
439
440                m_DumpData.m_Modules.push_back(m);
441                m_DumpData.m_ModuleIndex[m.m_uBaseAddr] = m_DumpData.m_Modules.size()-1;          
442
443                CString sMsg;
444                if(m.m_bImageUnmatched)
445                    sMsg.Format(_T("Loaded '*%s'"), sModuleName);
446                else
447                    sMsg.Format(_T("Loaded '%s'"), m.m_sLoadedImageName);
448
449                if(m.m_bImageUnmatched)
450                    sMsg += _T(", No matching binary found.");          
451                else if(m.m_bPdbUnmatched)
452                    sMsg += _T(", No matching PDB file found.");          
453                else
454                {
455                    if(m.m_bNoSymbolInfo)            
456                        sMsg += _T(", No symbols loaded.");          
457                    else
458                        sMsg += _T(", Symbols loaded.");          
459                }
460                m_DumpData.m_LoadLog.push_back(sMsg);
461            }
462        }
463    }
464    else
465    {
466        return 1;
467    }
468
469    return 0;
470}
471
472int CMiniDumpReader::GetModuleRowIdByBaseAddr(DWORD64 dwBaseAddr)
473{
474    std::map<DWORD64, size_t>::iterator it = m_DumpData.m_ModuleIndex.find(dwBaseAddr);
475    if(it!=m_DumpData.m_ModuleIndex.end())
476        return (int)it->second;
477    return -1;
478}
479
480int CMiniDumpReader::GetModuleRowIdByAddress(DWORD64 dwAddress)
481{
482    UINT i;
483    for(i=0;i<m_DumpData.m_Modules.size();i++)
484    {
485        if(m_DumpData.m_Modules[i].m_uBaseAddr<=dwAddress && 
486            dwAddress<m_DumpData.m_Modules[i].m_uBaseAddr+m_DumpData.m_Modules[i].m_uImageSize)
487            return i;
488    }
489
490    return -1;
491}
492
493int CMiniDumpReader::GetThreadRowIdByThreadId(DWORD dwThreadId)
494{
495    std::map<DWORD, size_t>::iterator it = m_DumpData.m_ThreadIndex.find(dwThreadId);
496    if(it!=m_DumpData.m_ThreadIndex.end())
497        return (int)it->second;
498    return -1;
499}
500
501int CMiniDumpReader::ReadMemoryListStream()
502{
503    LPVOID pStreamStart = NULL;
504    ULONG uStreamSize = 0;
505    MINIDUMP_DIRECTORY* pmd = NULL;
506    BOOL bRead = FALSE;
507
508    bRead = MiniDumpReadDumpStream(
509        m_pMiniDumpStartPtr, 
510        MemoryListStream, 
511        &pmd, 
512        &pStreamStart, 
513        &uStreamSize);
514
515    if(bRead)
516    {
517        MINIDUMP_MEMORY_LIST* pMemStream = (MINIDUMP_MEMORY_LIST*)pStreamStart;
518        if(pMemStream!=NULL)
519        {
520            ULONG32 uNumberOfMemRanges = pMemStream->NumberOfMemoryRanges;
521            ULONG i;
522            for(i=0; i<uNumberOfMemRanges; i++)
523            {
524                MINIDUMP_MEMORY_DESCRIPTOR* pMemDesc = (MINIDUMP_MEMORY_DESCRIPTOR*)(&pMemStream->MemoryRanges[i]);
525                MdmpMemRange mr;
526                mr.m_u64StartOfMemoryRange = pMemDesc->StartOfMemoryRange;
527                mr.m_uDataSize = pMemDesc->Memory.DataSize;
528                mr.m_pStartPtr = (LPBYTE)m_pMiniDumpStartPtr+pMemDesc->Memory.Rva;
529
530                m_DumpData.m_MemRanges.push_back(mr);
531            }
532        }
533    }
534    else    
535    {
536        return 1;
537    }
538
539    return 0;
540}
541
542int CMiniDumpReader::ReadThreadListStream()
543{
544    LPVOID pStreamStart = NULL;
545    ULONG uStreamSize = 0;
546    MINIDUMP_DIRECTORY* pmd = NULL;
547    BOOL bRead = FALSE;
548
549    bRead = MiniDumpReadDumpStream(
550        m_pMiniDumpStartPtr, 
551        ThreadListStream, 
552        &pmd, 
553        &pStreamStart, 
554        &uStreamSize);
555
556    if(bRead)
557    {
558        MINIDUMP_THREAD_LIST* pThreadList = (MINIDUMP_THREAD_LIST*)pStreamStart;
559        if(pThreadList!=NULL && 
560            uStreamSize>=sizeof(MINIDUMP_THREAD_LIST))
561        {
562            ULONG32 uThreadCount = pThreadList->NumberOfThreads;
563
564            ULONG32 i;
565            for(i=0; i<uThreadCount; i++)
566            {
567                MINIDUMP_THREAD* pThread = (MINIDUMP_THREAD*)(&pThreadList->Threads[i]);
568
569                MdmpThread mt;
570                mt.m_dwThreadId = pThread->ThreadId;
571                mt.m_pThreadContext = (CONTEXT*)(((LPBYTE)m_pMiniDumpStartPtr)+pThread->ThreadContext.Rva);
572
573                m_DumpData.m_Threads.push_back(mt);
574                m_DumpData.m_ThreadIndex[mt.m_dwThreadId] = m_DumpData.m_Threads.size()-1;        
575            }
576        }  
577    }
578    else
579    {
580        return 1;
581    }
582
583    return 0;
584}
585
586int CMiniDumpReader::StackWalk(DWORD dwThreadId)
587{ 
588    int nThreadIndex = GetThreadRowIdByThreadId(dwThreadId);
589    if(m_DumpData.m_Threads[nThreadIndex].m_bStackWalk == TRUE)
590        return 0; // Already done
591
592    CONTEXT* pThreadContext = NULL;
593
594    if(m_DumpData.m_Threads[nThreadIndex].m_dwThreadId==m_DumpData.m_uExceptionThreadId)
595        pThreadContext = m_DumpData.m_pExceptionThreadContext;
596    else
597        pThreadContext = m_DumpData.m_Threads[nThreadIndex].m_pThreadContext;  
598
599    if(pThreadContext==NULL)
600        return 1;
601
602    // Make modifiable context
603    CONTEXT Context;
604    memcpy(&Context, pThreadContext, sizeof(CONTEXT));
605
606    g_pMiniDumpReader = this;
607
608    // Init stack frame with correct initial values
609    // See this:
610    // http://www.codeproject.com/KB/threads/StackWalker.aspx
611    //
612    // Given a current dbghelp, your code should:
613    //  1. Always use StackWalk64
614    //  2. Always set AddrPC to the current instruction pointer (Eip on x86, Rip on x64 and StIIP on IA64)
615    //  3. Always set AddrStack to the current stack pointer (Esp on x86, Rsp on x64 and IntSp on IA64)
616    //  4. Set AddrFrame to the current frame pointer when meaningful. On x86 this is Ebp, on x64 you 
617    //     can use Rbp (but is not used by VC2005B2; instead it uses Rdi!) and on IA64 you can use RsBSP. 
618    //     StackWalk64 will ignore the value when it isn't needed for unwinding.
619    //  5. Set AddrBStore to RsBSP for IA64. 
620
621    STACKFRAME64 sf;
622    memset(&sf, 0, sizeof(STACKFRAME64));
623
624    sf.AddrPC.Mode = AddrModeFlat;  
625    sf.AddrFrame.Mode = AddrModeFlat;  
626    sf.AddrStack.Mode = AddrModeFlat;  
627    sf.AddrBStore.Mode = AddrModeFlat;  
628
629    DWORD dwMachineType = 0;
630    switch(m_DumpData.m_uProcessorArchitecture)
631    {
632#ifdef _X86_
633  case PROCESSOR_ARCHITECTURE_INTEL: 
634      dwMachineType = IMAGE_FILE_MACHINE_I386;
635      sf.AddrPC.Offset = pThreadContext->Eip;    
636      sf.AddrStack.Offset = pThreadContext->Esp;
637      sf.AddrFrame.Offset = pThreadContext->Ebp;
638      break;
639#endif
640#ifdef _AMD64_
641  case PROCESSOR_ARCHITECTURE_AMD64:
642      dwMachineType = IMAGE_FILE_MACHINE_AMD64;
643      sf.AddrPC.Offset = pThreadContext->Rip;    
644      sf.AddrStack.Offset = pThreadContext->Rsp;
645      sf.AddrFrame.Offset = pThreadContext->Rbp;
646      break;
647#endif
648#ifdef _IA64_
649  case PROCESSOR_ARCHITECTURE_AMD64:
650      dwMachineType = IMAGE_FILE_MACHINE_IA64;
651      sf.AddrPC.Offset = pThreadContext->StIIP;
652      sf.AddrStack.Offset = pThreadContext->IntSp;
653      sf.AddrFrame.Offset = pThreadContext->RsBSP;    
654      sf.AddrBStore.Offset = pThreadContext->RsBSP;
655      break;
656#endif 
657  default:
658      {
659          assert(0);
660          return 1; // Unsupported architecture
661      }
662    }
663
664    for(;;)
665    {    
666        BOOL bWalk = ::StackWalk64(
667            dwMachineType,               // machine type
668            m_DumpData.m_hProcess,       // our process handle
669            (HANDLE)dwThreadId,          // thread ID
670            &sf,                         // stack frame
671            dwMachineType==IMAGE_FILE_MACHINE_I386?NULL:(&Context), // used for non-I386 machines 
672            ReadProcessMemoryProc64,     // our routine
673            FunctionTableAccessProc64,   // our routine
674            GetModuleBaseProc64,         // our routine
675            NULL                         // safe to be NULL
676            );
677
678        if(!bWalk)
679            break;      
680
681        MdmpStackFrame stack_frame;
682        stack_frame.m_dwAddrPCOffset = sf.AddrPC.Offset;
683
684        // Get module info
685        IMAGEHLP_MODULE64 mi;
686        memset(&mi, 0, sizeof(IMAGEHLP_MODULE64));
687        mi.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
688        BOOL bGetModuleInfo = SymGetModuleInfo64(m_DumpData.m_hProcess, sf.AddrPC.Offset, &mi);     
689        if(bGetModuleInfo)
690        {
691            stack_frame.m_nModuleRowID = GetModuleRowIdByBaseAddr(mi.BaseOfImage);      
692        }
693
694        // Get symbol info
695        DWORD64 dwDisp64;
696        BYTE buffer[4096];
697        SYMBOL_INFO* sym_info = (SYMBOL_INFO*)buffer;
698        sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
699        sym_info->MaxNameLen = 4096-sizeof(SYMBOL_INFO)-1;
700        BOOL bGetSym = SymFromAddr(
701            m_DumpData.m_hProcess, 
702            sf.AddrPC.Offset, 
703            &dwDisp64, 
704            sym_info);
705
706        if(bGetSym)
707        {
708            stack_frame.m_sSymbolName = CString(sym_info->Name, sym_info->NameLen);
709            stack_frame.m_dw64OffsInSymbol = dwDisp64;
710        }
711
712        // Get source filename and line
713        DWORD dwDisplacement;
714        IMAGEHLP_LINE64 line;
715        BOOL bGetLine = SymGetLineFromAddr64(
716            m_DumpData.m_hProcess, 
717            sf.AddrPC.Offset,
718            &dwDisplacement,
719            &line);
720
721        if(bGetLine)
722        {
723            stack_frame.m_sSrcFileName = line.FileName;
724            stack_frame.m_nSrcLineNumber = line.LineNumber;
725        }
726
727        m_DumpData.m_Threads[nThreadIndex].m_StackTrace.push_back(stack_frame);
728    }
729
730
731    CString sStackTrace;
732    UINT i;
733    for(i=0; i<m_DumpData.m_Threads[nThreadIndex].m_StackTrace.size(); i++)
734    {
735        MdmpStackFrame& frame = m_DumpData.m_Threads[nThreadIndex].m_StackTrace[i];
736
737        if(frame.m_sSymbolName.IsEmpty())
738            continue;
739
740        CString sModuleName;
741        CString sAddrPCOffset;
742        CString sSymbolName;            
743        CString sOffsInSymbol;
744        CString sSourceFile;
745        CString sSourceLine;
746
747        if(frame.m_nModuleRowID>=0)
748        {
749            sModuleName = m_DumpData.m_Modules[frame.m_nModuleRowID].m_sModuleName;
750        }           
751
752        sSymbolName = frame.m_sSymbolName;
753        sAddrPCOffset.Format(_T("0x%I64x"), frame.m_dwAddrPCOffset);
754        sSourceFile = frame.m_sSrcFileName;
755        sSourceLine.Format(_T("%d"), frame.m_nSrcLineNumber);
756        sOffsInSymbol.Format(_T("0x%I64x"), frame.m_dw64OffsInSymbol);
757
758        CString str;
759        str = sModuleName;
760        if(!str.IsEmpty())
761            str += _T("!");
762
763        if(sSymbolName.IsEmpty())
764            str += sAddrPCOffset;  
765        else
766        {
767            str += sSymbolName;
768            str += _T("+");
769            str += sOffsInSymbol;
770        }
771
772        if(!sSourceFile.IsEmpty())
773        {
774            int pos = sSourceFile.ReverseFind('\\');
775            if(pos>=0)
776                sSourceFile = sSourceFile.Mid(pos+1);
777            str += _T(" [ ");
778            str += sSourceFile;
779            str += _T(": ");
780            str += sSourceLine;
781            str += _T(" ] ");
782        } 
783
784        sStackTrace += str; 
785        sStackTrace += _T("\n");
786    }
787
788    if(!sStackTrace.IsEmpty())
789    {
790        strconv_t strconv;
791        LPCSTR szStackTrace = strconv.t2utf8(sStackTrace);
792        MD5 md5;
793        MD5_CTX md5_ctx;
794        unsigned char md5_hash[16];
795        md5.MD5Init(&md5_ctx);  
796        md5.MD5Update(&md5_ctx, (unsigned char*)szStackTrace, (unsigned int)strlen(szStackTrace));  
797        md5.MD5Final(md5_hash, &md5_ctx);
798
799        for(i=0; i<16; i++)
800        {
801            CString number;
802            number.Format(_T("%02x"), md5_hash[i]);
803            m_DumpData.m_Threads[nThreadIndex].m_sStackTraceMD5 += number;
804        }
805    }
806
807    m_DumpData.m_Threads[nThreadIndex].m_bStackWalk = TRUE;
808
809
810    return 0;
811}
812
813// This callback function is used by StackWalk64. It provides access to 
814// ranges of memory stored in minidump file
815BOOL CALLBACK ReadProcessMemoryProc64(
816                                      HANDLE hProcess,
817                                      DWORD64 lpBaseAddress,
818                                      PVOID lpBuffer,
819                                      DWORD nSize,
820                                      LPDWORD lpNumberOfBytesRead)
821{
822    *lpNumberOfBytesRead = 0;
823
824    // Validate input parameters
825    if(hProcess!=g_pMiniDumpReader->m_DumpData.m_hProcess ||
826        lpBaseAddress==NULL ||
827        lpBuffer==NULL ||
828        nSize==0)
829    {
830        // Invalid parameter
831        return FALSE;
832    }
833
834    ULONG i;
835    for(i=0; i<g_pMiniDumpReader->m_DumpData.m_MemRanges.size(); i++)
836    {
837        MdmpMemRange& mr = g_pMiniDumpReader->m_DumpData.m_MemRanges[i];
838        if(lpBaseAddress>=mr.m_u64StartOfMemoryRange &&
839            lpBaseAddress<mr.m_u64StartOfMemoryRange+mr.m_uDataSize)
840        {
841            DWORD64 dwOffs = lpBaseAddress-mr.m_u64StartOfMemoryRange;
842
843            LONG64 lBytesRead = 0;
844
845            if(mr.m_uDataSize-dwOffs>nSize)
846                lBytesRead = nSize;
847            else
848                lBytesRead = mr.m_uDataSize-dwOffs;
849
850            if(lBytesRead<=0 || nSize<lBytesRead)
851                return FALSE;
852
853            *lpNumberOfBytesRead = (DWORD)lBytesRead;
854            memcpy(lpBuffer, (LPBYTE)mr.m_pStartPtr+dwOffs, (size_t)lBytesRead);
855
856            return TRUE;
857        }
858    }
859
860    return FALSE;
861}
862
863// This callback function is used by StackWalk64. It provides access to 
864// function table stored in minidump file
865PVOID CALLBACK FunctionTableAccessProc64(
866    HANDLE hProcess,
867    DWORD64 AddrBase)
868{   
869    return SymFunctionTableAccess64(hProcess, AddrBase);
870}
871
872// This callback function is used by StackWalk64. It provides access to 
873// module list stored in minidump file
874DWORD64 CALLBACK GetModuleBaseProc64(
875                                     HANDLE hProcess,
876                                     DWORD64 Address)
877{  
878    return SymGetModuleBase64(hProcess, Address);
879}