一个C++调试工具类

可以捕捉所有未知异常和生成包含程序名的Core dump 文件。

/*
* DebugUtility.h
*
* Created on: Jun 4, 2014
* Author: root
*
* Use following two ways to help debugging application when application is crashed:
*
* 1 Turn on core dump and generate core dump file by forking child process and rename the child process dump
* file to new name. Including application name in core dump file is more easy to identify then default
* file name.
* 2 Overwrite terminate() to handle un-handled exception and print backtrace before abort.
* Use gdb to get backtrace and save into log file /tmp/[app_name]_backtrace
*
* Requriement:
* Linux, gcc, gdb
*
* How to use it:
*
* Add following lines at the beginning of main function to initialize:
* Be attention: app_name can't include path.
*
* char * app_name;
* if ( (app_name = strrchr(argv[0], '/')) == NULL )
* {
* DebugUtility::GetInstance().Setup(argv[0], true);
* }
* else
* {
* DebugUtility::GetInstance().Setup(app_name + 1, true);
* }
*
* To generate core dump file, you need to call DebugUtility::GetInstance().GenerateCoreDump() in signal
* handler code.
*
* For example:
*
* void signal_handler(int signal, siginfo_t * p_signinfo, void * p_context)
* {
* DebugUtility::GetInstance().GenerateCoreDump();
* exit(0);
* }
*
* In main function:
*
* struct sigaction sa;
* sa.sa_sigaction = signal_handler;
* sigemptyset(&sa.sa_mask);
* sa.sa_flags = SA_RESTART | SA_SIGINFO;
* sigaction(SIGTERM, &sa, (struct sigaction *) NULL);
*
* For application name test, if it crashed, you should be able to find core dump file core.test.[pid].
*
* For application name test, if it quit because of raised exception, you should be able to find backtrace
* log file /tmp/test_backtrace
*/

#ifndef DEBUGUTILITY_H_
#define DEBUGUTILITY_H_

#include <stdlib.h>
#include <string>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
#include <sys/wait.h>
#include <iostream>
#include <exception>

using namespace std;

class DebugUtility
{
public:

// Overwrite default global terminate handler to handle all un-handled exceptions
// Print backtrace before calling abort()
static void my_terminate()
{
DebugUtility::GetInstance().PrintBacktrace();

abort();
}

// Use singleton pattern to be sure only one DebugUtility object
static DebugUtility & GetInstance()
{
static DebugUtility instance;

return instance;
}

// Setup debug environment
// Parameters:
// app_name: application name which will be part of core dump and backtrace file.
// core_dump_enabled: whether enable core dump, by default true.
void Setup(string app_name, bool core_dump_enabled = true)
{
m_app_name = app_name;

m_core_dump_enabled = core_dump_enabled;

re_throw_flag = true;

if (m_core_dump_enabled)
EnableCoreDump();

std::set_terminate(DebugUtility::my_terminate);
}

// Generate core dump file based on application name
// For example application name test and pid is 12345, the core dump file is core.test.12345
void GenerateCoreDump()
{
try
{
if (m_core_dump_enabled)
{
// Fork child process to generate core dump file
// Then rename file name with application name

pid_t childpid = fork();

// child process generates core dump
if (childpid == 0)
{
// Send SIGABRT signal to terminate child process and generate core dump
abort();
}

if (childpid > 0)
{
waitpid(childpid, 0, 0);
}

char core_dump_file_name[1000];
char child_core_dump_file_name[1000];

// Rename the core dump name.
sprintf(core_dump_file_name, "core.%s.%d", m_app_name.c_str(), getpid());
sprintf(child_core_dump_file_name, "core.%d", childpid);

// try with core.pid
int rename_rval = rename(child_core_dump_file_name, core_dump_file_name);

if (rename_rval == -1)
{
// try with just core which may happen on HP server
rename_rval = rename("core", core_dump_file_name);
}
}
} catch (...)
{
// Catch all exceptions
}
}

// Try to re-throw exception again and print error message to std:cerr
// Generate back trace by using gdb and save under /tmp
// For example application name test, the backtrace file is /tmp/test_backtrace
void PrintBacktrace()
{
try
{
// try once to re-throw currently active exception
if (re_throw_flag)
{
re_throw_flag = false;
throw;
}
} catch (const std::exception &e)
{
std::cerr << __FUNCTION__ << " caught unhandled exception. what(): " << e.what() << std::endl;
} catch (...)
{
std::cerr << __FUNCTION__ << " caught unknown/unhandled exception." << std::endl;
}

try
{
char command_line[1000];
snprintf(command_line, sizeof(command_line), "gdb 2>/dev/null --batch -n -ex thread -ex bt full --exec=%s --pid=%d > /tmp/%s_backtrace",
m_app_name.c_str(), getpid(), m_app_name.c_str());
system(command_line);
} catch (...)
{
// Catch all exceptions
}
}

~DebugUtility()
{
}

private:

DebugUtility()
{

}

// Enable core dump
void EnableCoreDump()
{
m_core_dump_enabled = true;
// Set core dump limit to unlimited to enable core dump
rlimit core_limit =
{ RLIM_INFINITY, RLIM_INFINITY };
setrlimit(RLIMIT_CORE, &core_limit);
}

// Don't forget to declare these two. You want to make sure they
// are unaccessable otherwise you may accidently get copies of
// your singleton appearing.

DebugUtility(DebugUtility const&); // Don't Implement
void operator=(DebugUtility const&); // Don't implement

// Application name which will be used in backtrace file name and core dump file name
string m_app_name;

// Whether generate core dump file
bool m_core_dump_enabled;

// Re-throw flag
bool re_throw_flag;
};

#endif /* DEBUGUTILITY_H_ */



使用范例代码:


#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DebugUtility.h"
#include <exception>
#include <stdexcept>
#include <iostream>

using namespace std;

void signal_handler(int signal, siginfo_t * p_signinfo, void * p_context)
{
DebugUtility::GetInstance().GenerateCoreDump();
exit(0);
}

void func1()
{

throw std::runtime_error("test");
}

void func2()
{
func1();
}

int main(int argc, char* argv[])
{
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!

char * app_name;
if ( (app_name = strrchr(argv[0], '/')) == NULL )
{
DebugUtility::GetInstance().Setup(argv[0], true);
}
else
{
DebugUtility::GetInstance().Setup(app_name + 1, true);
}

struct sigaction sa;
sa.sa_sigaction = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO;

sigaction(SIGTERM, &sa, (struct sigaction *) NULL);
sigaction(SIGINT, &sa, (struct sigaction *) NULL);

func2();

return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值