dreamtale90 发表于 2017-06-28 11:39

[已解决]backtrace在子进程中解析不了符号信息

本帖最后由 dreamtale90 于 2017-07-12 08:55 编辑

有个程序要以子进程的方式启动,但是这种方式下出现段错误的时候,backtrace这组函数并没有解析出相应的符号信息,如果直接执行该程序,就能够解析出符号信息,图片中是写的小demo,fork_child程序会以vfork的方式执行backtrace程序,backtrace程序中故意制造了除零错误。求解答。

dreamtale90 发表于 2017-06-28 11:57

本帖最后由 dreamtale90 于 2017-06-28 12:04 编辑

图好像挂了,重新上传一个,另外补充一下,编译时候加了rdynamic选项。

dreamtale90 发表于 2017-06-28 13:49

附上demo的代码,这是backtrace.c
#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

const char *SigInfo[] = {
    {
      "SIGSEGV: Address not mapped to object.",
      "SIGSEGV: Invalid permissions for mapped object.",
    },
    {
      "SIGFPE: Integer divide by zero.",
      "SIGFPE: Integer overflow.",
      "SIGFPE: Floating point divide by zero.",
      "SIGFPE: Floating point overflow.",
      "SIGFPE: Floating point underflow.",
      "SIGFPE: Floating point inexact result.",
      "SIGFPE: Floating point invalid operation.",
      "SIGFPE: Subscript out of range.",
    },
};

const char *GetSigCodeInfo(int signo, int code)
{
    int sigIndex = 0, codeIndex = code - 1;

    if(signo == SIGSEGV)
    {   
      sigIndex = 0;
    }   
    else if(signo == SIGFPE)
    {   
      sigIndex = 1;
    }   
    else
    {   
      return "Error signal info.";
    }   

    return SigInfo;
}

void CatchSignalHandler(int n, siginfo_t *siginfo, void *myact)
{
    void *array;
    int i = 0;
    int num = backtrace(array, sizeof(array)/sizeof(array));
    char **calls = backtrace_symbols(array, num);
   
    printf("%s Fault address:%p\n", GetSigCodeInfo(siginfo->si_signo, siginfo->si_code), siginfo->si_addr);
    for (i = num - 1; i > 1; i--)
    {   
      printf("%s\n", calls);
    }   

    exit(1);
}

void func(void)
{
    int a, b, c = 0;

    a = b / c;
}


int main()
{
    /* Init Signal Process */
#if   1
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    sigaddset(&act.sa_mask, SIGSEGV);
    sigaddset(&act.sa_mask, SIGFPE);
    act.sa_sigaction = CatchSignalHandler;
    act.sa_flags = SA_SIGINFO;
    sigaction(SIGSEGV, &act, NULL);
    sigaction(SIGFPE, &act, NULL);
#endif

    func();
    return 0;
}下面是fork_child.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
   
   
int StartTask(const char *path)
{   
    int ret = 0;
   
    pid_t pid = vfork();
    if(pid == -1)
    {
      perror("vfork");
      ret = -1;
    }   
    //start task
    else if(pid == 0)
    {
      execl(path, NULL);
      exit(0);
    }
    else
    {
      printf("start task %s, pid is %d\n", path, pid);
    }
   
    return ret;
}   
   
int main(int argc, char **argv)
{   
    if(argc != 2){
      printf("%s child\n", argv);
      return -1;
    }

    StartTask(argv);
   
    sleep(1);
   
    return 0;
}

wlmqgzm 发表于 2017-06-28 20:13

本帖最后由 wlmqgzm 于 2017-06-28 20:26 编辑

我这边做backtracegcc中添加下列选项-g选项, -rdynamic选项



signal( SIGSEGV, signal_crash_handler );
   signal( SIGABRT, signal_crash_handler );

void signal_crash_handler( int signum )
{
charchars_tmp;
std::string str_msg;
try   {
    str_msg.reserve( 256 );
    str_msg = "#########################################################\n";
    str_msg += " crash signal number:";
    str_msg += haisql::int_to_chars( signum, chars_tmp );
    std::cout << str_msg << std::endl;
   
    void* array1;
    char** char_strings = nullptr;
    signal( signum, SIG_DFL );
    size_tsize1 = backtrace( array1, MAX_STACK_FRAMES );
    char_strings = (char**)backtrace_symbols( array1, size1 );
    for ( size_t i = 0; i < size1; ++i )    {
      str_msg = haisql::uint_to_chars( i, chars_tmp );
      str_msg += " ";
      str_msg += char_strings;
      str_msg += "\r\n";
      std::cout << str_msg << std::endl;
      }
    if( char_strings !=nullptr ){
      free( char_strings );
      char_strings = nullptr;
      }
    }
catch (...)   {
    }

exit( -1 );
return;
}

dreamtale90 发表于 2017-06-28 21:11

回复 4# wlmqgzm

很感谢你的回复,-g和-rdynamic我都加过,但还是一样。
我觉得我这个问题应该是vfork+execl导致的,
我这样试过,把子进程backtrace的main改个名字,然后父进程在vfork后直接调用子进程backtrace,这样可以正常解析出符号信息
感觉像是vfork+execl这种方式致使子进程没有加载自己的符号信息,或者其他什么?

nswcfd 发表于 2017-07-10 16:00

本帖最后由 nswcfd 于 2017-07-10 16:23 编辑

跟在sigstack上调用bt有关系么?

[更新]已验证,没有关系。
跟fork/vfork没有关系,跟exec有关。
调用的时候没有提供arg0。

dreamtale90 发表于 2017-07-12 08:49

nswcfd 发表于 2017-07-10 16:00 static/image/common/back.gif
跟在sigstack上调用bt有关系么?

[更新]已验证,没有关系。

太感谢了http://bbs.chinaunix.net//mobcent//app/data/phiz/default/23.png,我后来也发现是execl的问题了,就是没想明白符号信息为什么没有装载进来。一直以来的疑惑终于解开了。3Q
页: [1]
查看完整版本: [已解决]backtrace在子进程中解析不了符号信息