--- /dev/null
+/* Copyright (c) 2005-2019. The SimGrid Team.
+ * All rights reserved. */
+
+#ifndef SIMGRIX_XBT_BACKTRACE_HPP
+#define SIMGRIX_XBT_BACKTRACE_HPP
+
+#include <cstddef>
+
+#include <string>
+#include <memory>
+#include <vector>
+
+#include <xbt/base.h>
+#include <xbt/backtrace.h>
+
+namespace simgrid {
+namespace xbt {
+
+/** Try to demangle a C++ name
+ *
+ * Return the origin string if this fails.
+ */
+XBT_PUBLIC() std::unique_ptr<char, void(*)(void*)> demangle(const char* name);
+
+/** Get the current backtrace */
+XBT_PUBLIC(std::vector<xbt_backtrace_location_t>) backtrace();
+
+/* Translate the backtrace in a human friendly form
+ *
+ * Try ro resolve symbols and source code location.
+ */
+XBT_PUBLIC(std::vector<std::string>) resolveBacktrace(
+ xbt_backtrace_location_t const* loc, std::size_t count);
+
+}
+}
+
+#endif
#include <string>
#include <vector>
#include <stdexcept>
+#include <xbt/exception.hpp>
#endif
#include "xbt/base.h"
} xbt_errcat_t;
#ifdef __cplusplus
-XBT_PUBLIC_CLASS xbt_ex : public std::runtime_error {
+XBT_PUBLIC_CLASS xbt_ex :
+ public std::runtime_error,
+ public simgrid::xbt::WithContextException {
public:
xbt_ex() : std::runtime_error("") {}
xbt_ex(const char* message) : std::runtime_error(message) {}
xbt_errcat_t category; /**< category like HTTP (what went wrong) */
int value; /**< like errno (why did it went wrong) */
- /* throw point */
- std::string procname; /**< Name of the process who thrown this */
- int pid; /**< PID of the process who thrown this */
const char *file; /**< Thrown point */
int line; /**< Thrown point */
const char *func; /**< Thrown point */
- std::vector<void*> bt; /**< Backtrace */
};
#endif
--- /dev/null
+/* Copyright (c) 2005-2016. The SimGrid Team.All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef SIMGRID_XBT_EXCEPTION_HPP
+#define SIMGRID_XBT_EXCEPTION_HPP
+
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include <xbt/base.h>
+#include <xbt/backtrace.h>
+#include <xbt/backtrace.hpp>
+#include <xbt/log.h>
+#include <xbt/misc.h> // xbt_procname
+#include <xbt/virtu.h> // xbt_getpid
+
+namespace simgrid {
+namespace xbt {
+
+typedef std::vector<xbt_backtrace_location_t> Backtrace;
+
+/** A polymorphic mixin class for adding context to an exception */
+XBT_PUBLIC_CLASS WithContextException {
+public:
+ WithContextException() :
+ backtrace_(simgrid::xbt::backtrace()),
+ procname_(xbt_procname()),
+ pid_(xbt_getpid())
+ {}
+ WithContextException(Backtrace bt) :
+ backtrace_(std::move(bt)),
+ procname_(xbt_procname()),
+ pid_(xbt_getpid())
+ {}
+ virtual ~WithContextException();
+ Backtrace const& backtrace() const
+ {
+ return backtrace_;
+ }
+ int pid() const { return pid_; }
+ std::string const& processName() const { return procname_; }
+private:
+ Backtrace backtrace_;
+ std::string procname_; /**< Name of the process who thrown this */
+ int pid_; /**< PID of the process who thrown this */
+};
+
+/** Internal class used to mixin the two classes */
+template<class E>
+class WithContext : public E, public WithContextException
+{
+public:
+ WithContext(E exception)
+ : E(std::move(exception)) {}
+ WithContext(E exception, Backtrace backtrace)
+ : E(std::move(exception)), WithContextException(std::move(backtrace)) {}
+ WithContext(E exception, WithContextException context)
+ : E(std::move(exception)), WithContextException(std::move(context)) {}
+ ~WithContext() override {}
+};
+
+/** Throw a given exception a context
+ *
+ * @param exception exception to throw
+ * @param backtrace backtrace to attach
+ */
+template<class E>
+[[noreturn]] inline
+typename std::enable_if< !std::is_base_of<WithContextException,E>::value >::type
+throwWithContext(
+ E exception,
+ // Thanks to the default argument, we are taking the backtrace in the caller:
+ Backtrace backtrace = simgrid::xbt::backtrace())
+{
+ throw WithContext<E>(std::move(exception), std::move(backtrace));
+}
+
+}
+}
+
+#endif
--- /dev/null
+/* Copyright (c) 2016. The SimGrid Team. All rights reserved.*/
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <xbt/log.h>
+#include <xbt/exception.hpp>
+
+namespace simgrid {
+namespace xbt {
+
+/** Display informations about an exception
+ *
+ * We display: the exception type, name, attached backtarces (if any) and
+ * the nested exception (if any).
+ */
+XBT_PUBLIC(void) logException(
+ e_xbt_log_priority_t priority,
+ const char* context, std::exception const& exception);
+
+}
+}
#include <string>
#include <cstdarg>
+#include <stdlib.h>
#if HAVE_MC
#define __XBT_VIRTU_H__
#include "xbt/misc.h"
-#include "xbt/sysdep.h"
+#include "xbt/base.h"
#include "xbt/function_types.h"
#include "xbt/dynar.h"
"See the Install section of simgrid-java documentation (in doc/install.html) for more on coroutines.",
thread_amount, ex.what());
xbt_ex new_exception(str);
- free(str);
new_exception.category = ex.category;
new_exception.value = ex.value;
- new_exception.procname = ex.procname;
- new_exception.file = ex.file;
- new_exception.line = ex.line;
- new_exception.func = ex.func;
- new_exception.pid = ex.pid;
- new_exception.bt = ex.bt;
- throw new_exception;
+ new_exception.file = __FILE__;
+ new_exception.line = __LINE__;
+ new_exception.func = __func__;
+ std::throw_with_nested(std::move(new_exception));
}
} else {
this->thread = nullptr;
xbt_ex e(msg); \
e.category = cat; \
e.value = val; \
- e.procname = xbt_procname(); \
- e.pid = xbt_getpid(); \
e.file = __FILE__; \
e.line = __LINE__; \
e.func = __func__; \
/* Copyright (c) 2005-2016. The SimGrid Team. All rights reserved. */
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
#include <cstddef>
+#include <cstdlib>
+
+#include <vector>
+
+// Try to detect and use the C++ intanium ABI for name demangling:
+#ifdef __GXX_ABI_VERSION
+#include <cxxabi.h>
+#endif
-#include <xbt/log.h>
#include <xbt/backtrace.h>
+#include <xbt/backtrace.hpp>
+#include <xbt/log.h>
+#include <xbt/sysdep.h>
#include "src/internal_config.h"
xbt_backtrace_display(bt, used);
}
+namespace simgrid {
+namespace xbt {
+
+std::unique_ptr<char, void(*)(void*)> demangle(const char* name)
+{
+#ifdef __GXX_ABI_VERSION
+ int status;
+ auto res = std::unique_ptr<char, void(*)(void*)>(
+ abi::__cxa_demangle(name, NULL, NULL, &status),
+ std::free
+ );
+ if (res != nullptr)
+ return res;
+ // We did not manage to resolve this. Probably because this is not a mangled
+ // symbol:
+#endif
+ // Return the symbol:
+ return std::unique_ptr<char, void(*)(void*)>(xbt_strdup(name), std::free);
+}
+
+std::vector<xbt_backtrace_location_t> backtrace()
+{
+ const std::size_t size = 10;
+ xbt_backtrace_location_t loc[size];
+ size_t used = xbt_backtrace_current(loc, size);
+ return std::vector<xbt_backtrace_location_t>(loc, loc + used);
+}
+
+}
+}
+
#if HAVE_BACKTRACE && HAVE_EXECINFO_H && HAVE_POPEN && defined(ADDR2LINE)
# include "src/xbt/backtrace_linux.cpp"
#else
#include "src/xbt_modinter.h"
#include "src/xbt/ex_interface.h"
+#include <xbt/backtrace.hpp>
+
/* Module creation/destruction */
void xbt_backtrace_preinit(void)
{
namespace xbt {
std::vector<std::string> resolveBacktrace(
- xbt_backtrace_location_t* loc, std::size_t count)
+ xbt_backtrace_location_t const* loc, std::size_t count)
{
return std::vector<std::string>();
}
/* backtrace_linux - backtrace displaying on linux platform */
/* This file is included by ex.cpp on need (have execinfo.h, popen & addrline)*/
-/* Copyright (c) 2008-2015. The SimGrid Team.
+/* Copyright (c) 2008-2016. The SimGrid Team.
* All rights reserved. */
/* This program is free software; you can redistribute it and/or modify it
/* This file is to be included in ex.cpp, so the following headers are not mandatory, but it's to make sure that eclipse see them too */
#include <xbt/string.hpp>
+#include <xbt/backtrace.hpp>
#include "xbt/ex.h"
#include "src/xbt/ex_interface.h"
#include "xbt/log.h"
{
struct stat stat_buf;
+ if (xbt_binary_name == nullptr)
+ return "";
+
// We found it, we are happy:
if (stat(xbt_binary_name, &stat_buf) == 0)
return xbt_binary_name;
//FIXME: This code could be greatly improved/simplifyied with
// http://cairo.sourcearchive.com/documentation/1.9.4/backtrace-symbols_8c-source.html
std::vector<std::string> resolveBacktrace(
- xbt_backtrace_location_t* loc, std::size_t count)
+ xbt_backtrace_location_t const* loc, std::size_t count)
{
std::vector<std::string> result;
- /* no binary name, nothing to do */
- if (xbt_binary_name == NULL)
- return result;
-
if (count == 0)
return result;
+ if (xbt_binary_name == nullptr)
+ XBT_WARN("XBT not initialized, the backtrace will not be resolved.");
+
// Drop the first one:
loc++; count--;
char** backtrace_syms = backtrace_symbols(loc, count);
std::string binary_name = get_binary_path();
+ if (binary_name.empty()) {
+ for (std::size_t i = 0; i < count; i++)
+ result.push_back(simgrid::xbt::string_printf("%p", loc[i]));
+ return std::move(result);
+ }
+
// Create the system command for add2line:
std::ostringstream stream;
stream << ADDR2LINE << " -f -e " << binary_name << ' ';
}
if (strcmp("??", line_func) != 0) {
- XBT_DEBUG("Found static symbol %s() at %s", line_func, line_pos);
+ auto name = simgrid::xbt::demangle(line_func);
+ XBT_DEBUG("Found static symbol %s at %s", name.get(), line_pos);
result.push_back(simgrid::xbt::string_printf(
- "%s() at %s", line_func, line_pos
+ "%s at %s, %p", name.get(), line_pos, loc[i]
));
} else {
/* Damn. The symbol is in a dynamic library. Let's get wild */
/* check whether the trick worked */
if (strcmp("??", line_func)) {
- XBT_DEBUG("Found dynamic symbol %s() at %s", line_func, line_pos);
+ auto name = simgrid::xbt::demangle(line_func);
+ XBT_DEBUG("Found dynamic symbol %s at %s", name.get(), line_pos);
result.push_back(simgrid::xbt::string_printf(
- "%s() at %s", line_func, line_pos));
+ "%s at %s, %p", name.get(), line_pos, loc[i]));
} else {
/* damn, nothing to do here. Let's print the raw address */
XBT_DEBUG("Dynamic symbol not found. Raw address = %s", backtrace_syms[i]);
#include <stdio.h>
#include <stdlib.h>
+#include <xbt/backtrace.hpp>
#include "src/internal_config.h" /* execinfo when available */
#include "xbt/ex.h"
+#include "xbt/log.h"
+#include "xbt/log.hpp"
#include "xbt/backtrace.h"
+#include "xbt/backtrace.hpp"
#include "xbt/str.h"
#include "xbt/synchro_core.h"
#include "src/xbt_modinter.h" /* backtrace initialization headers */
#include "simgrid/simix.h" /* SIMIX_process_self_get_name() */
+
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mechanism");
xbt_ex::~xbt_ex() {}
e.file = file;
e.line = line;
e.func = func;
- e.procname = xbt_procname();
- e.pid = xbt_getpid();
throw e;
}
/** @brief shows an exception content and the associated stack if available */
void xbt_ex_display(xbt_ex_t * e)
{
- char *thrower = NULL;
- if (e->pid != xbt_getpid())
- thrower = bprintf(" on process %d",e->pid);
-
- std::fprintf(stderr, "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
- "** %s\n"
- "** Thrown by %s()%s\n",
- xbt_binary_name, xbt_getpid(), xbt_ex_catname(e->category), e->value, e->what(),
- e->procname.c_str(), thrower ? thrower : " in this process");
- XBT_CRITICAL("%s", e->what());
- xbt_free(thrower);
-
- if (xbt_initialized==0 || smx_cleaned) {
- fprintf(stderr, "Ouch. SimGrid is not initialized yet, or already closing. No backtrace available.\n");
- return; /* Not started yet or already closing. Trying to generate a backtrace would probably fail */
- }
-
- std::vector<std::string> backtrace = simgrid::xbt::resolveBacktrace(
- e->bt.data(), e->bt.size());
-
-#ifdef HAVE_BACKTRACE
- if (!backtrace.empty()) {
- /* We have everything to build neat backtraces */
- int cutpath = 0;
- try { // We don't want to have an exception while checking how to deal with the one we already have, do we?
- cutpath = xbt_cfg_get_boolean("exception/cutpath");
- }
- catch(xbt_ex& e) {
- // Nothing to do
- }
-
- std::fprintf(stderr, "\n");
- for (std::string const& s : backtrace) {
-
- // TODO, move this logic into solveBacktrace
- if (cutpath) {
- // TODO, simplify this
- char* p = xbt_strdup(s.c_str());
- xbt_str_rtrim(p, ":0123456789");
- char* filename = strrchr(p, '/')+1;
- char* end_of_message = strrchr(p, ' ');
- int length = strlen(p)-strlen(end_of_message);
- char* dest = (char*) std::malloc(length);
- std::memcpy(dest, &p[0], length);
- dest[length] = 0;
- std::fprintf(stderr, "%s %s\n", dest, filename);
- std::free(dest);
- std::free(p);
- }
- else {
- std::fprintf(stderr, "%s\n", s.c_str());
- }
- }
- } else
-#endif
- std::fprintf(stderr, "\n"
- "** In %s() at %s:%d\n"
- "** (no backtrace available)\n", e->func, e->file, e->line);
+ simgrid::xbt::logException(xbt_log_priority_critical, "UNCAUGHT EXCEPTION", *e);
}
/** \brief returns a short name for the given exception category */
namespace simgrid {
namespace xbt {
-/* Change raw libc symbols to file names and line numbers */
-XBT_PUBLIC(std::vector<std::string>) resolveBacktrace(
- xbt_backtrace_location_t* loc, std::size_t count);
-
}
}
--- /dev/null
+/* Copyright (c) 2005-2016. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <exception>
+#include <typeinfo>
+#include <memory>
+
+#include <xbt/backtrace.hpp>
+#include <xbt/exception.hpp>
+#include <xbt/log.h>
+#include <xbt/log.hpp>
+
+extern "C" {
+XBT_LOG_EXTERNAL_CATEGORY(xbt);
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_exception, xbt, "Exceptions");
+}
+
+namespace simgrid {
+namespace xbt {
+
+WithContextException::~WithContextException() {}
+
+void logException(
+ e_xbt_log_priority_t prio,
+ const char* context, std::exception const& exception)
+{
+ try {
+ auto name = simgrid::xbt::demangle(typeid(exception).name());
+
+ auto with_context =
+ dynamic_cast<const simgrid::xbt::WithContextException*>(&exception);
+ if (with_context != nullptr)
+ XBT_LOG(prio, "%s %s by %s/%d: %s",
+ context, name.get(),
+ with_context->processName().c_str(), with_context->pid(),
+ exception.what());
+ else
+ XBT_LOG(prio, "%s %s: %s", context, name.get(), exception.what());
+
+ // Do we have a backtrace?
+ if (with_context != nullptr) {
+ auto backtrace = simgrid::xbt::resolveBacktrace(
+ with_context->backtrace().data(), with_context->backtrace().size());
+ for (std::string const& s : backtrace)
+ XBT_LOG(prio, " -> %s", s.c_str());
+ }
+
+ // Do we have a nested exception?
+ auto with_nested = dynamic_cast<const std::nested_exception*>(&exception);
+ if (with_nested == nullptr || with_nested->nested_ptr() == nullptr)
+ return;
+ try {
+ with_nested->rethrow_nested();
+ }
+ catch (std::exception& nested_exception) {
+ logException(prio, "Caused by", nested_exception);
+ }
+ // We could catch nested_exception or WithContextException but we don't bother:
+ catch (...) {
+ XBT_LOG(prio, "Caused by an unknown exception");
+ }
+ }
+ catch (...) {
+ // Don't log exceptions we got when trying to log exception
+ }
+}
+
+}
+}
XBT_LOG_CONNECT(xbt_dyn);
XBT_LOG_CONNECT(xbt_ex);
XBT_LOG_CONNECT(xbt_backtrace);
+ XBT_LOG_CONNECT(xbt_exception);
XBT_LOG_CONNECT(xbt_fifo);
XBT_LOG_CONNECT(xbt_graph);
XBT_LOG_CONNECT(xbt_heap);
src/xbt/dict_elm.c
src/xbt/dynar.cpp
src/xbt/ex.cpp
+ src/xbt/exception.cpp
src/xbt/fifo.c
src/xbt/graph.c
src/xbt/heap.c
include/xbt/dynar.h
include/xbt/dynar.hpp
include/xbt/ex.h
+ include/xbt/exception.hpp
include/xbt/backtrace.h
+ include/xbt/backtrace.hpp
include/xbt/fifo.h
include/xbt/file.h
include/xbt/function_types.h
include/xbt/lib.h
include/xbt/Extendable.hpp
include/xbt/log.h
+ include/xbt/log.hpp
include/xbt/mallocator.h
include/xbt/matrix.h
include/xbt/memory.hpp