libuv 编译使用,打印调用堆栈

7 篇文章 0 订阅

libuv 编译选项:

CFLAGS='-g -O0 -funwind-tables' ./configure --disable-silent-rules --disable-udev --enable-debug-log

make -j8 V=1

其中 -funwind-tables 可以打印详细调用堆栈。

写程序使用:t1.cc

#include <ux.h>
#include <unistd.h>
#include <signal.h>
#include <execinfo.h>
#include <cstdio>
#include <cstdlib>
#include <thread>

using namespace std;


void handler(int sig)
{
    void* buffer[10];
    FILE* fp = fopen("callstack.txt", "w");

    backtrace_symbols_fd(buffer, backtrace(buffer, sizeof(buffer) / sizeof(buffer[0])), fileno(fp));
    fclose(fp);
    _exit(1);
}

int main(void)
{
        signal(SIGSEGV, handler);
        auto loop = uv_default_loop();
        uv_tcp_t *tcp = (uv_tcp_t*)-1;
        uv_tcp_init(loop, tcp);
        return 0;
}


/* 此处使用静态库,转化堆栈地址更直接,如果是动态库,首先要找到偏移地址,再加上移动地址,才是真正地址
 g++ -g -O0 -I./build/include -o t1 t1.cc ./.libs/libux.a -pthread
*/

运行:./t1

查看 callstack.txt

#如果是动态库,显示如下,拿第4行来看:这时真正地址为 uv_tcp_init_ex+0x74
#可以使用 nm /home/test/Desktop/libuv/.libs/libux.so.1 | grep uv_tcp_init_ex 来找到偏移地址(为16进制),这时再加上 0x74 即为真正地址

./t1(+0xc1c)[0x557f338c1c]
linux-vdso.so.1(__kernel_rt_sigreturn+0x0)[0x7faaa866a0]
/home/test/Desktop/libuv/.libs/libux.so.1(+0x24510)[0x7faaa32510]
/home/test/Desktop/libuv/.libs/libux.so.1(uv_tcp_init_ex+0x74)[0x7faaa35da0]
/home/test/Desktop/libuv/.libs/libux.so.1(uv_tcp_init+0x20)[0x7faaa35e38]
./t1(+0xc84)[0x557f338c84]
/lib/aarch64-linux-gnu/libc.so.6(__libc_start_main+0xe0)[0x7faa8b46e0]
./t1(+0xb04)[0x557f338b04]



#如果是静态库就简单多了,显示的就是真实地址

./t1(+0x3e2c)[0x556a706e2c]
linux-vdso.so.1(__kernel_rt_sigreturn+0x0)[0x7f934366a0]
./t1(+0x10e7c)[0x556a713e7c]
./t1(+0x1470c)[0x556a71770c]
./t1(+0x147a4)[0x556a7177a4]
./t1(+0x3e94)[0x556a706e94]
/lib/aarch64-linux-gnu/libc.so.6(__libc_start_main+0xe0)[0x7f932856e0]
./t1(+0x3d14)[0x556a706d14]

使用 addr2line 查看堆栈信息:

addr2line -e ./t1 0x147a4

或者使用下面的工具查看:addrtool.cc

/*  
 * Compile with g++ -std=c++11 -O2 -o addrtool addrtool.cc
 */

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <regex>
#include <string>

using namespace std;

#define ADDR2LINE   "addr2line"


string do_addr2line(const char *exec_file, const string &address)
{
    char cmd[256];
    char output[1035];
    snprintf(cmd, sizeof(cmd), "%s -e %s %s", ADDR2LINE, exec_file, address.c_str());
    FILE *fp = popen(cmd, "r");
    if (!fp) return string();
    if (!fgets(output, sizeof(output)-1, fp))
    {
        pclose(fp);
        return string();
    }
    pclose(fp);
    return string(output);
}


int main(int argc, char *argv[])
{
    if (argc < 3)
    {
        printf("Usage: %s <exec_file> <callstack_dump>\n", argv[0]);
        exit(1);
    }

    FILE *fp = fopen(argv[2], "r");
    if (!fp)
    {
        fprintf(stderr, "Error: open %s error: %s\n", argv[1], strerror(errno));
        exit(1);
    }

    char line[1025];
    smatch sm1, sm2;
	const regex pat1("\\(\\+(0x[0-9a-f]+)\\)"), pat2("^\\?{0,}\\:\\?{0,}");
    printf("CallStack is\n==================================\n");
    while (fgets(line, sizeof(line)-1, fp) != nullptr)
    {
        auto s = string(line);
        if (regex_search(s, sm1, pat1))
        {
            auto output = do_addr2line(argv[1], sm1[1].str());
            printf("%s", output.empty() || regex_search(output, sm2, pat2) ? line : output.c_str());
        }
        else
            printf("%s", line);
    }

    fclose(fp);
    return 0;
}

用法:addrtool ./t1 callstack.txt

test:~/Desktop/libuv$ ~/addrtool t1 callstack.txt

CallStack is
==================================
/home/test/Desktop/libuv/t1.cc:17
linux-vdso.so.1(__kernel_rt_sigreturn+0x0)[0x7f934366a0]
/home/test/Desktop/libuv/uv/unix/stream.c:82
/home/test/Desktop/libuv/uv/unix/tcp.c:133
/home/test/Desktop/libuv/uv/unix/tcp.c:147
/home/test/Desktop/libuv/t1.cc:28
/lib/aarch64-linux-gnu/libc.so.6(__libc_start_main+0xe0)[0x7f932856e0]
./t1(+0x3d14)[0x556a706d14]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值