LinuxX86中打印堆栈的简易使用说明

在某些多路径的函数(例如退出),我们希望通过在日志中打印堆栈,确认调用途径,以定位一些奇怪的业务逻辑问题。
在Linux中,我们可以使用backtrace函数进行追踪。
*Android不支持此方法

1.使用示例

*以下代码节选自backtrace的man

int j, nptrs;
void *buffer[100];
char **strings;
nptrs = backtrace(buffer, 100);
strings = backtrace_symbols(buffer, nptrs);
if (strings != NULL)
{
   for (j = 0; j < nptrs; j++)
       printf("%s\n",strings[j]);
   free(strings);
}

打印结果示例

lib/libpt.so.2.12.8(_ZN7PThread9TerminateEv+0x106) [0x7ffff783e932]
lib/libpt.so.2.12.8(_ZN8PProcess11PreShutdownEv+0x31b) [0x7ffff78696e9]
lib/libpt.so.2.12.8(_ZN8PProcessD1Ev+0x82) [0x7ffff783f422]
/opt/code/server_cloud/pkg/H323Gateway(_ZN8CMainAppD1Ev+0x35) [0x4d3ee9]
/opt/code/server_cloud/pkg/H323Gateway(_ZN8CMainAppD0Ev+0x18) [0x4d3f18]
/opt/code/server_cloud/pkg/H323Gateway(H323GW_UnInit+0x39) [0x4f8e98]
/opt/code/server_cloud/pkg/H323Gateway(main+0x28) [0x4f8ecd]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7ffff4f46505]
/opt/code/server_cloud/pkg/H323Gateway() [0x4be389]

2. 进阶玩法-崩溃时自动打印堆栈

在某些特殊情况下,我们无法生成CORE(可能是存储空间问题,或者其他问题);那么可以借用这个代码,简单定位一些明显的逻辑问题


void OnCrash(int nSig)
{
    switch (nSig)
    {
    case SIGFPE:
        printf("%s\n", "Program Crashed with SIGFPE: ");
        break;
    case SIGSEGV:
        printf("%s\n", "Program Crashed with SIGSEGV: ");
        break;
    case SIGBUS:
       	printf("%s\n", "Program Crashed with SIGBUS: ");
        break;
    }
    int j, nptrs;
    void *buffer[100];
    char **strings;
    nptrs = backtrace(buffer, 100);
    strings = backtrace_symbols(buffer, nptrs);

    if (strings != NULL)
    {
        for (j = 0; j < nptrs; j++)
            printf("%s\n", strings[j]);
        free(strings);
    }
   
    signal(SIGSEGV, SIG_DFL);
    signal(SIGFPE, SIG_DFL);
    signal(SIGBUS, SIG_DFL);
    raise(SIGQUIT); // Dump core
    _exit(-1); // Fail safe if raise() didn't dump core and exit
}

int main(int argc, char** argv)
{
	//……
	//也可以不在main中,在其他初始化必然经过的代码中
    signal(SIGSEGV, OnCrash);
    signal(SIGFPE, OnCrash);
    signal(SIGBUS, OnCrash);
    //……
}

3. 常见问题

  • Q:我的打印中只显示了地址,没有显示具体的函数名,是怎么回事?
    A:需要在CFLAGS参数中,增加 -rdynamic

  • Q:我还想知道具体的行号,怎么处理?
    A:可以将最后方括号里面的函数地址,用addr2line函数配套EXE来解决。此方法同样可以解决没有打印具体函数名时的排查问题。

示例:

addr2line --exe=H323Gateway -i 0x4f8e98

结果:

/opt/code/server_cloud/applications/h323gw/main.cpp:85 (discriminator 1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值