Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Use addr2line as a fallback for stacktraces when backtrace is not available
[simgrid.git] / src / mc / remote / RemoteClient.cpp
index f96e1e5..3dea617 100644 (file)
@@ -1,59 +1,32 @@
-/* Copyright (c) 2014-2017. The SimGrid Team. All rights reserved.          */
+/* Copyright (c) 2014-2019. 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. */
 
 #define _FILE_OFFSET_BITS 64 /* needed for pread_whole to work as expected on 32bits */
 
-#include <assert.h>
-#include <errno.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include <sys/ptrace.h>
+#include "src/mc/remote/RemoteClient.hpp"
 
-#include <cstdio>
+#include "xbt/file.hpp"
+#include "xbt/log.h"
+#include "src/mc/mc_smx.hpp"
+#include "src/mc/sosp/mc_snapshot.hpp"
 
 #include <fcntl.h>
-#include <regex.h>
-#include <sys/mman.h> // PROT_*
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <pthread.h>
-
-#include <libgen.h>
-
 #include <libunwind-ptrace.h>
-#include <libunwind.h>
-
-#include "xbt/base.h"
-#include "xbt/log.h"
-#include <xbt/mmalloc.h>
-
-#include "src/mc/mc_smx.h"
-#include "src/mc/mc_snapshot.h"
-#include "src/mc/mc_unw.h"
-
-#include "src/mc/AddressSpace.hpp"
-#include "src/mc/ObjectInformation.hpp"
-#include "src/mc/Variable.hpp"
-#include "src/mc/remote/RemoteClient.hpp"
+#include <sys/mman.h> // PROT_*
 
 using simgrid::mc::remote;
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc, "MC process information");
 
-// ***** Helper stuff
-
 namespace simgrid {
 namespace mc {
 
-#define SO_RE "\\.so[\\.0-9]*$"
-#define VERSION_RE "-[\\.0-9-]*$"
+// ***** Helper stuff
 
 // List of library which memory segments are not considered:
-static const char* const filtered_libraries[] = {
+static const std::vector<std::string> filtered_libraries = {
 #ifdef __linux__
     "ld",
 #elif defined __FreeBSD__
@@ -64,16 +37,17 @@ static const char* const filtered_libraries[] = {
     "libthr",      /* thread library */
     "libutil",
 #endif
-    "libasan", /* gcc sanitizers */
     "libargp", /* workarounds for glibc-less systems */
-    "libtsan",
-    "libubsan",
-    "libbz2",
+    "libasan", /* gcc sanitizers */
     "libboost_chrono",
     "libboost_context",
     "libboost_context-mt",
+    "libboost_stacktrace_addr2line",
+    "libboost_stacktrace_backtrace",
     "libboost_system",
     "libboost_thread",
+    "libboost_timer",
+    "libbz2",
     "libc",
     "libc++",
     "libcdt",
@@ -84,57 +58,62 @@ static const char* const filtered_libraries[] = {
     "libdw",
     "libelf",
     "libevent",
+    "libexecinfo",
+    "libflang",
+    "libflangrti",
     "libgcc_s",
+    "libgfortran",
+    "libimf",
+    "libintlc",
+    "libirng",
     "liblua5.1",
     "liblua5.3",
     "liblzma",
     "libm",
+    "libomp",
+    "libpapi",
+    "libpfm",
+    "libpgmath",
     "libpthread",
+    "libquadmath",
     "librt",
     "libstdc++",
+    "libsvml",
+    "libtsan",  /* gcc sanitizers */
+    "libubsan", /* gcc sanitizers */
     "libunwind",
-    "libunwind-x86_64",
-    "libunwind-x86",
     "libunwind-ptrace",
+    "libunwind-x86",
+    "libunwind-x86_64",
     "libz"};
 
-static bool is_simgrid_lib(const char* libname)
+static bool is_simgrid_lib(const std::string& libname)
 {
-  return not strcmp(libname, "libsimgrid");
+  return libname == "libsimgrid";
 }
 
-static bool is_filtered_lib(const char* libname)
+static bool is_filtered_lib(const std::string& libname)
 {
-  for (const char* filtered_lib : filtered_libraries)
-    if (strcmp(libname, filtered_lib) == 0)
-      return true;
-  return false;
+  return std::find(begin(filtered_libraries), end(filtered_libraries), libname) != end(filtered_libraries);
 }
 
-struct s_mc_memory_map_re {
-  regex_t so_re;
-  regex_t version_re;
-};
-
-static char* get_lib_name(const char* pathname, struct s_mc_memory_map_re* res)
+static std::string get_lib_name(const std::string& pathname)
 {
-  char* map_basename = xbt_basename(pathname);
-
-  regmatch_t match;
-  if (regexec(&res->so_re, map_basename, 1, &match, 0)) {
-    free(map_basename);
-    return nullptr;
-  }
-
-  char* libname = strndup(map_basename, match.rm_so);
-  free(map_basename);
-  map_basename = nullptr;
-
-  // Strip the version suffix:
-  if (libname && not regexec(&res->version_re, libname, 1, &match, 0)) {
-    char* temp = libname;
-    libname    = strndup(temp, match.rm_so);
-    free(temp);
+  std::string map_basename = simgrid::xbt::Path(pathname).get_base_name();
+  std::string libname;
+
+  size_t pos = map_basename.rfind(".so");
+  if (pos != std::string::npos) {
+    // strip the extension (matching regex "\.so.*$")
+    libname.assign(map_basename, 0, pos);
+
+    // strip the version suffix (matching regex "-[.0-9-]*$")
+    while (true) {
+      pos = libname.rfind('-');
+      if (pos == std::string::npos || libname.find_first_not_of(".0123456789", pos + 1) != std::string::npos)
+        break;
+      libname.erase(pos);
+    }
   }
 
   return libname;
@@ -222,12 +201,12 @@ void RemoteClient::init()
   this->memory_file = fd;
 
   // Read std_heap (is a struct mdesc*):
-  simgrid::mc::Variable* std_heap_var = this->find_variable("__mmalloc_default_mdp");
+  const simgrid::mc::Variable* std_heap_var = this->find_variable("__mmalloc_default_mdp");
   if (not std_heap_var)
     xbt_die("No heap information in the target process");
   if (not std_heap_var->address)
     xbt_die("No constant address for this variable");
-  this->read_bytes(&this->heap_address, sizeof(struct mdesc*), remote(std_heap_var->address),
+  this->read_bytes(&this->heap_address, sizeof(mdesc*), remote(std_heap_var->address),
                    simgrid::mc::ProcessIndexDisabled);
 
   this->smx_actors_infos.clear();
@@ -261,9 +240,8 @@ void RemoteClient::refresh_heap()
 {
   // Read/dereference/refresh the std_heap pointer:
   if (not this->heap)
-    this->heap = std::unique_ptr<s_xbt_mheap_t>(new s_xbt_mheap_t());
-  this->read_bytes(this->heap.get(), sizeof(struct mdesc), remote(this->heap_address),
-                   simgrid::mc::ProcessIndexDisabled);
+    this->heap.reset(new s_xbt_mheap_t());
+  this->read_bytes(this->heap.get(), sizeof(mdesc), remote(this->heap_address), simgrid::mc::ProcessIndexDisabled);
   this->cache_flags_ |= RemoteClient::cache_heap;
 }
 
@@ -295,11 +273,6 @@ void RemoteClient::init_memory_map_info()
   this->binary_info     = nullptr;
   this->libsimgrid_info = nullptr;
 
-  struct s_mc_memory_map_re res;
-
-  if (regcomp(&res.so_re, SO_RE, 0) || regcomp(&res.version_re, VERSION_RE, 0))
-    xbt_die(".so regexp did not compile");
-
   std::vector<simgrid::xbt::VmMap> const& maps = this->memory_map_;
 
   const char* current_name = nullptr;
@@ -334,13 +307,10 @@ void RemoteClient::init_memory_map_info()
       continue;
 
     const bool is_executable = not i;
-    char* libname            = nullptr;
+    std::string libname;
     if (not is_executable) {
-      libname = get_lib_name(pathname, &res);
-      if (not libname)
-        continue;
+      libname = get_lib_name(pathname);
       if (is_filtered_lib(libname)) {
-        free(libname);
         continue;
       }
     }
@@ -350,14 +320,10 @@ void RemoteClient::init_memory_map_info()
     this->object_infos.push_back(info);
     if (is_executable)
       this->binary_info = info;
-    else if (libname && is_simgrid_lib(libname))
+    else if (is_simgrid_lib(libname))
       this->libsimgrid_info = info;
-    free(libname);
   }
 
-  regfree(&res.so_re);
-  regfree(&res.version_re);
-
   // Resolve time (including across different objects):
   for (auto const& object_info : this->object_infos)
     postProcessObjectInformation(this, object_info.get());
@@ -400,7 +366,7 @@ simgrid::mc::Frame* RemoteClient::find_function(RemotePtr<void> ip) const
 
 /** Find (one occurrence of) the named variable definition
  */
-simgrid::mc::Variable* RemoteClient::find_variable(const char* name) const
+const simgrid::mc::Variable* RemoteClient::find_variable(const char* name) const
 {
   // First lookup the variable in the executable shared object.
   // A global variable used directly by the executable code from a library
@@ -408,13 +374,13 @@ simgrid::mc::Variable* RemoteClient::find_variable(const char* name) const
   // We need to look up the variable in the executable first.
   if (this->binary_info) {
     std::shared_ptr<simgrid::mc::ObjectInformation> const& info = this->binary_info;
-    simgrid::mc::Variable* var                                  = info->find_variable(name);
+    const simgrid::mc::Variable* var                            = info->find_variable(name);
     if (var)
       return var;
   }
 
   for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info : this->object_infos) {
-    simgrid::mc::Variable* var = info->find_variable(name);
+    const simgrid::mc::Variable* var = info->find_variable(name);
     if (var)
       return var;
   }
@@ -424,10 +390,10 @@ simgrid::mc::Variable* RemoteClient::find_variable(const char* name) const
 
 void RemoteClient::read_variable(const char* name, void* target, size_t size) const
 {
-  simgrid::mc::Variable* var = this->find_variable(name);
+  const simgrid::mc::Variable* var = this->find_variable(name);
   xbt_assert(var->address, "No simple location for this variable");
   xbt_assert(var->type->full_type, "Partial type for %s, cannot check size", name);
-  xbt_assert((size_t)var->type->full_type->byte_size == size, "Unexpected size for %s (expected %zi, was %zi)", name,
+  xbt_assert((size_t)var->type->full_type->byte_size == size, "Unexpected size for %s (expected %zu, was %zu)", name,
              size, (size_t)var->type->full_type->byte_size);
   this->read_bytes(target, size, remote(var->address));
 }
@@ -437,7 +403,6 @@ std::string RemoteClient::read_string(RemotePtr<char> address) const
   if (not address)
     return {};
 
-  // TODO, use std::vector with .data() in C++17 to avoid useless copies
   std::vector<char> res(128);
   off_t off = 0;
 
@@ -463,12 +428,12 @@ std::string RemoteClient::read_string(RemotePtr<char> address) const
 }
 
 const void* RemoteClient::read_bytes(void* buffer, std::size_t size, RemotePtr<void> address, int process_index,
-                                     ReadOptions options) const
+                                     ReadOptions /*options*/) const
 {
-  if (process_index != simgrid::mc::ProcessIndexDisabled) {
-    std::shared_ptr<simgrid::mc::ObjectInformation> const& info = this->find_object_info_rw((void*)address.address());
-// Segment overlap is not handled.
 #if HAVE_SMPI
+  if (process_index != simgrid::mc::ProcessIndexDisabled) {
+    std::shared_ptr<simgrid::mc::ObjectInformation> const& info = this->find_object_info_rw(address);
+    // Segment overlap is not handled.
     if (info.get() && this->privatized(*info)) {
       if (process_index < 0)
         xbt_die("Missing process index");
@@ -487,8 +452,8 @@ const void* RemoteClient::read_bytes(void* buffer, std::size_t size, RemotePtr<v
       size_t offset = address.address() - (std::uint64_t)info->start_rw;
       address       = remote((char*)privatization_region.address + offset);
     }
-#endif
   }
+#endif
   if (pread_whole(this->memory_file, buffer, size, (size_t)address.address()) < 0)
     xbt_die("Read at %p from process %lli failed", (void*)address.address(), (long long)this->pid_);
   return buffer;
@@ -608,10 +573,7 @@ void RemoteClient::unignore_heap(void* address, size_t size)
   while (start <= end) {
     cursor       = (start + end) / 2;
     auto& region = ignored_heap_[cursor];
-    if (region.address == address) {
-      ignored_heap_.erase(ignored_heap_.begin() + cursor);
-      return;
-    } else if (region.address < address)
+    if (region.address < address)
       start = cursor + 1;
     else if ((char*)region.address <= ((char*)address + size)) {
       ignored_heap_.erase(ignored_heap_.begin() + cursor);
@@ -667,21 +629,20 @@ void RemoteClient::dumpStack()
     return;
   }
 
-  simgrid::mc::dumpStack(stderr, cursor);
+  simgrid::mc::dumpStack(stderr, std::move(cursor));
 
   _UPT_destroy(context);
   unw_destroy_addr_space(as);
-  return;
 }
 
 bool RemoteClient::actor_is_enabled(aid_t pid)
 {
-  s_mc_message_actor_enabled msg{MC_MESSAGE_ACTOR_ENABLED, pid};
+  s_mc_message_actor_enabled_t msg{MC_MESSAGE_ACTOR_ENABLED, pid};
   process()->getChannel().send(msg);
   char buff[MC_MESSAGE_LENGTH];
   ssize_t received = process()->getChannel().receive(buff, MC_MESSAGE_LENGTH, true);
-  xbt_assert(received == sizeof(s_mc_message_int), "Unexpected size in answer to ACTOR_ENABLED");
-  return ((mc_message_int_t*)buff)->value;
+  xbt_assert(received == sizeof(s_mc_message_int_t), "Unexpected size in answer to ACTOR_ENABLED");
+  return ((s_mc_message_int_t*)buff)->value;
 }
 }
 }