diff --git a/CMake/FindBacktrace.cmake b/CMake/FindBacktrace.cmake deleted file mode 100644 index 0b19a8538c2..00000000000 --- a/CMake/FindBacktrace.cmake +++ /dev/null @@ -1,106 +0,0 @@ -# This is cloned from -# https://github.com/Kitware/CMake/blob/master/Modules/ -# The module is already included in CMake since 3.0. Until we -# require CMake 3.0 this module works as a backport. - -# Find provider for backtrace(3). -# -# Checks if OS supports backtrace(3) via either libc or custom library. -# This module defines the following variables: -# -# ``Backtrace_HEADER`` -# The header file needed for backtrace(3). Cached. -# Could be forcibly set by user. -# ``Backtrace_INCLUDE_DIRS`` -# The include directories needed to use backtrace(3) header. -# ``Backtrace_LIBRARIES`` -# The libraries (linker flags) needed to use backtrace(3), if any. -# ``Backtrace_FOUND`` -# Is set if and only if backtrace(3) support detected. -# -# The following cache variables are also available to set or use: -# -# ``Backtrace_LIBRARY`` -# The external library providing backtrace, if any. -# ``Backtrace_INCLUDE_DIR`` -# The directory holding the backtrace(3) header. -# -# Typical usage is to generate of header file using configure_file() with the -# contents like the following:: -# -# #cmakedefine01 Backtrace_FOUND -# #if Backtrace_FOUND -# # include <${Backtrace_HEADER}> -# #endif -# -# And then reference that generated header file in actual source. - -#============================================================================= -# Copyright 2013 Vadim Zhukov -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - - -include(CMakePushCheckState) -include(CheckSymbolExists) -include(FindPackageHandleStandardArgs) - -# List of variables to be provided to find_package_handle_standard_args() -set(_Backtrace_STD_ARGS Backtrace_INCLUDE_DIR) - -if(Backtrace_HEADER) - set(_Backtrace_HEADER_TRY "${Backtrace_HEADER}") -else(Backtrace_HEADER) - set(_Backtrace_HEADER_TRY "execinfo.h") -endif(Backtrace_HEADER) - -find_path(Backtrace_INCLUDE_DIR "${_Backtrace_HEADER_TRY}") -set(Backtrace_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR}) - -if (NOT DEFINED Backtrace_LIBRARY) - # First, check if we already have backtrace(), e.g., in libc - cmake_push_check_state(RESET) - set(CMAKE_REQUIRED_INCLUDES ${Backtrace_INCLUDE_DIRS}) - set(CMAKE_REQUIRED_QUIET ${Backtrace_FIND_QUIETLY}) - check_symbol_exists("backtrace" "${_Backtrace_HEADER_TRY}" - _Backtrace_SYM_FOUND) - cmake_pop_check_state() -endif() - -if(_Backtrace_SYM_FOUND) - # Avoid repeating the message() call below each time CMake is run. - if(NOT Backtrace_FIND_QUIETLY AND NOT DEFINED Backtrace_LIBRARY) - message(STATUS "backtrace facility detected in default set of libraries") - endif() - set(Backtrace_LIBRARY "" CACHE FILEPATH "Library providing backtrace(3), - empty for default set of libraries") -else() - # Check for external library, for non-glibc systems - if(Backtrace_INCLUDE_DIR) - # OpenBSD has libbacktrace renamed to libexecinfo - find_library(Backtrace_LIBRARY "execinfo") - elseif() # respect user wishes - set(_Backtrace_HEADER_TRY "backtrace.h") - find_path(Backtrace_INCLUDE_DIR ${_Backtrace_HEADER_TRY}) - find_library(Backtrace_LIBRARY "backtrace") - endif() - - # Prepend list with library path as it's more common practice - set(_Backtrace_STD_ARGS Backtrace_LIBRARY ${_Backtrace_STD_ARGS}) -endif() - -set(Backtrace_LIBRARIES ${Backtrace_LIBRARY}) -set(Backtrace_HEADER "${_Backtrace_HEADER_TRY}" CACHE STRING "Header - providing backtrace(3) facility") - -find_package_handle_standard_args(Backtrace FOUND_VAR Backtrace_FOUND - REQUIRED_VARS ${_Backtrace_STD_ARGS}) -mark_as_advanced(Backtrace_HEADER Backtrace_INCLUDE_DIR Backtrace_LIBRARY) \ No newline at end of file diff --git a/CMake/FindBfd.cmake b/CMake/FindBfd.cmake new file mode 100644 index 00000000000..19b1b5bd9c3 --- /dev/null +++ b/CMake/FindBfd.cmake @@ -0,0 +1,89 @@ +# - Try to find libbfd +# Once done this will define +# +# LIBBFD_FOUND - system has libbfd +# LIBBFD_INCLUDE_DIRS - the libbfd include directory +# LIBBFD_LIBRARIES - Link these to use libbfd +# LIBBFD_DEFINITIONS - Compiler switches required for using libbfd +# +# Based on: +# +# Copyright (c) 2008 Bernhard Walle +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + + +if (LIBBFD_LIBRARIES AND LIBBFD_INCLUDE_DIRS) + set (LIBBFD_FIND_QUIETLY TRUE) +endif (LIBBFD_LIBRARIES AND LIBBFD_INCLUDE_DIRS) + +find_path (LIBBFD_INCLUDE_DIRS + NAMES + bfd.h + dis-asm.h + PATHS + /usr/include + /usr/local/include + /opt/local/include + /opt/include + ENV CPATH) + +# Ugly, yes ugly... +find_library (LIBBFD_BFD_LIBRARY + NAMES + bfd + PATHS + /usr/lib + /usr/lib64 + /usr/local/lib + /usr/local/lib64 + /usr/include + /opt/local/lib + /opt/usr/lib64 + ENV LIBRARY_PATH + ENV LD_LIBRARY_PATH) + +#find_library (LIBBFD_IBERTY_LIBRARY +# NAMES +# iberty +# PATHS +# /usr/lib +# /usr/lib64 +# /usr/local/lib +# /usr/local/lib64 +# /usr/include +# /opt/local/lib +# /opt/usr/lib64 +# ENV LIBRARY_PATH +# ENV LD_LIBRARY_PATH) + +#find_library (LIBBFD_OPCODES_LIBRARY +# NAMES +# opcodes +# PATHS +# /usr/lib +# /usr/lib64 +# /usr/local/lib +# /usr/local/lib64 +# /usr/include +# /opt/local/lib +# /opt/usr/lib64 +# ENV LIBRARY_PATH +# ENV LD_LIBRARY_PATH) + + +include (FindPackageHandleStandardArgs) + + +# handle the QUIETLY and REQUIRED arguments and set LIBBFD_FOUND to TRUE if all listed variables are TRUE +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBBFD DEFAULT_MSG + LIBBFD_BFD_LIBRARY +# LIBBFD_IBERTY_LIBRARY +# LIBBFD_OPCODES_LIBRARY + LIBBFD_INCLUDE_DIRS) + +set(LIBBFD_LIBRARIES "${LIBBFD_BFD_LIBRARY}") +mark_as_advanced(LIBBFD_INCLUDE_DIRS LIBBFD_LIBRARIES) \ No newline at end of file diff --git a/CMake/FindLibDL.cmake b/CMake/FindLibDL.cmake new file mode 100644 index 00000000000..52fd399514e --- /dev/null +++ b/CMake/FindLibDL.cmake @@ -0,0 +1,32 @@ +# - Try to find libdl +# Once done this will define +# +# LIBDL_FOUND - system has libdl +# LIBDL_INCLUDE_DIRS - the libdl include directory +# LIBDL_LIBRARIES - Link these to use libdl +# LIBDL_NEEDS_UNDERSCORE - If extern "C" symbols are prefixed (BSD/Apple) +# + +find_path (LIBDL_INCLUDE_DIRS NAMES dlfcn.h) +find_library (LIBDL_LIBRARIES NAMES dl) +include (FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibDL DEFAULT_MSG + LIBDL_LIBRARIES + LIBDL_INCLUDE_DIRS) + +SET(CMAKE_REQUIRED_LIBRARIES dl) +INCLUDE(CheckCSourceRuns) +CHECK_C_SOURCE_RUNS("#include +#include +void testfunc() {} +int main() { + testfunc(); + if (dlsym(0, \"_testfunc\") != (void*)0) { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +}" LIBDL_NEEDS_UNDERSCORE) + +mark_as_advanced(LIBDL_INCLUDE_DIRS LIBDL_LIBRARIES LIBDL_NEEDS_UNDERSCORE) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e3912c79557..6afd2c4ab9c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,20 @@ if(DEBUG) add_definitions(-DDEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -ftemplate-backtrace-limit=0") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g -O0") + # mlpack uses it's own mlpack::backtrace class based on Binary File Descriptor + # and linux Dynamic Loader and more portable version in future + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + find_package(Bfd) + find_package(LibDL) + if(LIBBFD_FOUND AND LIBDL_FOUND) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -rdynamic") + include_directories(${LIBBFD_INCLUDE_DIRS}) + include_directories(${LIBDL_INCLUDE_DIRS}) + add_definitions(-DHAS_BFD_DL) + else(LIBBFD_FOUND AND LIBDL_FOUND) + message(WARNING "No libBFD and/or libDL has been found!") + endif(LIBBFD_FOUND AND LIBDL_FOUND) + endif(CMAKE_SYSTEM_NAME STREQUAL "Linux") else() add_definitions(-DARMA_NO_DEBUG) add_definitions(-DNDEBUG) @@ -80,16 +94,6 @@ if(CMAKE_COMPILER_IS_GNUCC AND PROFILE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg") endif(CMAKE_COMPILER_IS_GNUCC AND PROFILE) -# mlpack uses backtrace() facilities. On some systems (e.g., GNU/Linux), it -# resides in libc itself and requires ; on other (e.g., OpenBSD) -# it's provided by a separate library. -find_package(Backtrace) -if(Backtrace_FOUND) - include_directories(${Backtrace_INCLUDE_DIRS}) - add_definitions(-DBACKTRACE_FOUND) - add_definitions(-DBACKTRACE_HEADER="${Backtrace_HEADER}") -endif(Backtrace_FOUND) - # If the user asked for running test cases with verbose output, turn that on. if(TEST_VERBOSE) add_definitions(-DTEST_VERBOSE) diff --git a/doc/guide/iodoc.hpp b/doc/guide/iodoc.hpp index 8e32005104a..769cdcea29c 100644 --- a/doc/guide/iodoc.hpp +++ b/doc/guide/iodoc.hpp @@ -23,7 +23,8 @@ Output to Log::Debug does not show (and has no performance penalty) when mlpack is compiled without debugging symbols. Output to Log::Info is only shown when the program is run with the --verbose (or -v) flag. Log::Warn is always shown, and Log::Fatal will throw a std::runtime_error exception, when a newline is sent -to it. +to it only. If mlpack was compiled with debugging symbols, Log::Fatal will +always throw a std::runtime_error exception and print backtrace. Here is a simple example, and its output: @@ -48,13 +49,28 @@ int main(int argc, char** argv) } @endcode -With debugging output and --verbose, the following is shown: +With debugging output--verbose, the following is shown: @code -$ ./main --verbose [DEBUG] Compiled with debugging symbols. [INFO ] Some test informational output. [WARN ] A warning! +[FATAL] [bt]: (1) /absolute/path/to/file/example.cpp:6: function() +[FATAL] Program has crashed. +terminate called after throwing an instance of 'std::runtime_error' + what(): fatal error; see Log::Fatal output +Aborted +@endcode + +With debugging output, compilation flags -g -rdynamic and --verbose, +the following is shown: + +@code +[DEBUG] Compiled with debugging symbols. +[INFO ] Some test informational output. +[WARN ] A warning! +[FATAL] Cannot give backtrace because program was compiled without: -g -rdynamic +[FATAL] For a backtrace, recompile with: -g -rdynamic. [FATAL] Program has crashed. terminate called after throwing an instance of 'std::runtime_error' what(): fatal error; see Log::Fatal output diff --git a/src/mlpack/CMakeLists.txt b/src/mlpack/CMakeLists.txt index d100ae39908..aace30fca42 100644 --- a/src/mlpack/CMakeLists.txt +++ b/src/mlpack/CMakeLists.txt @@ -41,11 +41,13 @@ if(UNIX AND NOT APPLE) target_link_libraries(mlpack rt) endif(UNIX AND NOT APPLE) -# Log::Assert may require linking against whatever provides backtrace -# functionality. -if(Backtrace_FOUND) - target_link_libraries(mlpack ${Backtrace_LIBRARIES}) -endif(Backtrace_FOUND) +# Backtrace for Linux need those libs. +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + if(LIBBFD_FOUND AND LIBDL_FOUND AND DEBUG) + target_link_libraries(mlpack ${LIBBFD_LIBRARIES}) + target_link_libraries(mlpack ${LIBDL_LIBRARIES}) + endif(LIBBFD_FOUND AND LIBDL_FOUND AND DEBUG) +endif(CMAKE_SYSTEM_NAME STREQUAL "Linux") # Collect all header files in the library. file(GLOB_RECURSE INCLUDE_H_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) diff --git a/src/mlpack/core.hpp b/src/mlpack/core.hpp index 3896276e202..df6e01ebe7c 100644 --- a/src/mlpack/core.hpp +++ b/src/mlpack/core.hpp @@ -205,6 +205,10 @@ #include #include #include +//mlpack::backtrace only for linux +#ifdef HAS_BFD_DL + #include +#endif // Include kernel traits. #include diff --git a/src/mlpack/core/util/CMakeLists.txt b/src/mlpack/core/util/CMakeLists.txt index 98b2d83e9f9..39b40101029 100644 --- a/src/mlpack/core/util/CMakeLists.txt +++ b/src/mlpack/core/util/CMakeLists.txt @@ -3,6 +3,8 @@ set(SOURCES arma_config.hpp arma_config_check.hpp + backtrace.hpp + backtrace.cpp cli.hpp cli.cpp cli_deleter.hpp diff --git a/src/mlpack/core/util/backtrace.cpp b/src/mlpack/core/util/backtrace.cpp new file mode 100644 index 00000000000..494242c5b75 --- /dev/null +++ b/src/mlpack/core/util/backtrace.cpp @@ -0,0 +1,191 @@ +/** + * @file backtrace.cpp + * @author Grzegorz Krajewski + * + * Implementation of the Backtrace class. + * + * This file is part of mlpack 2.0.1. + * + * mlpack is free software; you may redstribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ + +#include + +#ifdef HAS_BFD_DL + #include + #include + #include + #include + #include + #include +#endif + +#include "prefixedoutstream.hpp" +#include "backtrace.hpp" +#include "log.hpp" + +// Easier to read Backtrace::DecodeAddress(). +#ifdef HAS_BFD_DL + #define TRACE_CONDITION_1 (!dladdr(trace[i], &addressHandler)) + #define FIND_LINE (bfd_find_nearest_line(abfd, text, syms, offset, &frame.file, &frame.function, &frame.line) && frame.file) +#endif + +using namespace mlpack; + +// Initialize Backtrace static inctances. +Backtrace::Frames Backtrace::frame; +std::vector Backtrace::stack; + +#ifdef HAS_BFD_DL +// Binary File Descriptor objects. +bfd* abfd = 0; // Descriptor datastructure. +asymbol **syms = 0; // Symbols datastructure. +asection *text = 0; // Strings datastructure. +#endif + +#ifdef HAS_BFD_DL +Backtrace::Backtrace(int maxDepth) +{ + frame.address = NULL; + frame.function = "0"; + frame.file = "0"; + frame.line = 0; + + stack.clear(); + + GetAddress(maxDepth); +} +#else +Backtrace::Backtrace() +{ + // Dummy constructor +} +#endif + +#ifdef HAS_BFD_DL +void Backtrace::GetAddress(int maxDepth) +{ + void* trace[maxDepth]; + int stackDepth = backtrace(trace, maxDepth); + + // Skip first stack frame (points to Backtrace::Backtrace). + for (int i = 1; i < stackDepth; i++) + { + Dl_info addressHandler; + + //No backtrace will be printed if no compile flags: -g -rdynamic + if(TRACE_CONDITION_1) + { + return ; + } + + frame.address = addressHandler.dli_saddr; + + DecodeAddress((long)frame.address); + } +} + +void Backtrace::DecodeAddress(long addr) +{ + // Check to see if there is anything to descript. If it doesn't, we'll + // dump running program. + if (!abfd) + { + char ename[1024]; + int l = readlink("/proc/self/exe",ename,sizeof(ename)); + if (l == -1) + { + perror("Failed to open executable!\n"); + return; + } + ename[l] = 0; + + bfd_init(); + + abfd = bfd_openr(ename, 0); + if (!abfd) + { + perror("bfd_openr failed: "); + return; + } + + bfd_check_format(abfd,bfd_object); + + unsigned storage_needed = bfd_get_symtab_upper_bound(abfd); + syms = (asymbol **) malloc(storage_needed); + + text = bfd_get_section_by_name(abfd, ".text"); + } + + long offset = addr - text->vma; + + if (offset > 0) + { + if(FIND_LINE) + { + DemangleFunction(); + // Save retrieved informations. + stack.push_back(frame); + } + } +} + +void Backtrace::DemangleFunction() +{ + int status; + char* tmp = abi::__cxa_demangle(frame.function, 0, 0, &status); + + // If demangling is successful, reallocate 'frame.function' pointer to + // demangled name. Else if 'status != 0', leave 'frame.function as it is. + if (status == 0) + { + frame.function = tmp; + } +} +#else +void Backtrace::GetAddress(int /* maxDepth */) { } +void Backtrace::DecodeAddress(long /* address */) { } +void Backtrace::DemangleFunction() { } +#endif + +std::string Backtrace::ToString() +{ + std::string stackStr; + +#ifdef HAS_BFD_DL + std::ostringstream lineOss; + std::ostringstream it; + + if(stack.size() <= 0) + { + stackStr = "Cannot give backtrace because program was compiled"; + stackStr += " without: -g -rdynamic\nFor a backtrace,"; + stackStr += " recompile with: -g -rdynamic.\n"; + + return stackStr; + } + + for(unsigned int i = 0; i < stack.size(); i++) + { + frame = stack[i]; + + lineOss << frame.line; + it << i + 1; + + stackStr += "[bt]: (" + it.str() + ") " + + frame.file + ":" + + lineOss.str() + " " + + frame.function + ":\n"; + + lineOss.str(""); + it.str(""); + } +#else + stackStr = "[bt]: No backtrace for this OS. Work in progress."; +#endif + + return stackStr; +} diff --git a/src/mlpack/core/util/backtrace.hpp b/src/mlpack/core/util/backtrace.hpp new file mode 100644 index 00000000000..443d1033f5f --- /dev/null +++ b/src/mlpack/core/util/backtrace.hpp @@ -0,0 +1,98 @@ +/** + * @file backtrace.hpp + * @author Grzegorz Krajewski + * + * Definition of the Backtrace class. + * + * This file is part of mlpack 2.0.1. + * + * mlpack is free software; you may redstribute it and/or modify it under the + * terms of the 3-clause BSD license. You should have received a copy of the + * 3-clause BSD license along with mlpack. If not, see + * http://www.opensource.org/licenses/BSD-3-Clause for more information. + */ +#ifndef __MLPACK_CORE_UTIL_BACKTRACE_HPP +#define __MLPACK_CORE_UTIL_BACKTRACE_HPP + +#include +#include + +namespace mlpack { + +/** + * Provides a backtrace. + * + * The Backtrace class retrieve addresses of each called function from the + * stack and decode file name, function & line number. Retrieved informations + * can be printed in form: + * + * @code + * [b]: (count) /directory/to/file.cpp:function(args):line_number + * @endcode + * + * Backtrace is printed always when Log::Assert failed. + * An example is given below. + * + * @code + * if (!someImportantCondition()) + * { + * Log::Fatal << "someImportantCondition() is not satisfied! Terminating."; + * Log::Fatal << std::endl; + * } + * @endcode + * + * @note Log::Assert will not be shown when compiling in non-debug mode. + * + * @see PrefixedOutStream, Log + */ +class Backtrace +{ + public: + /** + * Constructor initialize fields and call GetAddress to retrieve addresses + * for each frame of backtrace. + * + * @param maxDepth Maximum depth of backtrace. Default 32 steps. + */ +#ifdef HAS_BFD_DL + Backtrace(int maxDepth = 32); +#else + Backtrace(); +#endif + //! Returns string of backtrace. + std::string ToString(); + + private: + /** + * Gets addresses of each called function from the stack. + * + * @param maxDepth Maximum depth of backtrace. Default 32 steps. + */ + static void GetAddress(int maxDepth); + + /** + * Decodes file name, function & line number. + * + * @param address Address of traced frame. + */ + static void DecodeAddress(long address); + + //! Demangles function name. + static void DemangleFunction(); + + //! Backtrace datastructure. + struct Frames + { + void *address; + const char* function; + const char* file; + unsigned line; + } static frame; + + //! A vector for all the backtrace information. + static std::vector stack; +}; + +}; //namespace mlpack + +#endif diff --git a/src/mlpack/core/util/log.cpp b/src/mlpack/core/util/log.cpp index 2ff9cf84adc..cc5a4249f51 100644 --- a/src/mlpack/core/util/log.cpp +++ b/src/mlpack/core/util/log.cpp @@ -4,15 +4,10 @@ * * Implementation of the Log class. */ -#ifndef _WIN32 - #include - #include -#endif - #include "log.hpp" -#ifdef BACKTRACE_FOUND - #include BACKTRACE_HEADER +#ifdef HAS_BFD_DL + #include "backtrace.hpp" #endif // Color code escape sequences -- but not on Windows. @@ -56,76 +51,14 @@ void Log::Assert(bool condition, const std::string& message) { if (!condition) { -#ifdef BACKTRACE_FOUND - void* array[25]; - size_t size = backtrace(array, sizeof(array) / sizeof(void*)); - char** messages = backtrace_symbols(array, size); - - // Skip first stack frame (points here). - for (size_t i = 1; i < size && messages != NULL; ++i) - { - char *mangledName = 0, *offsetBegin = 0, *offsetEnd = 0; - - // Find parentheses and +address offset surrounding mangled name. - for (char *p = messages[i]; *p; ++p) - { - if (*p == '(') - { - mangledName = p; - } - else if (*p == '+') - { - offsetBegin = p; - } - else if (*p == ')') - { - offsetEnd = p; - break; - } - } - - // If the line could be processed, attempt to demangle the symbol. - if (mangledName && offsetBegin && offsetEnd && - mangledName < offsetBegin) - { - *mangledName++ = '\0'; - *offsetBegin++ = '\0'; - *offsetEnd++ = '\0'; - - int status; - char* realName = abi::__cxa_demangle(mangledName, 0, 0, &status); - - // If demangling is successful, output the demangled function name. - if (status == 0) - { - Log::Debug << "[bt]: (" << i << ") " << messages[i] << " : " - << realName << "+" << offsetBegin << offsetEnd - << std::endl; - - } - // Otherwise, output the mangled function name. - else - { - Log::Debug << "[bt]: (" << i << ") " << messages[i] << " : " - << mangledName << "+" << offsetBegin << offsetEnd - << std::endl; - } - free(realName); - } - // Otherwise, print the whole line. - else - { - Log::Debug << "[bt]: (" << i << ") " << messages[i] << std::endl; - } - } +#ifdef HAS_BFD_DL + Backtrace bt; + + Log::Debug << bt.ToString(); #endif Log::Debug << message << std::endl; -#ifdef BACKTRACE_FOUND - free(messages); -#endif - - throw std::runtime_error("Log::Assert() failed:" + message); + throw std::runtime_error("Log::Assert() failed: " + message); } } #else diff --git a/src/mlpack/core/util/prefixedoutstream_impl.hpp b/src/mlpack/core/util/prefixedoutstream_impl.hpp index d86763fed88..8c6ccda2d19 100644 --- a/src/mlpack/core/util/prefixedoutstream_impl.hpp +++ b/src/mlpack/core/util/prefixedoutstream_impl.hpp @@ -10,6 +10,11 @@ // Just in case it hasn't been included. #include "prefixedoutstream.hpp" + +#ifdef HAS_BFD_DL + #include "backtrace.hpp" +#endif + #include namespace mlpack { @@ -61,11 +66,32 @@ void PrefixedOutStream::BaseLogic(const T& val) return; } - // Now, we need to check for newlines in this line. If we find one, output - // up until the newline, then output the newline and the prefix and continue - // looking. + // Now, we need to check for newlines in retrieved backtrace. + //If we find one, output up until the newline, then output the newline + //and the prefix and continue looking. size_t nl; size_t pos = 0; +#ifdef HAS_BFD_DL + if(fatal) + { + Backtrace bt; + std::string btLine = bt.ToString(); + while ((nl = btLine.find('\n', pos)) != std::string::npos) + { + PrefixIfNeeded(); + + destination << btLine.substr(pos, nl - pos); + destination << std::endl; + newlined = true; + + carriageReturned = true; // Regardless of whether or not we display it. + + pos = nl + 1; + } + pos = 0; + } +#endif + //The same logic like above, but this time for 'line'. while ((nl = line.find('\n', pos)) != std::string::npos) { PrefixIfNeeded(); @@ -93,7 +119,10 @@ void PrefixedOutStream::BaseLogic(const T& val) // If we displayed a newline and we need to throw afterwards, do that. if (fatal && newlined) + { + std::cout << std::endl; throw std::runtime_error("fatal error; see Log::Fatal output"); + } } // This is an inline function (that is why it is here and not in .cc).