Commit c3a12e20 authored by Vít Hanousek's avatar Vít Hanousek
Browse files

New Debuging Tool - StackBackTrace with File and Line info - copied from web,...

New Debuging Tool - StackBackTrace with File and Line info - copied from web, possible memory leaks.
Heavy unsystematicly bastled into TNL but usefull.
parent f6ee280c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -87,10 +87,10 @@ set( CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "" )
set( CMAKE_SHARED_LIBRARY_LINK_C_FLAGS_DEBUG "-rdynamic" )
set( CMAKE_SHARED_LIBRARY_LINK_C_FLAGS_RELEASE "" )
set( CMAKE_EXE_LINKER_FLAGS "" )
set( CMAKE_EXE_LINKER_FLAGS_DEBUG "-rdynamic" )
set( CMAKE_EXE_LINKER_FLAGS_DEBUG "-rdynamic -lbfd" )
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "" )
set( CMAKE_SHARED_LINKER_FLAGS "" )
set( CMAKE_SHARED_LINKER_FLAGS_DEBUG "-rdynamic" )
set( CMAKE_SHARED_LINKER_FLAGS_DEBUG "-rdynamic -lbfd" )
set( CMAKE_SHARED_LINKER_FLAGS_RELEASE "" )

get_filename_component( CXX_COMPILER_NAME ${CMAKE_CXX_COMPILER} NAME )
+4 −3
Original line number Diff line number Diff line
@@ -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

+2 −1
Original line number Diff line number Diff line
@@ -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}
+271 −0
Original line number Diff line number Diff line
#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


}
}
+80 −0
Original line number Diff line number Diff line

#pragma once

#ifndef NDEBUG

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <bfd.h>
#include <dlfcn.h>
#include <link.h>
#include <linux/types.h>
#include <execinfo.h>
#include <cxxabi.h>



//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