[mlpack-git] master: Add mlpack::backtrace for Ubuntu (C++, Clang). (e671aa8)

gitdub at mlpack.org gitdub at mlpack.org
Wed Feb 24 15:22:10 EST 2016


Repository : https://github.com/mlpack/mlpack
On branch  : master
Link       : https://github.com/mlpack/mlpack/compare/fd84f3a2e53592d723a8e8a76dadb8aa76820913...1a9c41a86be1fa1dcc5c3b90dd959c2255c3bb8e

>---------------------------------------------------------------

commit e671aa8479cb80927319edfb53a640b9dbfc0c8b
Author: krajekg at gmail.com <krajekg at gmail.com>
Date:   Wed Feb 24 21:22:10 2016 +0100

    Add mlpack::backtrace for Ubuntu (C++, Clang).


>---------------------------------------------------------------

e671aa8479cb80927319edfb53a640b9dbfc0c8b
 .directory                         |   4 +
 CMake/FindBfd.cmake                |  89 ++++++++++++++++++
 CMake/FindLibDL.cmake              |  32 +++++++
 src/mlpack/core/util/backtrace.cpp | 183 +++++++++++++++++++++++++++++++++++++
 src/mlpack/core/util/backtrace.hpp |  95 +++++++++++++++++++
 5 files changed, 403 insertions(+)

diff --git a/.directory b/.directory
new file mode 100644
index 0000000..08356bf
--- /dev/null
+++ b/.directory
@@ -0,0 +1,4 @@
+[Dolphin]
+Timestamp=2016,2,24,21,12,46
+Version=3
+ViewMode=1
diff --git a/CMake/FindBfd.cmake b/CMake/FindBfd.cmake
new file mode 100644
index 0000000..19b1b5b
--- /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 <bernhard.walle at gmx.de>
+#
+#  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 0000000..52fd399
--- /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 <dlfcn.h>
+#include <stdlib.h>
+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/src/mlpack/core/util/backtrace.cpp b/src/mlpack/core/util/backtrace.cpp
new file mode 100644
index 0000000..f718591
--- /dev/null
+++ b/src/mlpack/core/util/backtrace.cpp
@@ -0,0 +1,183 @@
+/**
+ * @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 <sstream>
+
+#ifdef HAS_BFD_DL
+  #include <execinfo.h>
+  #include <signal.h>
+  #include <unistd.h>
+  #include <cxxabi.h>
+  #include <bfd.h>
+  #include <dlfcn.h>
+#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::Frames> Backtrace::stack;
+
+// Binary File Descriptor objects.
+bfd* abfd = 0;		// Descriptor datastructure.
+asymbol **syms = 0;	// Symbols datastructure.
+asection *text = 0;	// Strings datastructure.
+
+Backtrace::Backtrace(int maxDepth)
+{
+  frame.address = NULL;
+  frame.function = "0";
+  frame.file = "0";
+  frame.line = 0;
+  
+  stack.clear();
+#ifdef HAS_BFD_DL
+  GetAddress(maxDepth);
+#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 + ":"
+	       + frame.function + ":"
+	       + lineOss.str() + "\n";
+	     
+    lineOss.str("");
+    it.str("");
+  }
+#else
+  stackStr = "[bt]: No backtrace for this OS. Work in progress.";
+#endif
+
+  return stackStr;
+}
\ No newline at end of file
diff --git a/src/mlpack/core/util/backtrace.hpp b/src/mlpack/core/util/backtrace.hpp
new file mode 100644
index 0000000..8e5bbb0
--- /dev/null
+++ b/src/mlpack/core/util/backtrace.hpp
@@ -0,0 +1,95 @@
+/**
+ * @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 <string>
+#include <vector>
+
+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.
+   */
+  Backtrace(int maxDepth = 32);
+  
+  //! 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<Frames> stack;
+};
+
+}; //namespace mlpack
+
+#endif
\ No newline at end of file




More information about the mlpack-git mailing list