MiniDump (Error Dump System) is a feature provided by ProudNet that allows you to collect error information directly from the developer when a game client or game server crashes while playing an online game service in order to track the cause and take quick action.
Error information is collected in a *.DMP file, and developers can open the collected dump file in a development tool (such as Visual Studio) to see on which lines of the source file the crash occurred.
Tutorial on building an error dump system
The Building an Error Dump System tutorial included a game server and client.
(1) Install the DbgHelp library
Copy dbghelp.dll to the folder where your OS is installed (C:\Windows\system32) or to the program's current folder.
dbghelp.dll is located in (ProudNet installation path)\ProudNet\Sample\Bin.
(2) Setting Visual Studio Compilation Options
For MiniDump (Error Dump System), you need to configure C++ compilation as below.
For Visual Studio 2003, you cannot set it as above, so you need to select 'No' and add /EHa in Configuration Properties -> C/C++ -> Command Line -> Additional Options.
(3) Example of creating a dump server
Responsible for collecting error information dump files sent by the dump client.
The dump client is responsible for sending dump files containing error information to the dump server.
If the process crashes, a temporary *.DMP dump file is automatically created and the error level information is attached to the Command Argument as the process runs again.
The error level information received as a command argument must be branched according to its severity, and in the case of MiniDumpAction_AlarmCrash, it is a critical error, so you must write code to send the dump file to the dump server.
(5) Creating a Dump Client for a Game Server
Since game servers typically do not provide a user UI, you will need to write code to send the *.DMP dump file directly to the dump server without popping up an error reporting dialog.
(6) Creating a Dump Client for Game Clients
Game clients typically have a user UI, so you will need to write code to prompt the game user if they want to send the generated *.DMP dump file to the dump server with an error report or skip it before proceeding.
Caution
We do not support dump clients on all mobile environments.
You must initialize the dump system using Proud.CMiniDumpParameter.
For the Unicode programming model, you can define a wide-character version of the main function, where the argv and envp parameters to the wmain function must use the wchar_t* format.
For MiniDumpAction_AlarmCrash, MiniDumpAction_DoNothing, you must terminate the program after branching because you can get stuck in an infinite loop by calling return.
#include "stdafx.h"
#include <atlpath.h>
#include "../../include/MiniDumper.h"
#include "../../include/DumpCommon.h"
using namespace Proud;
const int _MAX_PATH2 = 8192;
#define _COUNTOF(array) (sizeof(array)/sizeof(array[0]))
void GetDumpFilePath(LPWSTR output)
{
WCHAR path[_MAX_PATH2];
WCHAR drive[_MAX_PATH2];
WCHAR dir[_MAX_PATH2];
WCHAR fname[_MAX_PATH2];
WCHAR ext[_MAX_PATH2];
WCHAR module_file_name[_MAX_PATH2];
GetModuleFileNameW(NULL, module_file_name, _COUNTOF(module_file_name));
_tsplitpath_s(module_file_name, drive, _MAX_PATH2, dir, _MAX_PATH2, fname, _MAX_PATH2, ext, _MAX_PATH2);
_tmakepath_s(path, _MAX_PATH2, drive, dir, L"", L"");
wsprintf(output, L"%s%s.DMP", path, fname);
};
void AccessViolation()
{
int* a = 0;
*a = 1;
}
// void wmain(int argc, wchar_t* argv[])
int main(int argc, char* argv[])
{
int nRetCode = 0;
int *data = 0;
int menu = 0;
WCHAR dumpFileName[_MAX_PATH2] = { 0, };
GetDumpFilePath(dumpFileName);
CMiniDumpParameter parameter;
parameter.m_dumpFileName = dumpFileName;
parameter.m_miniDumpType = SmallMiniDumpType;
switch (CMiniDumper::Instance().Startup(parameter))
{
case MiniDumpAction_AlarmCrash:
// ์ค๋ฅ ๋ฐ์์ผ๋ก ์๋ก์ด ํ๋ก์ธ์ค์์ ๋คํ ํ์ผ์ ์์ฑํ ํ, ์ด ๊ฐ์ด return์ด ๋ฉ๋๋ค.
// ์์ฑ๋ ๋คํ ํ์ผ์ ๋ฉ์ผ๋ก ๋ณด๋ด๊ฑฐ๋ ์๋ฌ ์ฐฝ์ ๋ณด์ด๋ ๋ฑ ์ ์ ๊ฐ ๋คํ ํ์ผ ์์ฑ ํ, ์ฒ๋ฆฌํด์ผํ ์์ ์ ์ฒ๋ฆฌํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
// A dump file is created at a new process due to error occurrence and then this value will be returned.
// After a user create a dump file, do works that need to be done such as sending a created dump file by email or showing an error window.
// ๅ ๅบ็ฐ้่ฏฏ๏ผๅจๆฐ็processไธญ็ๆ่ฝฌๅจๆไปถๅ่ฏฅๅผๅฐ่ขซ่ฟ่ฟใ
// ๅฐ็ๆ็่ฝฌๅจๆไปถไปฅ้ฎไปถ็ๅฝขๅผๅ้๏ผๆๅฏไปฅ็ๅฐ Errorๅฏน่ฏๆก็็จๆท็ๆ่ฝฌๅญๆไปถๅ๏ผๅค็ๅบๅค็็ไบๅณๅฏ
// ใจใฉใผ็บ็ใซใใๆฐใใใใญใปในใใใใณใใใกใคใซใ็ๆใใๅพใใใฎๅคใreturnใใใพใใ
// ็ๆใใใใใณใใใกใคใซใใกใผใซใง้ใฃใใใใจใฉใผใกใใปใผใธใๆ็คบใใใใชใฉใฆใผใถใผใใใณใใใกใคใซ็ๆๅพใๅฆ็ใในใใฎไฝๆฅญใใใฆใใ ใใใ
...
return nRetCode;
case MiniDumpAction_DoNothing:
// ์ ์ ํธ์ถ๋ก ์๋ก์ด ํ๋ก์ธ์ค์์ ๋คํ ํ์ผ์ ์์ฑํ ํ, ์ด ๊ฐ์ด ๋ฐํ๋ฉ๋๋ค.
// ์ด ๊ฒฝ์ฐ์๋ ์๋ฌด๊ฒ๋ ํ์ง ๋ง์์ผํฉ๋๋ค.
// After creating a dump file at a new process by calling a user, this value will be returned.
// In this case, you should not do anything.
// ๅ ็จๆทๅผๅซ๏ผๅจๆฐ็processไธญ็ๆ่ฝฌๅจๆไปถๅ๏ผ่ฏฅๅผๅฐ่ขซ่ฟ่ฟใ
// ๅจ่ฟ็งๆ ๅต๏ผไธ่ฆๅไปปไฝไบๆ ใ.
// ใฆใผใถใผๅผใณๅบใใซใใๆฐใใใใญใปในใใใใณใใใกใคใซใ็ๆใใๅพใใใฎๅคใ่ฟ้ใใใพใใ
// ใใฎๅ ดๅไฝใใใชใใงใใ ใใใ
...
return nRetCode;
default:
// MiniDumpAction_None
// ์ผ๋ฐ์ ์ผ๋ก ์ฑ ์คํ ์, ์ด ๊ฐ์ด ๋ฐํ๋ฉ๋๋ค.
// ์ฌ๊ธฐ์๋ ์ผ๋ฐ์ ์ผ๋ก ์ฒ๋ฆฌํด์ผํ ์ผ์ ์ฒ๋ฆฌํด์ฃผ์๋ฉด ๋ฉ๋๋ค.
// When executing apps, this value will be returned.
// In this case, do works that generally need to be done.
// ไธ่ฌ่ฟ่กAppๆถ๏ผ่ฏฅๅผๅฐ่ขซ่ฟ่ฟใ
//ๅจ่ฟ้ๅค็ไธ่ฌๅบๅค็็ไบๆ ๅณๅฏใ
// ไธ่ฌ็ใซใขใใชๅฎ่กๅพใใใฎๅคใ่ฟ้ใใใพใใ
// ใใใงใฏไธ่ฌ็ใซๅฆ็ใในใใฎไบใๅฆ็ใใฆใใ ใใใ
...
break;
}
while (1)
{
puts("MENU: 1. Access Violation('a')");
printf("> ");
menu = getchar();
switch (menu)
{
case 'a':
AccessViolation();
break;
default:
break;
}
}
return 0;
}
Utilize an error dump system
- Intercepting C Runtime Errors from the Error Dump System
Out-of-range errors in the STL or errors where a purely virtual function is called at runtime are not detected by the error dump system by default.
The error dump system only handles Structured Exceptions, because these errors are digested by the C runtime library. Therefore, you must divert them to Structured Exceptions before they can be digested by the C runtime library to leave an error dump.
Below is how to leave an error dump.
// Pure virtual function called" Bypassing errors to be received by the error dump system.
void myPurecallHandler(void)
{
printf("In _purecall_handler.");
int* a = 0;
*a = 1; // Causing a crash. Bypassing the error dump system.
}
int main()
{
/* Bypasses the pure virtual function called error handler to a user-defined function.
You only need to put it in at the beginning of the program.*/
_set_purecall_handler(myPurecallHandler);
...
}
// Bypassing "out of the range errors" in the STL to be received by the error dump system.
// Caution!!! The _CrtSetReportHook can enter the function you set using ATLTRACE, so retportType == _CRT_WARN should be ignored.
int YourReportHook(int reportType, char *message, int *returnValue)
{
//Ignore _CRT_WARN or 0.
if (reprotType != _CRT_WARN)
{
int* a = 0;
*a = 1; // Causing a crash. Bypassing the error dump system.
}
return 1;
}
int main()
{
/* Bypasses the handler of a C runtime library error to a user-defined function.
You only need to put it in at the beginning of the program.*/
_CrtSetReportHook(YourReportHook);
std::vector<int> a;
a[1] = 0; // Test if an error handler has been bypassed
}
ProudNet provides a feature that, when an error occurs in a program, continues to log the location of the error without terminating the program. This is called a uninterrupted error dump system(Exception Logger).
A typical game server will immediately dump the situation and restart the program when it crashes, but in some cases it may be necessary to force the game server to stay up and running without restarting the program.
However, it is dangerous to continue running a server program that has already corrupted its memory state.
Checklist for creating a uninterrupted error dump system
You need to install the DbgHelp library (dbghelp.dll).
You need to set the C++ Exception compilation option in Visual Studio.
Include : DumpCommon.h, MiniDumper.h
Link : ProudNetCommon.lib
Production examples
Make sure to initialize the CExceptionLogger instance by calling the CExceptionLogger::Instance().Init() function at the Main Entry Point of the program. Define the path to the dump file by inheriting from the IExceptionLoggerDelegate abstract class and overriding the GetDumpDirectory() member. If it returns a blank (""), the dumpfile is saved in the current folder.
Works on Windows XP and Windows 2003 Server or later versions of the operating system.
If you mix the CExceptionLogger class with ATLTRACE() or OutputDebugString(), the load of log entries can degrade program performance.
The source files for this example are located in <install folder>\Sample\SimpleExceptionLogger.
The SimpleExceptionLogger example is not supported since version 1.7.33863.
#include "stdafx.h"
#include <atlpath.h>
#include "../../include/DumpCommon.h"
#include "../../include/MiniDumper.h"
using namespace Proud;
class CIExceptionLoggerDelegate : public IExceptionLoggerDelegate
{
public:
virtual String GetDumpDirectory()
{
return L"";
}
};
CIExceptionLoggerDelegate g_loggerInfo;
void AccessViolation()
{
try
{
int* a = 0;
// ์ด ๋ฃจํด์ ํฌ๋์ฌ๋ฅผ ์๋์ ์ผ๋ก ๋ฐ์์ํต๋๋ค.
// This routine incurs crash on purpose.
// ่ฏฅไพ็จๅฐไผๆ ๆ้ ๆๅดฉๆบใ
// ใใฎใซใผใใฃใณใฏใฏใฉใใทใฅใๆๅณ็ใซ็บ็ใใใพใ
*a = 1;
}
catch (...) // catch(...) syntax itself is the usable C++ keyword!
{
// ์ try ๊ตฌ๋ฌธ์ ์ํด ํฌ๋์ฌ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ
// ํ๋ก๊ทธ๋จ์ด ์ข ๋ฃ๋์ง ์๊ณ ์ฌ๊ธฐ๋ก ์คํ ์ง์ ์ด ์ค๊ฒ ๋ฉ๋๋ค.
// ํํธ exception logger์ ์ํด ์ค๋ฅ ๋ก๊ทธ๊ฐ ํ์ผ๋ก ๋จ๊ฒ ๋ฉ๋๋ค.
// When crash occurs by the above try syntax,
// the execution point moves to here without terminating the program.
// At the same time, exception logger leaves an error log file.
}
}
void main(int argc, char* argv[])
{
int menu = 0;
CExceptionLogger::Instance().Init(&g_loggerInfo);
while (1)
{
puts("MENU: 1. Access Violation('a')");
printf("> ");
menu = getchar();
switch (menu)
{
case 'a':
AccessViolation();
break;
default:
break;
}
}
}
- Leave a dump file of the current state of the process
It has the ability to leave a dump file of the current state of the process, even if it is not in an error situation, which can be opened along with the debug information file (.pdb) that was generated when the program that it dumped was built, to see what the process was doing at the source level.
This feature allows you to leave a dump of the current state of the process, even in difficult debugging environments.
Calling Proud.CMiniDumper.WriteDumpFromHere saves the call stack of all threads in the process at the time of the call to a dump file.
Setting up compilation to use the error dump system
This feature allows you to dump the current state of a process, even in environments where debugging is difficult.