程序运行时崩溃生成崩溃文件(Windows & Linux)

文章介绍了在Linux和Windows环境下,如何设置和利用崩溃文件(coredump或MiniDump)进行程序调试。在Linux中,通过调整`ulimit-c`和`kernel.core_pattern`来启用和配置coredump,而在Windows中,则通过自定义异常过滤器`MyUnhandledExceptionFilter`生成MiniDump文件,便于后期分析错误原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记:在实际开发过程中,程序可以通过IDE来排查崩溃问题,但是当程序部署到没有开发环境的电脑上时,为方便调试和排查问题,势必要通过崩溃文件来记录崩溃瞬间的信息,这样就可以通过查找堆栈信息来排查问题。

一、Linux环境

  1. 查看是否允许崩溃文件产生
    打开终端,输入
ulimit -c

如果此时显示为 0,则表示崩溃文件产生大小为0,此时

vi ~/.bashrc

ulimit -c unlimited

追加到文件末尾,shift + :进入命令行模式,输入 wq,保存退出,然后 输入

source ~/.bashrc

此时,再次输入ulimit -c,显示unlimited即可。
ulimit-c

  1. 添加崩溃文件配置信息
    将默认生成崩溃文件的路径(必须是存在的路径)和崩溃文件名称添加到系统配置
echo /home/zhenglg/coredump/core-%e-%p-$t-%E > /proc/sys/kernel/core_pattern

然后

sudo vi /etc/sysctl.conf

添加

kernel.core_pattern=/home/zhenglg/coredump/core-%e-%p-$t-%E
  1. 测试
#include <iostream>
#include <cstring>

int main(int argc, char* argv[])
{
	char* p = NULL;
	strncpy(p, "abc", 3);
	
	return 0;
}

编译

g++ test.cpp -o app

运行

./app

./app
此时在之前配置的路径下生成了崩溃文件
coredump
4. 调试崩溃文件
debug
此时即可看到函数信息。

二、Windows环境

  1. 添加崩溃捕捉代码
#CoredumpHelper.h


#pragma once 
#include <windows.h> 
#include <DbgHelp.h> 
#include <stdlib.h> 
#pragma comment(lib, "dbghelp.lib") 
#ifndef _WIN32 
#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, L"coredump.dmp");
    MessageBox(0, L"Error", L"error", MB_OK);
    /*printf("Error address %x/n", pExceptionInfo->ExceptionRecord->ExceptionAddress); printf("CPU register:/n"); printf("eax %x ebx %x ecx %x edx %x/n", pExceptionInfo->ContextRecord->Eax, pExceptionInfo->ContextRecord->Ebx, pExceptionInfo->ContextRecord->Ecx, pExceptionInfo->ContextRecord->Edx);*/
    return   EXCEPTION_EXECUTE_HANDLER;
}
// 此函数一旦成功调用,之后对 SetUnhandledExceptionFilter 的调用将无效 
void DisableSetUnhandledExceptionFilter()
{
    void* addr = (void*)GetProcAddress(LoadLibrary(L"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();
}
#pragma once
  1. 注册异常函数
    在主程序最开始处调用 InitMinDump()
  2. 运行
    在程序运行路径下生成了coredump.dmp的崩溃文件,同时附有提示框。
    coredump_window
  3. 调试
    将dmp文件用VS打开,或者用windbg运行,即可看到程序崩溃处。
    windows_core_debug
    windows_coredump_debug_source

三、注意

  1. 此处Linux使用Ubuntu20.04TSL,Window使用VS + QT进行的测试;
  2. 实际使用中我用Ubuntu、Kylin下的Qt Creater也可以。

2023-03-30
ChengDu China
ZLG

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值