<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          windows程序崩潰調(diào)試終極武器

          共 7234字,需瀏覽 15分鐘

           ·

          2021-08-21 01:42

          windows程序崩潰調(diào)試終極武器---dump文件

          一、前言

          前不久開發(fā)了一款windows程序,目前已經(jīng)是測試跑了,對于windows程序熟悉的童鞋,應(yīng)該都知道一個事,就是他運行時有一個黑框,如果崩潰的就是下面這種情形~

          這種情況有時候會給我們一種不知所措的感覺,看日志吧~有時候崩潰了,不一定出現(xiàn)在什么地方;異常處理吧,又不像JAVA那么多的異常,所以很多時候,我們遇到這種情況就有些不知所措了~

          今天,帶來一款終極秘密武器---dump文件;


          二、實戰(zhàn)

          1、dump文件簡介

          dump文件是進程的內(nèi)存鏡像,可以吧程序的執(zhí)行狀態(tài)通過調(diào)試器保存到dump文件中;


          2、通過任務(wù)管理生成dump文件

          首先,我們寫一段測試程序:

          #include <iostream>

          using namespace std;

          void fun(int* p)
          {
           p[0] = 1;
          }

          int main()
          {
           fun(NULL);
           return 0;
          }

          然后我們編譯一把,再運行

          我們會得到這么一個錯誤:

          此時,我們不要做關(guān)閉這個框,我們只需要吧任務(wù)管理器打開,找到該進程,然后導出文件就可以了

          我們打開路徑,拷貝該文件到我們exe所在的目錄:

          然后我們打開vs,這里使用的是vs2015

          由于我吧dmp文件放在了exedpb目錄下,不用設(shè)置符號路徑

          這里千萬注意一點,很多博客上都沒有說到這一點:32位程序和64位程序調(diào)試是不同的

          如果我們程序是32位的,但是我們的開發(fā)機是64位,通過轉(zhuǎn)存儲文件生成的文件就不是我們32位程序?qū)?yīng)的文件了,就會無法調(diào)試;


          3、通過程序生成dump文件

          上面我們說到了通過任務(wù)管理器生成的dump文件的方式會出現(xiàn)不兼容或者說是錯誤,那么怎么去解決這個問題呢?

          還好微軟也提供了API出來,我們可以再程序中使用微軟的API進行調(diào)用,這樣通過程序產(chǎn)生的dump文件就沒有位數(shù)的問題了;

          這里提供一個通用的代碼,是直接可以拿過來用的~感覺我吧

          minidmp.h

          #pragma once
          #include <windows.h>
          #include <DbgHelp.h>
          #include <stdlib.h>
          #pragma comment(lib, "dbghelp.lib")
          #pragma warning(disable:4996) //全部關(guān)掉
          #pragma warning(once:4996) //僅顯示一個

          /*
          #ifndef _M_IX86
          #error "The following code only works for x86!"
          #endif
          */


          inline BOOL IsDataSectionNeeded(const WCHAR* pModuleName)
          {
           if (pModuleName == 0)
           {
            return FALSE;
           }

           WCHAR szFileName[_MAX_FNAME] = L"";
           _wsplitpath(pModuleName, NULLNULL, szFileName, NULL);

           if (wcsicmp(szFileName, L"ntdll") == 0)
            return TRUE;

           return FALSE;
          }

          inline BOOL CALLBACK MiniDumpCallback(PVOID                            pParam,
           const PMINIDUMP_CALLBACK_INPUT   pInput,
           PMINIDUMP_CALLBACK_OUTPUT        pOutput)

          {
           if (pInput == 0 || pOutput == 0)
            return FALSE;

           switch (pInput->CallbackType)
           {
           case ModuleCallback:
            if (pOutput->ModuleWriteFlags & ModuleWriteDataSeg)
             if (!IsDataSectionNeeded(pInput->Module.FullPath))
              pOutput->ModuleWriteFlags &= (~ModuleWriteDataSeg);
           case IncludeModuleCallback:
           case IncludeThreadCallback:
           case ThreadCallback:
           case ThreadExCallback:
            return TRUE;
           default:;
           }

           return FALSE;
          }

          inline void CreateMiniDump(PEXCEPTION_POINTERS pep, LPCTSTR strFileName)
          {
           HANDLE hFile = CreateFile(strFileName, GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

           if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
           {
            MINIDUMP_EXCEPTION_INFORMATION mdei;
            mdei.ThreadId = GetCurrentThreadId();
            mdei.ExceptionPointers = pep;
            mdei.ClientPointers = NULL;

            MINIDUMP_CALLBACK_INFORMATION mci;
            mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
            mci.CallbackParam = 0;

            ::MiniDumpWriteDump(::GetCurrentProcess(), ::GetCurrentProcessId(), hFile, MiniDumpNormal, (pep != 0) ? &mdei : 0NULL, &mci);

            CloseHandle(hFile);
           }
          }

          LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
          {
           CreateMiniDump(pExceptionInfo, "orderBookMatchEngine.dmp");

           // EXCEPTION_EXECUTE_HANDLER equ 1 表示我已經(jīng)處理了異常, 可以優(yōu)雅地結(jié)束了
           // EXCEPTION_CONTINUE_SEARCH equ 0 表示我不處理, 其他人來吧, 于是windows調(diào)用默認的處理程序顯示一個錯誤框, 并結(jié)束
           // EXCEPTION_CONTINUE_EXECUTION equ - 1 表示錯誤已經(jīng)被修復(fù), 請從異常發(fā)生處繼續(xù)執(zhí)行
           return EXCEPTION_EXECUTE_HANDLER;
          }

          // 此函數(shù)一旦成功調(diào)用,之后對 SetUnhandledExceptionFilter 的調(diào)用將無效
          void DisableSetUnhandledExceptionFilter()
          {
           void* addr = (void*)GetProcAddress(LoadLibrary("kernel32.dll"),
            "SetUnhandledExceptionFilter");

           if (addr)
           {
            unsigned char code[16];
            int size = 0;

            code[size++] = 0x33;
            code[size++] = 0xC0;
            code[size++] = 0xC2;
            code[size++] = 0x04;
            code[size++] = 0x00;

            DWORD dwOldFlag, dwTempFlag;
            VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
            WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
            VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
           }
          }
          LPTOP_LEVEL_EXCEPTION_FILTER WINAPI MyDummySetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
          {
           return NULL;
          }

          BOOL PreventSetUnhandledExceptionFilter()
          {
           HMODULE hKernel32 = LoadLibrary("kernel32.dll");
           if (hKernel32 == NULLreturn FALSE;
           void *pOrgEntry = GetProcAddress(hKernel32, "SetUnhandledExceptionFilter");
           if (pOrgEntry == NULLreturn FALSE;
           unsigned char newJump[100];
           DWORD dwOrgEntryAddr = (DWORD)pOrgEntry;
           dwOrgEntryAddr += 5// add 5 for 5 op-codes for jmp far
           void *pNewFunc = &MyDummySetUnhandledExceptionFilter;
           DWORD dwNewEntryAddr = (DWORD)pNewFunc;
           DWORD dwRelativeAddr = dwNewEntryAddr - dwOrgEntryAddr;

           newJump[0] = 0xE9;  // JMP absolute
           memcpy(&newJump[1], &dwRelativeAddr, sizeof(pNewFunc));
           SIZE_T bytesWritten;
           BOOL bRet = WriteProcessMemory(GetCurrentProcess(),
            pOrgEntry, newJump, sizeof(pNewFunc) + 1, &bytesWritten);
           return bRet;
          }

          void InitMinDump()
          {
           //注冊異常處理函數(shù)
           SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);

           // PreventSetUnhandledExceptionFilter();
           //使SetUnhandledExceptionFilter
           DisableSetUnhandledExceptionFilter();
          }

          在main函數(shù)中只要在最開始吧的時候使用初始化函數(shù)就可以了~

          案例:

          #include <iostream>
          #include "minidmp.h"

          using namespace std;

          void fun(int* p)
          {
           p[0] = 1;
          }

          int main()
          {
           InitMinDump();
           fun(NULL);
           return 0;
          }

          然后編譯運行,會在當前文件夾中出現(xiàn)orderBookMatchEngine.dmp文件,然后按照上面的流程打開調(diào)試就可以了~


          三、總結(jié)

          調(diào)試程序和尋找BUG,是一個程序員必備的技能之一,很多處理問題的能力是從工作中遇到的問題總結(jié)得到的,也是其他地方學習不到的~

          學習更多的調(diào)試技能和知識,才能在工作中游刃有余~

          瀏覽 97
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  做爱小网站 | 国产一级精品成人无码毛片 | 99一二区 | 麻豆网站-麻豆午夜在线-成人AV | 日本在线影院 |