Use of Windows platform crash dump system crashrpt

Overview

CrashRpt is a free, lightweight open source error reporting library designed to intercept exceptions in C++ programs, collect technical information about crashes and send error reports to software vendors over the Internet for use in Microsoft Visual Studio IDE Create and run C++ applications in Windows. (Not cross-platform)

The official website is: CrashRpt - A crash reporting system for Windows applications (sourceforge.net)

The official website states that it supports Visual C++ 2005, 2008, 2010, 2012 and Visual C++ Express. The compiler used by the author, Visual Studio 2022, also supports it. Can be compiled for 32-bit and 64-bit platforms. As of October 2022, it is applicable to operating systems above Windows XP.

1. It can handle exceptions in the main thread and all worker threads of user-mode programs: SEH exceptions (Structured Exception Handling), unhandled C++ type exceptions, signals and CRT (C Runtime) errors. Among the error types that CrashRpt can handle are: NULL pointer allocation, access violation, infinite recursion, stack overflow, memory exhaustion, etc.

2. It can generate error reports, including small crash dump minidump files, extensible crash description XML files, application-customized files (such as program log files), desktop screenshots and screen capture videos.

3. It provides a UI that allows users to view crash reports and supports privacy policy definition.

4. It can display its UI in different languages, which makes it more suitable for multi-language applications.

5. It sends an error report in the background after the user agrees.

6. Crash analysis files can be uploaded from the client via HTTP (or HTTPS), SMTP and Simple MAPI.

7. Automatically restart the application when it crashes (if the user agrees).

8. Use command line tools to automatically handle error reports on the developer side. This option is useful when you receive a large number of bug reports from software users.

9. Provide error reports for API function interface access.

10. The CrashRpt library is lightweight, which means you should only distribute approximately 1.9 Mb of additional files with your software (dbghelp.dll, CrashRpt.dll, CrashSender.exe).

Architecture overview

CrashRpt contains two functions: error reporting function and error report analysis function .

1. The error reporting function is distributed with the client software and is responsible for handling exceptions in the client software and delivering error reports to developers.

2. The error report analysis function is designed to help developers extract the data contained in error reports and simplify error report analysis. It usually resides on the developer's side and is not released with the client software.

Error reporting function

The error reporting functionality consists of two core modules: CrashRpt.dll and CrashSender.exe.

CrashRpt.dll contains functionality for handling exceptions in client software.

CrashSender.exe contains functionality to send error reports to the software support team.

Note: There are multiple versions of CrashRpt. The writing here is abbreviation. The names of the actually compiled dll and exe are similar to ( CrashRpt1400.dllCrashSender1400.exe

Typically, an executable file loads CrashRpt.dll into its address space when the process starts. This instance of CrashRpt is shared among all DLL modules loaded into the process address space. A client application uses the CrashRpt function to set an exception handler once in the process, usually in its main() (or WinMain()) function. In a multi-threaded program, the client additionally sets an exception handler at the beginning of each worker thread's thread process.

Error report analysis function

The error reporting functionality also consists of two core modules: CrashRptProbe.dll and crprober.exe.

CrashRptProbe.dll implements an API that can be used to access error reporting data.

crprober.exe is a console tool that helps extract error report data and write summaries in human-readable form.

When you receive many error reports from software users, you will have to spend a lot of time opening each report, analyzing its content and writing some summaries about the report. There may be many reports related to the same problem, so opening such a report will not provide anything new, the error report analysis feature is designed to solve these problems.

Features

Error Reporting Dialog

When a crash occurs in a client application, the Error Report dialog box appears (see image below).

 Error Report Details Dialog Box

What does this report in the interface above contain? Link opens the Error Report Details dialog box.

What does a bug report contain?

A bug report is a collection of files designed to help developers diagnose the cause of a crash: a crash minidump file, a crash description XML file, and other optional files.

The crash minidump file (crashdump.dmp) contains the operating system version, processor type, CPU register state, local variables, and call stack for each thread of execution.

A minidump file can be used on the developer side to determine the cause of the crash and attempt to resolve the issue. (Use Windbg tool combined with pdb symbol file to find out where the bug is)

How to create minidump files:

1. All threads of the parent process will be suspended and a "snapshot" of the process will be recorded.

2. The snapshot includes the names and versions of all DLL modules loaded into the process, as well as the list of threads working in the process.

3. For each thread, a call stack image is recorded.

4. Additionally, information about the operating system version, CPU number, and its brand name will be written to a minidump file.

5. Minidumps are usually created with the help of the MiniDumpWriteDump() function of the DbgHelp DLL.

6. For additional information about the MiniDumpWriteDump() function, please refer to MSDN.

 CrashRpt generates an XML crash description file (crashrpt.xml) to supplement the minidump.

The XML file contains various information such as the application name and version, the sender's email address and geographical location, user-provided problem description, exception type and address, etc.

Custom files, such as application log files, desktop screenshots, and screen capture videos, can be included in crash reports through the API functionality provided by CrashRpt.

CompileCrashRpt

By default, the bin directory of the CrashRpt archive contains binaries compiled in Visual Studio 2010. These files are for demonstration purposes only. It is strongly recommended that you use the Visual Studio version to compile CrashRpt yourself. This is necessary to ensure that CrashRpt uses the same version of the C Runtime Library (CRT) as the application.

The top-level directory of the CrashRpt distribution contains the solution file for Visual Studio 2010 (CrashRpt_vs2010.sln). Open this solution file to compile CrashRpt in Visual C++ 2010 or Visual C++ Express 2010.

If the compiler is not the above version, it needs to be converted. The author's compiler is Visual Studio 2022 and needs to be converted using the CMake tool. The steps are as follows:

1. Download CMake (version 2.8 or higher) and install it.

2. Fill in the path as shown in the picture (the location of the CrashRpt folder you downloaded) and proceed:

Configure configuration: 

Once completed you will see the generated CrashRpt.sln file, which you can use to compile CrashRpt (open it in Visual Studio). 

solution structure

After opening the project file we can see the following projects:

ConsoleDemo is a console application that helps test how CrashRpt works with console applications.

The CrashRpt project contains API implementation and provides the function of intercepting exceptions.

The CrashRptProbe project contains functionality for handling error reports.

The CrashSender project contains functionality for displaying the GUI, sending error reports, and showing error report sending progress.

crprober is a console tool for error report handling.

The jpeg project contains JPEG file management functions.

The libogg project contains OGG video container management functionality (for use with libtheora).

The libpng project contains PNG file management functions.

The libtheora project contains OGG Theora video codec functionality.

MFCDemo is a GUI application that helps test whether the CrashRpt API functions work as expected with MFC-based applications.

The minizip project contains ZIP file management functions.

Tests contains automatic testing functions.

The tinyxml project contains XML file management functions.

WTLDemo is a GUI application that helps test whether CrashRpt API functions work as expected with WTL-based applications.

The Zlib project contains file compression functionality.

Just recompile the entire project. After compilation is completed, you can find the CrashRpt executable file in the bin directory and the library file in the lib directory.

The following documents are the most important:

bin\CrashRptXXXX.dll - This is the CrashRpt crash handler module;

bin\CrashSenderXXXX.exe - This is the crash report sender module;

lib\CrashRptXXXX.lib - This is the CrashRpt import library.

Above, the XXXX placeholder is the version number of CrashRpt.

Debug, Release and Release LIB compilation configuration

Under normal circumstances, CrashRpt is compiled in Release mode. In this configuration, a binary file is generated that can be used in a production environment.

Compile CrashRpt in Debug mode, which is used for CrashRpt debugging and should not be used in production mode. In this configuration, d suffix files are generated, such as CrashRptXXXXd.dll and CrashSenderXXXXd.exe.

Release LIB configuration is a supplement to Debug and Release generated configurations. Normally, you should compile CrashRpt in Release mode, but if using static CRT linking, you need to compile it in Release LIB. In the Release LIB configuration, compile and generate the CrashSenderXXXX.exe executable file and the CrashRptLIB.lib static library. In this configuration, CrashSenderXXXX.exe and CrashRptLIB.lib are statically linked to the CRT.

An example using CrashRpt

 The following example demonstrates how to use the CrashRpt API functions and structures to enable crash reporting support in a console C++ application.

Project configuration

Generally, we need to copy the files generated in the include directory, bin directory, and lib directory in CrashRpt to our own project.

My example directory is organized like this:

include directory configuration:

lib directory configuration:

lib file configuration:

Note that the import library here (for more convenient use of dll) is not a static link library.

Add a post-compile event to automatically copy files in the bin directory and config directory:

Some additional project configuration:

Please be sure to use CRT as a multi-threaded DLL (/MD) in the Release configuration. This is the recommended method in MSDN and is also the default configuration of the project.

Use the same CRT version for all application modules

 Make sure that all modules present in the application use the same CRT version, if some dependent modules were compiled with an older version of the CRT, they should be recompiled to ensure that a single version or CRT DLL is used. For example, suppose you use Visual Studio 2008 and CRT 9.0 to link as a DLL, but some dependent modules in your application were compiled in Visual Studio 2005 and use CRT 8.0 to link as a DLL. In this case, CRT errors in dependent modules are not intercepted by CrashRpt because the error handler only works with CRT 9.0.

Release configuration enabler database

To be able to recover a stack trace from a crash minidump, the debugger requires the application's debug symbols (PDB file). To enable the generation of PDB files:

 

 The above settings should be made for all projects in the solution

Disable omitted frame pointer optimization

We recommend turning off the frame pointer omission (FPO) optimization in release build configurations, as this optimization doesn't really provide a noticeable benefit but can make dump analysis very complicated. The /Oy compiler option makes using the debugger more difficult because the compiler suppresses display of frame pointer information. Additionally, in Visual Studio 2010, this optimization is disabled by default.

Sample source code

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <stdarg.h>
#include "CrashRpt.h"

// 应用程序日志文件句柄
FILE* g_hLog = NULL;

// 程序崩溃时的回调函数
int CALLBACK CrashCallback(CR_CRASH_CALLBACK_INFO* pInfo)
{
	// 应用程序崩溃了!

	// 关闭日志文件,避免日志文件一直被客户程序占用
	// 确保CrashRpt能够有Read权限把他包含到错误报告中
	if (g_hLog != NULL)
	{
		// 关闭句柄
		fclose(g_hLog);
		g_hLog = NULL;
	}

	// 返回CR_CB_DODEFAULT以生成错误报告
	return CR_CB_DODEFAULT;
}

// 写日志
void log_write(int num_args, LPCTSTR szFormat, ...)
{
	if (g_hLog == NULL)
		return;

	va_list args;
	va_start(args, num_args);
	_vftprintf_s(g_hLog, szFormat, args);
	fflush(g_hLog);
}

// 线程函数
DWORD WINAPI ThreadProc(LPVOID lpParam)
{
	crInstallToCurrentThread2(0);

	log_write(1, _T("Entering the thread proc\n"));

	while (true)
	{
		int* p = NULL;
		*p = 13;         // 这里会引发非法访问异常(Access Violation)
	}

	log_write(1, _T("Leaving the thread proc\n"));

	crUninstallFromCurrentThread();

	return 0;
}

// 安装CrashRpt
bool InstallCrashRpt()
{
	// 定义CrashRpt配置参数
	CR_INSTALL_INFO info;
	memset(&info, 0, sizeof(CR_INSTALL_INFO));
	info.cb = sizeof(CR_INSTALL_INFO);

	// 应用程序名称
	info.pszAppName = _T("MyApp");

	// 应用程序版本
	info.pszAppVersion = _T("1.0.0");

	// 邮件主题
	info.pszEmailSubject = _T("MyApp 1.0.0 Error Report");

	// 崩溃日志收件地址
	info.pszEmailTo = _T("[email protected]");

	// 崩溃日志应该上传的服务器
	info.pszUrl = _T("http://myapp.com/tools/crashrpt.php");

	info.uPriorities[CR_HTTP] = 3;  // 首先使用HTTP发送错误报告
	info.uPriorities[CR_SMTP] = 2;  // 其次使用SMTP发送错误报告
	info.uPriorities[CR_SMAPI] = 1; // 然后使用Simple MAPI发送错误报告

	// 对所有可能出现的异常进行处理
	info.dwFlags |= CR_INST_ALL_POSSIBLE_HANDLERS;

	// 崩溃时重启程序
	info.dwFlags |= CR_INST_APP_RESTART;

	// 对以前未发送成功的错误报告,CrashRpt应该进行发送操作
	info.dwFlags |= CR_INST_SEND_QUEUED_REPORTS;

	// 程序重启命令行
	info.pszRestartCmdLine = _T("/restart");

	// 定义隐私策略网址
	info.pszPrivacyPolicyURL = _T("http://myapp.com/privacypolicy.html");

	// 安装错误报告
	int nResult = crInstall(&info);
	if (nResult != 0)
	{
		// 出错了,获取错误信息
		TCHAR szErrorMsg[512] = _T("");
		crGetLastErrorMsg(szErrorMsg, 512);
		_tprintf_s(_T("%s\n"), szErrorMsg);
		return false;
	}

	return true;
}

// 添加CrashRpt功能
void AddCrashRptFunction()
{
	crSetCrashCallback(CrashCallback, NULL);

	// 增加日志文件到错误报告中
	crAddFile2(_T("log.txt"), NULL, _T("Log File"), CR_AF_MAKE_FILE_COPY);

	// 增加整个桌面的截图到崩溃报告文件中
	crAddScreenshot2(CR_AS_VIRTUAL_SCREEN, 0);

	// 将命名属性添加到崩溃说明 XML 文件中
	crAddProperty(_T("VideoCard"), _T("nVidia GeForce 8600 GTS"));
}

// 卸载CrashRpt
void UninstallCrashRpt()
{
	// 在主线程退出前卸载CrashRpt
	crUninstall();
}

int _tmain(int argc, _TCHAR* argv[])
{
	// 安装CrashRpt
	if (!InstallCrashRpt())
		// 安装失败
		return 1;

	// 添加CrashRpt功能
	AddCrashRptFunction();

	// 打开日志文件
	errno_t err = _tfopen_s(&g_hLog, _T("log.txt"), _T("wt"));
	if (err != 0 || g_hLog == NULL)
	{
		// 不能打开日志文件
		_tprintf_s(_T("Error opening log.txt\n"));
		return 1;
	}

	log_write(1, _T("Started successfully\n"));

	// 创建工作线程
	HANDLE hWorkingThread = CreateThread(NULL, 0, ThreadProc, (LPVOID)NULL, 0, NULL);

	log_write(1, _T("Created working thread\n"));

	// 这里会引发无效参数异常
	TCHAR* szFormatString = NULL;
	_tprintf_s(szFormatString);

	// 等待工作线程退出
	WaitForSingleObject(hWorkingThread, INFINITE);

	log_write(1, _T("Working thread has exited\n"));

	// 关闭日志文件
	if (g_hLog != NULL)
	{
		// 关闭日志文件句柄
		fclose(g_hLog);
		g_hLog = NULL;
	}

	// 退出时卸载CrashRpt
	UninstallCrashRpt();
	return 0;
}

Modify CrashRpt interface language

The default CrashRpt has an English interface. We can rename crashrpt_lang_ZH-CN.ini in the lang_files directory under the CrashRpt root directory to crashrpt_lang.ini and replace the file with the same name in our project, so that the interface can be displayed in Chinese. .

Guess you like

Origin blog.csdn.net/u013404885/article/details/127592243