From ebeea3fa9992d5ceb71806b24ae94c8601638717 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Mon, 27 May 2019 22:43:59 +0300 Subject: Add backtrace() --- libbutl/backtrace.cxx | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ libbutl/backtrace.mxx | 43 +++++++++++++++++++++ libbutl/buildfile | 28 +++++++++----- 3 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 libbutl/backtrace.cxx create mode 100644 libbutl/backtrace.mxx (limited to 'libbutl') diff --git a/libbutl/backtrace.cxx b/libbutl/backtrace.cxx new file mode 100644 index 0000000..7a8d615 --- /dev/null +++ b/libbutl/backtrace.cxx @@ -0,0 +1,101 @@ +// file : libbutl/backtrace.cxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef __cpp_modules_ts +#include +#endif + +// We only enable backtrace during bootstrap if we can do it without any +// complications of the build scripts/makefiles. +// +// With glibc linking with -rdynamic gives (non-static) function names. +// FreeBSD requires explicitly linking -lexecinfo. +// +#ifndef BUILD2_BOOTSTRAP +# if defined(__linux__) || \ + defined(__APPLE__) || \ + defined(__FreeBSD__) +# define LIBBUTL_BACKTRACE +# endif +#else +# if defined(__linux__) || \ + defined(__APPLE__) +# define LIBBUTL_BACKTRACE +# endif +#endif + +#ifdef LIBBUTL_BACKTRACE +# include // free() +# include +#endif + +#include + +#ifndef __cpp_lib_modules_ts +#include + +#ifdef LIBBUTL_BACKTRACE +# include // unique_ptr +# include // size_t +#endif + +#include +#endif + +// Other includes. + +#ifdef __cpp_modules_ts +module butl.backtrace; + +// Only imports additional to interface. +#ifdef __clang__ +#ifdef __cpp_lib_modules_ts +import std.core; +#endif +#endif + +#endif + +using namespace std; + +namespace butl +{ + string + backtrace () noexcept + try + { + string r; + +#ifdef LIBBUTL_BACKTRACE + + // Note: backtrace() returns int on Linux and MacOS and size_t on FreeBSD. + // + void* buf[1024]; + auto n (::backtrace (buf, 1024)); + + assert (n >= 0); + + char** fs (backtrace_symbols (buf, n)); // Note: returns NULL on error. + + if (fs != nullptr) + { + unique_ptr deleter ( + fs, [] (char** s) {::free (s);}); + + for (size_t i (0); i != static_cast (n); ++i) + { + r += fs[i]; + r += '\n'; + } + } + +#endif + + return r; + } + catch (const std::exception&) + { + return string (); + } +} diff --git a/libbutl/backtrace.mxx b/libbutl/backtrace.mxx new file mode 100644 index 0000000..25d0dcd --- /dev/null +++ b/libbutl/backtrace.mxx @@ -0,0 +1,43 @@ +// file : libbutl/backtrace.mxx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef __cpp_modules_ts +#pragma once +#endif + +// C includes. + +#ifndef __cpp_lib_modules_ts +#include +#endif + +// Other includes. + +#ifdef __cpp_modules_ts +export module butl.backtrace; +#ifdef __cpp_lib_modules_ts +import std.core; +#endif +#endif + +#include + +LIBBUTL_MODEXPORT namespace butl +{ + // Return the calling thread's backtrace or empty string if this + // functionality is not supported or an error has occurred. The exact + // backtrace format is implementation-defined; it normally contains a line + // with the binary name, address in that binary, and, if available, the + // function name for each stack frame. + // + // Currently this functionality is only available on Linux, FreeBSD, and Mac + // OS. On the first two platforms the address can be mapped to the function + // name and, if built with debug info, to source location using the + // addr2line(1) utility: + // + // $ addr2line -f -C -e + // + LIBBUTL_SYMEXPORT std::string + backtrace () noexcept; +} diff --git a/libbutl/buildfile b/libbutl/buildfile index 8e88402..feb2f96 100644 --- a/libbutl/buildfile +++ b/libbutl/buildfile @@ -16,7 +16,15 @@ lib{butl}: {hxx ixx txx cxx}{** -uuid-* +uuid-io -win32-utility} \ hxx{**.hxx -uuid-*.hxx +uuid-io.hxx -win32-utility.hxx \ -version.hxx} hxx{version} -windows = ($cxx.target.class == 'windows') +tclass = $cxx.target.class +tsys = $cxx.target.system + +linux = ($tclass == 'linux') +macos = ($tclass == 'macos') +windows = ($tclass == 'windows') +freebsd = ($tsys == 'freebsd') + +mingw = ($tsys == 'mingw32') # Exclude these from compilation on non-Windows targets. # @@ -30,17 +38,19 @@ lib{butl}: file{*.c *.h} # Platform-specific UUID implementations. # -lib{butl}: cxx{uuid-linux}: include = ($cxx.target.class == 'linux') -lib{butl}: cxx{uuid-macos}: include = ($cxx.target.class == 'macos') +lib{butl}: cxx{uuid-linux}: include = $linux +lib{butl}: cxx{uuid-macos}: include = $macos lib{butl}: cxx{uuid-windows}: include = $windows -lib{butl}: cxx{uuid-freebsd}: include = ($cxx.target.system == 'freebsd') +lib{butl}: cxx{uuid-freebsd}: include = $freebsd -if ($cxx.target.class == 'linux') +if $linux cxx.libs += -ldl -elif ($cxx.target.class == 'macos') +elif $macos cxx.libs += -framework CoreFoundation -elif ($windows) - cxx.libs += ($cxx.target.system == 'mingw32' ? -lrpcrt4 : rpcrt4.lib) +elif $windows + cxx.libs += ($mingw ? -lrpcrt4 : rpcrt4.lib) +elif $freebsd + cxx.libs += -lexecinfo # Include the generated version header into the distribution (so that we don't # pick up an installed one) and don't remove it when cleaning in src (so that @@ -63,7 +73,7 @@ objs{*} bmis{*}: cxx.poptions += -DLIBBUTL_SHARED_BUILD # Additional system libraries. # if $windows - cxx.libs += ($cxx.target.system == 'mingw32' ? -limagehlp : imagehlp.lib) + cxx.libs += ($mingw ? -limagehlp : imagehlp.lib) else cxx.libs += -lpthread -- cgit v1.1