Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use libunwind for stack unwinding #249

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ jobs:
automake \
curl \
libcurl4-openssl-dev \
libunwind \
libunwind-dev \
git \
libev-dev \
libtool \
Expand Down
4 changes: 2 additions & 2 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -571,8 +571,8 @@ EXTRA_DIST = \
generate_commit_hash.sh \
commit_hash.h

AM_CXXFLAGS = -Wall -Werror $(PTHREAD_CFLAGS) $(libev_CFLAGS) $(SQLITE3_CFLAGS) $(CURL_CFLAGS) $(CLBOSS_CXXFLAGS)
LDADD = libclboss.la $(PTHREAD_LIBS) $(libev_LIBS) $(SQLITE3_LIBS) $(CURL_LIBS)
AM_CXXFLAGS = -Wall -Werror $(PTHREAD_CFLAGS) $(libev_CFLAGS) $(SQLITE3_CFLAGS) $(CURL_CFLAGS) $(CLBOSS_CXXFLAGS) $(LIBUNWIND_CFLAGS)
LDADD = libclboss.la $(PTHREAD_LIBS) $(libev_LIBS) $(SQLITE3_LIBS) $(CURL_LIBS) $(LIBUNWIND_LIBS)

ACLOCAL_AMFLAGS = -I m4

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,23 @@ Debian-derived systems:
* `libev-dev`
* `libcurl4-gnutls-dev`
* `libsqlite3-dev`
* `libunwind-dev`

RPM-dervied :
* `groupinstall "Development Tools"`
* `pkg-config`
* `libev-devel`
* `libcurl-devel`
* `libsqlite3x-devel`
* `libunwind-devel`

Alpine:
* `build-base`
* `pkgconf`
* `libev-dev`
* `curl-dev`
* `sqlite-dev`
* `libunwind-dev`

Equivalent packages have a good probability of existing in
non-Debian-derived distributions as well.
Expand Down Expand Up @@ -132,6 +135,7 @@ release:
pkg install libev
pkg install pkgconf
pkg install sqlite3
pkg install libunwind

In addition, you have to use `gmake` for building, not the
system `make`, as the included `libsecp256k1` requires
Expand Down
33 changes: 27 additions & 6 deletions Util/BacktraceException.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>

#ifdef HAVE_CONFIG_H
# include"config.h"
#endif

extern std::string g_argv0;

#define UNW_LOCAL_ONLY
#include <libunwind.h>

namespace Util {

/** class Util::BacktraceException<E>
Expand Down Expand Up @@ -54,23 +58,40 @@ class BacktraceException : public T {
static constexpr size_t MAX_FRAMES = 100;
mutable bool formatted_ = false;
mutable std::string full_message_;
mutable void* backtrace_addresses_[MAX_FRAMES];
mutable std::vector<unw_word_t> backtrace_addresses_;
mutable size_t stack_depth;

void capture_backtrace() {
memset(backtrace_addresses_, 0, sizeof(backtrace_addresses_));
stack_depth = backtrace(backtrace_addresses_, sizeof(backtrace_addresses_) / sizeof(void*));
unw_cursor_t cursor;
unw_context_t context;
unw_getcontext(&context);
unw_init_local(&cursor, &context);

while (unw_step(&cursor) > 0 && backtrace_addresses_.size() < MAX_FRAMES) {
unw_word_t ip;
unw_get_reg(&cursor, UNW_REG_IP, &ip);
backtrace_addresses_.push_back(ip);
}

stack_depth = backtrace_addresses_.size();
}

std::string format_backtrace() const {
char** symbols = backtrace_symbols(backtrace_addresses_, stack_depth);
// Create an array of pointers compatible with `backtrace_symbols`.
std::vector<void*> pointers(backtrace_addresses_.size());
for (size_t i = 0; i < backtrace_addresses_.size(); ++i) {
pointers[i] = reinterpret_cast<void*>(backtrace_addresses_[i]);
}

// Use `backtrace_symbols` with the adapted pointers.
char** symbols = backtrace_symbols(pointers.data(), stack_depth);
std::ostringstream oss;
for (size_t i = 0; i < stack_depth; ++i) {
oss << '#' << std::left << std::setfill(' ') << std::setw(2) << i << ' ';
auto line = addr2line(backtrace_addresses_[i]);
auto line = addr2line(pointers[i]);
if (line.find("??") != std::string::npos) {
// If addr2line doesn't find a good
// answer use basic information
// answer, use basic information
// instead.
oss << symbols[i] << std::endl;
} else {
Expand Down
16 changes: 16 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@ AX_LIB_CURL(,[:],[
AC_MSG_ERROR([Need libcurl.])
])

# Check for libunwind
PKG_CHECK_MODULES([LIBUNWIND], [libunwind], [
AC_DEFINE([HAVE_LIBUNWIND], [1], [Define if libunwind is available])
], [
AC_MSG_ERROR([libunwind is required but not found])
])

# https://github.com/ZmnSCPxj/clboss/issues/245
case "$host_os" in
*alpine*)
LDFLAGS="$LDFLAGS -lexecinfo"
;;
esac

AC_SUBST(LDFLAGS)

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.
Expand Down
1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
libev
libevdev
curl
libunwind
sqlite
bind
autoconf
Expand Down
Loading