admin管理员组

文章数量:1530842

文章目录

    • 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。

本文标签: 堆栈程序方法Linuxcoredump