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

This commit is contained in:
krajekg@gmail.com
2016-02-24 21:22:10 +01:00
parent dc368011ee
commit e671aa8479
5 changed files with 403 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
[Dolphin]
Timestamp=2016,2,24,21,12,46
Version=3
ViewMode=1
+89
View File
@@ -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@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)
+32
View File
@@ -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)
+183
View File
@@ -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;
}
+95
View File
@@ -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