From c3a12e20712df113599c915b008664eb3cbf9daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Hanousek=20-=20vz?= <vithanousek@seznam.cz> Date: Sun, 23 Sep 2018 14:04:06 +0200 Subject: [PATCH] New Debuging Tool - StackBackTrace with File and Line info - copied from web, possible memory leaks. Heavy unsystematicly bastled into TNL but usefull. --- CMakeLists.txt | 4 +- src/TNL/Assert.h | 7 +- src/TNL/CMakeLists.txt | 3 +- src/TNL/Debugging/backtrace2line.cpp | 271 +++++++++++++++++++++++++++ src/TNL/Debugging/backtrace2line.h | 80 ++++++++ 5 files changed, 359 insertions(+), 6 deletions(-) create mode 100644 src/TNL/Debugging/backtrace2line.cpp create mode 100644 src/TNL/Debugging/backtrace2line.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ed064eb1d..684b18f498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/src/TNL/Assert.h b/src/TNL/Assert.h index 6d13e35b11..32bb74cbc1 100644 --- a/src/TNL/Assert.h +++ b/src/TNL/Assert.h @@ -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 diff --git a/src/TNL/CMakeLists.txt b/src/TNL/CMakeLists.txt index cd07ae6591..7ffd2bf068 100644 --- a/src/TNL/CMakeLists.txt +++ b/src/TNL/CMakeLists.txt @@ -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} diff --git a/src/TNL/Debugging/backtrace2line.cpp b/src/TNL/Debugging/backtrace2line.cpp new file mode 100644 index 0000000000..ab2ff8edb8 --- /dev/null +++ b/src/TNL/Debugging/backtrace2line.cpp @@ -0,0 +1,271 @@ +#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 + + +} +} diff --git a/src/TNL/Debugging/backtrace2line.h b/src/TNL/Debugging/backtrace2line.h new file mode 100644 index 0000000000..7f2bacb283 --- /dev/null +++ b/src/TNL/Debugging/backtrace2line.h @@ -0,0 +1,80 @@ + +#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 -- GitLab