...
 
Commits (5)
......@@ -50,7 +50,8 @@
#include <stdio.h>
#include <TNL/Devices/CudaCallable.h>
#include <TNL/Debugging/StackBacktrace.h>
//#include <TNL/Debugging/StackBacktrace.h>
#include <TNL/Debugging/backtrace2line.h>
namespace TNL {
namespace Assert {
......@@ -90,7 +91,7 @@ printDiagnosticsHost( const char* assertion,
<< "Line: " << line << "\n"
<< "Diagnostics:\n" << diagnostics << std::endl;
PrintStackBacktrace;
PrintStackBacktraceWithLines;
throw AssertionError( str.str() );
}
......@@ -113,7 +114,7 @@ printDiagnosticsHost( const char* assertion,
<< "Line: " << line << "\n"
<< "Diagnostics:\n" << diagnostics << std::endl;
PrintStackBacktrace;
PrintStackBacktraceWithLines;
}
#endif // TNL_THROW_ASSERTION_ERROR
......
......@@ -43,7 +43,8 @@ set( common_SOURCES
Object.cpp
Logger.cpp
String.cpp
Timer.cpp )
Timer.cpp
Debugging/backtrace2line.cpp)
set( tnl_SOURCES ${tnl_config_SOURCES}
${tnl_containers_SOURCES}
......@@ -97,6 +98,9 @@ SET_TARGET_PROPERTIES( tnl PROPERTIES
TARGET_LINK_LIBRARIES( tnl
${DCMTK_LIBRARIES} )
# libbfd needed for backtrace2line
target_link_libraries( tnl debug bfd )
INSTALL( TARGETS tnl DESTINATION lib )
......
#include "backtrace2line.h"
namespace TNL {
namespace Debugging {
#ifndef NDEBUG
FileMatch::FileMatch( void* addr ) : mAddress( addr ), mFile( NULL ), mBase( NULL ) {}
int findMatchingFile( struct dl_phdr_info* info, size_t size, void* data )
{
FileMatch* match = (FileMatch*)data;
for ( u32 i = 0; i < info->dlpi_phnum; i++ )
{
const ElfW(Phdr)& phdr = info->dlpi_phdr[i];
if ( phdr.p_type == PT_LOAD )
{
ElfW(Addr) vaddr = phdr.p_vaddr + info->dlpi_addr;
ElfW(Addr) maddr = ElfW(Addr)(match->mAddress);
if (( maddr >= vaddr ) &&
( maddr < vaddr + phdr.p_memsz ))
{
match->mFile = info->dlpi_name;
match->mBase = (void*)info->dlpi_addr;
return 1;
}
}
}
return 0;
}
asymbol** kstSlurpSymtab( bfd* abfd, const char* fileName )
{
if ( !( bfd_get_file_flags( abfd ) & HAS_SYMS ))
{
printf( "Error bfd file \"%s\" flagged as having no symbols.\n", fileName );
return NULL;
}
asymbol** syms;
unsigned int size;
long symcount = bfd_read_minisymbols( abfd, false, (void**)&syms, &size );
if ( symcount == 0 )
symcount = bfd_read_minisymbols( abfd, true, (void**)&syms, &size );
if ( symcount < 0 )
{
printf( "Error bfd file \"%s\", found no symbols.\n", fileName );
return NULL;
}
return syms;
}
FileLineDesc::FileLineDesc( asymbol** syms, bfd_vma pc ) : mPc( pc ), mFound( false ), mSyms( syms ) {}
void FileLineDesc::findAddressInSection( bfd* abfd, asection* section )
{
if ( mFound )
return;
if (( bfd_get_section_flags( abfd, section ) & SEC_ALLOC ) == 0 )
return;
bfd_vma vma = bfd_get_section_vma( abfd, section );
if ( mPc < vma )
return;
bfd_size_type size = bfd_section_size( abfd, section );
if ( mPc >= ( vma + size ))
return;
mFound = bfd_find_nearest_line( abfd, section, mSyms, ( mPc - vma ),
(const char**)&mFilename, (const char**)&mFunctionname, &mLine );
}
void FindAddressInSection( bfd* abfd, asection* section, void* data )
{
FileLineDesc* desc = (FileLineDesc*)data;
//assert( desc );
return desc->findAddressInSection( abfd, section );
}
char** translateAddressesBuf( bfd* abfd, bfd_vma* addr, int numAddr, asymbol** syms )
{
char** ret_buf = NULL;
s32 total = 0;
char b;
char* buf = &b;
s32 len = 0;
for ( u32 state = 0; state < 2; state++ )
{
if ( state == 1 )
{
ret_buf = (char**)malloc( total + ( sizeof(char*) * numAddr ));
buf = (char*)(ret_buf + numAddr);
len = total;
}
for ( s32 i = 0; i < numAddr; i++ )
{
FileLineDesc desc( syms, addr[i] );
if ( state == 1 )
ret_buf[i] = buf;
bfd_map_over_sections( abfd, FindAddressInSection, (void*)&desc );
if ( !desc.mFound )
{
total += snprintf( buf, len, "[0x%llx] \?\? \?\?:0", (long long unsigned int) addr[i] ) + 1;
} else {
const char* name = desc.mFunctionname;
if ( name == NULL || *name == '\0' )
{
name = "??";
}
else
{
//demangle
int status;
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
char* ret = abi::__cxa_demangle(name, funcname, &funcnamesize, &status);
if (status == 0) {
name = ret; // use possibly realloc()-ed string
}
else {
// demangling failed. Output function name as a C function with no arguments.
//printf("%s-Demangling Faliled\n",name);
}
}
if ( desc.mFilename != NULL )
{
char* h = strrchr( desc.mFilename, '/' );
if ( h != NULL )
desc.mFilename = h + 1;
}
total += snprintf( buf, len, "%s:%u %s", desc.mFilename ? desc.mFilename : "??", desc.mLine, name ) + 1;
// elog << "\"" << buf << "\"\n";
}
}
if ( state == 1 )
{
buf = buf + total + 1;
}
}
return ret_buf;
}
char** processFile( const char* fileName, bfd_vma* addr, int naddr )
{
bfd* abfd = bfd_openr( fileName, NULL );
if ( !abfd )
{
printf( "Error opening bfd file \"%s\"\n", fileName );
return NULL;
}
if ( bfd_check_format( abfd, bfd_archive ) )
{
printf( "Cannot get addresses from archive \"%s\"\n", fileName );
bfd_close( abfd );
return NULL;
}
char** matching;
if ( !bfd_check_format_matches( abfd, bfd_object, &matching ))
{
printf( "Format does not match for archive \"%s\"\n", fileName );
bfd_close( abfd );
return NULL;
}
asymbol** syms = kstSlurpSymtab( abfd, fileName );
if ( !syms )
{
printf( "Failed to read symbol table for archive \"%s\"\n", fileName );
bfd_close( abfd );
return NULL;
}
char** retBuf = translateAddressesBuf( abfd, addr, naddr, syms );
free( syms );
bfd_close( abfd );
return retBuf;
}
char** backtraceSymbols( void* const* addrList, int numAddr )
{
char*** locations = (char***) alloca( sizeof( char** ) * numAddr );
// initialize the bfd library
bfd_init();
int total = 0;
u32 idx = numAddr;
for ( s32 i = 0; i < numAddr; i++ )
{
// find which executable, or library the symbol is from
FileMatch match( addrList[--idx] );
dl_iterate_phdr( findMatchingFile, &match );
// adjust the address in the global space of your binary to an
// offset in the relevant library
bfd_vma addr = (bfd_vma)( addrList[idx] );
addr -= (bfd_vma)( match.mBase );
// lookup the symbol
if ( match.mFile && strlen( match.mFile ))
locations[idx] = processFile( match.mFile, &addr, 1 );
else
locations[idx] = processFile( "/proc/self/exe", &addr, 1 );
total += strlen( locations[idx][0] ) + 1;
}
// return all the file and line information for each address
char** final = (char**)malloc( total + ( numAddr * sizeof( char* )));
char* f_strings = (char*)( final + numAddr );
for ( s32 i = 0; i < numAddr; i++ )
{
strcpy( f_strings, locations[i][0] );
free( locations[i] );
final[i] = f_strings;
f_strings += strlen( f_strings ) + 1;
}
return final;
}
void printStackBacktraceWithLines( FILE *out, unsigned int max_frames)
{
void* addrlist[max_frames+1];
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
char ** lines=backtraceSymbols( addrlist, addrlen );
fprintf(out,"\n\nStack Backtrace:\n\n");
for(int i=0;i<addrlen;i++)
{
fprintf(out,"\n==================================================================\n\n");
fprintf(out,"%s\n",lines[i]);
}
free(lines);
}
#endif
}
}
#pragma once
#ifndef NDEBUG
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <dlfcn.h>
#include <link.h>
#include <linux/types.h>
#include <execinfo.h>
#include <cxxabi.h>
// THe PACKAGE and PACKAGE_VERSION macros are needed for bfd.h,
// see https://stackoverflow.com/a/11748919
#define PACKAGE
#define PACKAGE_VERSION
#include <bfd.h>
#undef PACKAGE
#undef PACKAGE_VERSION
//from: https://oroboro.com/printing-stack-traces-file-line/
typedef char s8;
typedef short s16;
typedef int s32;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#endif
namespace TNL {
namespace Debugging {
#ifndef NDEBUG
class FileMatch
{
public:
FileMatch( void* addr );
void* mAddress;
const char* mFile;
void* mBase;
};
class FileLineDesc
{
public:
FileLineDesc( asymbol** syms, bfd_vma pc );
void findAddressInSection( bfd* abfd, asection* section );
bfd_vma mPc;
char* mFilename;
char* mFunctionname;
unsigned int mLine;
int mFound;
asymbol** mSyms;
};
int findMatchingFile( struct dl_phdr_info* info, size_t size, void* data );
asymbol** kstSlurpSymtab( bfd* abfd, const char* fileName );
void FindAddressInSection( bfd* abfd, asection* section, void* data );
char** translateAddressesBuf( bfd* abfd, bfd_vma* addr, int numAddr, asymbol** syms );
char** processFile( const char* fileName, bfd_vma* addr, int naddr );
char** backtraceSymbols( void* const* addrList, int numAddr );
void printStackBacktraceWithLines( FILE *out = stderr, unsigned int max_frames = 63 );
#endif
} // namespace Debugging
} // namespace TNL
#ifdef NDEBUG
#define PrintStackBacktraceWithLines
#else
#define PrintStackBacktraceWithLines TNL::Debugging::printStackBacktraceWithLines();
#endif