* under the terms of the license (GNU LGPL) which comes with this package. */
#define _GNU_SOURCE
-#define UNW_LOCAL_ONLY
#include <unistd.h>
#include "../simix/smx_private.h"
-#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <libelf.h>
#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");
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)
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;
}
}
-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;
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);
}
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);
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)
{
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);
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
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, ¤t_variable->locations,
current_variable->object_info,
&(stack_frame->unw_cursor),
}
}
-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 =
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");
&& !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");
}
}
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;
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);
}
}
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);
}
}
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");
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;
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;
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();
}
#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
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++){
&& 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();
}
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();
-}