Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Read smpi_loaded_page from MCed in MC_process_init()
[simgrid.git] / src / mc / mc_checkpoint.c
index 45201cf..897ff8f 100644 (file)
@@ -5,7 +5,6 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #define _GNU_SOURCE
-#define UNW_LOCAL_ONLY
 
 #include <unistd.h>
 
@@ -25,7 +24,6 @@
 
 #include "../simix/smx_private.h"
 
-#define UNW_LOCAL_ONLY
 #include <libunwind.h>
 #include <libelf.h>
 
@@ -35,6 +33,9 @@
 #include "mc_snapshot.h"
 #include "mc_object_info.h"
 #include "mc_mmu.h"
+#include "mc_unw.h"
+#include "mc_protocol.h"
+#include "mc_smx.h"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_checkpoint, mc,
                                 "Logging specific to mc_checkpoint");
@@ -47,13 +48,16 @@ static void MC_snapshot_stack_free(mc_snapshot_stack_t s)
   if (s) {
     xbt_dynar_free(&(s->local_variables));
     xbt_dynar_free(&(s->stack_frames));
+    mc_unw_destroy_context(s->context);
+    xbt_free(s->context);
     xbt_free(s);
   }
 }
 
 static void MC_snapshot_stack_free_voidp(void *s)
 {
-  MC_snapshot_stack_free((mc_snapshot_stack_t) * (void **) s);
+  mc_snapshot_stack_t stack = (mc_snapshot_stack_t) * (void **) s;
+  MC_snapshot_stack_free(stack);
 }
 
 static void local_variable_free(local_variable_t v)
@@ -121,7 +125,9 @@ static mc_mem_region_t mc_region_new_dense(
   region->permanent_addr = permanent_addr;
   region->size = size;
   region->flat.data = xbt_malloc(size);
-  MC_process_read(&mc_model_checker->process, region->flat.data, permanent_addr, size);
+  MC_process_read(&mc_model_checker->process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+    region->flat.data, permanent_addr, size,
+    MC_PROCESS_INDEX_DISABLED);
   XBT_DEBUG("New region : type : %d, data : %p (real addr %p), size : %zu",
             region_type, region->flat.data, permanent_addr, size);
   return region;
@@ -185,18 +191,11 @@ static void MC_region_restore(mc_mem_region_t region, mc_mem_region_t ref_region
   }
 }
 
-static inline
-void* MC_privatization_address(mc_process_t process, int process_index)
-{
-  xbt_assert(process_index >= 0);
-  return smpi_privatisation_regions[process_index].address;
-}
-
 static mc_mem_region_t MC_region_new_privatized(
     mc_region_type_t region_type, void *start_addr, void* permanent_addr, size_t size,
     mc_mem_region_t ref_reg)
 {
-  size_t process_count = smpi_process_count();
+  size_t process_count = MC_smpi_process_count();
   mc_mem_region_t region = xbt_new(s_mc_mem_region_t, 1);
   region->region_type = region_type;
   region->storage_type = MC_REGION_STORAGE_TYPE_PRIVATIZED;
@@ -206,13 +205,22 @@ static mc_mem_region_t MC_region_new_privatized(
   region->privatized.regions_count = process_count;
   region->privatized.regions = xbt_new(mc_mem_region_t, process_count);
 
+  // Read smpi_privatisation_regions from MCed:
+  smpi_privatisation_region_t remote_smpi_privatisation_regions;
+  MC_process_read_variable(&mc_model_checker->process,
+    "smpi_privatisation_regions",
+    &remote_smpi_privatisation_regions, sizeof(remote_smpi_privatisation_regions));
+  s_smpi_privatisation_region_t privatisation_regions[process_count];
+  MC_process_read_simple(&mc_model_checker->process, &privatisation_regions,
+    remote_smpi_privatisation_regions, sizeof(privatisation_regions));
+
   for (size_t i = 0; i < process_count; i++) {
     mc_mem_region_t ref_subreg = NULL;
     if (ref_reg && ref_reg->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED)
       ref_subreg = ref_reg->privatized.regions[i];
     region->privatized.regions[i] =
       MC_region_new(region_type, start_addr,
-        MC_privatization_address(&mc_model_checker->process, i), size,
+        privatisation_regions[i].address, size,
         ref_subreg);
   }
 
@@ -233,8 +241,8 @@ static void MC_snapshot_add_region(int index, mc_snapshot_t snapshot, mc_region_
     ref_reg = mc_model_checker->parent_snapshot->snapshot_regions[index];
 
   mc_mem_region_t region;
-  const bool privatization_aware = object_info && MC_object_info_executable(object_info);
-  if (privatization_aware && smpi_privatize_global_variables && smpi_process_count())
+  const bool privatization_aware = MC_object_info_is_privatized(object_info);
+  if (privatization_aware && MC_smpi_process_count())
     region = MC_region_new_privatized(type, start_addr, permanent_addr, size, ref_reg);
   else
     region = MC_region_new(type, start_addr, permanent_addr, size, ref_reg);
@@ -244,40 +252,46 @@ static void MC_snapshot_add_region(int index, mc_snapshot_t snapshot, mc_region_
   return;
 }
 
-static void MC_get_memory_regions(mc_snapshot_t snapshot)
+static void MC_get_memory_regions(mc_process_t process, mc_snapshot_t snapshot)
 {
-  const mc_process_t process = &mc_model_checker->process;
   const size_t n = process->object_infos_size;
   snapshot->snapshot_regions_count = n + 1;
   snapshot->snapshot_regions = xbt_new0(mc_mem_region_t, n + 1);
 
   for (size_t i = 0; i!=n; ++i) {
-    mc_object_info_t object_info = mc_model_checker->process.object_infos[i];
+    mc_object_info_t object_info = process->object_infos[i];
     MC_snapshot_add_region(i, snapshot, MC_REGION_TYPE_DATA, object_info,
       object_info->start_rw, object_info->start_rw,
       object_info->end_rw - object_info->start_rw);
   }
 
-  void *start_heap = std_heap->base;
-  void *end_heap = std_heap->breakval;
+  xbt_mheap_t heap = MC_process_get_heap(process);
+  void *start_heap = heap->base;
+  void *end_heap = heap->breakval;
+
   MC_snapshot_add_region(n, snapshot, MC_REGION_TYPE_HEAP, NULL,
                         start_heap, start_heap,
                         (char *) end_heap - (char *) start_heap);
-  snapshot->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
+  snapshot->heap_bytes_used = mmalloc_get_bytes_used_remote(
+    heap->heaplimit,
+    MC_process_get_malloc_info(process));
 
 #ifdef HAVE_SMPI
-  if (smpi_privatize_global_variables && smpi_process_count()) {
-    snapshot->privatization_index = smpi_loaded_page;
+  if (smpi_privatize_global_variables && MC_smpi_process_count()) {
+    // snapshot->privatization_index = smpi_loaded_page
+    MC_process_read_variable(&mc_model_checker->process,
+      "smpi_loaded_page", &snapshot->privatization_index,
+      sizeof(snapshot->privatization_index));
   } else
 #endif
   {
-    snapshot->privatization_index = MC_NO_PROCESS_INDEX;
+    snapshot->privatization_index = MC_PROCESS_INDEX_MISSING;
   }
 }
 
 /** \brief Fills the position of the segments (executable, read-only, read/write).
  *
- * TODO, use dl_iterate_phdr to be more robust
+ *  `dl_iterate_phdr` would be more robust but would not work in cross-process.
  * */
 void MC_find_object_address(memory_map_t maps, mc_object_info_t result)
 {
@@ -317,6 +331,18 @@ void MC_find_object_address(memory_map_t maps, mc_object_info_t result)
     i++;
   }
 
+  result->start = result->start_rw;
+  if ((const void*) result->start_ro > result->start)
+    result->start = result->start_ro;
+  if ((const void*) result->start_exec > result->start)
+    result->start = result->start_exec;
+
+  result->end = result->end_rw;
+  if (result->end_ro && (const void*) result->end_ro < result->end)
+    result->end = result->end_ro;
+  if (result->end_exec && (const void*) result->end_exec > result->end)
+    result->end = result->end_exec;
+
   xbt_assert(result->file_name);
   xbt_assert(result->start_rw);
   xbt_assert(result->start_exec);
@@ -361,6 +387,7 @@ static void mc_fill_local_variables_values(mc_stack_frame_t stack_frame,
       continue;
 
     int region_type;
+    // FIXME, get rid of `region_type`
     if ((long) stack_frame->ip > (long) process->libsimgrid_info->start_exec)
       region_type = 1;
     else
@@ -377,6 +404,7 @@ static void mc_fill_local_variables_values(mc_stack_frame_t stack_frame,
       new_var->address = current_variable->address;
     } else if (current_variable->locations.size != 0) {
       s_mc_location_t location;
+      // FIXME, cross-process support
       mc_dwarf_resolve_locations(&location, &current_variable->locations,
                                               current_variable->object_info,
                                               &(stack_frame->unw_cursor),
@@ -430,7 +458,7 @@ static void MC_stack_frame_free_voipd(void *s)
   }
 }
 
-static xbt_dynar_t MC_unwind_stack_frames(void *stack_context)
+static xbt_dynar_t MC_unwind_stack_frames(mc_unw_context_t stack_context)
 {
   mc_process_t process = &mc_model_checker->process;
   xbt_dynar_t result =
@@ -439,7 +467,7 @@ static xbt_dynar_t MC_unwind_stack_frames(void *stack_context)
   unw_cursor_t c;
 
   // TODO, check condition check (unw_init_local==0 means end of frame)
-  if (unw_init_local(&c, (unw_context_t *) stack_context) != 0) {
+  if (mc_unw_init_cursor(&c, stack_context) != 0) {
 
     xbt_die("Could not initialize stack unwinding");
 
@@ -478,11 +506,11 @@ static xbt_dynar_t MC_unwind_stack_frames(void *stack_context)
           && !strcmp(frame->name, "smx_ctx_sysv_wrapper"))
         break;
 
-      int ret = ret = unw_step(&c);
+      int ret = unw_step(&c);
       if (ret == 0) {
         xbt_die("Unexpected end of stack.");
       } else if (ret < 0) {
-        xbt_die("Error while unwinding stack.");
+        xbt_die("Error while unwinding stack");
       }
     }
 
@@ -504,9 +532,19 @@ static xbt_dynar_t MC_take_snapshot_stacks(mc_snapshot_t * snapshot)
   unsigned int cursor = 0;
   stack_region_t current_stack;
 
+  // FIXME, cross-process support (stack_areas)
   xbt_dynar_foreach(stacks_areas, cursor, current_stack) {
     mc_snapshot_stack_t st = xbt_new(s_mc_snapshot_stack_t, 1);
-    st->stack_frames = MC_unwind_stack_frames(current_stack->context);
+
+    unw_context_t* original_context = (unw_context_t*) current_stack->context;
+
+    st->context = xbt_new0(s_mc_unw_context_t, 1);
+    if (mc_unw_init_context(st->context, &mc_model_checker->process,
+      original_context) < 0) {
+      xbt_die("Could not initialise the libunwind context.");
+    }
+
+    st->stack_frames = MC_unwind_stack_frames(st->context);
     st->local_variables = MC_get_local_variables_values(st->stack_frames, current_stack->process_index);
     st->process_index = current_stack->process_index;
 
@@ -557,23 +595,27 @@ static void mc_free_snapshot_ignored_data_pvoid(void* data) {
 
 static void MC_snapshot_handle_ignore(mc_snapshot_t snapshot)
 {
+  xbt_assert(snapshot->process);
   snapshot->ignored_data = xbt_dynar_new(sizeof(s_mc_snapshot_ignored_data_t), mc_free_snapshot_ignored_data_pvoid);
 
   // Copy the memory:
   unsigned int cursor = 0;
   mc_checkpoint_ignore_region_t region;
-  xbt_dynar_foreach (mc_checkpoint_ignore, cursor, region) {
+  xbt_dynar_foreach (mc_model_checker->process.checkpoint_ignore, cursor, region) {
     s_mc_snapshot_ignored_data_t ignored_data;
     ignored_data.start = region->addr;
     ignored_data.size = region->size;
     ignored_data.data = malloc(region->size);
-    memcpy(ignored_data.data, region->addr, region->size);
+    // TODO, we should do this once per privatization segment:
+    MC_process_read(snapshot->process,
+      MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+      ignored_data.data, region->addr, region->size, MC_PROCESS_INDEX_DISABLED);
     xbt_dynar_push(snapshot->ignored_data, &ignored_data);
   }
 
   // Zero the memory:
-  xbt_dynar_foreach (mc_checkpoint_ignore, cursor, region) {
-    memset(region->addr, 0, region->size);
+  xbt_dynar_foreach (mc_model_checker->process.checkpoint_ignore, cursor, region) {
+    MC_process_clear_memory(snapshot->process, region->addr, region->size);
   }
 
 }
@@ -583,7 +625,8 @@ static void MC_snapshot_ignore_restore(mc_snapshot_t snapshot)
   unsigned int cursor = 0;
   s_mc_snapshot_ignored_data_t ignored_data;
   xbt_dynar_foreach (snapshot->ignored_data, cursor, ignored_data) {
-    memcpy(ignored_data.start, ignored_data.data, ignored_data.size);
+    MC_process_write(snapshot->process,
+      ignored_data.data, ignored_data.start, ignored_data.size);
   }
 }
 
@@ -606,17 +649,18 @@ int mc_important_snapshot(mc_snapshot_t snapshot)
   return false;
 }
 
-static void MC_get_current_fd(mc_snapshot_t snapshot){
+static void MC_get_current_fd(mc_snapshot_t snapshot)
+{
 
   snapshot->total_fd = 0;
 
   const size_t fd_dir_path_size = 20;
   char fd_dir_path[fd_dir_path_size];
   if (snprintf(fd_dir_path, fd_dir_path_size,
-    "/proc/%lli/fd", (long long int) getpid()) > fd_dir_path_size)
+    "/proc/%lli/fd", (long long int) snapshot->process->pid) > fd_dir_path_size)
     xbt_die("Unexpected buffer is too small for fd_dir_path");
 
-  DIR* fd_dir = opendir (fd_dir_path);
+  DIR* fd_dir = opendir(fd_dir_path);
   if (fd_dir == NULL)
     xbt_die("Cannot open directory '/proc/self/fd'\n");
 
@@ -631,7 +675,8 @@ static void MC_get_current_fd(mc_snapshot_t snapshot){
 
     const size_t source_size = 25;
     char source[25];
-    if (snprintf(source, source_size, "/proc/self/fd/%s", fd_number->d_name) > source_size)
+    if (snprintf(source, source_size, "/proc/%lli/fd/%s",
+        (long long int) snapshot->process->pid, fd_number->d_name) > source_size)
       xbt_die("Unexpected buffer is too small for fd %s", fd_number->d_name);
 
     const size_t link_size = 200;
@@ -658,6 +703,10 @@ static void MC_get_current_fd(mc_snapshot_t snapshot){
     if (strncmp(link, "pipe:", 5) == 0 || strncmp(link, "socket:", 7) == 0)
       continue;
 
+    // If dot_output enabled, do not handle the corresponding file
+    if (dot_output !=  NULL && strcmp(basename(link), _sg_mc_dot_output_file) == 0)
+      continue;
+
     // This is probably a shared memory used by lttng-ust:
     if(strncmp("/dev/shm/ust-shm-tmp-", link, 21)==0)
       continue;
@@ -677,26 +726,34 @@ static void MC_get_current_fd(mc_snapshot_t snapshot){
   closedir (fd_dir);
 }
 
+static s_mc_address_space_class_t mc_snapshot_class = {
+  .read = (void*) &MC_snapshot_read
+};
+
 mc_snapshot_t MC_take_snapshot(int num_state)
 {
+  mc_process_t mc_process = &mc_model_checker->process;
   mc_snapshot_t snapshot = xbt_new0(s_mc_snapshot_t, 1);
+  snapshot->process = mc_process;
+  snapshot->address_space.address_space_class = &mc_snapshot_class;
 
   snapshot->enabled_processes = xbt_dynar_new(sizeof(int), NULL);
+
   smx_process_t process;
-  xbt_swag_foreach(process, simix_global->process_list) {
-    xbt_dynar_push_as(snapshot->enabled_processes, int, (int)process->pid);
-  }
+  MC_EACH_SIMIX_PROCESS(process,
+    xbt_dynar_push_as(snapshot->enabled_processes, int, (int)process->pid));
 
   MC_snapshot_handle_ignore(snapshot);
 
-  MC_get_current_fd(snapshot);
+  if (_sg_mc_snapshot_fds)
+    MC_get_current_fd(snapshot);
 
   const bool use_soft_dirty = _sg_mc_sparse_checkpoint
     && _sg_mc_soft_dirty
-    && MC_process_is_self(&mc_model_checker->process);
+    && MC_process_is_self(mc_process);
 
   /* Save the std heap and the writable mapped pages of libsimgrid and binary */
-  MC_get_memory_regions(snapshot);
+  MC_get_memory_regions(mc_process, snapshot);
   if (use_soft_dirty)
     mc_softdirty_reset();
 
@@ -734,6 +791,7 @@ void MC_restore_snapshot_regions(mc_snapshot_t snapshot)
   }
 
 #ifdef HAVE_SMPI
+  // TODO, send a message to implement this in the MCed process
   if(snapshot->privatization_index >= 0) {
     // We just rewrote the global variables.
     // The privatisation segment SMPI thinks
@@ -749,6 +807,9 @@ void MC_restore_snapshot_regions(mc_snapshot_t snapshot)
 static inline
 void MC_restore_snapshot_fds(mc_snapshot_t snapshot)
 {
+  if (mc_mode == MC_MODE_SERVER)
+    xbt_die("FD snapshot not implemented in client/server mode.");
+
   int new_fd;
   size_t i;
   for(i=0; i < snapshot->total_fd; i++){
@@ -774,7 +835,8 @@ void MC_restore_snapshot(mc_snapshot_t snapshot)
     && MC_process_is_self(&mc_model_checker->process);
 
   MC_restore_snapshot_regions(snapshot);
-  MC_restore_snapshot_fds(snapshot);
+  if (_sg_mc_snapshot_fds)
+    MC_restore_snapshot_fds(snapshot);
   if (use_soft_dirty) {
     mc_softdirty_reset();
   }
@@ -782,14 +844,11 @@ void MC_restore_snapshot(mc_snapshot_t snapshot)
   if (use_soft_dirty) {
     mc_model_checker->parent_snapshot = snapshot;
   }
+
+  mc_model_checker->process.cache_flags = 0;
 }
 
 mc_snapshot_t simcall_HANDLER_mc_snapshot(smx_simcall_t simcall)
 {
   return MC_take_snapshot(1);
 }
-
-void *MC_snapshot(void)
-{
-  return simcall_mc_snapshot();
-}