博客
关于我
C++封装一个易用的打印backtrace信息的函数
阅读量:733 次
发布时间:2019-03-21

本文共 2567 字,大约阅读时间需要 8 分钟。

如何通过C++编写一个易于使用的打印堆栈信息函数

  • 堆栈信息追踪的重要性

    在调试程序过程中,当遇到错误时,能够快速获取当前函数调用堆栈信息至关重要。通常,这会在调用assert函数之前进行,以便定位问题所在。

  • 查看所需的核心函数

  • 2.1 backtrace函数

    backtrace函数的原型为:

    int backtrace(void **buffer, int size);

    使用说明:

    该函数会将当前程序的堆栈信息写入buffer数组。每个数组元素是返回地址,信息是倒序存储的(最近调用在前,遥远调用在后)。通过确保buffer大小和容量足够,可以获取完整的堆栈日志。返回值表示实际获取到的堆栈信息数量,数值不会超过size

    2.2 backtrace_symbols函数

    backtrace_symbols函数的原型为:

    char **backtrace_symbols(void *const *buffer, int size);

    使用说明:

    该函数接受backtrace返回的地址数组,将其转换为字符串数组。每个字符串包含函数名(如果确定可知)、十六进制偏移量和实际返回地址。返回值是一个指针,指向新的字符串数组。注意,这个数组的内存必须由调用者释放,但字符串内容不需要处理。

    2.3 __cxa_demangle函数

    __cxa_demangle函数的原型为:

    char* __cxa_demangle(const char *mangled_name, char *output_buffer, size_t *length, int *status);

    使用说明:

    这个C++内联函数反转编译器添加的符号信息,将其转换为原始函数名。主要作用是解析 και符号sequences。调用者应提供被编译后的符号字符串,并处理返回结果,注意释放动态分配的内存。

    1. 测试各函数的实际使用情况
    2. 3.1 调用backtrace获取日志

      举例:

      void fun(){      static int count = 0;      if (++count == 5){          Backtrace(50, 0);          return;      }      fun();  }  int main(int argc, char* argv[]){      fun();      return 0;  }

      运行后,期望输出包含5次fun调用的堆栈信息。

      3.2 转换为符号名称

      调用backtrace_symbols后,输出应类似于:

      ./all(_Z9BacktraceiiRKSs+0x58) [0x401c43]./all(_Z3funv+0x48)...

      需要提取括号内的名称并解析。

      3.3 使用__cxa_demangle获取原始函数名

      最终结果应类似于:

      Backtrace(int, int, std::string const&).fun()fun()fun()fun()fun()./all(main+0x9)...

      结果表明,其中Backtrace被调用5次,遵循预期调用次数。

      1. 完整代码示例
      2. #include 
        #include
        #include
        #include
        #include
        #include
        #include
        #include
        namespace detail { std::string demangle(const char* str) { size_t size = 0; int status = 0; std::string sstr; sstr.resize(256); if (1 == sscanf(str, "%*[^(]%*[^_]%255[^)+]", &sstr[0])) { char* tmp = abi::__cxa_demangle(&sstr[0], nullptr, &size, &status); if (tmp) { std::string result(tmp); free(tmp); return result; } } if (1 == sscanf(str, "%255s", &sstr[0])) return sstr; return str; } std::string Backtrace(int size = 64, int skip = 2, const std::string& prefix = "") { void* array[size]; size_t s = backtrace(array, size); char** str = backtrace_symbols(array, s); std::vector
        bt; std::stringstream ss; if (str) { for (size_t i = skip; i < s; ++i) { bt.push_back(demangle(str[i])); } free(str); } else { ss << "backtrace_symbols failed"; goto good; } for (const auto& b : bt) { ss << prefix << b << "\n"; }good: return ss.str(); } void fun() { static int count = 0; if (++count == 5) { Backtrace(50, 0); return; } fun(); } int main(int argc, char* argv[]) { fun(); return 0; }}

        以上代码展示了一个完整的解决方案,包括函数定义、调试工具的使用和示例测试程序。通过这种方法,可以方便地获取和解析堆栈信息,使调试过程更加高效。

    转载地址:http://wxsgz.baihongyu.com/

    你可能感兴趣的文章
    MySQL5.7.19-win64安装启动
    查看>>
    mysql5.7.19安装图解_mysql5.7.19 winx64解压缩版安装配置教程
    查看>>
    MySQL5.7.37windows解压版的安装使用
    查看>>
    mysql5.7免费下载地址
    查看>>
    mysql5.7命令总结
    查看>>
    mysql5.7安装
    查看>>
    mysql5.7性能调优my.ini
    查看>>
    MySQL5.7新增Performance Schema表
    查看>>
    Mysql5.7深入学习 1.MySQL 5.7 中的新增功能
    查看>>
    Webpack 之 basic chunk graph
    查看>>
    Mysql5.7版本单机版my.cnf配置文件
    查看>>
    mysql5.7的安装和Navicat的安装
    查看>>
    mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
    查看>>
    Mysql8 数据库安装及主从配置 | Spring Cloud 2
    查看>>
    mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
    查看>>
    MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
    查看>>
    MYSQL8.0以上忘记root密码
    查看>>
    Mysql8.0以上重置初始密码的方法
    查看>>
    mysql8.0新特性-自增变量的持久化
    查看>>
    Mysql8.0注意url变更写法
    查看>>