編寫的windows程式,崩潰時產生crash dump檔案的辦法
一、引言
dump檔案是C++程式發生異常時,儲存當時程式執行狀態的檔案,是除錯異常程式重要的方法,所以程式崩潰時,除了日誌檔案,dump檔案便成了我們查詢錯誤的最後一根救命的稻草。windows程式產生dump檔案和linux程式產生dump檔案的方式不一樣,linux預設是不讓產生core dump檔案,只要在使用者自己的~/.bash_profile檔案中增加
ulimit -S -c unlimited > /dev/null 2>&1
這樣程式崩潰就可以產生可除錯的core dump檔案了。但是windows環境就得寫程式碼才能實現了。
二、原理
windows程式當遇到異常,沒有try-catch或者try-catch也無法捕獲到的異常時,程式就會自動退出,如果這時候沒有dump檔案的話,我們是沒有得到任何程式退出的資訊。在windows程式異常退出之前,會預先呼叫一個在程式中註冊的異常處理回撥函式(預設是沒有設定),只要我們在這個回撥函式中呼叫MiniDumpWriteDump函式就可以產生我們想要的dump檔案。
三、實現
1.呼叫SetUnhandledExceptionFilter註冊一個自定義的異常處理回撥函式
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
異常處理回撥函式的原型
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);
2.CreateFile建立dump檔案,呼叫MiniDumpWriteDump函式往dump檔案寫異常資訊
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 : 0, NULL, &mci); CloseHandle(hFile); } }
CreateMiniDump函式是在異常處理回撥函式MyUnhandledExceptionFilter中呼叫的
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
CreateMiniDump(pExceptionInfo, "core.dmp");
return EXCEPTION_EXECUTE_HANDLER;
}
3.將SetUnhandledExceptionFilter失效
vs2005中,編譯的過程中,編譯器會自動給你的程式加上一句SetUnhandledExceptionFilter(NULL),這就會導致你之前自定義的
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
無效,就有可能不會產生dump檔案,因此我們必須在自定義的SetUnhandledExceptionFilter之後,讓之後呼叫的SetUnhandledExceptionFilter無效。增加以下程式碼:
// 此函式一旦成功呼叫,之後對 SetUnhandledExceptionFilter 的呼叫將無效
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);
}
}
最終程式碼整理:
//minidump.h
#pragma once
#include <windows.h>
#include <DbgHelp.h>
#include <stdlib.h>
#pragma comment(lib, "dbghelp.lib")
#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, NULL, NULL, 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 : 0, NULL, &mci);
CloseHandle(hFile);
}
}
LONG __stdcall MyUnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
{
CreateMiniDump(pExceptionInfo, "core.dmp");
return EXCEPTION_EXECUTE_HANDLER;
}
// 此函式一旦成功呼叫,之後對 SetUnhandledExceptionFilter 的呼叫將無效
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);
}
}
void InitMinDump()
{
//註冊異常處理函式
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
//使SetUnhandledExceptionFilter
DisableSetUnhandledExceptionFilter();
}
4.測試程式碼
//test.cpp
#include <iostream>
#include "minidump.h"
void test()
{
std::string s = "abcd";
try{
s[100] = 'b';
}
catch(std::exception& e)
{
std::cout << "with exception:[" << e.what() << "]" << std::endl;
}
catch(...)
{
std::cout << "with unknown exception" << std::endl;
}
}
void main()
{
InitMinDump();
test();
system("pause");
}
相關推薦
編寫的windows程式,崩潰時產生crash dump檔案的辦法
一、引言 dump檔案是C++程式發生異常時,儲存當時程式執行狀態的檔案,是除錯異常程式重要的方法,所以程式崩潰時,除了日誌檔案,dump檔案便成了我們查詢錯誤的最後一根救命的稻草。windows程式產生dump檔案和linux程式產生dump檔案的方式不一樣,linux預
編寫的windows程式,崩潰時產生crash dump檔案的辦法 .
一、引言 dump檔案是C++程式發生異常時,儲存當時程式執行狀態的檔案,是除錯異常程式重要的方法,所以程式崩潰時,除了日誌檔案,dump檔案便成了我們查詢錯誤的最後一根救命的稻草。windows程式產生dump檔案和linux程式產生dump檔案的方式不一樣,linux預
如何在程式異常或者崩潰時產生一個dump檔案
核心API是: CreateFile() MinDumpWriteDump() 需要包含標頭檔案: #include <DbgHelp.h> #pragma comment(lib, "d
windows程式崩潰時自動生成dump檔案方法
/****************第一步新增createdump.h********************************* 新增一個頭檔案:createdump.h #pragma once #include <windows.h> #inclu
利用Windows自帶的功能當程式崩潰時產生崩潰轉儲檔案(dmp)
何志丹 以管理員身份 執行 :OpenDump.bat 其本質是寫登錄檔。 執行後: 任何程式崩潰都會在C:\CrashDump 產生dmp檔案(比較大,約50到200M)。 至少在Win7、Win10的電腦,Win10的平板上執行正確。 OpenDump.bat @e
windows下idea編寫WordCount程式,並打jar包上傳到hadoop叢集執行(傻瓜版)
通常會在IDE中編制程式,然後打成jar包,然後提交到叢集,最常用的是建立一個Maven專案,利用Maven來管理jar包的依賴。 一、生成WordCount的jar包 1. 開啟IDEA,File→New→Project→Maven→Next→填寫Groupld和Artifactld→Ne
c# 編寫windows 服務,並制作安裝包
階段 其他 編譯 code 工程 component partial 控制臺程序 自定義 對服務的認識有很多個階段。 第一階段:當時還在用c++,知道在一個進程裏while(True){},然後裏面做很多很多事情,這就叫做服務了,界面可能當時還用Console控
P68——編寫一個程式,讀取一個浮點數,先列印成再列印成如果系統......
#include <stdio.h> int main(void) { float a; printf("enter a floating-point value:"); scanf("%f",&a); printf("fixed-point notation:
P68——編寫一個程式,發出一聲警報,然後列印下面的文字
要列印的文字內容: Startled by the sudden sound,sally shouted, "By the great pumkin,wahat was that!" 程式程式碼如下: #include <stdio.h> int main(void) {
P68——編寫一個程式,要求提示輸入一個ASCII碼值(如66),然後列印輸入的字元
錯誤程式碼如下: 錯在定義了錯誤的輸入物件型別,使用者輸入時也弄錯了輸入型別, 更改後正確程式碼如下: #include <stdio.h> int main(void) { int a; printf("please enter a ASCII ma:");
山科java實驗4-1 編寫一個程式,使用者可以從鍵盤錄入若干個學生的姓名和分數(程式每次提示使用者輸入“Y”或“N”決定是否繼續錄入學生資訊,如果使用者輸入“N”則使用者輸入完畢。輸入的“Y”、“N”不區分
編寫一個程式,使用者可以從鍵盤錄入若干個學生的姓名和分數(程式每次提示使用者輸入“Y”或“N”決定是否繼續錄入學生資訊,如果使用者輸入“N”則使用者輸入完畢。輸入的“Y”、“N”不區分大小寫)。使用者錄入完畢後,程式按成績由高到低的順序輸出學生的姓名和分數(姓名和分數之間用一個空格分割)。【說明
c語言 編寫一個程式,輸入a b c三個值,輸出其中最大者
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!  
用指標方法編寫一個程式,輸入3個整數,將它們按由小到大的順序輸出
#include <stdio.h> void swap(int *pa,int *pb) { int temp; temp = *pa; *pa = *pb; *pb = temp; } void main() { int
編寫一個程式,指定一個資料夾,能自動計算出其總容量
package filetest;import java.io.File;import java.io.IOException; public class FileEdit { double size=0.0; //計算檔案或資料夾的大小,單位MB public double getSize(File fi
編寫一個程式,啟動三個執行緒,三個執行緒的名稱分別是 A,B,C; 每個執行緒將自己的名稱在螢幕上列印5遍,列印順序是ABCABC...
設定標誌位flag 當flag==1時,列印A 當flag==2時,列印B 當flag==3時,列印C 用count控制列印的次數,題目要求列印5遍,即15個字元 這裡的用notifyAll()的原因:是要把其餘兩個全都喚醒,因為如果用notify
編寫一個程式,它從標準輸入讀取C原始碼,並驗證所有的花括號都正確的成對出現。
編寫一個程式,它從標準輸入讀取C原始碼,並驗證所有的花括號都正確的成對出現。 (VS ctrl+z退出 回車即可) int Is_judge_both() { char ch = 0; int count = 0; while((ch=getchar()) !=
編寫一個程式,對一個整型陣列的元素求和,結果使用全域性變數sum儲存,另外對陣列元素中的奇數求和,結果使用區域性變數sum儲存,在主程式將兩個結果輸出。
#include<iostream> using namespace std; int sum_1(int a[]);//定義計算奇數的和; int main() { int a[]={1,2,3,4,5,6,7,8,9,10};//定義陣列並附初值; int i,sum=0,s
IDA附加除錯apk程式,並修改記憶體,編寫IDA指令碼程式,把修改後的dex檔案dump到本地
我的測試環境:模擬器 Android 4.2 armeavi-v7a 1.IDA附加除錯apk程式 找到IDA所在目錄,在dbgsrv資料夾下找到程式android_server 在這裡按住“Shift +滑鼠右鍵”,開啟控制檯 把程式android_server
.編寫一個程式,可以一直接收鍵盤字元, 如果是小寫字元就輸出對應的大寫字元, 如果接收的是大寫字元,就輸出對應的小寫字元, 如果是數字不輸出。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include<stdlib.h> int main() { int i = 0; printf("請輸入一個數字:"); scanf("%d", &i);
python3 自己編寫一個程式,把大寫字母轉換為小寫字母(即自程式設計實現了 字串的lower()方法)
#定義一個函式,可以把列表輸入的帶有大寫字母的列表,轉換為全小寫字母 #比如:輸入列表['Hello','worlD','HAHA'] ====> ['hello','world','haha'] #程式碼如下: #定義一個函式,可以把列表輸入的帶有大寫字母的列表