免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2823 | 回复: 6
打印 上一主题 下一主题

[C] [已解决]backtrace在子进程中解析不了符号信息 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2017-06-28 11:39 |只看该作者 |倒序浏览
本帖最后由 dreamtale90 于 2017-07-12 08:55 编辑

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

论坛徽章:
0
2 [报告]
发表于 2017-06-28 11:57 |只看该作者
本帖最后由 dreamtale90 于 2017-06-28 12:04 编辑

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

论坛徽章:
0
3 [报告]
发表于 2017-06-28 13:49 |只看该作者
附上demo的代码,这是backtrace.c
  1. #include <execinfo.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <signal.h>

  6. const char *SigInfo[][8] = {
  7.     {
  8.         "SIGSEGV: Address not mapped to object.",
  9.         "SIGSEGV: Invalid permissions for mapped object.",
  10.     },
  11.     {
  12.         "SIGFPE: Integer divide by zero.",
  13.         "SIGFPE: Integer overflow.",
  14.         "SIGFPE: Floating point divide by zero.",
  15.         "SIGFPE: Floating point overflow.",
  16.         "SIGFPE: Floating point underflow.",
  17.         "SIGFPE: Floating point inexact result.",
  18.         "SIGFPE: Floating point invalid operation.",
  19.         "SIGFPE: Subscript out of range.",
  20.     },
  21. };

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

  25.     if(signo == SIGSEGV)
  26.     {   
  27.         sigIndex = 0;
  28.     }   
  29.     else if(signo == SIGFPE)
  30.     {   
  31.         sigIndex = 1;
  32.     }   
  33.     else
  34.     {   
  35.         return "Error signal info.";
  36.     }   

  37.     return SigInfo[sigIndex][codeIndex];
  38. }

  39. void CatchSignalHandler(int n, siginfo_t *siginfo, void *myact)
  40. {
  41.     void *array[100];
  42.     int i = 0;
  43.     int num = backtrace(array, sizeof(array)/sizeof(array[0]));
  44.     char **calls = backtrace_symbols(array, num);
  45.    
  46.     printf("%s Fault address:%p\n", GetSigCodeInfo(siginfo->si_signo, siginfo->si_code), siginfo->si_addr);
  47.     for (i = num - 1; i > 1; i--)
  48.     {   
  49.         printf("%s\n", calls[i]);
  50.     }   

  51.     exit(1);
  52. }

  53. void func(void)
  54. {
  55.     int a, b, c = 0;

  56.     a = b / c;
  57. }


  58. int main()
  59. {
  60.     /* Init Signal Process */
  61. #if     1
  62.     struct sigaction act;
  63.     sigemptyset(&act.sa_mask);
  64.     sigaddset(&act.sa_mask, SIGSEGV);
  65.     sigaddset(&act.sa_mask, SIGFPE);
  66.     act.sa_sigaction = CatchSignalHandler;
  67.     act.sa_flags = SA_SIGINFO;
  68.     sigaction(SIGSEGV, &act, NULL);
  69.     sigaction(SIGFPE, &act, NULL);
  70. #endif

  71.     func();
  72.     return 0;
  73. }
复制代码
下面是fork_child.c
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <limits.h>
  5. #include <errno.h>
  6.    
  7.    
  8. int StartTask(const char *path)
  9. {   
  10.     int ret = 0;
  11.    
  12.     pid_t pid = vfork();
  13.     if(pid == -1)
  14.     {
  15.         perror("vfork");
  16.         ret = -1;
  17.     }   
  18.     //start task
  19.     else if(pid == 0)
  20.     {
  21.         execl(path, NULL);
  22.         exit(0);
  23.     }
  24.     else
  25.     {
  26.         printf("start task %s, pid is %d\n", path, pid);
  27.     }
  28.    
  29.     return ret;
  30. }   
  31.    
  32. int main(int argc, char **argv)
  33. {   
  34.     if(argc != 2){
  35.         printf("%s child\n", argv[9]);
  36.         return -1;
  37.     }

  38.     StartTask(argv[1]);
  39.    
  40.     sleep(1);
  41.    
  42.     return 0;
  43. }
复制代码

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
4 [报告]
发表于 2017-06-28 20:13 |只看该作者
本帖最后由 wlmqgzm 于 2017-06-28 20:26 编辑

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



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

void signal_crash_handler( int signum )
{
  char  chars_tmp[24];
  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[MAX_STACK_FRAMES];
    char** char_strings = nullptr;
    signal( signum, SIG_DFL );
    size_t  size1 = 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;
}

论坛徽章:
0
5 [报告]
发表于 2017-06-28 21:11 |只看该作者
回复 4# wlmqgzm

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

论坛徽章:
20
程序设计版块每日发帖之星
日期:2015-08-17 06:20:00程序设计版块每日发帖之星
日期:2016-07-16 06:20:00程序设计版块每日发帖之星
日期:2016-07-18 06:20:00每日论坛发贴之星
日期:2016-07-18 06:20:00黑曼巴
日期:2016-12-26 16:00:3215-16赛季CBA联赛之江苏
日期:2017-06-26 11:05:5615-16赛季CBA联赛之上海
日期:2017-07-21 18:12:5015-16赛季CBA联赛之青岛
日期:2017-09-04 17:32:0515-16赛季CBA联赛之吉林
日期:2018-03-26 10:02:16程序设计版块每日发帖之星
日期:2016-07-15 06:20:0015-16赛季CBA联赛之江苏
日期:2016-07-07 18:37:512015亚冠之萨济拖拉机
日期:2015-08-17 12:21:08
6 [报告]
发表于 2017-07-10 16:00 |只看该作者
本帖最后由 nswcfd 于 2017-07-10 16:23 编辑

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

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

论坛徽章:
0
7 [报告]
发表于 2017-07-12 08:49 |只看该作者
nswcfd 发表于 2017-07-10 16:00
跟在sigstack上调用bt有关系么?

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

太感谢了,我后来也发现是execl的问题了,就是没想明白符号信息为什么没有装载进来。一直以来的疑惑终于解开了。3Q
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP