From: Martin Quinson Date: Mon, 29 Oct 2018 15:51:45 +0000 (+0100) Subject: replace our own crude code with Boost.stacktrace X-Git-Tag: v3_22~828 X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/1a553ba8e68c04a338d76960f59be6b92535e9c0 replace our own crude code with Boost.stacktrace --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 61416d942e..bd1bca7bd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,20 +306,17 @@ endif() CHECK_INCLUDE_FILE("valgrind/valgrind.h" HAVE_VALGRIND_H) CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H) -CHECK_INCLUDE_FILE("execinfo.h" HAVE_EXECINFO_H) CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H) CHECK_INCLUDE_FILE("sys/param.h" HAVE_SYS_PARAM_H) CHECK_INCLUDE_FILE("sys/sysctl.h" HAVE_SYS_SYSCTL_H) CHECK_INCLUDE_FILE("ucontext.h" HAVE_UCONTEXT_H) CHECK_INCLUDE_FILE("linux/futex.h" HAVE_FUTEX_H) -CHECK_FUNCTION_EXISTS(backtrace HAVE_BACKTRACE) CHECK_FUNCTION_EXISTS(dlfunc HAVE_DLFUNC) CHECK_FUNCTION_EXISTS(gettimeofday HAVE_GETTIMEOFDAY) CHECK_FUNCTION_EXISTS(nanosleep HAVE_NANOSLEEP) CHECK_FUNCTION_EXISTS(getdtablesize HAVE_GETDTABLESIZE) CHECK_FUNCTION_EXISTS(sysconf HAVE_SYSCONF) -CHECK_FUNCTION_EXISTS(popen HAVE_POPEN) CHECK_FUNCTION_EXISTS(process_vm_readv HAVE_PROCESS_VM_READV) CHECK_FUNCTION_EXISTS(mmap HAVE_MMAP) CHECK_FUNCTION_EXISTS(mremap HAVE_MREMAP) @@ -547,12 +544,6 @@ endif() file(REMOVE test_stackgrowth) #-------------------------------------------------------------------------------------------------- -### check for addr2line -find_path(ADDR2LINE NAMES addr2line PATHS NO_DEFAULT_PATHS) -if(ADDR2LINE) - set(ADDR2LINE "${ADDR2LINE}/addr2line") -endif() - ############### ## GIT version check ## diff --git a/ChangeLog b/ChangeLog index def69222d4..89b116148f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,11 @@ SimGrid (3.22) NOT RELEASED (Release Target: December 21. 2018, 22:23 UTC) Java: - Expose host load plugin: loadInit, getCurrentLoad, getComputedFlops, getAvgLoad +Core: + - Replace our own code to display a backtrace (that was forking addr2line) + with the Boost.Stacktrace library. + You won't see your backtraces without this optional dependency. + Fixed bugs: - #261: Document the parameters of parallel execution's constructor diff --git a/include/xbt/backtrace.hpp b/include/xbt/backtrace.hpp index 55712c98d6..ff2e3f2e70 100644 --- a/include/xbt/backtrace.hpp +++ b/include/xbt/backtrace.hpp @@ -43,11 +43,11 @@ public: ~Backtrace(); }; -/* Translate the backtrace in a human friendly form +/* Translate the backtrace in an human friendly form * - * Try resolve symbols and source code location. + * Try resolve symbols and source code locations. */ -XBT_PUBLIC std::vector resolve_backtrace(const Backtrace& bt); +XBT_PUBLIC std::string resolve_backtrace(const Backtrace& bt); } } diff --git a/src/xbt/backtrace.cpp b/src/xbt/backtrace.cpp index 469b757bb1..743f0a4d4f 100644 --- a/src/xbt/backtrace.cpp +++ b/src/xbt/backtrace.cpp @@ -25,9 +25,6 @@ #ifdef __GXX_ABI_VERSION #include #endif -#if HAVE_EXECINFO_H -#include -#endif #if HAVE_BOOST_STACKTRACE #define BOOST_STACKTRACE_USE_BACKTRACE @@ -43,21 +40,13 @@ static bool startWith(std::string str, const char* prefix) void xbt_backtrace_display(const simgrid::xbt::Backtrace& bt) { - std::vector backtrace = simgrid::xbt::resolve_backtrace(bt); + std::string backtrace = simgrid::xbt::resolve_backtrace(bt); if (backtrace.empty()) { - fprintf(stderr, "(backtrace not set -- maybe unavailable on this architecture?)\n"); + fprintf(stderr, "(backtrace not set -- did you install Boost.Stacktrace?)\n"); return; } - fprintf(stderr, "Backtrace (displayed in process %s):\n", SIMIX_process_self_get_name()); - for (std::string const& s : backtrace) { - if (startWith(s, "xbt_backtrace_display_current")) - continue; - - std::fprintf(stderr, "---> '%s'\n", s.c_str()); - if (startWith(s, "SIMIX_simcall_handle") || - startWith(s, "simgrid::xbt::MainFunction") /* main used with thread factory */) - break; - } + fprintf(stderr, "Backtrace (displayed in actor %s):\n", SIMIX_process_self_get_name()); + std::fprintf(stderr, "%s\n", backtrace.c_str()); } /** @brief show the backtrace of the current point (lovely while debugging) */ @@ -98,8 +87,6 @@ public: } #if HAVE_BOOST_STACKTRACE boost::stacktrace::stacktrace st; -#elif HAVE_BACKTRACE - std::vector frames; #endif }; @@ -108,17 +95,6 @@ Backtrace::Backtrace() #if HAVE_BOOST_STACKTRACE impl_ = new BacktraceImpl(); impl_->st = boost::stacktrace::stacktrace(); -#elif HAVE_BACKTRACE - impl_ = new BacktraceImpl(); - impl_->frames.resize(15); - int used = backtrace(impl_->frames.data(), impl_->frames.size()); - if (used == 0) { - std::fprintf(stderr, "The backtrace() function failed, which probably means that the memory is exhausted\n."); - std::fprintf(stderr, "Bailing out now since there is nothing I can do without a decent amount of memory\n."); - std::fprintf(stderr, "Please go fix the memleaks\n"); - std::exit(1); - } - impl_->frames.shrink_to_fit(); #endif } Backtrace::Backtrace(const Backtrace& bt) @@ -139,238 +115,15 @@ Backtrace::~Backtrace() namespace simgrid { namespace xbt { -/** Find the path of the binary file from the name found in argv */ -static std::string get_binary_path() +std::string resolve_backtrace(const Backtrace& bt) { - 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; - - // Not found, look in the PATH: - char* path = getenv("PATH"); - if (path == nullptr) - return ""; - - XBT_DEBUG("Looking in the PATH: %s\n", path); - std::vector path_list; - boost::split(path_list, path, boost::is_any_of(":;")); - - for (std::string const& path_item : path_list) { - std::string binary_name = simgrid::xbt::string_printf("%s/%s", path_item.c_str(), xbt_binary_name); - bool found = (stat(binary_name.c_str(), &stat_buf) == 0); - XBT_DEBUG("Looked in the PATH for the binary. %s %s", found ? "Found" : "Not found", binary_name.c_str()); - if (found) - return binary_name; - } - - // Not found at all: - return ""; -} - -std::vector resolve_backtrace(const Backtrace& bt) -{ - std::vector result; + std::string result(""); #if HAVE_BOOST_STACKTRACE std::stringstream ss; ss << bt.impl_->st; - result.push_back(ss.str()); -#elif HAVE_BACKTRACE && HAVE_EXECINFO_H && HAVE_POPEN && defined(ADDR2LINE) - // FIXME: This code could be greatly improved/simplified with - // http://cairo.sourcearchive.com/documentation/1.9.4/backtrace-symbols_8c-source.html - if (bt.impl_->frames.size() == 0) - return result; - - if (xbt_binary_name == nullptr) - XBT_WARN("XBT not initialized, the backtrace will not be resolved."); - - char** backtrace_syms = backtrace_symbols(bt.impl_->frames.data(), bt.impl_->frames.size()); - std::string binary_name = get_binary_path(); - - if (binary_name.empty()) { - for (std::size_t i = 1; i < bt.impl_->frames.size(); i++) // the first one is not interesting - result.push_back(simgrid::xbt::string_printf("%p", bt.impl_->frames[i])); - return result; - } - - // Create the system command for add2line: - std::ostringstream stream; - stream << ADDR2LINE << " -f -e " << binary_name << ' '; - std::vector addrs(bt.impl_->frames.size()); - for (std::size_t i = 1; i < bt.impl_->frames.size(); i++) { // the first one is not interesting - /* retrieve this address */ - XBT_DEBUG("Retrieving address number %zu from '%s'", i, backtrace_syms[i]); - char buff[256]; - snprintf(buff, 256, "%s", strchr(backtrace_syms[i], '[') + 1); - char* p = strchr(buff, ']'); - *p = '\0'; - if (strcmp(buff, "(nil)")) - addrs[i] = buff; - else - addrs[i] = "0x0"; - XBT_DEBUG("Set up a new address: %zu, '%s'", i, addrs[i].c_str()); - /* Add it to the command line args */ - stream << addrs[i] << ' '; - } - std::string cmd = stream.str(); - - /* size (in char) of pointers on this arch */ - int addr_len = addrs[0].size(); - - XBT_VERB("Fire a first command: '%s'", cmd.c_str()); - FILE* pipe = popen(cmd.c_str(), "r"); - xbt_assert(pipe, "Cannot fork addr2line to display the backtrace"); - - /* To read the output of addr2line */ - char line_func[1024]; - char line_pos[1024]; - for (std::size_t i = 1; i < bt.impl_->frames.size(); i++) { // The first one is not interesting - XBT_DEBUG("Looking for symbol %zu, addr = '%s'", i, addrs[i].c_str()); - if (fgets(line_func, 1024, pipe)) { - line_func[strlen(line_func) - 1] = '\0'; - } else { - XBT_VERB("Cannot run fgets to look for symbol %zu, addr %s", i, addrs[i].c_str()); - strncpy(line_func, "???", 4); - } - if (fgets(line_pos, 1024, pipe)) { - line_pos[strlen(line_pos) - 1] = '\0'; - } else { - XBT_VERB("Cannot run fgets to look for symbol %zu, addr %s", i, addrs[i].c_str()); - strncpy(line_pos, backtrace_syms[i], 1024); - } - - if (strcmp("??", line_func) != 0) { - 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, %p", name.get(), line_pos, bt.impl_->frames[i])); - } else { - /* Damn. The symbol is in a dynamic library. Let's get wild */ - - unsigned long int offset = 0; - int found = 0; - - /* let's look for the offset of this library in our addressing space */ - std::string maps_name = std::string("/proc/") + std::to_string(getpid()) + "/maps"; - std::ifstream maps(maps_name); - if (not maps) { - XBT_CRITICAL("open(\"%s\") failed: %s", maps_name.c_str(), strerror(errno)); - continue; - } - size_t pos; - unsigned long int addr = std::stoul(addrs[i], &pos, 16); - if (pos != addrs[i].length()) { - XBT_CRITICAL("Cannot parse backtrace address '%s' (addr=%#lx)", addrs[i].c_str(), addr); - } - XBT_DEBUG("addr=%s (as string) =%#lx (as number)", addrs[i].c_str(), addr); - - while (not found) { - unsigned long int first; - unsigned long int last; - - std::string maps_buff; - if (not std::getline(maps, maps_buff)) - break; - if (i == 0) { - XBT_DEBUG("map line: %s", maps_buff.c_str()); - } - first = std::stoul(maps_buff, &pos, 16); - maps_buff.erase(0, pos + 1); - last = std::stoul(maps_buff, nullptr, 16); - if (first < addr && addr < last) { - offset = first; - found = 1; - } - if (found) { - XBT_DEBUG("%#lx in [%#lx-%#lx]", addr, first, last); - XBT_DEBUG("Symbol found, map lines not further displayed (even if looking for next ones)"); - } - } - maps.close(); - addrs[i].clear(); - - if (not found) { - XBT_VERB("Problem while reading the maps file. Following backtrace will be mangled."); - XBT_DEBUG("No dynamic. Static symbol: %s", backtrace_syms[i]); - result.push_back(simgrid::xbt::string_printf("?? (%s)", backtrace_syms[i])); - continue; - } - - /* Ok, Found the offset of the maps line containing the searched symbol. - We now need to substract this from the address we got from backtrace. - */ - - addrs[i] = simgrid::xbt::string_printf("0x%0*lx", addr_len - 2, addr - offset); - XBT_DEBUG("offset=%#lx new addr=%s", offset, addrs[i].c_str()); - - /* Got it. We have our new address. Let's get the library path and we are set */ - std::string p(backtrace_syms[i]); - if (p[0] == '[') { - /* library path not displayed in the map file either... */ - snprintf(line_func, 3, "??"); - } else { - size_t p2 = p.find_first_of("( "); - if (p2 != std::string::npos) - p.erase(p2); - - /* Here we go, fire an addr2line up */ - std::string subcmd = std::string(ADDR2LINE) + " -f -e " + p + " " + addrs[i]; - XBT_VERB("Fire another command: '%s'", subcmd.c_str()); - FILE* subpipe = popen(subcmd.c_str(), "r"); - if (not subpipe) { - xbt_die("Cannot fork addr2line to display the backtrace"); - } - if (fgets(line_func, 1024, subpipe)) { - line_func[strlen(line_func) - 1] = '\0'; - } else { - XBT_VERB("Cannot read result of subcommand %s", subcmd.c_str()); - strncpy(line_func, "???", 4); - } - if (fgets(line_pos, 1024, subpipe)) { - line_pos[strlen(line_pos) - 1] = '\0'; - } else { - XBT_VERB("Cannot read result of subcommand %s", subcmd.c_str()); - strncpy(line_pos, backtrace_syms[i], 1024); - } - pclose(subpipe); - } - - /* check whether the trick worked */ - if (strcmp("??", line_func)) { - 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, %p", name.get(), line_pos, bt.impl_->frames[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]); - result.push_back(simgrid::xbt::string_printf("?? at %s", backtrace_syms[i])); - } - } - addrs[i].clear(); - - /* Mask the bottom of the stack */ - const char* const breakers[] = { - "main", - "_ZN7simgrid6kernel7context13ThreadContext7wrapperE", // simgrid::kernel::context::ThreadContext::wrapper - "_ZN7simgrid6kernel7context8UContext7wrapperE" // simgrid::kernel::context::UContext::wrapper - }; - bool do_break = false; - for (const char* b : breakers) { - if (strncmp(b, line_func, strlen(b)) == 0) { - do_break = true; - break; - } - } - if (do_break) - break; - } - pclose(pipe); - xbt_free(backtrace_syms); -#endif /* ADDR2LINE usable to resolve the backtrace */ + result.append(ss.str()); +#endif return result; } diff --git a/src/xbt/exception.cpp b/src/xbt/exception.cpp index fe4c6b58a0..042232c277 100644 --- a/src/xbt/exception.cpp +++ b/src/xbt/exception.cpp @@ -91,8 +91,7 @@ void log_exception(e_xbt_log_priority_t prio, const char* context, std::exceptio // Do we have a backtrace? if (with_context != nullptr && not simgrid::config::get_value("exception/cutpath")) { auto backtrace = simgrid::xbt::resolve_backtrace(with_context->throw_point().backtrace_); - for (std::string const& s : backtrace) - XBT_LOG(prio, " -> %s", s.c_str()); + XBT_LOG(prio, " -> %s", backtrace.c_str()); } // Do we have a nested exception? @@ -121,10 +120,9 @@ static void show_backtrace(const simgrid::xbt::Backtrace& bt) XBT_LOG(xbt_log_priority_critical, "Display of current backtrace disabled by --cfg=exception/cutpath."); return; } - std::vector res = resolve_backtrace(bt); + std::string res = resolve_backtrace(bt); XBT_LOG(xbt_log_priority_critical, "Current backtrace:"); - for (std::string const& s : res) - XBT_LOG(xbt_log_priority_critical, " -> %s", s.c_str()); + XBT_LOG(xbt_log_priority_critical, " -> %s", res.c_str()); } static std::terminate_handler previous_terminate_handler = nullptr; diff --git a/tools/cmake/src/internal_config.h.in b/tools/cmake/src/internal_config.h.in index 20ffec75d4..2944eca422 100644 --- a/tools/cmake/src/internal_config.h.in +++ b/tools/cmake/src/internal_config.h.in @@ -11,8 +11,6 @@ #include "simgrid/config.h" /* what was compiled in? */ /* Non-standard header files */ -/* */ -#cmakedefine01 HAVE_EXECINFO_H /* */ #cmakedefine01 HAVE_FUTEX_H /* */ @@ -87,8 +85,6 @@ #cmakedefine01 HAVE_SENDFILE /* Other function checks */ -/* Function backtrace */ -#cmakedefine01 HAVE_BACKTRACE /* Function dlfunc */ #cmakedefine01 HAVE_DLFUNC /* Function mmap */ @@ -97,16 +93,12 @@ #cmakedefine01 HAVE_MREMAP /* Function sem_init (part of XPG6 standard only) */ #cmakedefine01 HAVE_SEM_INIT -/* Function popen */ -#cmakedefine01 HAVE_POPEN /* Function sysconf */ #cmakedefine01 HAVE_SYSCONF /* Function vasprintf */ #cmakedefine01 HAVE_VASPRINTF /* Other checks */ -/* Path to the addr2line tool */ -#cmakedefine ADDR2LINE "@ADDR2LINE@" /* The graphviz library */ #cmakedefine01 HAVE_GRAPHVIZ /* The lib unwind library (for MC and backtrace display) */