可以捕捉所有未知异常和生成包含程序名的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;
}
分享到:
相关推荐
"C++文件操作工具类"是一个专门为C++开发者设计的实用工具,它简化了对文件进行读写、创建、删除等操作的过程。 首先,我们要理解C++中的文件操作基本概念。C++通过标准库中的`fstream`头文件提供了一套接口,允许...
本篇文章将详细介绍如何在C++中实现一个基础的日志工具类。 首先,我们需要定义日志级别。这些级别可以是枚举类型,例如: ```cpp enum class LogLevel { DEBUG, INFO, WARN, ERROR, FATAL }; ``` 接下来,...
VC6 调试器是一个功能强大且易于使用的调试工具。通过了解和掌握这些调试技巧,我们可以更好地解决问题,提高我们的调试效率。 调试器分类 在 Windows 平台上,调试器可以分为两大类:用户模式调试器和内核模式...
这似乎是目前这个 Visual C++ 6.0 版本的一个 bug,可以按照以下步骤使其正常:关闭 Project,删除“工程名.ncb”文件,然后重新打开工程。 8. 如何将一个通过 ClassWizard 生成的类彻底删除? 首先在工作区的 ...
总之,“VC/C++调试工具”是一个面向C++开发者的实用工具,通过控制台显示和日志生成,它能帮助开发者有效地定位和解决问题,提高开发效率。在没有Visual C++环境或需要轻量级调试方案的情况下,这款工具将发挥巨大...
在Windows平台上,Visual Studio是一个优秀的集成开发环境(IDE),支持C++开发,并提供了丰富的调试和代码编辑功能。 BLE技术是蓝牙技术的一个分支,旨在实现低功耗、短距离的无线通信。它特别适合于物联网(IoT)...
这个源码包名为“源码 C++ MFC 源代码 串口调试助手”,显然是一款基于C++和MFC的串口通信调试工具。 串口通信是计算机通信技术中的一个重要部分,特别是在嵌入式系统和设备调试中。通过串行端口,设备可以相互通信...
"c、c++调试软件"便是这样一类工具,它们为程序员提供了一个直观的环境,以便检查程序的运行状态,找出潜在的bug。 Microsoft Visual Studio是其中的一款杰出代表,它是一个全面的集成开发环境(IDE),不仅支持C++...
- **使用Android Studio的C++调试器**:在Android Studio中设置断点,然后启动带有NDK调试配置的运行/调试会话。 - **使用GDB**:可以通过NDK提供的GDB工具进行远程调试,需要在应用中开启调试标志,并通过ADB连接...
本项目提供了一个C++实现的中英文敏感词检测工具类,该工具能够帮助开发者检查文本中是否存在特定的关键字,并在找到时进行替换,以保护数据的安全性和合规性。下面我们将详细探讨这个工具类的实现原理、功能特性...
windows visual studio C++ 蓝牙BLE客户端(蓝牙调试工具)的完整源码和例子,可用于调试蓝牙BLE的开发板,比如esp32。自己用了很多年,稳定,代码结构清晰 //注册通知回调 RegisterBleDeviceRecvData(call_back); ...
在Android开发中,JNI(Java Native Interface)是一个关键的组件,允许Java代码调用本地(C/C++)代码,反之亦然。这对于性能敏感的应用、底层库的集成以及利用现有C/C++库是非常有用的。本教程将聚焦于如何在...
调试工具通常包括了显示网络流量、捕获和解析网络包、模拟不同网络条件等功能,帮助开发者排查网络问题。 在实际开发中,理解和掌握TCP与UDP的特性及其在C++和C#中的应用至关重要。TCP的可靠性保证了数据的正确传输...
总的来说,这个C++源码项目为学习和实践串口通信提供了一个实例,可以帮助开发者深入理解串口工作的原理,以及如何在Windows环境下用C++编写串口通信程序。对于从事硬件开发、嵌入式系统或物联网应用的人来说,这是...
此外,C++和C#都有丰富的调试工具,如GDB和Visual Studio,它们可以帮助我们步进执行代码,观察变量状态,找出可能导致问题的源头。 总的来说,TCP网络调试是一项涉及网络基础、套接字编程和问题排查技能的工作。...
Java转C++代码工具J2C是一个专门用于将Java源代码转换为等效C++代码的工具。这个工具对于那些需要在不支持Java或者需要利用C++特定性能特性的环境中迁移Java项目的人来说非常有用。在深入探讨J2C之前,我们先理解...
6. **调试工具**:Turbo C++自带了一个简单的调试器,允许程序员设置断点,单步执行代码,查看变量值等,帮助调试程序。 7. **代码管理**:在DOS下,没有现代的版本控制系统,程序员可能需要手动管理源代码文件,...
《Visual C++ 6.0开发工具与调试详解》 Visual C++ 6.0是一款经典且强大的集成开发环境(IDE),它为程序员提供了丰富的工具和功能,支持C++编程语言,尤其在Windows应用程序开发中占据重要地位。本文将深入探讨其...
最后,一个全面的C++学习工具还应该包括调试工具。学会如何设置断点、查看变量状态、单步执行代码以及理解调用堆栈是成为一名熟练C++程序员的必要技能。 总之,C++学习工具是掌握这种语言的关键。它不仅要有完善的...