`
oliver_peng
  • 浏览: 43214 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

一个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;
}

分享到:
评论

相关推荐

    Visual C++开发工具与调试技巧整理

    Visual C++开发工具与调试技巧整理 1.如何在Release状态下进行调试2. Release和Debug有什么不同3....如何将一个通过ClassWizard生成的类彻底删除9. 如何将在workspace中消失的类找出来10. 如何清除所有的断点....

    DEV-C++ 5.rar

    Dev-C++是一个Windows环境下的一个适合于初学者使用的轻量级 C/C++ 集成开发环境(IDE)。它是一款自由软件,遵守GPL许可协议分发源代码。它集合了MinGW中的GCC编译器、GDB调试器和 AStyle格式整理器等众多自由软件...

    串口调试工具 VC码源

    使用c++开发的简易串口调试工具,使用serial port类,可在vc6.0及以上调试

    C++程序设计代码

    1.设计并定义一个交通工具类,并通过该类派生出新的类,编写程序定义这些类并测试它; 2.(选做)声明一个基类Shape,在此基础上派生Rectangle和Circle,二者都有GetArea()函数计算对象的面积,编写程序测试。 3...

    McGraw C++程序调试实用手册

    9.l 高级调试工具 9.l.l 内存卸出 9.1.2 定位错误参数从何处传递而来 9.1.3 查找何处修改了指针 9.2 Class View窗口要素 9.2.1 ClassView窗口的 Grouped by Access功能 9.2.2 ClassView窗口的 Base ...

    OD调试工具 for 64 win7-C++工具类资源

    64位系统下可用Ollydbg调试工具不多啊,好不容易下了个,浪费的8分,为了方便大家。我传了一个。 可在最新的WIN7下使用哦。

    Visual C++ 6.0 中文版.rar

    Visual C++6.0是一个功能强大的可视化软件开发工具。自1993年Microsoft公司推出Visual C++1.0后,随着其新版本的不断问世,Visual C++已成为专业程序员进行软件开发的首选工具。 虽然微软公司推出了Visual C++.NET...

    C++实验三.docx

    在Time类中增加拷贝构造函数的定义,主函数中调用该函数,运用调试工具跟踪,分析整个程序调用构造函数(包括拷贝构造函数)和析构函数的次数;再将f函数的形式参数分别修改为引用参数和指针参数(此时函数代码修改...

    Visual C++ 6.0 软件

    Visual C++ 6.0,简称VC或者VC6.0,是...Visual C++6.0由许多组件组成,包括编辑器、调试器以及程序向导AppWizard、类向导Class Wizard等开发工具。 这些组件通过一个名为Developer Studio的组件集成为和谐的开发环境。

    C/C++/Linux函数函数插桩(打桩)指南

    这样的需求一般称作:插桩,也就是对于一个指定的目标函数,新建一个包装函数,来完成一些额外的功能,如动态调试等。 本文主要讲解什么是打桩,以及编译阶段打桩、链接阶段打桩、执行阶段打桩三种方式。

    正宗《Visual C++2008入门经典》中文 高清完整版PDF part5(共6部分)

    本书系编程语言先驱者Ivor Horton的经典之作,是C++编程方面最畅销的图书品种之一,不仅涵盖了Visual C++ 2008编程知识,还全面介绍了标准C++语言和C++/CLI。本书延续了Ivor Horton讲解编程语言的独特方法,从中读者...

    C-Free好用的C/C++语言开发工具

    C-Free是一款支持多种编译器的专业化C/C++集成开发环境(IDE)。利用本软件,使用者可以轻松地编辑、编译、连接、运行、调试C/C++程序。 1. 支持多编译器,可以配置添加其他编译器;(0) 目前支持的编译器类型: (1)...

    C++实训教程(冯矢勇) Part2共2个文件

    第一篇 跟我练习 第1章 选择最方便的开发工具 1.1 可用的开发工具简介 1.1.1 Boland C++ 3.1/4.0/4.5 1.1.2 Boland C++ 5.0 1.1.3 Boland C++ Builder4.0/5.0/6.0 1.1.4 Visual C++ 6.0 1.2 Borland C++5.0...

    Visual C++范例大全

    《Visual C++范例大全》是孙皓创作的软硬件开发类书籍。 从工程应用出发,通过400余实例讲解VisualC++开发技术与要点涵盖VisualC++基本开发要素,也包含数据库,网络、多媒体等常用开发技术按照循序渐近、由浅入深...

    Visual C++6.0运行库参考手册

    全书共分成两大个部分:第一部分为iostream类参考,包括iostream编程和iostream类库按字母顺序参考两章;第二部分为运行库参考,包括运行库例程分类、全局变量和标准类型、全局常量、调试版C运行库和运行类库字母...

    C++实训教程(冯矢勇) Part1共2个文件

    第一篇 跟我练习 第1章 选择最方便的开发工具 1.1 可用的开发工具简介 1.1.1 Boland C++ 3.1/4.0/4.5 1.1.2 Boland C++ 5.0 1.1.3 Boland C++ Builder4.0/5.0/6.0 1.1.4 Visual C++ 6.0 1.2 Borland C++5.0...

    Visual C++开发实战宝典 明日科技 高清pdf

    包括Visual C++ 6.0开发环境,程序设计基础,流程控制,函数,类和对象,对话框程序设计,MFC通用控件,MFC高级控件,菜单、工具栏和状态栏设计,文本、图形图像处理技术,程序调试,打印技术,文件操作,ADO数据库...

    C++ Primer第四版【中文高清扫描版】.pdf

    16.5 一个泛型句柄类 560 16.5.1 定义句柄类 561 16.5.2 使用句柄 562 16.6 模板特化 564 16.6.1 函数模板的特化 565 16.6.2 类模板的特化 567 16.6.3 特化成员而不特化类 569 16.6.4 类模板的部分特化 570 16.7 ...

    易学C++(简单易懂的讲解)

    第十章如何阅读程序代码……112 10.1整体把握法……112 10.2经验法……114 ...调试工具——Debug ……138 习题……141 第十二章如何编写程序代码……144 12.1程序设计的基本步骤……144 12.2三类问题……144 12.3函数的...

    Visual C++ 2005入门经典.part08.rar (整理并添加所有书签)

    19.6 使用另一个记录集对象 19.6.1 添加记录集类 19.6.2 添加记录集的视图类 19.6.3 定制记录集 19.6.4 访问多个表视图 19.6.5 查看产品的订单 19.7 查看客户的详细情况 19.7.1 添加客户记录集 19.7.2 创建客户...

Global site tag (gtag.js) - Google Analytics