青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

大龍的博客

常用鏈接

統計

最新評論

記錄程序崩潰時的調用堆棧

在程序release之后,不可避免的會存在一些bug,測試人員和最終用戶如何在發現bug之后指導開發人員進行更正呢?在MS的網站上,有一篇名為"Under the hook"的文章,講述了如何把程序崩潰時的函數調用情況記錄為日志的方法,對此感興趣的讀者可以去看一看原文,那里提供源代碼和原理的說明。

文章的作者提供了一個MSJExceptionHandler類來實現這一功能,這個類的使用方法很簡單,只要把這個類加入到你的工程中并和你的程序一起編譯就可以了,由于在這個類的實現文件中把自己定義為一個全局的類對象,所以,不用加入任何代碼,#include都不需要。

當程序崩潰時,MSJExceptionHandler就會把崩潰時的堆棧調用情況記錄在一個.rpt文件中,軟件的測試人員或最終用戶只要把這個文件發給你,而你使用記事本打開這個文件就可以查看崩潰原因了。你需要在發行軟件的時候,為你的程序生成一個或幾個map文件,用于定位出錯的文件和函數。(我的另一篇blog中有關于生成map文件和定位錯誤的詳細說明)為了方便使用,這里附上該類的完整代碼:

// msjexhnd.h

#ifndef __MSJEXHND_H__
#define __MSJEXHND_H__

class MSJExceptionHandler
{
    public:
   
    MSJExceptionHandler( );
    ~MSJExceptionHandler( );
   
    void SetLogFileName( PTSTR pszLogFileName );

    private:

    // entry point where control comes on an unhandled exception
    static LONG WINAPI MSJUnhandledExceptionFilter(
                                PEXCEPTION_POINTERS pExceptionInfo );

    // where report info is extracted and generated
    static void GenerateExceptionReport( PEXCEPTION_POINTERS pExceptionInfo );

    // Helper functions
    static LPTSTR GetExceptionString( DWORD dwCode );
    static BOOL GetLogicalAddress(  PVOID addr, PTSTR szModule, DWORD len,
                                    DWORD& section, DWORD& offset );
    static void IntelStackWalk( PCONTEXT pContext );
    static int __cdecl _tprintf(const TCHAR * format, ...);

    // Variables used by the class
    static TCHAR m_szLogFileName[MAX_PATH];
    static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
    static HANDLE m_hReportFile;
};

extern MSJExceptionHandler g_MSJExceptionHandler;   //  global instance of class

#endif

// msjexhnd.cpp

//==========================================
// Matt Pietrek
// Microsoft Systems Journal, April 1997
// FILE: MSJEXHND.CPP
//==========================================

#include <windows.h>
#include <tchar.h>
#include "msjexhnd.h"

//============================== Global Variables =============================

//
// Declare the static variables of the MSJExceptionHandler class
//

TCHAR MSJExceptionHandler::m_szLogFileName[MAX_PATH];
LPTOP_LEVEL_EXCEPTION_FILTER MSJExceptionHandler::m_previousFilter;
HANDLE MSJExceptionHandler::m_hReportFile;


MSJExceptionHandler g_MSJExceptionHandler;  // Declare global instance of class

//============================== Class Methods =============================

//=============
// Constructor
//=============

MSJExceptionHandler::MSJExceptionHandler( )
{
    // Install the unhandled exception filter function
    m_previousFilter = SetUnhandledExceptionFilter(MSJUnhandledExceptionFilter);

    // Figure out what the report file will be named, and store it away
    GetModuleFileName( 0, m_szLogFileName, MAX_PATH );

    // Look for the '.' before the "EXE" extension.  Replace the extension
    // with "RPT"

    PTSTR pszDot = _tcsrchr( m_szLogFileName, _T('.') );
    if ( pszDot )
    {
        pszDot++;   // Advance past the '.'
        if ( _tcslen(pszDot) >= 3 )
            _tcscpy( pszDot, _T("RPT") );   // "RPT" -> "Report"
    }
}

//============
// Destructor
//============

MSJExceptionHandler::~MSJExceptionHandler( )
{
    SetUnhandledExceptionFilter( m_previousFilter );
}

//==============================================================
// Lets user change the name of the report file to be generated
//==============================================================

void MSJExceptionHandler::SetLogFileName( PTSTR pszLogFileName )
{
    _tcscpy( m_szLogFileName, pszLogFileName );
}

//===========================================================
// Entry point where control comes on an unhandled exception
//===========================================================

LONG WINAPI MSJExceptionHandler::MSJUnhandledExceptionFilter(
                                    PEXCEPTION_POINTERS pExceptionInfo )
{
    m_hReportFile = CreateFile( m_szLogFileName,
                                GENERIC_WRITE,
                                0,
                                0,
                                OPEN_ALWAYS,
                                FILE_FLAG_WRITE_THROUGH,
                                0 );

    if ( m_hReportFile )
    {
        SetFilePointer( m_hReportFile, 0, 0, FILE_END );

        GenerateExceptionReport( pExceptionInfo );

        CloseHandle( m_hReportFile );
        m_hReportFile = 0;
    }

    if ( m_previousFilter )
        return m_previousFilter( pExceptionInfo );
    else
        return EXCEPTION_CONTINUE_SEARCH;
}

//===========================================================================
// Open the report file, and write the desired information to it.  Called by
// MSJUnhandledExceptionFilter                                              
//===========================================================================
void MSJExceptionHandler::GenerateExceptionReport(
    PEXCEPTION_POINTERS pExceptionInfo )
{
    // Start out with a banner
    _tprintf( _T("http://=====================================================\n") );

    PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;

    // First print information about the type of fault
    _tprintf(   _T("Exception code: %08X %s\n"),
                pExceptionRecord->ExceptionCode,
                GetExceptionString(pExceptionRecord->ExceptionCode) );

    // Now print information about where the fault occured
    TCHAR szFaultingModule[MAX_PATH];
    DWORD section, offset;
    GetLogicalAddress(  pExceptionRecord->ExceptionAddress,
                        szFaultingModule,
                        sizeof( szFaultingModule ),
                        section, offset );

    _tprintf( _T("Fault address:  %08X %02X:%08X %s\n"),
                pExceptionRecord->ExceptionAddress,
                section, offset, szFaultingModule );

    PCONTEXT pCtx = pExceptionInfo->ContextRecord;

    // Show the registers
    #ifdef _M_IX86  // Intel Only!
    _tprintf( _T("\nRegisters:\n") );

    _tprintf(_T("EAX:%08X\nEBX:%08X\nECX:%08X\nEDX:%08X\nESI:%08X\nEDI:%08X\n"),
            pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, pCtx->Esi, pCtx->Edi );

    _tprintf( _T("CS:EIP:%04X:%08X\n"), pCtx->SegCs, pCtx->Eip );
    _tprintf( _T("SS:ESP:%04X:%08X  EBP:%08X\n"),
                pCtx->SegSs, pCtx->Esp, pCtx->Ebp );
    _tprintf( _T("DS:%04X  ES:%04X  FS:%04X  GS:%04X\n"),
                pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs );
    _tprintf( _T("Flags:%08X\n"), pCtx->EFlags );

    // Walk the stack using x86 specific code
    IntelStackWalk( pCtx );

    #endif

    _tprintf( _T("\n") );
}

//======================================================================
// Given an exception code, returns a pointer to a static string with a
// description of the exception                                        
//======================================================================

LPTSTR MSJExceptionHandler::GetExceptionString( DWORD dwCode )
{
    #define EXCEPTION( x ) case EXCEPTION_##x: return _T(#x);

    switch ( dwCode )
    {
        EXCEPTION( ACCESS_VIOLATION )
        EXCEPTION( DATATYPE_MISALIGNMENT )
        EXCEPTION( BREAKPOINT )
        EXCEPTION( SINGLE_STEP )
        EXCEPTION( ARRAY_BOUNDS_EXCEEDED )
        EXCEPTION( FLT_DENORMAL_OPERAND )
        EXCEPTION( FLT_DIVIDE_BY_ZERO )
        EXCEPTION( FLT_INEXACT_RESULT )
        EXCEPTION( FLT_INVALID_OPERATION )
        EXCEPTION( FLT_OVERFLOW )
        EXCEPTION( FLT_STACK_CHECK )
        EXCEPTION( FLT_UNDERFLOW )
        EXCEPTION( INT_DIVIDE_BY_ZERO )
        EXCEPTION( INT_OVERFLOW )
        EXCEPTION( PRIV_INSTRUCTION )
        EXCEPTION( IN_PAGE_ERROR )
        EXCEPTION( ILLEGAL_INSTRUCTION )
        EXCEPTION( NONCONTINUABLE_EXCEPTION )
        EXCEPTION( STACK_OVERFLOW )
        EXCEPTION( INVALID_DISPOSITION )
        EXCEPTION( GUARD_PAGE )
        EXCEPTION( INVALID_HANDLE )
    }

    // If not one of the "known" exceptions, try to get the string
    // from NTDLL.DLL's message table.

    static TCHAR szBuffer[512] = { 0 };

    FormatMessage(  FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
                    GetModuleHandle( _T("NTDLL.DLL") ),
                    dwCode, 0, szBuffer, sizeof( szBuffer ), 0 );

    return szBuffer;
}

//==============================================================================
// Given a linear address, locates the module, section, and offset containing 
// that address.                                                              
//                                                                            
// Note: the szModule paramater buffer is an output buffer of length specified
// by the len parameter (in characters!)                                      
//==============================================================================
BOOL MSJExceptionHandler::GetLogicalAddress(
        PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD& offset )
{
    MEMORY_BASIC_INFORMATION mbi;

    if ( !VirtualQuery( addr, &mbi, sizeof(mbi) ) )
        return FALSE;

    DWORD hMod = (DWORD)mbi.AllocationBase;

    if ( !GetModuleFileName( (HMODULE)hMod, szModule, len ) )
        return FALSE;

    // Point to the DOS header in memory
    PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;

    // From the DOS header, find the NT (PE) header
    PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);

    PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION( pNtHdr );

    DWORD rva = (DWORD)addr - hMod; // RVA is offset from module load address

    // Iterate through the section table, looking for the one that encompasses
    // the linear address.

    for (   unsigned i = 0;
            i < pNtHdr->FileHeader.NumberOfSections;
            i++, pSection++ )
    {
        DWORD sectionStart = pSection->VirtualAddress;
        DWORD sectionEnd = sectionStart
                    + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);

        // Is the address in this section???
        if ( (rva >= sectionStart) && (rva <= sectionEnd) )
        {
            // Yes, address is in the section.  Calculate section and offset,
            // and store in the "section" & "offset" params, which were
            // passed by reference.

            section = i+1;
            offset = rva - sectionStart;
            return TRUE;
        }
    }

    return FALSE;   // Should never get here!
}

//============================================================
// Walks the stack, and writes the results to the report file
//============================================================

void MSJExceptionHandler::IntelStackWalk( PCONTEXT pContext )
{
    _tprintf( _T("\nCall stack:\n") );

    _tprintf( _T("Address   Frame     Logical addr  Module\n") );

    DWORD pc = pContext->Eip;
    PDWORD pFrame, pPrevFrame;
   
    pFrame = (PDWORD)pContext->Ebp;

    do
    {
        TCHAR szModule[MAX_PATH] = _T("");
        DWORD section = 0, offset = 0;

        GetLogicalAddress((PVOID)pc, szModule,sizeof(szModule),section,offset );

        _tprintf( _T("%08X  %08X  %04X:%08X %s\n"),
                    pc, pFrame, section, offset, szModule );

        pc = pFrame[1];

        pPrevFrame = pFrame;

        pFrame = (PDWORD)pFrame[0]; // precede to next higher frame on stack

        if ( (DWORD)pFrame & 3 )    // Frame pointer must be aligned on a
            break;                  // DWORD boundary.  Bail if not so.

        if ( pFrame <= pPrevFrame )
            break;

        // Can two DWORDs be read from the supposed frame address?         
        if ( IsBadWritePtr(pFrame, sizeof(PVOID)*2) )
            break;

    } while ( 1 );
}

//============================================================================
// Helper function that writes to the report file, and allows the user to use
// printf style formating                                                    
//============================================================================

int __cdecl MSJExceptionHandler::_tprintf(const TCHAR * format, ...)
{
    TCHAR szBuff[1024];
    int retValue;
    DWORD cbWritten;
    va_list argptr;
         
    va_start( argptr, format );
    retValue = wvsprintf( szBuff, format, argptr );
    va_end( argptr );

    WriteFile( m_hReportFile, szBuff, retValue * sizeof(TCHAR), &cbWritten, 0 );

    return retValue;
}

posted on 2007-12-05 17:02 大龍 閱讀(3604) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区视频在线播放| 欧美成人在线免费视频| 亚洲尤物在线视频观看| 久久精品亚洲一区二区| 久久夜色精品亚洲噜噜国产mv| 日韩亚洲国产欧美| 欧美理论在线播放| 日韩视频在线免费| 亚洲人成毛片在线播放| 久久精品国产清自在天天线| 国产欧美大片| 久久精品欧美日韩精品| 亚洲欧美国产一区二区三区| 国产精品毛片a∨一区二区三区| 99精品欧美一区| 亚洲美女电影在线| 欧美日韩免费| 亚洲一区二区少妇| 亚洲欧美怡红院| 亚洲性图久久| 国产精品资源在线观看| 久久精品国产99| 久久男女视频| 99re8这里有精品热视频免费 | 国语自产精品视频在线看抢先版结局 | 欧美三级乱码| 国内视频一区| 一区二区不卡在线视频 午夜欧美不卡在 | 影音先锋亚洲一区| 一区二区av在线| 久久综合久久久久88| 亚洲精品在线免费| 久久婷婷国产综合国色天香| 国产精品成人一区二区| 亚洲人午夜精品免费| 久久久精品日韩| 一区二区三区精品| 免费久久99精品国产| 国产日本精品| 一区二区三区日韩欧美精品| 男女激情视频一区| 久久不射2019中文字幕| 性久久久久久久久久久久| 欧美日一区二区三区在线观看国产免| 国产精品一区在线播放| 91久久精品美女| 久久亚洲一区二区三区四区| 亚洲免费av电影| 欧美日韩麻豆| 麻豆精品精华液| 欧美性淫爽ww久久久久无| 国产麻豆精品在线观看| 中文网丁香综合网| 欧美 日韩 国产一区二区在线视频 | 亚洲欧美一区二区三区极速播放| 欧美激情一区二区| 一区二区不卡在线视频 午夜欧美不卡'| 亚洲精品一线二线三线无人区| 小黄鸭精品aⅴ导航网站入口| 国产精品久久九九| 亚洲欧美日韩视频一区| 一本久道久久综合婷婷鲸鱼| 欧美精品一区二| 亚洲香蕉成视频在线观看| 亚洲黑丝在线| 欧美激情二区三区| 日韩一级网站| 一区二区不卡在线视频 午夜欧美不卡在| 欧美久久精品午夜青青大伊人| 亚洲人精品午夜在线观看| 亚洲国产欧美日韩另类综合| 欧美激情一级片一区二区| 在线亚洲欧美视频| 亚洲午夜激情| 韩国在线一区| 亚洲国产网站| 国产精品久久久久久久久久直播| 亚洲欧美精品伊人久久| 午夜一区二区三区不卡视频| 狠狠久久亚洲欧美专区| 亚洲国产精品电影| 欧美日韩免费看| 欧美主播一区二区三区美女 久久精品人| 午夜视频在线观看一区二区三区| 激情久久中文字幕| 亚洲精品国产精品久久清纯直播| 欧美日韩综合在线| 久久夜色精品国产亚洲aⅴ| 欧美成人精品| 午夜精品影院| 国产精品视频成人| 亚洲国产一区二区三区高清| 蜜臀av性久久久久蜜臀aⅴ四虎| 亚洲精品在线观看免费| 亚洲一区二区三区中文字幕| 在线观看亚洲视频| 日韩一区二区免费看| 国产亚洲精品一区二区| 亚洲国产成人不卡| 国产色综合久久| 亚洲国产精品传媒在线观看| 国产日韩欧美三区| 日韩一级在线| 最新亚洲视频| 欧美中日韩免费视频| 亚洲国产三级网| 亚洲第一主播视频| 国产精品久久久久久久免费软件| 亚洲黄页一区| 久久久久九九九| 亚洲国产精品热久久| 亚洲欧洲日本国产| 女同性一区二区三区人了人一| 亚洲精品国产日韩| 欧美一级夜夜爽| 亚洲电影免费在线观看| 欧美极品一区二区三区| 亚洲视频 欧洲视频| 久久精品亚洲一区| 亚洲三级影院| 国产精品一区二区三区四区五区 | 在线视频日本亚洲性| 新片速递亚洲合集欧美合集| 国内精品免费午夜毛片| 欧美激情1区2区3区| 亚洲免费影视第一页| 欧美成人午夜视频| 亚洲中字黄色| 亚洲欧洲日本在线| 国产日韩亚洲欧美精品| 免费在线观看一区二区| 亚洲香蕉网站| 亚洲国产精品成人| 久久裸体视频| 在线亚洲+欧美+日本专区| 国产在线精品一区二区夜色| 欧美国产国产综合| 亚洲欧美久久| 99国产精品久久久久久久成人热| 久久久久欧美精品| 亚洲一级特黄| 最新日韩中文字幕| 红桃视频成人| 国产精品美女一区二区| 免费人成精品欧美精品| 亚洲欧美文学| 宅男66日本亚洲欧美视频 | 欧美另类亚洲| 久久久精品视频成人| 亚洲视屏在线播放| 欧美一区二区三区在线看| 美女久久网站| 99天天综合性| 午夜一区不卡| 国产一区深夜福利| 狼狼综合久久久久综合网| 亚洲第一狼人社区| 久久爱www.| 日韩午夜av| 乱中年女人伦av一区二区| 亚洲福利视频在线| 亚洲午夜精品一区二区三区他趣| 国产精品成人一区二区| 欧美中文在线观看| 亚洲国产精品激情在线观看| 亚洲一区二区三区免费视频 | 国产精品九九| 久久精品成人| 亚洲精品免费一二三区| 性久久久久久久久久久久| 影音先锋成人资源站| 欧美猛交免费看| 亚洲欧美视频在线| 亚洲人成人99网站| 国产在线一区二区三区四区| 麻豆国产va免费精品高清在线| 久久国产视频网| 久久国产99| 久久久之久亚州精品露出| 久久蜜桃香蕉精品一区二区三区| 久久国产精品99国产| 欧美中文字幕在线观看| 久久精品国产免费观看| 久久精品亚洲| 麻豆成人av| 欧美激情在线| 欧美精品日韩精品| 欧美三日本三级少妇三2023| 欧美视频亚洲视频| 国产精品区一区二区三区| 国产精品一区在线观看| 黄色免费成人| 最新国产成人在线观看| 艳妇臀荡乳欲伦亚洲一区| 亚洲一区制服诱惑| 久久久国产精品一区| 欧美成人免费网| 亚洲精品欧美日韩| 亚洲午夜激情免费视频| 久久精品日产第一区二区|