From fff238ec94ac6d45fc18c315d7bc590ddfaad63d Mon Sep 17 00:00:00 2001
From: moneromooo-monero <moneromooo-monero@users.noreply.github.com>
Date: Sat, 19 Mar 2016 21:48:36 +0000
Subject: [PATCH] Print stack trace upon exceptions

Useful for debugging users' logs
---
 CMakeLists.txt                                | 12 +++
 cmake/FindLibunwind.cmake                     | 25 ++++++
 contrib/epee/include/misc_log_ex.h            |  2 +-
 .../epee/include/net/abstract_tcp_server2.inl |  2 +-
 .../storages/portable_storage_from_bin.h      |  4 +-
 src/blockchain_db/blockchain_db.h             |  3 +-
 .../blockchain_export.cpp                     |  2 +-
 .../blockchain_import.cpp                     |  6 +-
 src/blockchain_utilities/bootstrap_file.cpp   | 44 +++++-----
 src/blockchain_utilities/fake_core.h          |  4 +-
 src/common/CMakeLists.txt                     |  3 +
 src/common/exception.cpp                      | 84 +++++++++++++++++++
 src/common/exception.h                        | 53 ++++++++++++
 src/cryptonote_core/blockchain_storage.h      |  3 +-
 src/cryptonote_core/checkpoints_create.cpp    |  1 +
 src/cryptonote_core/cryptonote_core.cpp       |  2 +-
 src/cryptonote_core/cryptonote_core.h         |  1 +
 src/cryptonote_core/miner.cpp                 |  1 +
 .../cryptonote_protocol_handler.h             |  1 +
 src/daemon/command_parser_executor.cpp        |  1 +
 src/daemon/command_server.cpp                 |  1 +
 src/daemon/daemon.cpp                         |  6 +-
 src/daemon/p2p.h                              |  2 +-
 src/daemon/protocol.h                         |  2 +-
 src/daemon/rpc.h                              |  4 +-
 src/daemon/rpc_command_executor.cpp           |  3 +-
 src/daemonizer/posix_fork.cpp                 |  3 +-
 src/miner/simpleminer.cpp                     |  1 +
 src/p2p/data_logger.cpp                       |  7 +-
 src/simplewallet/simplewallet.cpp             |  2 +-
 src/wallet/wallet2.cpp                        |  5 +-
 src/wallet/wallet2.h                          |  1 +
 src/wallet/wallet2_api.cpp                    |  1 +
 tests/core_proxy/core_proxy.h                 |  2 +-
 tests/core_tests/chaingen.cpp                 | 12 +--
 tests/core_tests/chaingen.h                   |  6 +-
 tests/core_tests/tx_validation.cpp            |  2 +-
 tests/net_load_tests/clt.cpp                  |  1 +
 tests/net_load_tests/srv.cpp                  |  1 +
 tests/unit_tests/ban.cpp                      |  2 +-
 tests/unit_tests/epee_boosted_tcp_server.cpp  |  2 +-
 tests/unit_tests/mnemonics.cpp                |  1 +
 tests/unit_tests/test_protocol_pack.cpp       |  1 +
 43 files changed, 259 insertions(+), 63 deletions(-)
 create mode 100644 cmake/FindLibunwind.cmake
 create mode 100644 src/common/exception.cpp
 create mode 100644 src/common/exception.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9674404bb..ea1d5d7e5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -243,6 +243,14 @@ endif()
 
 add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}")
 
+find_package(Libunwind)
+if(LIBUNWIND_FOUND)
+  message(STATUS "Using libunwind to provide stack traces")
+  add_definitions("-DHAVE_LIBUNWIND")
+else()
+  message(STATUS "Stack traces disabled")
+endif()
+
 if (UNIX AND NOT APPLE)
   # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail
   set(THREADS_PREFER_PTHREAD_FLAG ON)
@@ -274,6 +282,10 @@ if (BERKELEY_DB)
   include_directories(${BDB_INCLUDE})
 endif()
 
+# Final setup for libunwind
+include_directories(${LIBUNWIND_INCLUDE})
+link_directories(${LIBUNWIND_LIBRARY_DIRS})
+
 if(MSVC)
   add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__")
   # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline")
diff --git a/cmake/FindLibunwind.cmake b/cmake/FindLibunwind.cmake
new file mode 100644
index 000000000..9946e7cdd
--- /dev/null
+++ b/cmake/FindLibunwind.cmake
@@ -0,0 +1,25 @@
+# - Try to find libunwind
+# Once done this will define
+#
+#  LIBUNWIND_FOUND - system has libunwind
+#  LIBUNWIND_INCLUDE_DIR - the libunwind include directory
+#  LIBUNWIND_LIBRARIES - Link these to use libunwind
+#  LIBUNWIND_DEFINITIONS - Compiler switches required for using libunwind
+
+# Copyright (c) 2006, Alexander Dymo, <adymo@kdevelop.org>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+find_path(LIBUNWIND_INCLUDE_DIR libunwind.h
+  /usr/include
+  /usr/local/include
+)
+
+find_library(LIBUNWIND_LIBRARIES NAMES unwind )
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Libunwind "Could not find libunwind" LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES)
+# show the LIBUNWIND_INCLUDE_DIR and LIBUNWIND_LIBRARIES variables only in the advanced view
+mark_as_advanced(LIBUNWIND_INCLUDE_DIR LIBUNWIND_LIBRARIES )
+
diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h
index d1451ff12..58d47c472 100644
--- a/contrib/epee/include/misc_log_ex.h
+++ b/contrib/epee/include/misc_log_ex.h
@@ -1426,7 +1426,7 @@ POP_WARNINGS
 #define CATCH_ENTRY_L4(lacation, return_val) CATCH_ENTRY(lacation, return_val)
 
 
-#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw std::runtime_error(ss.str());}
+#define ASSERT_MES_AND_THROW(message) {LOG_ERROR(message); std::stringstream ss; ss << message; throw tools::runtime_error(ss.str());}
 #define CHECK_AND_ASSERT_THROW_MES(expr, message) {if(!(expr)) ASSERT_MES_AND_THROW(message);}
 
 
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 698e1947a..e4a461203 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -777,7 +777,7 @@ POP_WARNINGS
   {
     m_thread_name_prefix = prefix_name;
 		auto it = server_type_map.find(m_thread_name_prefix);
-		if (it==server_type_map.end()) throw std::runtime_error("Unknown prefix/server type:" + std::string(prefix_name));
+		if (it==server_type_map.end()) throw tools::runtime_error("Unknown prefix/server type:" + std::string(prefix_name));
     auto connection_type = it->second; // the value of type
     _info_c("net/RPClog", "Set server type to: " << connection_type << " from name: " << m_thread_name_prefix);
     _info_c("net/RPClog", "prefix_name = " << prefix_name);
diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h
index bc2fb1463..4cb2003e0 100644
--- a/contrib/epee/include/storages/portable_storage_from_bin.h
+++ b/contrib/epee/include/storages/portable_storage_from_bin.h
@@ -84,9 +84,9 @@ namespace epee
     inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz)
     {
       if(!ptr) 
-        throw std::runtime_error("throwable_buffer_reader: ptr==nullptr");
+        throw tools::runtime_error("throwable_buffer_reader: ptr==nullptr");
       if(!sz)
-        throw std::runtime_error("throwable_buffer_reader: sz==0");
+        throw tools::runtime_error("throwable_buffer_reader: sz==0");
       m_ptr = (uint8_t*)ptr;
       m_count = sz;
       m_recursion_count = 0;
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 3396b8c20..b9db6d196 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -33,6 +33,7 @@
 #include <list>
 #include <string>
 #include <exception>
+#include "common/exception.h"
 #include "crypto/hash.h"
 #include "cryptonote_core/cryptonote_basic.h"
 #include "cryptonote_core/difficulty.h"
@@ -151,7 +152,7 @@ struct output_data_t
 /***********************************
  * Exception Definitions
  ***********************************/
-class DB_EXCEPTION : public std::exception
+class DB_EXCEPTION : public tools::exception
 {
   private:
     std::string m;
diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp
index 964c610cd..4c5e5fd02 100644
--- a/src/blockchain_utilities/blockchain_export.cpp
+++ b/src/blockchain_utilities/blockchain_export.cpp
@@ -198,7 +198,7 @@ int main(int argc, char* argv[])
   else
   {
     LOG_ERROR("Attempted to use non-existent database type: " << db_type);
-    throw std::runtime_error("Attempting to use non-existent database type");
+    throw tools::runtime_error("Attempting to use non-existent database type");
   }
   LOG_PRINT_L0("database: " << db_type);
 
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 1aaf2bddc..43f6af6d5 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -359,14 +359,14 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path,
     str1.assign(buffer1, sizeof(chunk_size));
     if (! ::serialization::parse_binary(str1, chunk_size))
     {
-      throw std::runtime_error("Error in deserialization of chunk size");
+      throw tools::runtime_error("Error in deserialization of chunk size");
     }
     LOG_PRINT_L3("chunk_size: " << chunk_size);
 
     if (chunk_size > BUFFER_SIZE)
     {
       LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE);
-      throw std::runtime_error("Aborting: chunk size exceeds buffer size");
+      throw tools::runtime_error("Aborting: chunk size exceeds buffer size");
     }
     if (chunk_size > 100000)
     {
@@ -406,7 +406,7 @@ int import_from_file(FakeCore& simple_core, const std::string& import_file_path,
       str1.assign(buffer_block, chunk_size);
       bootstrap::block_package bp;
       if (! ::serialization::parse_binary(str1, bp))
-        throw std::runtime_error("Error in deserialization of chunk");
+        throw tools::runtime_error("Error in deserialization of chunk");
 
       int display_interval = 1000;
       int progress_interval = 10;
diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp
index da3b44593..247709f57 100644
--- a/src/blockchain_utilities/bootstrap_file.cpp
+++ b/src/blockchain_utilities/bootstrap_file.cpp
@@ -117,7 +117,7 @@ bool BootstrapFile::initialize_file()
   std::string blob;
   if (! ::serialization::dump_binary(file_magic, blob))
   {
-    throw std::runtime_error("Error in serialization of file magic");
+    throw tools::runtime_error("Error in serialization of file magic");
   }
   *m_raw_data_file << blob;
 
@@ -143,7 +143,7 @@ bool BootstrapFile::initialize_file()
 
   if (! ::serialization::dump_binary(bd_size, blob))
   {
-    throw std::runtime_error("Error in serialization of bootstrap::file_info size");
+    throw tools::runtime_error("Error in serialization of bootstrap::file_info size");
   }
   *output_stream_header << blob;
   *output_stream_header << bd;
@@ -154,7 +154,7 @@ bool BootstrapFile::initialize_file()
 
   if (! ::serialization::dump_binary(bd_size, blob))
   {
-    throw std::runtime_error("Error in serialization of bootstrap::blocks_info size");
+    throw tools::runtime_error("Error in serialization of bootstrap::blocks_info size");
   }
   *output_stream_header << blob;
   *output_stream_header << bd;
@@ -181,7 +181,7 @@ void BootstrapFile::flush_chunk()
   std::string blob;
   if (! ::serialization::dump_binary(chunk_size, blob))
   {
-    throw std::runtime_error("Error in serialization of chunk size");
+    throw tools::runtime_error("Error in serialization of chunk size");
   }
   *m_raw_data_file << blob;
 
@@ -197,7 +197,7 @@ void BootstrapFile::flush_chunk()
   if (static_cast<unsigned long>(num_chars_written) != chunk_size)
   {
     LOG_PRINT_RED_L0("Error writing chunk:  height: " << m_cur_height << "  chunk_size: " << chunk_size << "  num chars written: " << num_chars_written);
-    throw std::runtime_error("Error writing chunk");
+    throw tools::runtime_error("Error writing chunk");
   }
 
   m_buffer.clear();
@@ -221,7 +221,7 @@ void BootstrapFile::write_block(block& block)
   {
     if (tx_id == null_hash)
     {
-      throw std::runtime_error("Aborting: tx == null_hash");
+      throw tools::runtime_error("Aborting: tx == null_hash");
     }
 #if SOURCE_DB == DB_MEMORY
     const transaction* tx = m_blockchain_storage->get_tx(tx_id);
@@ -233,14 +233,14 @@ void BootstrapFile::write_block(block& block)
     if(tx == NULL)
     {
       if (! m_tx_pool)
-        throw std::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled");
+        throw tools::runtime_error("Aborting: tx == NULL, so memory pool required to get tx, but memory pool isn't enabled");
       else
       {
         transaction tx;
         if(m_tx_pool->get_transaction(tx_id, tx))
           txs.push_back(tx);
         else
-          throw std::runtime_error("Aborting: tx not found in pool");
+          throw tools::runtime_error("Aborting: tx not found in pool");
       }
     }
     else
@@ -362,16 +362,16 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file)
   char buf1[2048];
   import_file.read(buf1, sizeof(file_magic));
   if (! import_file)
-    throw std::runtime_error("Error reading expected number of bytes");
+    throw tools::runtime_error("Error reading expected number of bytes");
   str1.assign(buf1, sizeof(file_magic));
 
   if (! ::serialization::parse_binary(str1, file_magic))
-    throw std::runtime_error("Error in deserialization of file_magic");
+    throw tools::runtime_error("Error in deserialization of file_magic");
 
   if (file_magic != blockchain_raw_magic)
   {
     LOG_PRINT_RED_L0("bootstrap file not recognized");
-    throw std::runtime_error("Aborting");
+    throw tools::runtime_error("Aborting");
   }
   else
     LOG_PRINT_L0("bootstrap file recognized");
@@ -381,20 +381,20 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file)
   import_file.read(buf1, sizeof(buflen_file_info));
   str1.assign(buf1, sizeof(buflen_file_info));
   if (! import_file)
-    throw std::runtime_error("Error reading expected number of bytes");
+    throw tools::runtime_error("Error reading expected number of bytes");
   if (! ::serialization::parse_binary(str1, buflen_file_info))
-    throw std::runtime_error("Error in deserialization of buflen_file_info");
+    throw tools::runtime_error("Error in deserialization of buflen_file_info");
   LOG_PRINT_L1("bootstrap::file_info size: " << buflen_file_info);
 
   if (buflen_file_info > sizeof(buf1))
-    throw std::runtime_error("Error: bootstrap::file_info size exceeds buffer size");
+    throw tools::runtime_error("Error: bootstrap::file_info size exceeds buffer size");
   import_file.read(buf1, buflen_file_info);
   if (! import_file)
-    throw std::runtime_error("Error reading expected number of bytes");
+    throw tools::runtime_error("Error reading expected number of bytes");
   str1.assign(buf1, buflen_file_info);
   bootstrap::file_info bfi;
   if (! ::serialization::parse_binary(str1, bfi))
-    throw std::runtime_error("Error in deserialization of bootstrap::file_info");
+    throw tools::runtime_error("Error in deserialization of bootstrap::file_info");
   LOG_PRINT_L0("bootstrap file v" << unsigned(bfi.major_version) << "." << unsigned(bfi.minor_version));
   LOG_PRINT_L0("bootstrap magic size: " << sizeof(file_magic));
   LOG_PRINT_L0("bootstrap header size: " << bfi.header_size);
@@ -412,7 +412,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
   if (!boost::filesystem::exists(raw_file_path, ec))
   {
     LOG_PRINT_L0("bootstrap file not found: " << raw_file_path);
-    throw std::runtime_error("Aborting");
+    throw tools::runtime_error("Aborting");
   }
   std::ifstream import_file;
   import_file.open(import_file_path, std::ios_base::binary | std::ifstream::in);
@@ -421,7 +421,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
   if (import_file.fail())
   {
     LOG_PRINT_L0("import_file.open() fail");
-    throw std::runtime_error("Aborting");
+    throw tools::runtime_error("Aborting");
   }
 
   uint64_t full_header_size; // 4 byte magic + length of header structures
@@ -456,7 +456,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
 
     str1.assign(buf1, sizeof(chunk_size));
     if (! ::serialization::parse_binary(str1, chunk_size))
-      throw std::runtime_error("Error in deserialization of chunk_size");
+      throw tools::runtime_error("Error in deserialization of chunk_size");
     LOG_PRINT_L3("chunk_size: " << chunk_size);
 
     if (chunk_size > BUFFER_SIZE)
@@ -464,7 +464,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
       std::cout << refresh_string;
       LOG_PRINT_L0("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE
           << "  height: " << h-1);
-      throw std::runtime_error("Aborting: chunk size exceeds buffer size");
+      throw tools::runtime_error("Aborting: chunk size exceeds buffer size");
     }
     if (chunk_size > 100000)
     {
@@ -475,7 +475,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
     else if (chunk_size <= 0) {
       std::cout << refresh_string;
       LOG_PRINT_L0("ERROR: chunk_size " << chunk_size << " <= 0" << "  height: " << h-1);
-      throw std::runtime_error("Aborting");
+      throw tools::runtime_error("Aborting");
     }
     // skip to next expected block size value
     import_file.seekg(chunk_size, std::ios_base::cur);
@@ -483,7 +483,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path)
       std::cout << refresh_string;
       LOG_PRINT_L0("ERROR: unexpected end of file: bytes read before error: "
           << import_file.gcount() << " of chunk_size " << chunk_size);
-      throw std::runtime_error("Aborting");
+      throw tools::runtime_error("Aborting");
     }
     bytes_read += chunk_size;
 
diff --git a/src/blockchain_utilities/fake_core.h b/src/blockchain_utilities/fake_core.h
index 2fb5031d3..3840a1c13 100644
--- a/src/blockchain_utilities/fake_core.h
+++ b/src/blockchain_utilities/fake_core.h
@@ -78,7 +78,7 @@ struct fake_core_db
     else
     {
       LOG_ERROR("Attempted to use non-existent database type: " << db_type);
-      throw std::runtime_error("Attempting to use non-existent database type");
+      throw tools::runtime_error("Attempting to use non-existent database type");
     }
 
     boost::filesystem::path folder(path);
@@ -176,7 +176,7 @@ struct fake_core_memory
   {
     // TODO:
     // would need to refactor handle_block_to_main_chain() to have a direct add_block() method like Blockchain class
-    throw std::runtime_error("direct add_block() method not implemented for in-memory db");
+    throw tools::runtime_error("direct add_block() method not implemented for in-memory db");
     return 2;
   }
 
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 2289704e5..5537900ae 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -31,6 +31,7 @@ set(common_sources
   command_line.cpp
   dns_utils.cpp
   util.cpp
+  exception.cpp
   i18n.cpp)
 
 set(common_headers)
@@ -48,6 +49,7 @@ set(common_private_headers
   unordered_containers_boost_serialization.h
   util.h
   varint.h
+  exception.h
   i18n.h)
 
 bitmonero_private_headers(common
@@ -60,6 +62,7 @@ target_link_libraries(common
   LINK_PRIVATE
     crypto
     ${UNBOUND_LIBRARY}
+    ${LIBUNWIND_LIBRARIES}
     ${Boost_DATE_TIME_LIBRARY}
     ${Boost_FILESYSTEM_LIBRARY}
     ${Boost_SYSTEM_LIBRARY}
diff --git a/src/common/exception.cpp b/src/common/exception.cpp
new file mode 100644
index 000000000..f8954329f
--- /dev/null
+++ b/src/common/exception.cpp
@@ -0,0 +1,84 @@
+// Copyright (c) 2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+//    conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+//    of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+//    used to endorse or promote products derived from this software without specific
+//    prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "common/exception.h"
+#include "misc_log_ex.h"
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include <cxxabi.h>
+
+namespace tools
+{
+
+void log_stack_trace(const char *msg)
+{
+#ifdef HAVE_LIBUNWIND
+  unw_context_t ctx;
+  unw_cursor_t cur;
+  unw_word_t ip, off;
+  unsigned level;
+  char sym[512], *dsym;
+  int status;
+
+  if (msg)
+    LOG_PRINT_L0(msg);
+  LOG_PRINT_L0("Unwinded call stack:");
+  if (unw_getcontext(&ctx) < 0) {
+    LOG_PRINT_L0("Failed to create unwind context");
+    return;
+  }
+  if (unw_init_local(&cur, &ctx) < 0) {
+    LOG_PRINT_L0("Failed to find the first unwind frame");
+    return;
+  }
+  for (level = 1; level < 999; ++level) { // 999 for safety
+    int ret = unw_step(&cur);
+    if (ret < 0) {
+      LOG_PRINT_L0("Failed to find the next frame");
+      return;
+    }
+    if (ret == 0)
+      break;
+    if (unw_get_reg(&cur, UNW_REG_IP, &ip) < 0) {
+      LOG_PRINT_L0("  " << std::setw(4) << level);
+      continue;
+    }
+    if (unw_get_proc_name(&cur, sym, sizeof(sym), &off) < 0) {
+      LOG_PRINT_L0("  " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip);
+      continue;
+    }
+    dsym = abi::__cxa_demangle(sym, NULL, NULL, &status);
+    LOG_PRINT_L0("  " << std::setw(4) << level << std::setbase(16) << std::setw(20) << "0x" << ip << " " << (!status && dsym ? dsym : sym) << " + " << "0x" << off);
+    free(dsym);
+  }
+#else
+#warning libunwind disabled, no stack traces
+#endif
+}
+
+}  // namespace tools
diff --git a/src/common/exception.h b/src/common/exception.h
new file mode 100644
index 000000000..93e0d4013
--- /dev/null
+++ b/src/common/exception.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2016, The Monero Project
+// 
+// All rights reserved.
+// 
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+// 
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+//    conditions and the following disclaimer.
+// 
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+//    of conditions and the following disclaimer in the documentation and/or other
+//    materials provided with the distribution.
+// 
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+//    used to endorse or promote products derived from this software without specific
+//    prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef MONERO_EXCEPTION_H
+#define MONERO_EXCEPTION_H
+
+#include <stdexcept>
+#include <string>
+
+namespace tools
+{
+
+void log_stack_trace(const char *msg);
+
+class exception: public std::exception {
+public:
+  exception() { log_stack_trace(what()); }
+};
+
+class runtime_error: public std::runtime_error {
+public:
+  explicit runtime_error(const std::string &s): std::runtime_error(s) { log_stack_trace(what()); }
+  explicit runtime_error(const char *s): std::runtime_error(s) { log_stack_trace(what()); }
+};
+
+}  // namespace tools
+
+#endif
diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h
index 878202cf1..e25f80116 100644
--- a/src/cryptonote_core/blockchain_storage.h
+++ b/src/cryptonote_core/blockchain_storage.h
@@ -41,6 +41,7 @@
 
 #include "syncobj.h"
 #include "string_tools.h"
+#include "common/exception.h"
 #include "tx_pool.h"
 #include "cryptonote_basic.h"
 #include "common/util.h"
@@ -314,7 +315,7 @@ namespace cryptonote
             "m_invalid_blocks: " << m_invalid_blocks.size() << ENDL  << 
             "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit);
 
-          throw std::runtime_error("Blockchain data corruption");
+          throw tools::runtime_error("Blockchain data corruption");
         }
       }
     }
diff --git a/src/cryptonote_core/checkpoints_create.cpp b/src/cryptonote_core/checkpoints_create.cpp
index 41f2321d5..41246e8d8 100644
--- a/src/cryptonote_core/checkpoints_create.cpp
+++ b/src/cryptonote_core/checkpoints_create.cpp
@@ -28,6 +28,7 @@
 //
 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
 
+#include "common/exception.h"
 #include "checkpoints_create.h"
 #include "common/dns_utils.h"
 #include "include_base_utils.h"
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 6f0fe88a4..907f9d803 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -161,7 +161,7 @@ namespace cryptonote
       cryptonote::checkpoints checkpoints;
       if (!cryptonote::create_checkpoints(checkpoints))
       {
-        throw std::runtime_error("Failed to initialize checkpoints");
+        throw tools::runtime_error("Failed to initialize checkpoints");
       }
       set_checkpoints(std::move(checkpoints));
 
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 32f0b2ad4..186c1c93b 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -36,6 +36,7 @@
 #include <boost/program_options/variables_map.hpp>
 #include <boost/interprocess/sync/file_lock.hpp>
 
+#include <common/exception.h>
 #include "p2p/net_node_common.h"
 #include "cryptonote_protocol/cryptonote_protocol_handler_common.h"
 #include "storages/portable_storage_template_helper.h"
diff --git a/src/cryptonote_core/miner.cpp b/src/cryptonote_core/miner.cpp
index bad3f30bd..7bc126cd8 100644
--- a/src/cryptonote_core/miner.cpp
+++ b/src/cryptonote_core/miner.cpp
@@ -34,6 +34,7 @@
 #include <boost/interprocess/detail/atomic.hpp>
 #include <boost/limits.hpp>
 #include <boost/foreach.hpp>
+#include "common/exception.h"
 #include "misc_language.h"
 #include "include_base_utils.h"
 #include "cryptonote_basic_impl.h"
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h
index 1c92958c9..2112b5082 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.h
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h
@@ -38,6 +38,7 @@
 #include <string>
 #include <ctime>
 
+#include "common/exception.h"
 #include "storages/levin_abstract_invoke2.h"
 #include "warnings.h"
 #include "cryptonote_protocol_defs.h"
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 0b42257e7..c48b836e9 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -26,6 +26,7 @@
 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include "common/exception.h"
 #include "cryptonote_core/cryptonote_basic_impl.h"
 #include "daemon/command_parser_executor.h"
 
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 206de9d4a..7e5139636 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -26,6 +26,7 @@
 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include "common/exception.h"
 #include "cryptonote_config.h"
 #include "version.h"
 #include "daemon/command_server.h"
diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp
index e79823d08..d44538358 100644
--- a/src/daemon/daemon.cpp
+++ b/src/daemon/daemon.cpp
@@ -110,7 +110,7 @@ bool t_daemon::run(bool interactive)
 {
   if (nullptr == mp_internals)
   {
-    throw std::runtime_error{"Can't run stopped daemon"};
+    throw tools::runtime_error{"Can't run stopped daemon"};
   }
   tools::signal_handler::install(std::bind(&daemonize::t_daemon::stop_p2p, this));
 
@@ -155,7 +155,7 @@ void t_daemon::stop()
 {
   if (nullptr == mp_internals)
   {
-    throw std::runtime_error{"Can't stop stopped daemon"};
+    throw tools::runtime_error{"Can't stop stopped daemon"};
   }
   mp_internals->p2p.stop();
   mp_internals->rpc.stop();
@@ -166,7 +166,7 @@ void t_daemon::stop_p2p()
 {
   if (nullptr == mp_internals)
   {
-    throw std::runtime_error{"Can't send stop signal to a stopped daemon"};
+    throw tools::runtime_error{"Can't send stop signal to a stopped daemon"};
   }
   mp_internals->p2p.get().send_stop_signal();
 }
diff --git a/src/daemon/p2p.h b/src/daemon/p2p.h
index 3858989ce..b74a5e72d 100644
--- a/src/daemon/p2p.h
+++ b/src/daemon/p2p.h
@@ -60,7 +60,7 @@ public:
     LOG_PRINT_L0("Initializing p2p server...");
     if (!m_server.init(vm))
     {
-      throw std::runtime_error("Failed to initialize p2p server.");
+      throw tools::runtime_error("Failed to initialize p2p server.");
     }
     LOG_PRINT_L0("P2p server initialized OK");
   }
diff --git a/src/daemon/protocol.h b/src/daemon/protocol.h
index 8e2add4a2..5f6c317b1 100644
--- a/src/daemon/protocol.h
+++ b/src/daemon/protocol.h
@@ -50,7 +50,7 @@ public:
     LOG_PRINT_L0("Initializing cryptonote protocol...");
     if (!m_protocol.init(vm))
     {
-      throw std::runtime_error("Failed to initialize cryptonote protocol.");
+      throw tools::runtime_error("Failed to initialize cryptonote protocol.");
     }
     LOG_PRINT_L0("Cryptonote protocol initialized OK");
   }
diff --git a/src/daemon/rpc.h b/src/daemon/rpc.h
index bfd2afd84..caeae9a3d 100644
--- a/src/daemon/rpc.h
+++ b/src/daemon/rpc.h
@@ -55,7 +55,7 @@ public:
     LOG_PRINT_L0("Initializing core rpc server...");
     if (!m_server.init(vm))
     {
-      throw std::runtime_error("Failed to initialize core rpc server.");
+      throw tools::runtime_error("Failed to initialize core rpc server.");
     }
     LOG_PRINT_GREEN("Core rpc server initialized OK on port: " << m_server.get_binded_port(), LOG_LEVEL_0);
   }
@@ -65,7 +65,7 @@ public:
     LOG_PRINT_L0("Starting core rpc server...");
     if (!m_server.run(2, false))
     {
-      throw std::runtime_error("Failed to start core rpc server.");
+      throw tools::runtime_error("Failed to start core rpc server.");
     }
     LOG_PRINT_L0("Core rpc server started ok");
   }
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index ffda7cde3..13cc5fadc 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -28,6 +28,7 @@
 //
 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
 
+#include "common/exception.h"
 #include "string_tools.h"
 #include "common/scoped_message_writer.h"
 #include "daemon/rpc_command_executor.h"
@@ -88,7 +89,7 @@ t_rpc_command_executor::t_rpc_command_executor(
   {
     if (rpc_server == NULL)
     {
-      throw std::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null");
+      throw tools::runtime_error("If not calling commands via RPC, rpc_server pointer must be non-null");
     }
   }
 
diff --git a/src/daemonizer/posix_fork.cpp b/src/daemonizer/posix_fork.cpp
index c068912ec..84ff88869 100644
--- a/src/daemonizer/posix_fork.cpp
+++ b/src/daemonizer/posix_fork.cpp
@@ -4,6 +4,7 @@
 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 
+#include "common/exception.h"
 #include "daemonizer/posix_fork.h"
 #include "misc_log_ex.h"
 
@@ -20,7 +21,7 @@ namespace {
   void quit(std::string const & message)
   {
     LOG_ERROR(message);
-    throw std::runtime_error(message);
+    throw tools::runtime_error(message);
   }
 }
 
diff --git a/src/miner/simpleminer.cpp b/src/miner/simpleminer.cpp
index ba956d90b..19db3f534 100644
--- a/src/miner/simpleminer.cpp
+++ b/src/miner/simpleminer.cpp
@@ -28,6 +28,7 @@
 // 
 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
 
+#include "common/exception.h"
 #include "common/command_line.h"
 #include "misc_log_ex.h"
 #include "simpleminer.h"
diff --git a/src/p2p/data_logger.cpp b/src/p2p/data_logger.cpp
index ca0726c5f..d3ff0ca8e 100644
--- a/src/p2p/data_logger.cpp
+++ b/src/p2p/data_logger.cpp
@@ -33,6 +33,7 @@
 #include <boost/filesystem.hpp>
 #include <boost/thread.hpp>
 #include <chrono>
+#include "common/exception.h"
 #include "../../contrib/otshell_utils/utils.hpp"
 
 namespace epee
@@ -43,7 +44,7 @@ namespace net_utils
 		boost::call_once(m_singleton, 
 			[] { 
 				_info_c("dbg/data","Creating singleton of data_logger");
-				if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw std::runtime_error("data_logger singleton"); }
+				if (m_state != data_logger_state::state_before_init) { _erro_c("dbg/data","Internal error in singleton"); throw tools::runtime_error("data_logger singleton"); }
 				m_state = data_logger_state::state_during_init;
 				m_obj.reset(new data_logger());
 				m_state = data_logger_state::state_ready_to_use;
@@ -52,7 +53,7 @@ namespace net_utils
 		
 		if (m_state != data_logger_state::state_ready_to_use) {
 			_erro ("trying to use not working data_logger");
-			throw std::runtime_error("data_logger ctor state");
+			throw tools::runtime_error("data_logger ctor state");
 		}
 		
 		return * m_obj;
@@ -60,7 +61,7 @@ namespace net_utils
 	
 	data_logger::data_logger() {
 		_note_c("dbg/data","Starting data logger (for graphs data)");
-		if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw std::runtime_error("data_logger ctor state"); }
+		if (m_state != data_logger_state::state_during_init) { _erro_c("dbg/data","Singleton ctor state"); throw tools::runtime_error("data_logger ctor state"); }
 		boost::lock_guard<boost::mutex> lock(mMutex); // lock
 		
 		// prepare all the files for given data channels:
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 73b56f2b7..a6ef292ef 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -561,7 +561,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
 {
   if (args.empty())
   {
-    fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, default-mixin, auto-refresh, refresh-type");
+    fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers, store-tx-info, default-mixin, auto-refresh, refresh-type");
     return true;
   }
   else
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 2afe08cb1..ef17a770b 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -32,6 +32,7 @@
 #include <boost/archive/binary_iarchive.hpp>
 
 #include <boost/utility/value_init.hpp>
+#include "common/exception.h"
 #include "include_base_utils.h"
 using namespace epee;
 
@@ -803,7 +804,7 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re
       // handle error from async fetching thread
       if (error)
       {
-        throw std::runtime_error("proxy exception in refresh thread");
+        throw tools::runtime_error("proxy exception in refresh thread");
       }
     }
     catch (const std::exception&)
@@ -2012,7 +2013,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
     // Throw if split_amounts comes back with a vector of size different than it should
     if (split_values.size() != num_tx)
     {
-      throw std::runtime_error("Splitting transactions returned a number of potential tx not equal to what was requested");
+      throw tools::runtime_error("Splitting transactions returned a number of potential tx not equal to what was requested");
     }
 
     std::vector<pending_tx> ptx_vector;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index f798f404d..0961ad981 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -35,6 +35,7 @@
 #include <boost/serialization/vector.hpp>
 #include <atomic>
 
+#include "common/exception.h"
 #include "include_base_utils.h"
 #include "cryptonote_core/account.h"
 #include "cryptonote_core/account_boost_serialization.h"
diff --git a/src/wallet/wallet2_api.cpp b/src/wallet/wallet2_api.cpp
index 0644e3690..0cb253398 100644
--- a/src/wallet/wallet2_api.cpp
+++ b/src/wallet/wallet2_api.cpp
@@ -28,6 +28,7 @@
 // 
 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
 
+#include "common/exception.h"
 #include "wallet2_api.h"
 #include "wallet2.h"
 #include "mnemonics/electrum-words.h"
diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h
index 0315fc8c8..22f4c0421 100644
--- a/tests/core_proxy/core_proxy.h
+++ b/tests/core_proxy/core_proxy.h
@@ -82,7 +82,7 @@ namespace tests
     bool on_idle(){return true;}
     bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;}
     bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;}
-    cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); }
+    cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); }
     bool get_test_drop_download() {return true;}
     bool get_test_drop_download_height() {return true;}
     bool prepare_handle_incoming_blocks(const std::list<cryptonote::block_complete_entry>  &blocks) { return true; }
diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp
index 4fdd0a600..b897d9237 100644
--- a/tests/core_tests/chaingen.cpp
+++ b/tests/core_tests/chaingen.cpp
@@ -58,7 +58,7 @@ void test_generator::get_block_chain(std::vector<block_info>& blockchain, const
     auto it = m_blocks_info.find(curr);
     if (m_blocks_info.end() == it)
     {
-      throw std::runtime_error("block hash wasn't found");
+      throw tools::runtime_error("block hash wasn't found");
     }
 
     blockchain.push_back(it->second);
@@ -82,7 +82,7 @@ uint64_t test_generator::get_already_generated_coins(const crypto::hash& blk_id)
 {
   auto it = m_blocks_info.find(blk_id);
   if (it == m_blocks_info.end())
-    throw std::runtime_error("block hash wasn't found");
+    throw tools::runtime_error("block hash wasn't found");
 
   return it->second.already_generated_coins;
 }
@@ -323,7 +323,7 @@ bool init_output_indices(map_output_idx_t& outs, std::map<uint64_t, std::vector<
         BOOST_FOREACH(const crypto::hash &h, blk.tx_hashes) {
             const map_hash2tx_t::const_iterator cit = mtx.find(h);
             if (mtx.end() == cit)
-                throw std::runtime_error("block contains an unknown tx hash");
+                throw tools::runtime_error("block contains an unknown tx hash");
 
             vtx.push_back(cit->second);
         }
@@ -486,11 +486,11 @@ void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
   destinations.clear();
 
   if (!fill_tx_sources(sources, events, blk_head, from, amount + fee, nmix))
-    throw std::runtime_error("couldn't fill transaction sources");
+    throw tools::runtime_error("couldn't fill transaction sources");
 
   tx_destination_entry de;
   if (!fill_tx_destination(de, to, amount))
-    throw std::runtime_error("couldn't fill transaction destination");
+    throw tools::runtime_error("couldn't fill transaction destination");
   destinations.push_back(de);
 
   tx_destination_entry de_change;
@@ -498,7 +498,7 @@ void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
   if (0 < cache_back)
   {
     if (!fill_tx_destination(de_change, from, cache_back))
-      throw std::runtime_error("couldn't fill transaction cache back destination");
+      throw tools::runtime_error("couldn't fill transaction cache back destination");
     destinations.push_back(de_change);
   }
 }
diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h
index d0d912cbb..d51d9d320 100644
--- a/tests/core_tests/chaingen.h
+++ b/tests/core_tests/chaingen.h
@@ -284,7 +284,7 @@ bool do_check_tx_verification_context(const cryptonote::tx_verification_context&
 {
   // Default block verification context check
   if (tvc.m_verifivation_failed)
-    throw std::runtime_error("Transaction verification failed");
+    throw tools::runtime_error("Transaction verification failed");
   return true;
 }
 //--------------------------------------------------------------------------
@@ -307,7 +307,7 @@ bool do_check_block_verification_context(const cryptonote::block_verification_co
 {
   // Default block verification context check
   if (bvc.m_verifivation_failed)
-    throw std::runtime_error("Block verification failed");
+    throw tools::runtime_error("Block verification failed");
   return true;
 }
 //--------------------------------------------------------------------------
@@ -621,7 +621,7 @@ inline bool do_replay_file(const std::string& filename)
         if (!tools::serialize_obj_to_file(events, filename)) \
         { \
             std::cout << concolor::magenta << "Failed to serialize data to file: " << filename << concolor::normal << std::endl; \
-            throw std::runtime_error("Failed to serialize data to file"); \
+            throw tools::runtime_error("Failed to serialize data to file"); \
         } \
     }
 
diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp
index f72c906e5..41d5f1e26 100644
--- a/tests/core_tests/tx_validation.cpp
+++ b/tests/core_tests/tx_validation.cpp
@@ -156,7 +156,7 @@ namespace
       }
     }
 
-    throw std::runtime_error("invalid public key wasn't found");
+    throw tools::runtime_error("invalid public key wasn't found");
     return crypto::public_key();
   }
 }
diff --git a/tests/net_load_tests/clt.cpp b/tests/net_load_tests/clt.cpp
index 56089a4da..360261676 100644
--- a/tests/net_load_tests/clt.cpp
+++ b/tests/net_load_tests/clt.cpp
@@ -37,6 +37,7 @@
 
 #include "gtest/gtest.h"
 
+#include "common/exception.h"
 #include "include_base_utils.h"
 #include "misc_language.h"
 #include "misc_log_ex.h"
diff --git a/tests/net_load_tests/srv.cpp b/tests/net_load_tests/srv.cpp
index d8d3eae2e..13b31215e 100644
--- a/tests/net_load_tests/srv.cpp
+++ b/tests/net_load_tests/srv.cpp
@@ -31,6 +31,7 @@
 #include <mutex>
 #include <thread>
 
+#include "common/exception.h"
 #include "include_base_utils.h"
 #include "misc_log_ex.h"
 #include "storages/levin_abstract_invoke2.h"
diff --git a/tests/unit_tests/ban.cpp b/tests/unit_tests/ban.cpp
index a5ce244d9..5d40e90cf 100644
--- a/tests/unit_tests/ban.cpp
+++ b/tests/unit_tests/ban.cpp
@@ -56,7 +56,7 @@ public:
   bool on_idle(){return true;}
   bool find_blockchain_supplement(const std::list<crypto::hash>& qblock_ids, cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp){return true;}
   bool handle_get_objects(cryptonote::NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::request& rsp, cryptonote::cryptonote_connection_context& context){return true;}
-  cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); }
+  cryptonote::blockchain_storage &get_blockchain_storage() { throw tools::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class test_core."); }
   bool get_test_drop_download() const {return true;}
   bool get_test_drop_download_height() const {return true;}
   bool prepare_handle_incoming_blocks(const std::list<cryptonote::block_complete_entry>  &blocks) { return true; }
diff --git a/tests/unit_tests/epee_boosted_tcp_server.cpp b/tests/unit_tests/epee_boosted_tcp_server.cpp
index 946db292d..b68ce77bb 100644
--- a/tests/unit_tests/epee_boosted_tcp_server.cpp
+++ b/tests/unit_tests/epee_boosted_tcp_server.cpp
@@ -104,7 +104,7 @@ TEST(boosted_tcp_server, worker_threads_are_exception_resistant)
 
   // 2 theads, but 4 exceptions
   ASSERT_TRUE(srv.run_server(2, false));
-  ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::runtime_error("test 1"); }));
+  ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw tools::runtime_error("test 1"); }));
   ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw std::string("test 2"); }));
   ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw "test 3"; }));
   ASSERT_TRUE(srv.async_call([&counter_incrementer]() { counter_incrementer(); throw 4; }));
diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp
index 3dc5db7d4..3bf1df7ed 100644
--- a/tests/unit_tests/mnemonics.cpp
+++ b/tests/unit_tests/mnemonics.cpp
@@ -27,6 +27,7 @@
 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include "gtest/gtest.h"
+#include "common/exception.h"
 #include "mnemonics/electrum-words.h"
 #include "crypto/crypto.h"
 #include <stdlib.h>
diff --git a/tests/unit_tests/test_protocol_pack.cpp b/tests/unit_tests/test_protocol_pack.cpp
index a9a1a34a6..1ff70b4d9 100644
--- a/tests/unit_tests/test_protocol_pack.cpp
+++ b/tests/unit_tests/test_protocol_pack.cpp
@@ -30,6 +30,7 @@
 
 #include "gtest/gtest.h"
 
+#include "common/exception.h"
 #include "include_base_utils.h"
 #include "cryptonote_protocol/cryptonote_protocol_defs.h"
 #include "storages/portable_storage_template_helper.h"