neobytes/src/dashd.cpp
Alexander Block 48d92f116e Implement optional pretty printed stacktraces (#2420)
* Add libbacktrace to depends

This is currently only useful to extract symbols. It fails to gather
stacktraces when compiled with MinGW, so we can only use it to get symbol
information from a stack trace which we gathered outside of libbacktrace.

* Add -mbig-obj to CXXFLAGS for MinGW builds

* Implement stacktraces for C++ exceptions

This is a hack and should only be used for debugging. It works by wrapping
the C++ ABI __wrap___cxa_allocate_exception. The wrapper records a backtrace
and stores it in a global map. Later the stacktrace can be retrieved with
GetExceptionStacktraceStr.

This commit also adds handlers to pretty print uncaught exceptions and
signals.

* Use GetPrettyExceptionStr for all unhandled exceptions

* Use --enable-stacktraces in CI for linux32/linux64

* Register exception translators to pretty print exceptions in unit tests

* Catch and print python exceptions when stopping nodes

Otherwise the code at the bottom is never executed when nodes crash,
leading to no output of debug.log files on Travis.

* Remove now unneeded/unused TestCrash methods
2019-02-21 21:37:15 +03:00

206 lines
6.5 KiB
C++

// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2014-2019 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#if defined(HAVE_CONFIG_H)
#include "config/dash-config.h"
#endif
#include "chainparams.h"
#include "clientversion.h"
#include "compat.h"
#include "rpc/server.h"
#include "init.h"
#include "noui.h"
#include "scheduler.h"
#include "util.h"
#include "httpserver.h"
#include "httprpc.h"
#include "utilstrencodings.h"
#include "stacktraces.h"
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <stdio.h>
/* Introduction text for doxygen: */
/*! \mainpage Developer documentation
*
* \section intro_sec Introduction
*
* This is the developer documentation of the reference client for an experimental new digital currency called Dash (https://www.dash.org/),
* which enables instant payments to anyone, anywhere in the world. Dash uses peer-to-peer technology to operate
* with no central authority: managing transactions and issuing money are carried out collectively by the network.
*
* The software is a community-driven open source project, released under the MIT license.
*
* \section Navigation
* Use the buttons <code>Namespaces</code>, <code>Classes</code> or <code>Files</code> at the top of the page to start navigating the code.
*/
void WaitForShutdown(boost::thread_group* threadGroup)
{
bool fShutdown = ShutdownRequested();
// Tell the main threads to shutdown.
while (!fShutdown)
{
MilliSleep(200);
fShutdown = ShutdownRequested();
}
if (threadGroup)
{
Interrupt(*threadGroup);
threadGroup->join_all();
}
}
//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
boost::thread_group threadGroup;
CScheduler scheduler;
bool fRet = false;
//
// Parameters
//
// If Qt is used, parameters/dash.conf are parsed in qt/dash.cpp's main()
ParseParameters(argc, argv);
// Process help and version before taking care about datadir
if (IsArgSet("-?") || IsArgSet("-h") || IsArgSet("-help") || IsArgSet("-version"))
{
std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";
if (IsArgSet("-version"))
{
strUsage += FormatParagraph(LicenseInfo());
}
else
{
strUsage += "\n" + _("Usage:") + "\n" +
" dashd [options] " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n";
strUsage += "\n" + HelpMessage(HMM_BITCOIND);
}
fprintf(stdout, "%s", strUsage.c_str());
return true;
}
try
{
bool datadirFromCmdLine = IsArgSet("-datadir");
if (datadirFromCmdLine && !boost::filesystem::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
return false;
}
try
{
ReadConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME));
} catch (const std::exception& e) {
fprintf(stderr,"Error reading configuration file: %s\n", e.what());
return false;
}
if (!datadirFromCmdLine && !boost::filesystem::is_directory(GetDataDir(false)))
{
fprintf(stderr, "Error: Specified data directory \"%s\" from config file does not exist.\n", GetArg("-datadir", "").c_str());
return EXIT_FAILURE;
}
// Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
try {
SelectParams(ChainNameFromCommandLine());
} catch (const std::exception& e) {
fprintf(stderr, "Error: %s\n", e.what());
return false;
}
// Command-line RPC
bool fCommandLine = false;
for (int i = 1; i < argc; i++)
if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "dash:"))
fCommandLine = true;
if (fCommandLine)
{
fprintf(stderr, "Error: There is no RPC client functionality in dashd anymore. Use the dash-cli utility instead.\n");
exit(EXIT_FAILURE);
}
// -server defaults to true for bitcoind but not for the GUI so do this here
SoftSetBoolArg("-server", true);
// Set this early so that parameter interactions go to console
InitLogging();
InitParameterInteraction();
if (!AppInitBasicSetup())
{
// InitError will have been called with detailed error, which ends up on console
exit(EXIT_FAILURE);
}
if (!AppInitParameterInteraction())
{
// InitError will have been called with detailed error, which ends up on console
exit(EXIT_FAILURE);
}
if (!AppInitSanityChecks())
{
// InitError will have been called with detailed error, which ends up on console
exit(EXIT_FAILURE);
}
if (GetBoolArg("-daemon", false))
{
#if HAVE_DECL_DAEMON
fprintf(stdout, "Dash Core server starting\n");
// Daemonize
if (daemon(1, 0)) { // don't chdir (1), do close FDs (0)
fprintf(stderr, "Error: daemon() failed: %s\n", strerror(errno));
return false;
}
#else
fprintf(stderr, "Error: -daemon is not supported on this operating system\n");
return false;
#endif // HAVE_DECL_DAEMON
}
fRet = AppInitMain(threadGroup, scheduler);
} catch (...) {
PrintExceptionContinue(std::current_exception(), "AppInit()");
}
if (!fRet)
{
Interrupt(threadGroup);
// threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
// the startup-failure cases to make sure they don't result in a hang due to some
// thread-blocking-waiting-for-another-thread-during-startup case
} else {
WaitForShutdown(&threadGroup);
}
Shutdown();
return fRet;
}
int main(int argc, char* argv[])
{
RegisterPrettyTerminateHander();
RegisterPrettySignalHandlers();
SetupEnvironment();
// Connect dashd signal handlers
noui_connect();
return (AppInit(argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
}