首页 > 其他分享 >几种backtrace方法

几种backtrace方法

时间:2023-02-01 22:45:47浏览次数:40  
标签:return int backtrace void 几种 printf include 方法

backtrace就是回溯程序的函数栈,我们在代码调试中经常会遇到,现总结下笔者所知道的以下四种backtrace方式:

1、直接调用libc函数 int  backtrace(void**, int)

2、通过gcc内置函数__builtin_return_address获取函数返回地址,从而得到栈信息

3、直接内嵌汇编指令,读取寄存器数据,获取函数返回地址

4、使用libunwind.so接口函数int  unw_backtrace (void**, int)

对比上述4种方式的性能, 1)的性能最差,和2)、3)、4)差一个数量级; 2)和3)性能最好, 性能是4)的3倍多

具体测试代码如下:

#include <execinfo.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <thread>
#include <dlfcn.h>

/*  gcc内置函数 */
/***********************************************/
#define GCCBT(i) \
    if(i >= size) return i;\
    frameNow = __builtin_frame_address(i);\
    if((unsigned long)frameNow <= (unsigned long)frameLast ||\
    ((unsigned long)frameLast != 0 && (unsigned long)frameNow > (unsigned long)frameLast + (1ULL<<24)))\
        return i;\
    frameLast = frameNow;\
    stack[i] = __builtin_extract_return_addr(__builtin_return_address(i));\

static int gccBacktrace(void** stack, int size)
{
    void* frameNow = 0; 
    void* frameLast = 0;
    GCCBT(0); GCCBT(1); GCCBT(2); GCCBT(3); GCCBT(4); GCCBT(5); GCCBT(6); GCCBT(7);
    GCCBT(8); GCCBT(9); GCCBT(10); GCCBT(11); GCCBT(12); GCCBT(13); GCCBT(14); GCCBT(15);
    GCCBT(16); GCCBT(17); GCCBT(18); GCCBT(19); GCCBT(20); GCCBT(21); GCCBT(22); GCCBT(23);
    GCCBT(24); GCCBT(25); GCCBT(26); GCCBT(27); GCCBT(28); GCCBT(29); GCCBT(30); GCCBT(31);
    return 32;
}

/*  内置汇编获取寄存器返回值 */
/***********************************************/
static int asmBacktrace(void** stack, int size)
{
#ifndef __x86_64__
    return 0;
#else
    int frame = 0;
    void ** ebp;
    unsigned long long func_frame_distance = 0;
    __asm__ __volatile__("mov %%rbp, %0;\n\t" : "=m"(ebp) ::"memory");
    while (ebp && frame < size
        && (unsigned long long)(*ebp) < (unsigned long long)(ebp) + (1ULL << 24)//16M
        && (unsigned long long)(*ebp) > (unsigned long long)(ebp))
    {
        stack[frame++] = *(ebp + 1);
        ebp = (void**)(*ebp);
    }
    return frame;
#endif
}

static int flag = 1;
static int(*pfnBt)(void**, int);
void func5()
{
    void *btbuf[16];
    int btnum = pfnBt(btbuf, 16);
    if (flag == 1)
    {
        flag = 2;
        char **strings = backtrace_symbols(btbuf, btnum);
        for (int i = 0; i < btnum; ++i)
        {
            printf("%p %s\n", btbuf[i], strings[i]);
        }
        free(strings);
    }
}
void func4()
{
    func5();
}

void func3()
{
    func4();
}
void func2()
{
    func3();
}
void func1(int num)
{
    for (int i = 0; i < num; ++i)
    {
        func2();
    }
}

int main(int argc, char** argv)
{
    if (argc != 3)
    {
        printf("param1: int -- each thread loop number\n");
        printf("param2: string --bt method libc/gcc/asm/unw\n");
        return -1;
    }
    int loopNum = atoi(argv[1]);
    std::string method = argv[2];
    if (method == "libc")
    {
        printf("test libc\n");
        pfnBt = backtrace;
    }
    else if (method == "gcc")
    {
        printf("test gcc\n");
        pfnBt = gccBacktrace;
    }
    else if (method == "asm")
    {
        printf("test asm\n");
        pfnBt = asmBacktrace;
    }
    else if (method == "uwn")
    {
        printf("test uwn\n");
        void* handle = dlopen("./libunwind.so",RTLD_LAZY|RTLD_LOCAL);
        if (handle == NULL)
        {
            printf("dlopen failed, %s\n", dlerror());
            return -1;
        }
        pfnBt = (int(*)(void**, int))dlsym(handle, "unw_backtrace");
        if (pfnBt == NULL)
        {
            printf("dlsym failed, %s\n", dlerror());
            return -1;
        }
    }
    else
    {
        printf("please input right method lic/gcc/asm/uwn\n");
        return -1;
    }
    std::thread thd[20];
    for (int i = 0; i < 20; ++i)
    {
        thd[i] = std::thread(func1, loopNum);
    }
    for (int i = 0; i < 20; ++i)
    {
        thd[i].join();
    }
    return 0;
}

编译命令:

  g++ bt.cpp -o bt -lpthread -ldl -std=c++11 -g

对比测试效果截图如下:

  

  

 

   

 

      

标签:return,int,backtrace,void,几种,printf,include,方法
From: https://www.cnblogs.com/ho966/p/17084350.html

相关文章

  • P61 回顾方法及加深
    方法的定义example:com.oop.demo01修饰符返回类型break和return的区别跳出switch,结束循环continue-结束本次循环break-结束全部循环return-方法结束方......
  • HttpClient 正确使用方法
    如何正确模拟 Http请求,建议使用HttpClient 错误用法   varhttpClient=newHttpClient(); 正确用法ServiceCollection.AddHttpClient();publicc......
  • LabVIEW|小技巧1:秒破加密的vi文件方法
    可以利用专门的网站进行vi文件的解密,网站如下:​​https://www.hmilch.net/h/labview​​步骤:点击-选择按钮->空白框里输入“YES"->点击-提交;成功后下载解密的vi文件(注:此vi文......
  • C# DataTable中Compute方法用法集锦(数值/字符串/运算符/表等操作)
    DataTabledt=newDataTable();//嵌套的三元运算牛叉到五体投地objectobj=dt.Compute("iif(1000=5,1000,iif(100>100,4001,2000))",null);Response.Write(obj);......
  • 浅谈爬虫开发中几种形式的cookie的互相转换与利用
    前言在我们写爬虫的过程中,cookie一般是我们最经常接触到的东西。而由于在爬虫过程中的各个阶段的难度往往不同,所以我们很多时候会采用浏览器、requests等等各种方案来在采......
  • 大一寸照片的尺寸是多少?一寸照片拍摄方法分享!​
    大一寸照片的尺寸是多少?很多小伙伴日常在生活和学习中,都需要接触我们日常所说的证件照,那么证件照也分非常多的尺寸,如我们最常说的一寸照片,还有二寸照片等等,当然小伙伴们不可......
  • Windows设置电脑定时关机的简单方法(干货)
    卓越电脑定时关机软件是一款操作简便,功能强大,绿色,无任何插件的电脑自动定时关机软件,是家长,公司文员和电脑办公人员的好助手。win7win8 win10win11电脑系统通用卓越电......
  • branch和tag同名的删除方法
    git删除远端分支,一般使用方法 gitpushorigin:branchName gitpushorigin-dbranchNamegit删除远端tag,一般使用gitpushorigintag-dtagName......
  • Spring开启@Async异步方法(javaconfig配置)
    在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。应用场景:某些耗时较长的......
  • sql优化的几种方法
    在sql查询中为了提高查询效率,我们常常会采取一些措施对查询语句进行sql优化,下面总结的一些方法,有需要的可以参考参考。1.对查询进行优化,应尽量避免全表扫描,首先应考虑在whe......