aboutsummaryrefslogtreecommitdiff
path: root/libbutl
diff options
context:
space:
mode:
authorKaren Arutyunov <karen@codesynthesis.com>2019-05-27 22:43:59 +0300
committerKaren Arutyunov <karen@codesynthesis.com>2019-05-28 16:00:00 +0300
commitebeea3fa9992d5ceb71806b24ae94c8601638717 (patch)
tree4167dc1ca41c7b84d6d4d89c57c3020560d353da /libbutl
parenta8582e25936da4343966c91761d686c4933e3f6b (diff)
Add backtrace()
Diffstat (limited to 'libbutl')
-rw-r--r--libbutl/backtrace.cxx101
-rw-r--r--libbutl/backtrace.mxx43
-rw-r--r--libbutl/buildfile28
3 files changed, 163 insertions, 9 deletions
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 <libbutl/backtrace.mxx>
+#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 <stdlib.h> // free()
+# include <execinfo.h>
+#endif
+
+#include <cassert>
+
+#ifndef __cpp_lib_modules_ts
+#include <string>
+
+#ifdef LIBBUTL_BACKTRACE
+# include <memory> // unique_ptr
+# include <cstddef> // size_t
+#endif
+
+#include <exception>
+#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<char*, void (*)(char**)> deleter (
+ fs, [] (char** s) {::free (s);});
+
+ for (size_t i (0); i != static_cast<size_t> (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 <string>
+#endif
+
+// Other includes.
+
+#ifdef __cpp_modules_ts
+export module butl.backtrace;
+#ifdef __cpp_lib_modules_ts
+import std.core;
+#endif
+#endif
+
+#include <libbutl/export.hxx>
+
+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 <binary> <addr>
+ //
+ 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