如何在C ++中直接使用addr2line

时间:2018-08-17 09:08:49

标签: c++ linux c++11

更新:this question不能满足我的需要,addr2line源不仅是400行源,而且与其他binutils源有关,我想提供一个简单的解决方案来获取“获取回溯行号”

我使用以下代码可以获取回溯行号:

addr2line -e /home/roroco/Dropbox/c/ro-c/cmake-build-debug/ex/test_backtrace_with_line_number  0x400d0b

但是如果我想回溯所有行号,我必须逐行调用addr2line cli,这很慢,有没有办法在没有cli的情况下获得回溯行号,而是使用纯c ++?或其他替代lib可以获取行号

我知道是否看到addr2line,我可以这样做,如果有更方便的c ++ lib,请告诉我

这是我用addr2line获取行号的代码,我希望用纯c ++解决方案代替addr2line cli

#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <zconf.h>
#include "regex"

std::string getexepath() {
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
}

std::string sh(std::string cmd) {
    std::array<char, 128> buffer;
    std::string result;
    std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
    if (!pipe) throw std::runtime_error("popen() failed!");
    while (!feof(pipe.get())) {
        if (fgets(buffer.data(), 128, pipe.get()) != nullptr) {
            result += buffer.data();
        }
    }
    return result;
}


void print_backtrace(void) {
    void *bt[1024];
    int bt_size;
    char **bt_syms;
    int i;

    bt_size = backtrace(bt, 1024);
    bt_syms = backtrace_symbols(bt, bt_size);
    std::regex re("\\[(.+)\\]");
    auto exec_path = getexepath();
    for (i = 1; i < bt_size; i++) {
        std::string sym = bt_syms[i];
        std::smatch ms;
        if (std::regex_search(sym, ms, re)) {
            std::string addr = ms[1];
            std::string cmd = "addr2line -e " + exec_path + " -f -C " + addr;
            auto r = sh(cmd);
            std::regex re2("\\n$");
            auto r2 = std::regex_replace(r, re2, "");
            std::cout << r2 << std::endl;
        }
    }
    free(bt_syms);
}

void test_m() {
    print_backtrace();
}

int main() {
    test_m();
    return 0;
}

1 个答案:

答案 0 :(得分:1)

更改addr2line源太难了,我放弃了, 我收到@ 500-内部服务器错误建议,addr2line cli可以接收多个addrs,所以我像下面那样更改代码,只运行一次addr2line

#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <zconf.h>
#include "regex"
#include "vector"

std::string getexepath() {
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
}

std::string sh(std::string cmd) {
    std::array<char, 128> buffer;
    std::string result;
    std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
    if (!pipe) throw std::runtime_error("popen() failed!");
    while (!feof(pipe.get())) {
        if (fgets(buffer.data(), 128, pipe.get()) != nullptr) {
            result += buffer.data();
        }
    }
    return result;
}


void print_backtrace(void) {
    void *bt[1024];
    int bt_size;
    char **bt_syms;
    int i;

    bt_size = backtrace(bt, 1024);
    bt_syms = backtrace_symbols(bt, bt_size);
    std::regex re("\\[(.+)\\]");
    auto exec_path = getexepath();
    std::string addrs = "";
    for (i = 1; i < bt_size; i++) {
        std::string sym = bt_syms[i];
        std::smatch ms;
        if (std::regex_search(sym, ms, re)) {
            std::string m = ms[1];
            addrs += " " + m;
        }
    }
    auto r = sh("addr2line -e " + exec_path + " -f -C " + addrs);
    std::cout << r << std::endl;
    free(bt_syms);
}

void test_m() {
    print_backtrace();
}

int main() {
    test_m();
    return 0;
}