X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/48eb2f1b9262fc74f527816c348ed2aa6efa9f65..HEAD:/src/mc/remote/RemoteClient.cpp diff --git a/src/mc/remote/RemoteClient.cpp b/src/mc/remote/RemoteClient.cpp deleted file mode 100644 index 3811904027..0000000000 --- a/src/mc/remote/RemoteClient.cpp +++ /dev/null @@ -1,687 +0,0 @@ -/* Copyright (c) 2014-2017. 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 -#include -#include -#include - -#include - -#include - -#include -#include -#include // PROT_* -#include -#include - -#include - -#include - -#include -#include - -#include "xbt/base.h" -#include "xbt/log.h" -#include - -#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" - -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-]*$" - -// List of library which memory segments are not considered: -static const char* const 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 - "libasan", /* gcc sanitizers */ - "libargp", /* workarounds for glibc-less systems */ - "libtsan", - "libubsan", - "libbz2", - "libboost_chrono", - "libboost_context", - "libboost_context-mt", - "libboost_system", - "libboost_thread", - "libc", - "libc++", - "libcdt", - "libcgraph", - "libcrypto", - "libcxxrt", - "libdl", - "libdw", - "libelf", - "libevent", - "libgcc_s", - "liblua5.1", - "liblua5.3", - "liblzma", - "libm", - "libpthread", - "librt", - "libstdc++", - "libunwind", - "libunwind-x86_64", - "libunwind-x86", - "libunwind-ptrace", - "libz"}; - -static bool is_simgrid_lib(const char* libname) -{ - return not strcmp(libname, "libsimgrid"); -} - -static bool is_filtered_lib(const char* libname) -{ - for (const char* filtered_lib : filtered_libraries) - if (strcmp(libname, filtered_lib) == 0) - return true; - return false; -} - -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) -{ - 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); - } - - return libname; -} - -static ssize_t pread_whole(int fd, void* buf, size_t count, off_t offset) -{ - char* buffer = (char*)buf; - ssize_t real_count = count; - while (count) { - ssize_t res = pread(fd, buffer, count, offset); - if (res > 0) { - count -= res; - buffer += res; - offset += res; - } else if (res == 0) - return -1; - else if (errno != EINTR) { - perror("pread_whole"); - return -1; - } - } - return real_count; -} - -static ssize_t pwrite_whole(int fd, const void* buf, size_t count, off_t offset) -{ - const char* buffer = (const char*)buf; - ssize_t real_count = count; - while (count) { - ssize_t res = pwrite(fd, buffer, count, offset); - if (res > 0) { - count -= res; - buffer += res; - offset += res; - } else if (res == 0) - return -1; - else if (errno != EINTR) - return -1; - } - 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) -{ - const size_t buffer_size = 30; - char buffer[buffer_size]; - int res = snprintf(buffer, buffer_size, "/proc/%lli/mem", (long long)pid); - if (res < 0 || (size_t)res >= buffer_size) { - errno = ENAMETOOLONG; - return -1; - } - return open(buffer, flags); -} - -// ***** Process - -RemoteClient::RemoteClient(pid_t pid, int sockfd) : AddressSpace(this), pid_(pid), channel_(sockfd), running_(true) -{ -} - -void RemoteClient::init() -{ - this->memory_map_ = simgrid::xbt::get_memory_map(this->pid_); - this->init_memory_map_info(); - - int fd = open_vm(this->pid_, O_RDWR); - if (fd < 0) - xbt_die("Could not open file for process virtual address space"); - this->memory_file = fd; - - // Read std_heap (is a struct mdesc*): - 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), - simgrid::mc::ProcessIndexDisabled); - - 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_); -} - -RemoteClient::~RemoteClient() -{ - if (this->memory_file >= 0) - close(this->memory_file); - - if (this->unw_underlying_addr_space != unw_local_addr_space) { - if (this->unw_underlying_addr_space) - unw_destroy_addr_space(this->unw_underlying_addr_space); - if (this->unw_underlying_context) - _UPT_destroy(this->unw_underlying_context); - } - - unw_destroy_addr_space(this->unw_addr_space); -} - -/** Refresh the information about the process - * - * Do not use directly, this is used by the getters when appropriate - * in order to have fresh data. - */ -void RemoteClient::refresh_heap() -{ - // Read/dereference/refresh the std_heap pointer: - if (not this->heap) - this->heap = std::unique_ptr(new s_xbt_mheap_t()); - this->read_bytes(this->heap.get(), sizeof(struct mdesc), remote(this->heap_address), - simgrid::mc::ProcessIndexDisabled); - this->cache_flags_ |= RemoteClient::cache_heap; -} - -/** Refresh the information about the process - * - * Do not use direclty, this is used by the getters when appropriate - * in order to have fresh data. - * */ -void RemoteClient::refresh_malloc_info() -{ - // Refresh process->heapinfo: - if (this->cache_flags_ & RemoteClient::cache_malloc) - return; - size_t count = this->heap->heaplimit + 1; - if (this->heap_info.size() < count) - this->heap_info.resize(count); - this->read_bytes(this->heap_info.data(), count * sizeof(malloc_info), remote(this->heap->heapinfo), - simgrid::mc::ProcessIndexDisabled); - this->cache_flags_ |= RemoteClient::cache_malloc; -} - -/** @brief Finds the range of the different memory segments and binary paths */ -void RemoteClient::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->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 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(); - - // Nothing to do - if (maps[i].pathname.empty()) { - current_name = nullptr; - continue; - } - - // [stack], [vvar], [vsyscall], [vdso] ... - if (pathname[0] == '[') { - if ((reg.prot & PROT_WRITE) && not memcmp(pathname, "[stack]", 7)) { - this->maestro_stack_start_ = remote(reg.start_addr); - this->maestro_stack_end_ = remote(reg.end_addr); - } - current_name = nullptr; - continue; - } - - if (current_name && strcmp(current_name, pathname) == 0) - continue; - - current_name = pathname; - if (not(reg.prot & PROT_READ) && (reg.prot & PROT_EXEC)) - continue; - - const bool is_executable = not i; - char* libname = nullptr; - if (not is_executable) { - libname = get_lib_name(pathname, &res); - if (not libname) - continue; - if (is_filtered_lib(libname)) { - free(libname); - continue; - } - } - - std::shared_ptr info = - simgrid::mc::createObjectInformation(this->memory_map_, pathname); - this->object_infos.push_back(info); - if (is_executable) - this->binary_info = info; - else if (libname && 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()); - - xbt_assert(this->maestro_stack_start_, "Did not find maestro_stack_start"); - xbt_assert(this->maestro_stack_end_, "Did not find maestro_stack_end"); - - XBT_DEBUG("Get debug information done !"); -} - -std::shared_ptr RemoteClient::find_object_info(RemotePtr addr) const -{ - for (auto const& object_info : this->object_infos) - if (addr.address() >= (std::uint64_t)object_info->start && addr.address() <= (std::uint64_t)object_info->end) - return object_info; - return nullptr; -} - -std::shared_ptr RemoteClient::find_object_info_exec(RemotePtr addr) const -{ - for (std::shared_ptr const& info : this->object_infos) - if (addr.address() >= (std::uint64_t)info->start_exec && addr.address() <= (std::uint64_t)info->end_exec) - return info; - return nullptr; -} - -std::shared_ptr RemoteClient::find_object_info_rw(RemotePtr addr) const -{ - for (std::shared_ptr const& info : this->object_infos) - if (addr.address() >= (std::uint64_t)info->start_rw && addr.address() <= (std::uint64_t)info->end_rw) - return info; - return nullptr; -} - -simgrid::mc::Frame* RemoteClient::find_function(RemotePtr ip) const -{ - std::shared_ptr info = this->find_object_info_exec(ip); - return info ? info->find_function((void*)ip.address()) : nullptr; -} - -/** Find (one occurrence of) the named variable definition - */ -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 - // is reinstanciated in the executable memory .data/.bss. - // We need to look up the variable in the executable first. - if (this->binary_info) { - std::shared_ptr const& info = this->binary_info; - simgrid::mc::Variable* var = info->find_variable(name); - if (var) - return var; - } - - for (std::shared_ptr const& info : this->object_infos) { - simgrid::mc::Variable* var = info->find_variable(name); - if (var) - return var; - } - - return nullptr; -} - -void RemoteClient::read_variable(const char* name, void* target, size_t size) 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 %zu, was %zu)", name, - size, (size_t)var->type->full_type->byte_size); - this->read_bytes(target, size, remote(var->address)); -} - -std::string RemoteClient::read_string(RemotePtr address) const -{ - if (not address) - return {}; - - // TODO, use std::vector with .data() in C++17 to avoid useless copies - std::vector res(128); - off_t off = 0; - - while (1) { - ssize_t c = pread(this->memory_file, res.data() + off, res.size() - off, (off_t)address.address() + off); - if (c == -1) { - if (errno == EINTR) - continue; - else - xbt_die("Could not read from from remote process"); - } - if (c == 0) - xbt_die("Could not read string from remote process"); - - void* p = memchr(res.data() + off, '\0', c); - if (p) - return std::string(res.data()); - - off += c; - if (off == (off_t)res.size()) - res.resize(res.size() * 2); - } -} - -const void* RemoteClient::read_bytes(void* buffer, std::size_t size, RemotePtr address, int process_index, - ReadOptions options) const -{ - if (process_index != simgrid::mc::ProcessIndexDisabled) { - std::shared_ptr const& info = this->find_object_info_rw((void*)address.address()); -// Segment overlap is not handled. -#if HAVE_SMPI - if (info.get() && this->privatized(*info)) { - if (process_index < 0) - xbt_die("Missing process index"); - if (process_index >= (int)MC_smpi_process_count()) - xbt_die("Invalid process index"); - - // Read smpi_privatization_regions from MCed: - smpi_privatization_region_t remote_smpi_privatization_regions = - mc_model_checker->process().read_variable("smpi_privatization_regions"); - - s_smpi_privatization_region_t privatization_region = - mc_model_checker->process().read( - remote(remote_smpi_privatization_regions + process_index)); - - // Address translation in the privatization segment: - size_t offset = address.address() - (std::uint64_t)info->start_rw; - address = remote((char*)privatization_region.address + offset); - } -#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; -} - -/** Write data to a process memory - * - * @param buffer local memory address (source) - * @param len data size - * @param address target process memory address (target) - */ -void RemoteClient::write_bytes(const void* buffer, size_t len, RemotePtr address) -{ - if (pwrite_whole(this->memory_file, buffer, len, (size_t)address.address()) < 0) - xbt_die("Write to process %lli failed", (long long)this->pid_); -} - -void RemoteClient::clear_bytes(RemotePtr address, size_t len) -{ - pthread_once(&zero_buffer_flag, zero_buffer_init); - while (len) { - size_t s = len > zero_buffer_size ? zero_buffer_size : len; - this->write_bytes(zero_buffer, s, address); - address = remote((char*)address.address() + s); - len -= s; - } -} - -void RemoteClient::ignore_region(std::uint64_t addr, std::size_t size) -{ - IgnoredRegion region; - region.addr = addr; - region.size = size; - - if (ignored_regions_.empty()) { - ignored_regions_.push_back(region); - return; - } - - unsigned int cursor = 0; - IgnoredRegion* current_region = nullptr; - - int start = 0; - int end = ignored_regions_.size() - 1; - while (start <= end) { - cursor = (start + end) / 2; - current_region = &ignored_regions_[cursor]; - if (current_region->addr == addr) { - if (current_region->size == size) - return; - else if (current_region->size < size) - start = cursor + 1; - else - end = cursor - 1; - } else if (current_region->addr < addr) - start = cursor + 1; - else - end = cursor - 1; - } - - std::size_t position; - if (current_region->addr == addr) { - if (current_region->size < size) - position = cursor + 1; - else - position = cursor; - } else if (current_region->addr < addr) - position = cursor + 1; - else - position = cursor; - ignored_regions_.insert(ignored_regions_.begin() + position, region); -} - -void RemoteClient::ignore_heap(IgnoredHeapRegion const& region) -{ - if (ignored_heap_.empty()) { - ignored_heap_.push_back(std::move(region)); - return; - } - - typedef std::vector::size_type size_type; - - size_type start = 0; - size_type end = ignored_heap_.size() - 1; - - // Binary search the position of insertion: - size_type cursor; - while (start <= end) { - cursor = start + (end - start) / 2; - auto& current_region = ignored_heap_[cursor]; - if (current_region.address == region.address) - return; - else if (current_region.address < region.address) - start = cursor + 1; - else if (cursor != 0) - end = cursor - 1; - // Avoid underflow: - else - break; - } - - // Insert it mc_heap_ignore_region_t: - if (ignored_heap_[cursor].address < region.address) - ++cursor; - ignored_heap_.insert(ignored_heap_.begin() + cursor, region); -} - -void RemoteClient::unignore_heap(void* address, size_t size) -{ - typedef std::vector::size_type size_type; - - size_type start = 0; - size_type end = ignored_heap_.size() - 1; - - // Binary search: - size_type cursor; - 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) - start = cursor + 1; - else if ((char*)region.address <= ((char*)address + size)) { - ignored_heap_.erase(ignored_heap_.begin() + cursor); - return; - } else if (cursor != 0) - end = cursor - 1; - // Avoid underflow: - else - break; - } -} - -void RemoteClient::ignore_local_variable(const char* var_name, const char* frame_name) -{ - if (frame_name != nullptr && strcmp(frame_name, "*") == 0) - frame_name = nullptr; - for (std::shared_ptr const& info : this->object_infos) - info->remove_local_variable(var_name, frame_name); -} - -std::vector& RemoteClient::actors() -{ - this->refresh_simix(); - return smx_actors_infos; -} - -std::vector& RemoteClient::dead_actors() -{ - this->refresh_simix(); - return smx_dead_actors_infos; -} - -void RemoteClient::dumpStack() -{ - unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, BYTE_ORDER); - if (as == nullptr) { - XBT_ERROR("Could not initialize ptrace address space"); - return; - } - - void* context = _UPT_create(this->pid_); - if (context == nullptr) { - unw_destroy_addr_space(as); - XBT_ERROR("Could not initialize ptrace context"); - return; - } - - unw_cursor_t cursor; - if (unw_init_remote(&cursor, as, context) != 0) { - _UPT_destroy(context); - unw_destroy_addr_space(as); - XBT_ERROR("Could not initialiez ptrace cursor"); - return; - } - - simgrid::mc::dumpStack(stderr, 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}; - 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; -} -} -}