[已解决]backtrace在子进程中解析不了符号信息
本帖最后由 dreamtale90 于 2017-07-12 08:55 编辑有个程序要以子进程的方式启动,但是这种方式下出现段错误的时候,backtrace这组函数并没有解析出相应的符号信息,如果直接执行该程序,就能够解析出符号信息,图片中是写的小demo,fork_child程序会以vfork的方式执行backtrace程序,backtrace程序中故意制造了除零错误。求解答。
本帖最后由 dreamtale90 于 2017-06-28 12:04 编辑
图好像挂了,重新上传一个,另外补充一下,编译时候加了rdynamic选项。
附上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: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;
} 回复 4# wlmqgzm
很感谢你的回复,-g和-rdynamic我都加过,但还是一样。
我觉得我这个问题应该是vfork+execl导致的,
我这样试过,把子进程backtrace的main改个名字,然后父进程在vfork后直接调用子进程backtrace,这样可以正常解析出符号信息
感觉像是vfork+execl这种方式致使子进程没有加载自己的符号信息,或者其他什么?
本帖最后由 nswcfd 于 2017-07-10 16:23 编辑
跟在sigstack上调用bt有关系么?
[更新]已验证,没有关系。
跟fork/vfork没有关系,跟exec有关。
调用的时候没有提供arg0。
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]