C++ 如何修复C++;
我想跟踪一些程序捕获异常的信息时遇到问题 我使用了以下功能:C++ 如何修复C++;,c++,macos,debug-symbols,backtrace,C++,Macos,Debug Symbols,Backtrace,我想跟踪一些程序捕获异常的信息时遇到问题 我使用了以下功能: extern "C" void log_backtrace() { // Dump the callstack int callstack[128]; int frames = backtrace((void**) callstack, 128); char** strs = backtrace_symbols((void**) callstack, frames); for (int
extern "C" void log_backtrace()
{
// Dump the callstack
int callstack[128];
int frames = backtrace((void**) callstack, 128);
char** strs = backtrace_symbols((void**) callstack, frames);
for (int i = 1; i < frames; ++i)
{
char functionSymbol[64*1024];
char moduleName [64*1024];
int offset = 0;
sscanf(strs[i], "%*d %s %*s %s %*s %d", &moduleName, &functionSymbol, &offset);
int addr = callstack[i];
int validCppName;
char* functionName = abi::__cxa_demangle(functionSymbol, NULL, 0,
&validCppName);
if (validCppName == 0)
printf( "\t%8.8x — %s + %d\t\t(%s)\n", addr, functionName, offset, moduleName);
else
printf( "\t%8.8x — %s + %d\t\t(%s)\n", addr, functionSymbol, offset, moduleName);
if (functionName)
free(functionName);
}
free(strs);
}
extern“C”void log\u backtrace()
{
//转储调用堆栈
int调用堆栈[128];
int frames=backtrace((void**)调用堆栈,128);
char**strs=backtrace_符号((void**)调用堆栈,帧);
对于(int i=1;i
输出如下:
20:48:44 [ERROR]tcp_client::connect() failed. error:Connection refused
00000001 — latte::Log::out_error(std::string const&) + 151 (valhalla)
001a6637 — latte::tcp_client::connect(boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const&) + 307 (valhalla)
00000001 — valhalla::hall::start() + 388 (valhalla)
00204803 — main + 388 (valhalla)
00000001 — start + 52 (valhalla)
00143ae4 — 0x0 + 1 (???)
20:48:44[错误]tcp_客户端::connect()失败。错误:连接被拒绝
00000001-latte::Log::out_错误(std::string const&)+151(valhalla)
001a6637-拿铁::tcp_客户端::连接(boost::asio::ip::基本_端点常数&)+307(valhalla)
00000001-valhalla::hall::start()+388(valhalla)
00204803-干管+388(瓦尔哈拉)
00000001-启动+52(瓦尔哈拉)
00143ae4-0x0+1(?)
所有信息(名称空间、类名和方法名)都很好。但唯一的问题是行号错了
如何修复回溯中的行号?它们不是行号,而是从函数开始的偏移量。有一个名为
addr2line
的工具,它与binutils一起提供,可以将地址转换为给定调试符号的行号。您可以从程序中调用它(pipe()
+fork()
+exec()
),也可以查看它用于执行此操作的库
在我的Linux系统上,addr2line在内部用于此目的。虽然从我所看到的来看,它并没有很好的文档记录,但是从addr2line源代码中通过示例可以很容易地看到它。我也遇到过同样的问题,并四处寻找解决方案,但我什么也没找到。你已经在你的帖子中标记了OSX,所以我假设这就是你想让它工作的平台?OSX没有addr2line,至少OSX版本10.8/10.9中没有。我将下面的代码放在一起(使用来自不同来源的代码片段),它生成如下所示的回溯(它包括最上面的两个帧,它们是异常处理程序,如果您愿意,可以跳过这两个帧): 它只为执行模块中的帧生成函数+文件+行号。该代码仅适用于OSX,但也可适用于其他平台。将会有一些角落案例没有被涵盖,但希望这是一个好的起点。代码是:
namespace ExceptionHandler
{
char m_ExeFilename[ PATH_MAX ];
// Execute cmd store stdout into buf (up to bufSize).
int Execute( const char * cmd, char * buf, size_t bufSize )
{
char filename[ 512 ];
sprintf( filename, "%d.tmp", rand( ) );
if ( FILE * file = fopen( filename, "w" ) )
{
if ( FILE * ptr = popen( cmd, "r" ) )
{
while ( fgets( buf, bufSize, ptr ) != NULL )
{
fprintf( file, "%s", buf );
}
pclose( ptr );
}
fclose( file );
unlink( filename );
return 0;
}
return -1;
}
// Resolve symbol name and source location given the path to the executable and an address
int Addr2Line(char const * const program_name, void const * const addr, char * buff, size_t buffSize )
{
char addr2line_cmd[512] = {0};
sprintf( addr2line_cmd, "atos -d -o %.256s %p", program_name, addr );
return Execute( addr2line_cmd, buff, buffSize );
}
// Check if file exists.
bool FileExists( const char * filename )
{
if ( FILE * fh = fopen( filename, "r" ) )
{
fclose( fh );
return true;
}
return false;
}
// Print stack trace.
void PrintStackTrace( )
{
int trace_size = 0;
char ** messages = ( char ** )NULL;
static const size_t kMaxStackFrames = 64;
static void * stack_traces[ kMaxStackFrames ];
trace_size = backtrace( stack_traces, kMaxStackFrames );
messages = backtrace_symbols( stack_traces, trace_size );
for ( int i = 0; i < trace_size; ++i )
{
int stackLevel;
char filename[ 512 ];
uintptr_t address;
char symbol[ 512 ];
uintptr_t symbolOffset;
uintptr_t functionOffset;
bool symbolOffsetValid = false;
bool somethingValid = true;
if ( sscanf( messages[ i ], "%d%*[ \t]%s%*[ \t]%" SCNxPTR "%*[ \t]%" SCNxPTR "%*[ \t]+%*[ \t]%" SCNuPTR, &stackLevel, filename, &address, &symbolOffset, &functionOffset ) == 5 )
{
symbolOffsetValid = true;
}
else if ( sscanf( messages[ i ], "%d%*[ \t]%s%*[ \t]%" SCNxPTR "%*[ \t]%s%*[ \t]+%*[ \t]%" SCNuPTR, &stackLevel, filename, &address, symbol, &functionOffset ) == 5 )
{
}
else
{
somethingValid = false;
}
const size_t BUFF_SIZE = 4096;
char buff[ BUFF_SIZE ] = { '\0' };
if ( somethingValid )
{
if ( symbolOffsetValid && symbolOffset == 0 )
{
fprintf( stderr, "%3d %-32s %#16" PRIxPTR " %#" PRIxPTR " + %" PRIuPTR "\n", stackLevel, filename, address, symbolOffset, functionOffset );
}
else if ( FileExists( m_ExeFilename ) && Addr2Line( m_ExeFilename, stack_traces[ i ], buff, BUFF_SIZE) == 0 )
{
fprintf( stderr, "%3d %-32s %#16" PRIxPTR " %s", stackLevel, filename, address, buff );
}
else
{
fprintf( stderr, "%3d %-32s %#16" PRIxPTR " %#" PRIxPTR " + %" PRIuPTR "\n", stackLevel, filename, address, symbolOffset, functionOffset );
}
}
else
{
fprintf( stderr, "%s\n", messages[ i ] );
}
}
if (messages)
{
free( messages );
}
}
void Handler( int sig, siginfo_t * siginfo, void * context )
{
switch(sig)
{
case SIGSEGV:
fputs("Caught SIGSEGV: Segmentation Fault\n", stderr);
break;
case SIGBUS:
fputs("Caught SIGBUG: Bus error (bad memory access)\n", stderr);
break;
case SIGINT:
fputs("Caught SIGINT: Interactive attention signal, (usually ctrl+c)\n", stderr);
break;
case SIGFPE:
switch(siginfo->si_code)
{
case FPE_INTDIV:
fputs("Caught SIGFPE: (integer divide by zero)\n", stderr);
break;
case FPE_INTOVF:
fputs("Caught SIGFPE: (integer overflow)\n", stderr);
break;
case FPE_FLTDIV:
fputs("Caught SIGFPE: (floating-point divide by zero)\n", stderr);
break;
case FPE_FLTOVF:
fputs("Caught SIGFPE: (floating-point overflow)\n", stderr);
break;
case FPE_FLTUND:
fputs("Caught SIGFPE: (floating-point underflow)\n", stderr);
break;
case FPE_FLTRES:
fputs("Caught SIGFPE: (floating-point inexact result)\n", stderr);
break;
case FPE_FLTINV:
fputs("Caught SIGFPE: (floating-point invalid operation)\n", stderr);
break;
case FPE_FLTSUB:
fputs("Caught SIGFPE: (subscript out of range)\n", stderr);
break;
default:
fputs("Caught SIGFPE: Arithmetic Exception\n", stderr);
break;
}
break;
case SIGILL:
switch(siginfo->si_code)
{
case ILL_ILLOPC:
fputs("Caught SIGILL: (illegal opcode)\n", stderr);
break;
case ILL_ILLOPN:
fputs("Caught SIGILL: (illegal operand)\n", stderr);
break;
case ILL_ILLADR:
fputs("Caught SIGILL: (illegal addressing mode)\n", stderr);
break;
case ILL_ILLTRP:
fputs("Caught SIGILL: (illegal trap)\n", stderr);
break;
case ILL_PRVOPC:
fputs("Caught SIGILL: (privileged opcode)\n", stderr);
break;
case ILL_PRVREG:
fputs("Caught SIGILL: (privileged register)\n", stderr);
break;
case ILL_COPROC:
fputs("Caught SIGILL: (coprocessor error)\n", stderr);
break;
case ILL_BADSTK:
fputs("Caught SIGILL: (internal stack error)\n", stderr);
break;
default:
fputs("Caught SIGILL: Illegal Instruction\n", stderr);
break;
}
break;
case SIGTERM:
fputs("Caught SIGTERM: a termination request was sent to the program\n", stderr);
break;
case SIGABRT:
fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr);
break;
default:
break;
}
PrintStackTrace( );
fflush( stderr );
fflush( stdout );
_exit( 1 );
}
bool Initialise( const char * argv )
{
char path[ PATH_MAX ];
uint32_t size = sizeof( path );
if ( _NSGetExecutablePath( path, &size ) == 0 )
{
if ( ! realpath( path, m_ExeFilename ) )
{
strcpy( m_ExeFilename, path );
}
}
else
{
strcpy( m_ExeFilename, argv ? argv : "" );
}
struct sigaction sig_action = {};
sig_action.sa_sigaction = Handler;
sigemptyset(&sig_action.sa_mask);
sig_action.sa_flags = SA_SIGINFO;
int toCatch[ ] = {
SIGSEGV,
SIGBUS,
SIGFPE,
SIGINT,
SIGILL,
SIGTERM,
SIGABRT
};
bool okay = true;
for ( size_t toCatchIx = 0; toCatchIx < PiArraySize( toCatch ); ++toCatchIx )
{
okay &= sigaction( toCatch[ toCatchIx ], &sig_action, NULL ) == 0;
}
return okay;
}
}
int main( int argc, char ** argv )
{
argc = argc;
argv = argv;
ExceptionHandler::Initialise( argc > 0 ? argv[ 0 ] : NULL );
// Do something
return 0;
}
命名空间异常处理程序
{
charm_ExeFilename[PATH_MAX];
//将cmd store stdout执行到buf中(最大为bufSize)。
int执行(常量字符*cmd,字符*buf,大小\u t bufSize)
{
字符文件名[512];
sprintf(文件名为“%d.tmp”,rand());
如果(FILE*FILE=fopen(文件名,“w”))
{
如果(文件*ptr=popen(cmd,“r”))
{
while(fgets(buf,bufSize,ptr)!=NULL)
{
fprintf(文件“%s”,buf);
}
pclose(ptr);
}
fclose(文件);
取消链接(文件名);
返回0;
}
返回-1;
}
//给定可执行文件的路径和地址,解析符号名和源位置
int Addr2Line(字符常量*常量程序名,无效常量*常量地址,字符*buff,大小\u t buffSize)
{
char addr2line_cmd[512]={0};
sprintf(addr2line_cmd,“atos-d-o%.256s%p”,程序名,addr);
返回执行(addr2line_cmd、buff、buffSize);
}
//检查文件是否存在。
bool文件存在(常量字符*文件名)
{
如果(文件*fh=fopen(文件名,“r”))
{
fclose(fh);
返回true;
}
返回false;
}
//打印堆栈跟踪。
void PrintStackTrace()
{
int trace_size=0;
字符**消息=(字符**)空;
静态const size_t kMaxStackFrames=64;
静态void*堆栈_跟踪[kMaxStackFrames];
trace_size=回溯(堆栈_跟踪,帧);
消息=反向跟踪符号(堆栈跟踪、跟踪大小);
对于(int i=0;inamespace ExceptionHandler
{
char m_ExeFilename[ PATH_MAX ];
// Execute cmd store stdout into buf (up to bufSize).
int Execute( const char * cmd, char * buf, size_t bufSize )
{
char filename[ 512 ];
sprintf( filename, "%d.tmp", rand( ) );
if ( FILE * file = fopen( filename, "w" ) )
{
if ( FILE * ptr = popen( cmd, "r" ) )
{
while ( fgets( buf, bufSize, ptr ) != NULL )
{
fprintf( file, "%s", buf );
}
pclose( ptr );
}
fclose( file );
unlink( filename );
return 0;
}
return -1;
}
// Resolve symbol name and source location given the path to the executable and an address
int Addr2Line(char const * const program_name, void const * const addr, char * buff, size_t buffSize )
{
char addr2line_cmd[512] = {0};
sprintf( addr2line_cmd, "atos -d -o %.256s %p", program_name, addr );
return Execute( addr2line_cmd, buff, buffSize );
}
// Check if file exists.
bool FileExists( const char * filename )
{
if ( FILE * fh = fopen( filename, "r" ) )
{
fclose( fh );
return true;
}
return false;
}
// Print stack trace.
void PrintStackTrace( )
{
int trace_size = 0;
char ** messages = ( char ** )NULL;
static const size_t kMaxStackFrames = 64;
static void * stack_traces[ kMaxStackFrames ];
trace_size = backtrace( stack_traces, kMaxStackFrames );
messages = backtrace_symbols( stack_traces, trace_size );
for ( int i = 0; i < trace_size; ++i )
{
int stackLevel;
char filename[ 512 ];
uintptr_t address;
char symbol[ 512 ];
uintptr_t symbolOffset;
uintptr_t functionOffset;
bool symbolOffsetValid = false;
bool somethingValid = true;
if ( sscanf( messages[ i ], "%d%*[ \t]%s%*[ \t]%" SCNxPTR "%*[ \t]%" SCNxPTR "%*[ \t]+%*[ \t]%" SCNuPTR, &stackLevel, filename, &address, &symbolOffset, &functionOffset ) == 5 )
{
symbolOffsetValid = true;
}
else if ( sscanf( messages[ i ], "%d%*[ \t]%s%*[ \t]%" SCNxPTR "%*[ \t]%s%*[ \t]+%*[ \t]%" SCNuPTR, &stackLevel, filename, &address, symbol, &functionOffset ) == 5 )
{
}
else
{
somethingValid = false;
}
const size_t BUFF_SIZE = 4096;
char buff[ BUFF_SIZE ] = { '\0' };
if ( somethingValid )
{
if ( symbolOffsetValid && symbolOffset == 0 )
{
fprintf( stderr, "%3d %-32s %#16" PRIxPTR " %#" PRIxPTR " + %" PRIuPTR "\n", stackLevel, filename, address, symbolOffset, functionOffset );
}
else if ( FileExists( m_ExeFilename ) && Addr2Line( m_ExeFilename, stack_traces[ i ], buff, BUFF_SIZE) == 0 )
{
fprintf( stderr, "%3d %-32s %#16" PRIxPTR " %s", stackLevel, filename, address, buff );
}
else
{
fprintf( stderr, "%3d %-32s %#16" PRIxPTR " %#" PRIxPTR " + %" PRIuPTR "\n", stackLevel, filename, address, symbolOffset, functionOffset );
}
}
else
{
fprintf( stderr, "%s\n", messages[ i ] );
}
}
if (messages)
{
free( messages );
}
}
void Handler( int sig, siginfo_t * siginfo, void * context )
{
switch(sig)
{
case SIGSEGV:
fputs("Caught SIGSEGV: Segmentation Fault\n", stderr);
break;
case SIGBUS:
fputs("Caught SIGBUG: Bus error (bad memory access)\n", stderr);
break;
case SIGINT:
fputs("Caught SIGINT: Interactive attention signal, (usually ctrl+c)\n", stderr);
break;
case SIGFPE:
switch(siginfo->si_code)
{
case FPE_INTDIV:
fputs("Caught SIGFPE: (integer divide by zero)\n", stderr);
break;
case FPE_INTOVF:
fputs("Caught SIGFPE: (integer overflow)\n", stderr);
break;
case FPE_FLTDIV:
fputs("Caught SIGFPE: (floating-point divide by zero)\n", stderr);
break;
case FPE_FLTOVF:
fputs("Caught SIGFPE: (floating-point overflow)\n", stderr);
break;
case FPE_FLTUND:
fputs("Caught SIGFPE: (floating-point underflow)\n", stderr);
break;
case FPE_FLTRES:
fputs("Caught SIGFPE: (floating-point inexact result)\n", stderr);
break;
case FPE_FLTINV:
fputs("Caught SIGFPE: (floating-point invalid operation)\n", stderr);
break;
case FPE_FLTSUB:
fputs("Caught SIGFPE: (subscript out of range)\n", stderr);
break;
default:
fputs("Caught SIGFPE: Arithmetic Exception\n", stderr);
break;
}
break;
case SIGILL:
switch(siginfo->si_code)
{
case ILL_ILLOPC:
fputs("Caught SIGILL: (illegal opcode)\n", stderr);
break;
case ILL_ILLOPN:
fputs("Caught SIGILL: (illegal operand)\n", stderr);
break;
case ILL_ILLADR:
fputs("Caught SIGILL: (illegal addressing mode)\n", stderr);
break;
case ILL_ILLTRP:
fputs("Caught SIGILL: (illegal trap)\n", stderr);
break;
case ILL_PRVOPC:
fputs("Caught SIGILL: (privileged opcode)\n", stderr);
break;
case ILL_PRVREG:
fputs("Caught SIGILL: (privileged register)\n", stderr);
break;
case ILL_COPROC:
fputs("Caught SIGILL: (coprocessor error)\n", stderr);
break;
case ILL_BADSTK:
fputs("Caught SIGILL: (internal stack error)\n", stderr);
break;
default:
fputs("Caught SIGILL: Illegal Instruction\n", stderr);
break;
}
break;
case SIGTERM:
fputs("Caught SIGTERM: a termination request was sent to the program\n", stderr);
break;
case SIGABRT:
fputs("Caught SIGABRT: usually caused by an abort() or assert()\n", stderr);
break;
default:
break;
}
PrintStackTrace( );
fflush( stderr );
fflush( stdout );
_exit( 1 );
}
bool Initialise( const char * argv )
{
char path[ PATH_MAX ];
uint32_t size = sizeof( path );
if ( _NSGetExecutablePath( path, &size ) == 0 )
{
if ( ! realpath( path, m_ExeFilename ) )
{
strcpy( m_ExeFilename, path );
}
}
else
{
strcpy( m_ExeFilename, argv ? argv : "" );
}
struct sigaction sig_action = {};
sig_action.sa_sigaction = Handler;
sigemptyset(&sig_action.sa_mask);
sig_action.sa_flags = SA_SIGINFO;
int toCatch[ ] = {
SIGSEGV,
SIGBUS,
SIGFPE,
SIGINT,
SIGILL,
SIGTERM,
SIGABRT
};
bool okay = true;
for ( size_t toCatchIx = 0; toCatchIx < PiArraySize( toCatch ); ++toCatchIx )
{
okay &= sigaction( toCatch[ toCatchIx ], &sig_action, NULL ) == 0;
}
return okay;
}
}
int main( int argc, char ** argv )
{
argc = argc;
argv = argv;
ExceptionHandler::Initialise( argc > 0 ? argv[ 0 ] : NULL );
// Do something
return 0;
}