diff options
-rw-r--r-- | cmake/Modules/Findlibunwind.cmake | 29 | ||||
-rw-r--r-- | gnuradio-runtime/lib/CMakeLists.txt | 15 | ||||
-rw-r--r-- | gnuradio-runtime/lib/terminate_handler.cc | 147 | ||||
-rw-r--r-- | gnuradio-runtime/lib/terminate_handler.h | 19 | ||||
-rw-r--r-- | gnuradio-runtime/lib/top_block_impl.cc | 2 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gr/top_block.py | 2 |
6 files changed, 210 insertions, 4 deletions
diff --git a/cmake/Modules/Findlibunwind.cmake b/cmake/Modules/Findlibunwind.cmake new file mode 100644 index 0000000000..1985a9fd4b --- /dev/null +++ b/cmake/Modules/Findlibunwind.cmake @@ -0,0 +1,29 @@ +# - Try to find libunwind +# Once done, this will define +# +# libunwind_FOUND - system has libunwind +# libunwind_INCLUDE_DIRS - the libunwind include directories +# libunwind_LIBRARIES - link these to use libunwind + +include(LibFindMacros) + +# Use pkg-config to get hints about paths +libfind_pkg_check_modules(libunwind_PKGCONF libunwind) + +# Include dir +find_path(libunwind_INCLUDE_DIR + NAMES libunwind.h + PATHS ${libunwind_PKGCONF_INCLUDE_DIRS} +) + +# Finally the library itself +find_library(libunwind_LIBRARY + NAMES unwind + PATHS ${libunwind_PKGCONF_LIBRARY_DIRS} +) + +# Set the include dir variables and the libraries and let libfind_process do the rest. +# NOTE: Singular variables for this library, plural for libraries this this lib depends on. +set(libunwind_PROCESS_INCLUDES ${libunwind_INCLUDE_DIR}) +set(libunwind_PROCESS_LIBS libunwind_LIBRARY) +libfind_process(libunwind) diff --git a/gnuradio-runtime/lib/CMakeLists.txt b/gnuradio-runtime/lib/CMakeLists.txt index 50405cef83..815489108f 100644 --- a/gnuradio-runtime/lib/CMakeLists.txt +++ b/gnuradio-runtime/lib/CMakeLists.txt @@ -9,6 +9,14 @@ include(GrMiscUtils) gr_check_hdr_n_def(sys/resource.h HAVE_SYS_RESOURCE_H) ######################################################################## +# Look for libunwind +######################################################################## +find_package(libunwind) +if(libunwind_FOUND) + add_definitions(-DHAVE_LIBUNWIND) +endif(libunwind_FOUND) + +######################################################################## # Handle the generated constants ######################################################################## execute_process(COMMAND ${PYTHON_EXECUTABLE} -c @@ -23,7 +31,6 @@ string(REPLACE "\\" "\\\\" prefix "${prefix}") string(REPLACE "\\" "\\\\" SYSCONFDIR "${SYSCONFDIR}") string(REPLACE "\\" "\\\\" GR_PREFSDIR "${GR_PREFSDIR}") - ######################################################################### # Include subdirs rather to populate to the sources lists. ######################################################################## @@ -72,6 +79,7 @@ add_library(gnuradio-runtime sync_interpolator.cc sys_paths.cc tagged_stream_block.cc + terminate_handler.cc test.cc top_block.cc top_block_impl.cc @@ -196,12 +204,13 @@ target_link_libraries(gnuradio-runtime PUBLIC Log4Cpp::log4cpp MPLib::mplib ${PYTHON_LIBRARIES} + ${libunwind_LIBRARIES} ) target_include_directories(gnuradio-runtime PUBLIC - ${PYTHON_INCLUDE_DIR} - ${PYTHON_NUMPY_INCLUDE_DIR} + ${PYTHON_INCLUDE_DIR} + ${PYTHON_NUMPY_INCLUDE_DIR} ${pybind11_INCLUDE_DIR} $<INSTALL_INTERFACE:include> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../include> diff --git a/gnuradio-runtime/lib/terminate_handler.cc b/gnuradio-runtime/lib/terminate_handler.cc new file mode 100644 index 0000000000..ed3b1d93b4 --- /dev/null +++ b/gnuradio-runtime/lib/terminate_handler.cc @@ -0,0 +1,147 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <pmt/pmt.h> +#include <boost/thread.hpp> +#include <exception> +#include <iostream> +#include <regex> +#include <stdexcept> + +#include <cxxabi.h> + +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#include <cstdio> +#include <cstdlib> +#endif + +namespace gr { + +#ifdef HAVE_LIBUNWIND +void print_backtrace() +{ + unw_cursor_t cursor; + unw_context_t context; + + // Initialize cursor to current frame for local unwinding. + unw_getcontext(&context); + unw_init_local(&cursor, &context); + + // Unwind frames one by one, going up the frame stack. + while (unw_step(&cursor) > 0) { + unw_word_t offset, pc; + unw_get_reg(&cursor, UNW_REG_IP, &pc); + if (pc == 0) { + break; + } + std::fprintf(stderr, "0x%lx:", pc); + + char sym[256]; + if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) { + char* nameptr = sym; + int status; + char* demangled = abi::__cxa_demangle(sym, nullptr, nullptr, &status); + if (status == 0) { + nameptr = demangled; + } + std::fprintf(stderr, " (%s+0x%lx)\n", nameptr, offset); + std::free(demangled); + } else { + std::fprintf(stderr, + " -- error: unable to obtain symbol name for this frame\n"); + } + } +} +#endif + +void terminate_handler_impl() +{ + std::cerr << "terminate reached from thread id: " << boost::this_thread::get_id(); + try { + std::exception_ptr eptr = std::current_exception(); + if (eptr) { + std::rethrow_exception(eptr); + } + } catch (const std::out_of_range& e) { + std::cerr << "Got std::out_of_range" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::length_error& e) { + std::cerr << "Got std::length_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::domain_error& e) { + std::cerr << "Got std::domain_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::invalid_argument& e) { + std::cerr << "Got std::invalid_argument" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const pmt::exception& e) { + std::cerr << "Got pmt::exception" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::logic_error& e) { + std::cerr << "Got std::logic_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::ios_base::failure& e) { + std::cerr << "Got std::ios_base::falure" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::system_error& e) { + std::cerr << "Got std::system_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::regex_error& e) { + std::cerr << "Got std::regex_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::underflow_error& e) { + std::cerr << "Got std::underflow_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::overflow_error& e) { + std::cerr << "Got std::overflow_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::range_error& e) { + std::cerr << "Got std::range_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::runtime_error& e) { + std::cerr << "Got std::runtime_error" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_typeid& e) { + std::cerr << "Got std::bad_typeid" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_cast& e) { + std::cerr << "Got std::bad_cast" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_weak_ptr& e) { + std::cerr << "Got std::bad_weak_ptr" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_function_call& e) { + std::cerr << "Got std::bad_function_call" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_array_new_length& e) { + std::cerr << "Got std::bad_array_new_length" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_alloc& e) { + std::cerr << "Got std::bad_alloc" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::bad_exception& e) { + std::cerr << "Got std::bad_exception" << std::endl; + std::cerr << e.what() << std::endl; + } catch (const std::exception& e) { + std::cerr << "Got std::exception" << std::endl; + std::cerr << e.what() << std::endl; + } catch (...) { + std::cerr << "Got unknown exception" << std::endl; + } +#ifdef HAVE_LIBUNWIND + // Use libunwind to print a backtrace + print_backtrace(); +#endif + std::abort(); +} + +void install_terminate_handler() { std::set_terminate(&terminate_handler_impl); } +} // namespace gr diff --git a/gnuradio-runtime/lib/terminate_handler.h b/gnuradio-runtime/lib/terminate_handler.h new file mode 100644 index 0000000000..a7a671b06a --- /dev/null +++ b/gnuradio-runtime/lib/terminate_handler.h @@ -0,0 +1,19 @@ +/* -*- c++ -*- */ +/* + * Copyright 2018 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef INCLUDED_GR_TERMINATE_HANDLER_H +#define INCLUDED_GR_TERMINATE_HANDLER_H + +#include <gnuradio/api.h> + +namespace gr { +void install_terminate_handler() GR_RUNTIME_API; +} + +#endif /* INCLUDED_TERMINATE_HANDLER_H */ diff --git a/gnuradio-runtime/lib/top_block_impl.cc b/gnuradio-runtime/lib/top_block_impl.cc index 393f8adbe5..558fd763e0 100644 --- a/gnuradio-runtime/lib/top_block_impl.cc +++ b/gnuradio-runtime/lib/top_block_impl.cc @@ -14,6 +14,7 @@ #include "flat_flowgraph.h" #include "scheduler_tpb.h" +#include "terminate_handler.h" #include "top_block_impl.h" #include <gnuradio/logger.h> #include <gnuradio/prefs.h> @@ -79,6 +80,7 @@ top_block_impl::top_block_impl(top_block* owner, bool catch_exceptions = true) d_retry_wait(false), d_catch_exceptions(catch_exceptions) { + install_terminate_handler(); gr::configure_default_loggers(d_logger, d_debug_logger, "top_block_impl"); } diff --git a/gnuradio-runtime/python/gnuradio/gr/top_block.py b/gnuradio-runtime/python/gnuradio/gr/top_block.py index 1389e5968a..d44c6c46d4 100644 --- a/gnuradio-runtime/python/gnuradio/gr/top_block.py +++ b/gnuradio-runtime/python/gnuradio/gr/top_block.py @@ -88,7 +88,7 @@ class top_block(hier_block2): Create a top block with a given name. """ # not calling hier_block2.__init__, we set our own _impl - self._impl = top_block_pb(name) + self._impl = top_block_pb(name, catch_exceptions) self.handle_sigint = True def start(self, max_noutput_items=10000000): |