-/* Copyright (c) 2014-2021. The SimGrid Team. All rights reserved. */
+/* Copyright (c) 2014-2023. 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 <cerrno>
#include <cstring>
#include <memory>
+#include <mutex>
#include <string>
-
-using simgrid::mc::remote;
+#include <string_view>
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc, "MC process information");
-namespace simgrid {
-namespace mc {
+namespace simgrid::mc {
// ***** Helper stuff
-// List of library which memory segments are not considered:
-static const std::vector<std::string> filtered_libraries = {
-#ifdef __linux__
- "ld",
-#elif defined __FreeBSD__
- "ld-elf",
- "ld-elf32",
- "libkvm", /* kernel data access library */
- "libprocstat", /* process and file information retrieval */
- "libthr", /* thread library */
- "libutil",
-#endif
- "libargp", /* workarounds for glibc-less systems */
- "libasan", /* gcc sanitizers */
- "libasn1",
- "libboost_chrono",
- "libboost_context",
- "libboost_context-mt",
- "libboost_stacktrace_addr2line",
- "libboost_stacktrace_backtrace",
- "libboost_system",
- "libboost_thread",
- "libboost_timer",
- "libbrotlicommon",
- "libbrotlidec",
- "libbz2",
- "libc",
- "libc++",
- "libcdt",
- "libcgraph",
- "libcom_err",
- "libcrypt",
- "libcrypto",
- "libcurl",
- "libcurl-gnutls",
- "libcxxrt",
- "libdebuginfod",
- "libdl",
- "libdw",
- "libelf",
- "libevent",
- "libexecinfo",
- "libffi",
- "libflang",
- "libflangrti",
- "libgcc_s",
- "libgmp",
- "libgnutls",
- "libgcrypt",
- "libgfortran",
- "libgpg-error",
- "libgssapi",
- "libgssapi_krb5",
- "libhcrypto",
- "libheimbase",
- "libheimntlm",
- "libhx509",
- "libhogweed",
- "libidn2",
- "libimf",
- "libintlc",
- "libirng",
- "libk5crypto",
- "libkeyutils",
- "libkrb5",
- "libkrb5support", /*odd behaviour on fedora rawhide ... remove these when fixed*/
- "liblber",
- "libldap",
- "libldap_r",
- "liblua5.1",
- "liblua5.3",
- "liblzma",
- "libm",
- "libmd",
- "libnettle",
- "libnghttp2",
- "libomp",
- "libp11-kit",
- "libpapi",
- "libpcre2",
- "libpfm",
- "libpgmath",
- "libpsl",
- "libpthread",
- "libquadmath",
- "libresolv",
- "libroken",
- "librt",
- "librtmp",
- "libsasl2",
- "libselinux",
- "libsqlite3",
- "libssh",
- "libssh2",
- "libssl",
- "libstdc++",
- "libsvml",
- "libtasn1",
- "libtsan", /* gcc sanitizers */
- "libubsan", /* gcc sanitizers */
- "libunistring",
- "libunwind",
- "libunwind-ptrace",
- "libunwind-x86",
- "libunwind-x86_64",
- "libwind",
- "libz",
- "libzstd"};
-
-static bool is_filtered_lib(const std::string& libname)
+static bool is_filtered_lib(std::string_view libname)
{
- return std::find(begin(filtered_libraries), end(filtered_libraries), libname) != end(filtered_libraries);
+ return libname != "libsimgrid";
}
static std::string get_lib_name(const std::string& pathname)
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) {
+ if (size_t pos = map_basename.rfind(".so"); pos != std::string::npos) {
// strip the extension (matching regex "\.so.*$")
libname.assign(map_basename, 0, pos);
return real_count;
}
-static pthread_once_t zero_buffer_flag = PTHREAD_ONCE_INIT;
-static const void* zero_buffer;
-static const size_t zero_buffer_size = 10 * 4096;
-
-static void zero_buffer_init()
-{
- int fd = open("/dev/zero", O_RDONLY);
- if (fd < 0)
- xbt_die("Could not open /dev/zero");
- zero_buffer = mmap(nullptr, zero_buffer_size, PROT_READ, MAP_SHARED, fd, 0);
- if (zero_buffer == MAP_FAILED)
- xbt_die("Could not map the zero buffer");
- close(fd);
-}
-
int open_vm(pid_t pid, int flags)
{
std::string buffer = "/proc/" + std::to_string(pid) + "/mem";
RemoteProcess::RemoteProcess(pid_t pid) : AddressSpace(this), pid_(pid), running_(true) {}
-void RemoteProcess::init()
+void RemoteProcess::init(xbt_mheap_t mmalloc_default_mdp, unsigned long* maxpid)
{
+ this->heap_address = remote(mmalloc_default_mdp);
+ this->maxpid_addr_ = remote(maxpid);
+
this->memory_map_ = simgrid::xbt::get_memory_map(this->pid_);
this->init_memory_map_info();
xbt_assert(fd >= 0, "Could not open file for process virtual address space");
this->memory_file = fd;
- // Read std_heap (is a struct mdesc*):
- const simgrid::mc::Variable* std_heap_var = this->find_variable("__mmalloc_default_mdp");
- xbt_assert(std_heap_var, "No heap information in the target process");
- xbt_assert(std_heap_var->address, "No constant address for this variable");
- this->read_bytes(&this->heap_address, sizeof(mdesc*), remote(std_heap_var->address));
-
- this->smx_actors_infos.clear();
- this->smx_dead_actors_infos.clear();
this->unw_addr_space = simgrid::mc::UnwindContext::createUnwindAddressSpace();
this->unw_underlying_addr_space = simgrid::unw::create_addr_space();
this->unw_underlying_context = simgrid::unw::create_context(this->unw_underlying_addr_space, this->pid_);
void RemoteProcess::refresh_heap()
{
// Read/dereference/refresh the std_heap pointer:
- if (not this->heap)
- this->heap = std::make_unique<s_xbt_mheap_t>();
- this->read_bytes(this->heap.get(), sizeof(mdesc), remote(this->heap_address));
+ this->read(this->heap.get(), this->heap_address);
this->cache_flags_ |= RemoteProcess::cache_heap;
}
this->read_bytes(this->heap_info.data(), count * sizeof(malloc_info), remote(this->heap->heapinfo));
this->cache_flags_ |= RemoteProcess::cache_malloc;
}
+std::size_t RemoteProcess::get_remote_heap_bytes()
+{
+ return mmalloc_get_bytes_used_remote(get_heap()->heaplimit, get_malloc_info());
+}
/** @brief Finds the range of the different memory segments and binary paths */
void RemoteProcess::init_memory_map_info()
XBT_DEBUG("Get debug information ...");
this->maestro_stack_start_ = nullptr;
this->maestro_stack_end_ = nullptr;
- this->object_infos.resize(0);
+ this->object_infos.clear();
this->binary_info = nullptr;
std::vector<simgrid::xbt::VmMap> const& maps = this->memory_map_;
const char* current_name = nullptr;
- this->object_infos.clear();
-
for (size_t i = 0; i < maps.size(); i++) {
simgrid::xbt::VmMap const& reg = maps[i];
const char* pathname = maps[i].pathname.c_str();
continue;
xbt_assert(c > 0, "Could not read string from remote process");
- const void* p = memchr(res.data() + off, '\0', c);
- if (p)
- return std::string(res.data());
+ if (memchr(res.data() + off, '\0', c))
+ return res.data();
off += c;
if (off == (off_t)res.size())
void* RemoteProcess::read_bytes(void* buffer, std::size_t size, RemotePtr<void> address, ReadOptions /*options*/) const
{
- 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_);
+ xbt_assert(pread_whole(this->memory_file, buffer, size, (size_t)address.address()) != -1,
+ "Read at %p from process %lli failed", (void*)address.address(), (long long)this->pid_);
return buffer;
}
*/
void RemoteProcess::write_bytes(const void* buffer, size_t len, RemotePtr<void> address) const
{
- if (pwrite_whole(this->memory_file, buffer, len, (size_t)address.address()) < 0)
- xbt_die("Write to process %lli failed", (long long)this->pid_);
+ xbt_assert(pwrite_whole(this->memory_file, buffer, len, (size_t)address.address()) != -1,
+ "Write to process %lli failed", (long long)this->pid_);
+}
+
+static void zero_buffer_init(const void** zero_buffer, size_t zero_buffer_size)
+{
+ int fd = open("/dev/zero", O_RDONLY);
+ xbt_assert(fd >= 0, "Could not open /dev/zero");
+ *zero_buffer = mmap(nullptr, zero_buffer_size, PROT_READ, MAP_SHARED, fd, 0);
+ xbt_assert(*zero_buffer != MAP_FAILED, "Could not map the zero buffer");
+ close(fd);
}
void RemoteProcess::clear_bytes(RemotePtr<void> address, size_t len) const
{
- pthread_once(&zero_buffer_flag, zero_buffer_init);
+ static constexpr size_t zero_buffer_size = 10 * 4096;
+ static const void* zero_buffer;
+ static std::once_flag zero_buffer_flag;
+
+ std::call_once(zero_buffer_flag, zero_buffer_init, &zero_buffer, zero_buffer_size);
while (len) {
size_t s = len > zero_buffer_size ? zero_buffer_size : len;
this->write_bytes(zero_buffer, s, address);
info->remove_local_variable(var_name, frame_name);
}
-std::vector<simgrid::mc::ActorInformation>& RemoteProcess::actors()
-{
- this->refresh_simix();
- return smx_actors_infos;
-}
-
-std::vector<simgrid::mc::ActorInformation>& RemoteProcess::dead_actors()
-{
- this->refresh_simix();
- return smx_dead_actors_infos;
-}
-
void RemoteProcess::dump_stack() const
{
unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, BYTE_ORDER);
if (unw_init_remote(&cursor, as, context) != 0) {
_UPT_destroy(context);
unw_destroy_addr_space(as);
- XBT_ERROR("Could not initialiez ptrace cursor");
+ XBT_ERROR("Could not initialize ptrace cursor");
return;
}
_UPT_destroy(context);
unw_destroy_addr_space(as);
}
-
-unsigned long RemoteProcess::get_maxpid() const
-{
- static const char* name = nullptr;
- if (not name) {
- name = "simgrid::kernel::actor::maxpid";
- if (find_variable(name) == nullptr)
- name = "maxpid"; // We seem to miss the namespaces when compiling with GCC
- }
- unsigned long maxpid;
- read_variable(name, &maxpid, sizeof(maxpid));
- return maxpid;
-}
-
-void RemoteProcess::get_actor_vectors(RemotePtr<s_xbt_dynar_t>& actors, RemotePtr<s_xbt_dynar_t>& dead_actors)
-{
- static_assert(std::is_same<std::unique_ptr<simgrid::simix::Global>, decltype(simix_global)>::value,
- "Unexpected type for simix_global");
- static_assert(sizeof(simix_global) == sizeof(simgrid::simix::Global*), "Bad size for simix_global");
-
- // TODO, avoid to reload `&simix_global`, `simix_global`, `*simix_global`
- RemotePtr<simgrid::simix::Global> simix_global_p{this->read_variable<simgrid::simix::Global*>("simix_global")};
- Remote<simgrid::simix::Global> simix_global = this->read<simgrid::simix::Global>(simix_global_p);
-
- actors = remote(simix_global.get_buffer()->actors_vector);
- dead_actors = remote(simix_global.get_buffer()->dead_actors_vector);
-}
-} // namespace mc
-} // namespace simgrid
+} // namespace simgrid::mc