admin管理员组文章数量:1567302
文章目录
- 1. 概述
- 2. 使用boost::stacktrace
- 安装方法(针对Ubuntu系统)
- 测试代码
- CMake编译配置
- 3. 使用第三方库Backward-cpp
- 安装及配置示例(以BACKWARD_HAS_DW为例)
- Ubuntu系统安装libdw-dev
- 示例代码
- 输出到日志文件的示例代码
- CMake编译配置
- 4. Qt Creator启用内存泄漏/越界检查工具
- 5. 参考
- 其他
1. 概述
在Linux程序开发中,当使用-g选项编译程序时,如果程序发生崩溃(coredump),可以利用gdb调试生成的dump文件定位崩溃位置。对于C++程序,有几种组件可以用于打印崩溃时的堆栈信息。本文介绍了其中几种方法。
测试代码已上传至gitee。
2. 使用boost::stacktrace
boost::stacktrace
是从boost 1.65版本开始支持的堆栈跟踪功能。使用前请确保已安装libboost-stacktrace-dev
。
安装方法(针对Ubuntu系统)
sudo apt-get install libboost-stacktrace-dev
测试代码
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#define BOOST_STACKTRACE_USE_ADDR2LINE
#include <boost/stacktrace.hpp>
char *str = (char *)"test";
void core_test()
{
str[1] = 'T';
}
void handler(int signo)
{
if (std::ofstream file_stream("my_stacktrace.log", std::ios::trunc); file_stream.is_open())
{
std::stringstream ss;
ss << boost::stacktrace::stacktrace();
std::cout << boost::stacktrace::stacktrace() << std::endl;
file_stream.write(ss.str().c_str(), ss.str().size());
file_stream.close();
}
raise(signo);
}
int main()
{
struct sigaction act{};
act.sa_flags = SA_NODEFER | SA_RESETHAND;
act.sa_handler = &handler;
sigfillset(&act.sa_mask);
sigdelset(&act.sa_mask, SIGSEGV);
if (sigaction(SIGSEGV, &act, nullptr) == -1)
std::exit(EXIT_FAILURE);
core_test();
}
输出结果:
0# handler(int) at /usr/local/include/boost/stacktrace/stacktrace.hpp:129
1# 0x00007FF3691A0090 in /usr/lib/x86_64-linux-gnu/libc.so.6
2# core_test() at /home/dgliu/boost_stacktrace_demo/src/boost_stacktrace_demo.cpp:14
3# main at /home/dgliu/boost_stacktrace_demo/src/boost_stacktrace_demo.cpp:46
4# __libc_start_main in /usr/lib/x86_64-linux-gnu/libc.so.6
5# _start in ./bin/boost_stacktrace_demo
CMake编译配置
set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -fno-pie -ggdb3 -O0 -no-pie")
关于no-pie
的说明已在文中提及。
3. 使用第三方库Backward-cpp
Backward-cpp 是一个支持多平台堆栈跟踪的库,适用于x86和ARM平台。
安装及配置示例(以BACKWARD_HAS_DW为例)
Ubuntu系统安装libdw-dev
sudo apt-get install libdw-dev
示例代码
#include<stdio.h>
#include<stdlib.h>
#define BACKWARD_HAS_DW 1
#include "backward.hpp"
namespace backward{
backward::SignalHandling sh;
}
int main(){
char *c = "hello world";
c[1] = 'H';
}
输出到日志文件的示例代码
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fstream>
#include <iostream>
#define BACKWARD_HAS_DW 1
#include "backward.hpp"
namespace backward
{
backward::SignalHandling sh;
}
char *str = (char *)"test";
void core_test()
{
str[1] = 'T';
}
void handler(int signo)
{
if (std::ofstream file_stream("my_stacktrace.log", std::ios::trunc); file_stream.is_open())
{
file_stream << "Caught signal " << signo << ".\nTrace:\n";
backward::StackTrace st;
st.load_here(32);
backward::Printer p;
p.print(st, file_stream);
p.print(st, std::cout);
}
raise(signo);
}
int main()
{
struct sigaction act {};
act.sa_flags = SA_NODEFER | SA_RESETHAND;
act.sa_handler = &handler;
sigfillset(&act.sa_mask);
sigdelset(&act.sa_mask, SIGSEGV);
if (sigaction(SIGSEGV, &act, nullptr) == -1)
std::exit(EXIT_FAILURE);
core_test();
}
输出结果:
Stack trace (most recent call last):
#8 Object "", at 0xffffffffffffffff, in
#7 Object "/home/dgliu/backward-cpp_demo/bin/backward-cpp_demo", at 0x5619693b2f4d, in _start
#6 Source "../csu/libc-start.c", line 308, in __libc_start_main
#5 Source "/home/dgliu/backward-cpp_demo/src/backward-cpp_demo.cpp", line 51, in main
48: if (sigaction(SIGSEGV /* or other signal */, &act, nullptr) == -1)
49: std::exit(EXIT_FAILURE);
50:
> 51: core_test();
52: }
#4 Source "/home/dgliu/backward-cpp_demo/src/backward-cpp_demo.cpp", line 17, in core_test
14: char *str = (char *)"test";
15: void core_test()
16: {
> 17: str[1] = 'T';
18: }
19:
20: // This is definitely not async-signal-safe. Let's hope it doesn't crash or hang.
#3 Object "/usr/lib/x86_64-linux-gnu/libc-2.31.so", at 0x7ff6ce6ec08f, in
#2 Source "/home/dgliu/backward-cpp_demo/src/backward-cpp_demo.cpp", line 27, in handler
24: {
25: file_stream << "Caught signal " << signo << ".\nTrace:\n";
26: backward::StackTrace st;
> 27: st.load_here(32);
28: backward::Printer p;
29: p.print(st, file_stream);
30: p.print(st, std::cout);
#1 Source "/home/dgliu/backward-cpp_demo/include/backward.hpp", line 880, in load_here
877: return 0;
878: }
879: _stacktrace.resize(depth);
> 880: size_t trace_cnt = details::unwind(callback(*this), depth);
881: _stacktrace.resize(trace_cnt);
882: skip_n_firsts(0);
883: return size();
#0 Source "/home/dgliu/backward-cpp_demo/include/backward.hpp", line 862, in unwind<backward::StackTraceImpl<backward::system_tag::linux_tag>::callback>
860: template <typename F> size_t unwind(F f, size_t depth) {
861: Unwinder<F> unwinder;
> 862: return unwinder(f, depth);
863: }
CMake编译配置
set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
4. Qt Creator启用内存泄漏/越界检查工具
配置方法示例:
SOURCES += main.cpp
# 开启内存泄露检查功能
QMAKE_CXXFLAGS += "-fsanitize=leak"
QMAKE_CFLAGS += "-fsanitize=leak"
QMAKE_LFLAGS += "-fsanitize=leak"
# 开启地址越界检查功能
# 显示更详细的信息
QMAKE_CXXFLAGS += "-fsanitize=address -fno-omit-frame-pointer"
QMAKE_CFLAGS += "-fsanitize=address -fno-omit-frame-pointer"
QMAKE_LFLAGS += "-fsanitize=address"
5. 参考
- backward-cpp
- Backward-cpp 妈妈再也不用担心segmentation fault!
- 开源项目推荐:C++堆栈跟踪打印器,backward-cpp
- C++打印调用栈
- How to store back trace info to a file?
其他
在Windows下,一般使用Crashrpt来进行堆栈打印。如果有需要,几年前我曾修改过一个版本,代码地址在gitee。
版权声明:本文标题:C++的Linux程序在崩溃(coredump)后,打印调用堆栈的方法,支持x86和ARM 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1725889534a1047395.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论