VC++ 各种未处理异常的处理,并输出DUMP崩溃转储调试文件

本文包含:

信号处理器、STL标准库异常处理、STL未处理器异常处理、SEH结构化未处理异常处理、C++ 未定义虚函数异常处理、C/C++ 内存分配异常处理等。

设置异常处理器:

            // Windows platforms need to mount unhandled exception handlers so that they can print dump debug files for app crashes.
#if defined(_DEBUG)
            ::_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF);
#endif
            ::_set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT);

            ::_set_purecall_handler(Crt_HandlePureVirtualCall);
            ::_set_new_handler(Crt_NewHandler); /* std::set_new_handler(...) */

#if _MSC_VER >= 1400 
            ::_set_invalid_parameter_handler(Crt_InvalidParameterHandler);
#endif

            ::signal(SIGABRT, Crt_SigabrtHandler);
            ::signal(SIGINT, Crt_SigabrtHandler);
            ::signal(SIGTERM, Crt_SigabrtHandler);
            ::signal(SIGILL, Crt_SigabrtHandler);

            ::set_terminate(Crt_TerminateHandler);
            ::set_unexpected(Crt_UnexpectedHandler);

            ::SetUnhandledExceptionFilter(Seh_UnhandledExceptionFilter);

异常处理器实现:

        static ppp::string Seh_NewDumpFileName() noexcept
        {
            ppp::string path = ppp::GetExecutionFileName();
            std::size_t index = path.rfind(".");
            if (index != ppp::string::npos)
            {
                path = path.substr(0, index);
            }

            struct tm tm_;
            time_t datetime = time(NULL);
            localtime_s(&tm_, &datetime);

            char sz[1000];
            sprintf_s(sz, sizeof(sz), "%04d%02d%02d-%02d%02d%02d", 1900 + tm_.tm_year, 1 + tm_.tm_mon, tm_.tm_mday, tm_.tm_hour, tm_.tm_min, tm_.tm_sec);

            path = path + "-" + sz + ".dmp";
            path = "./" + path;
            path = ppp::io::File::RewritePath(path.data());
            path = ppp::io::File::GetFullPath(path.data());

            return path;
        }

        static LONG WINAPI Seh_UnhandledExceptionFilter(EXCEPTION_POINTERS* exceptionInfo) noexcept
        {
            // Give user code a chance to approve or prevent writing a minidump.  If the
            // filter returns false, don't handle the exception at all.  If this method
            // was called as a result of an exception, returning false will cause
            // HandleException to call any previous handler or return
            // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear
            // as though this handler were not present at all.
            HANDLE hFile = CreateFileA(Seh_NewDumpFileName().data(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
            if (hFile != INVALID_HANDLE_VALUE)
            {
                MINIDUMP_EXCEPTION_INFORMATION exceptionParam;
                exceptionParam.ThreadId = GetCurrentThreadId();
                exceptionParam.ExceptionPointers = exceptionInfo;
                exceptionParam.ClientPointers = TRUE;

                MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpWithFullMemory, &exceptionParam, NULL, NULL);
                CloseHandle(hFile);
            }

            // The handler either took care of the invalid parameter problem itself,
            // or passed it on to another handler.  "Swallow" it by exiting, paralleling
            // the behavior of "swallowing" exceptions.
            exit(-1); /* abort(); */
            return EXCEPTION_EXECUTE_HANDLER;
        }
        
#if _MSC_VER >= 1400 
        // https://chromium.googlesource.com/breakpad/breakpad/src/+/master/client/windows/handler/exception_handler.cc
        static void __CRTDECL Crt_InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) noexcept
        {
            std::wcerr << L"Invalid parameter detected:" << std::endl;
            std::wcerr << L"Expression: " << expression << std::endl;
            std::wcerr << L"Function: " << function << std::endl;
            std::wcerr << L"File: " << file << std::endl;
            std::wcerr << L"Line: " << line << std::endl;

            _CrtDumpMemoryLeaks();
            _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
            _CrtMemDumpAllObjectsSince(NULL);
            _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);

            // Make up an exception record for the current thread and CPU context
            // to make it possible for the crash processor to classify these
            // as do regular crashes, and to make it humane for developers to
            // analyze them.
            EXCEPTION_RECORD exception_record = {};
            CONTEXT exception_context = {};
            EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };

            ::RtlCaptureContext(&exception_context);

            exception_record.ExceptionCode = STATUS_INVALID_PARAMETER;

            // We store pointers to the the expression and function strings,
            // and the line as exception parameters to make them easy to
            // access by the developer on the far side.
            exception_record.NumberParameters = 4;
            exception_record.ExceptionInformation[0] = reinterpret_cast<ULONG_PTR>(expression);
            exception_record.ExceptionInformation[1] = reinterpret_cast<ULONG_PTR>(file);
            exception_record.ExceptionInformation[2] = line;
            exception_record.ExceptionInformation[3] = reinterpret_cast<ULONG_PTR>(function);

            // Deliver exceptions to unhandled exception handler.
            Seh_UnhandledExceptionFilter(&exception_ptrs);
        }
#endif

        static int Seh_NoncontinuableException() noexcept
        {
            // Make up an exception record for the current thread and CPU context
            // to make it possible for the crash processor to classify these
            // as do regular crashes, and to make it humane for developers to
            // analyze them.
            EXCEPTION_RECORD exception_record = {};
            CONTEXT exception_context = {};
            EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };

            ::RtlCaptureContext(&exception_context);

            exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;

            // We store pointers to the the expression and function strings,
            // and the line as exception parameters to make them easy to
            // access by the developer on the far side.
            exception_record.NumberParameters = 3;
            exception_record.ExceptionInformation[0] = NULL;
            exception_record.ExceptionInformation[1] = NULL;
            exception_record.ExceptionInformation[2] = 0;

            // Deliver exceptions to unhandled exception handler.
            return Seh_UnhandledExceptionFilter(&exception_ptrs);
        }

        static int __CRTDECL Crt_NewHandler(size_t) noexcept
        {
            return Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_HandlePureVirtualCall() noexcept
        {
            Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_TerminateHandler() noexcept
        {
            Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_UnexpectedHandler() noexcept
        {
            Seh_NoncontinuableException();
        }

        static void __CRTDECL Crt_SigabrtHandler(int) noexcept
        {
            Seh_NoncontinuableException();
        }

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Windows调试是一种通过分析崩溃时生成的dump文件来定位错误和问题的过程。dump文件是操作系统在程序崩溃时自动创建的一种保存程序状态和信息的文件。 通过dump文件定位崩溃的过程可以分为以下几个步骤: 1. 获取dump文件:当程序崩溃时,操作系统会自动创建一个dump文件,通常保存在程序的运行目录下。可以通过查看程序崩溃时的错误提示信息来确定dump文件的位置。 2. 安装符号文件:符号文件是包含程序源代码和编译器产生的调试信息的文件。在调试过程中,需要将符号文件dump文件关联起来,以便能够查看和分析源代码。可以从官方网站下载对应版本的符号文件。 3. 打开dump文件:可以使用调试工具(如Visual Studio、WinDbg等)打开dump文件。在打开文件后,工具会加载符号文件,显示出崩溃时的堆栈信息。 4. 分析堆栈信息:堆栈信息显示了程序在崩溃时的函数调用情况。从堆栈信息中,可以定位到导致崩溃的函数和代码所在的位置。通过查看源代码,可以进一步分析和解决错误。 5. 调试程序:在分析崩溃原因后,可以使用调试工具来逐步执行程序,观察变量的值和执行的过程,以便定位错误。可以设置断点、观察变量、修改变量的值等操作,帮助分析和解决问题。 通过以上步骤,我们可以利用dump文件进行Windows调试,快速定位程序崩溃的原因,并解决问题。调试过程需要了解一定的调试技巧和工具的使用方法,同时对于程序的结构和运行过程有一定的了解,这样才能更好地定位和解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值