Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Forgot to decrease the page refcounts when freeing a snapshot
[simgrid.git] / src / mc / mc_snapshot.c
1 /* Copyright (c) 2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <stdbool.h>
8
9 #include "mc_private.h"
10 #include "mc_mmu.h"
11 #include "mc_page_store.h"
12
13 mc_mem_region_t mc_get_snapshot_region(void* addr, mc_snapshot_t snapshot)
14 {
15   for (size_t i = 0; i != NB_REGIONS; ++i) {
16     mc_mem_region_t region = snapshot->regions[i];
17     void* start = region->start_addr;
18     void* end = (char*) start + region->size;
19
20     if (addr >= start && addr < end) {
21       return region;
22     }
23   }
24
25   return NULL;
26 }
27
28 void* mc_translate_address_region(uintptr_t addr, mc_mem_region_t region)
29 {
30   xbt_assert(mc_region_contain(region, (void*) addr), "Trying to read out of the region boundary.");
31
32   if (!region) {
33     return (void *) addr;
34   }
35
36   // Flat snapshot:
37   else if (region->data) {
38     uintptr_t offset = addr - (uintptr_t) region->start_addr;
39     return (void *) ((uintptr_t) region->data + offset);
40   }
41
42   // Per-page snapshot:
43   else if (region->page_numbers) {
44     size_t pageno = mc_page_number(region->start_addr, (void*) addr);
45     size_t snapshot_pageno = region->page_numbers[pageno];
46     const void* snapshot_page = mc_page_store_get_page(mc_model_checker->pages, snapshot_pageno);
47     return (char*) snapshot_page + mc_page_offset((void*) addr);
48   }
49
50   else {
51     xbt_die("No data for this memory region");
52   }
53 }
54
55 void* mc_translate_address(uintptr_t addr, mc_snapshot_t snapshot)
56 {
57
58   // If not in a process state/clone:
59   if (!snapshot) {
60     return (uintptr_t *) addr;
61   }
62
63   mc_mem_region_t region = mc_get_snapshot_region((void*) addr, snapshot);
64   return mc_translate_address_region(addr, region);
65 }
66
67 /** @brief Read memory from a snapshot region broken across fragmented pages
68  *
69  *  @param addr    Process (non-snapshot) address of the data
70  *  @param region  Snapshot memory region where the data is located
71  *  @param target  Buffer to store the value
72  *  @param size    Size of the data to read in bytes
73  *  @return Pointer where the data is located (target buffer of original location)
74  */
75 static void* mc_snapshot_read_fragmented(void* addr, mc_mem_region_t region, void* target, size_t size)
76 {
77   void* end = (char*) addr + size - 1;
78   size_t page_end = mc_page_number(NULL, end);
79   void* dest = target;
80
81   // Read each page:
82   while (mc_page_number(NULL, addr) != page_end) {
83     void* snapshot_addr = mc_translate_address_region((uintptr_t) addr, region);
84     void* next_page = mc_page_from_number(NULL, mc_page_number(NULL, addr) + 1);
85     size_t readable = (char*) next_page - (char*) addr;
86     memcpy(dest, snapshot_addr, readable);
87     addr = (char*) addr + readable;
88     dest = (char*) dest + readable;
89     size -= readable;
90   }
91
92   // Read the end:
93   void* snapshot_addr = mc_translate_address_region((uintptr_t)addr, region);
94   memcpy(dest, snapshot_addr, size);
95
96   return target;
97 }
98
99 /** @brief Read memory from a snapshot region
100  *
101  *  @param addr    Process (non-snapshot) address of the data
102  *  @param region  Snapshot memory region where the data is located
103  *  @param target  Buffer to store the value
104  *  @param size    Size of the data to read in bytes
105  *  @return Pointer where the data is located (target buffer of original location)
106  */
107 void* mc_snapshot_read_region(void* addr, mc_mem_region_t region, void* target, size_t size)
108 {
109   uintptr_t offset = (uintptr_t) addr - (uintptr_t) region->start_addr;
110
111   xbt_assert(addr >= region->start_addr && (char*) addr+size < (char*)region->start_addr+region->size,
112     "Trying to read out of the region boundary.");
113
114   // Linear memory region:
115   if (region->data) {
116     return (void*) ((uintptr_t) region->data + offset);
117   }
118
119   // Fragmented memory region:
120   else if (region->page_numbers) {
121     void* end = (char*) addr + size - 1;
122     if( mc_same_page(addr, end) ) {
123       // The memory is contained in a single page:
124       return mc_translate_address_region((uintptr_t) addr, region);
125     } else {
126       // The memory spans several pages:
127       return mc_snapshot_read_fragmented(addr, region, target, size);
128     }
129   }
130
131   else {
132     xbt_die("No data available for this region");
133   }
134 }
135
136 /** @brief Read memory from a snapshot
137  *
138  *  @param addr     Process (non-snapshot) address of the data
139  *  @param snapshot Snapshot (or NULL is no snapshot)
140  *  @param target   Buffer to store the value
141  *  @param size     Size of the data to read in bytes
142  *  @return Pointer where the data is located (target buffer of original location)
143  */
144 void* mc_snapshot_read(void* addr, mc_snapshot_t snapshot, void* target, size_t size)
145 {
146   if (snapshot) {
147     mc_mem_region_t region = mc_get_snapshot_region(addr, snapshot);
148     return mc_snapshot_read_region(addr, region, target, size);
149   } else {
150     return addr;
151   }
152 }
153
154 /** Compare memory between snapshots (with known regions)
155  *
156  * @param addr1 Address in the first snapshot
157  * @param snapshot2 Region of the address in the first snapshot
158  * @param addr2 Address in the second snapshot
159  * @param snapshot2 Region of the address in the second snapshot
160  * @return same as memcmp
161  * */
162 int mc_snapshot_region_memcp(
163   void* addr1, mc_mem_region_t region1,
164   void* addr2, mc_mem_region_t region2, size_t size)
165 {
166   // Using alloca() for large allocations may trigger stack overflow:
167   // use malloc if the buffer is too big.
168
169   bool stack_alloc = size < 64;
170   void* buffer = stack_alloc ? alloca(2*size) : malloc(2*size);
171   void* buffer1 = mc_snapshot_read_region(addr1, region1, buffer, size);
172   void* buffer2 = mc_snapshot_read_region(addr2, region2, (char*) buffer + size, size);
173   int res;
174   if (buffer1 == buffer2) {
175     res =  0;
176   } else {
177     res = memcmp(buffer1, buffer2, size);
178   }
179   if (!stack_alloc) {
180     free(buffer);
181   }
182   return res;
183 }
184
185 /** Compare memory between snapshots
186  *
187  * @param addr1 Address in the first snapshot
188  * @param snapshot1 First snapshot
189  * @param addr2 Address in the second snapshot
190  * @param snapshot2 Second snapshot
191  * @return same as memcmp
192  * */
193 int mc_snapshot_memcp(
194   void* addr1, mc_snapshot_t snapshot1,
195   void* addr2, mc_snapshot_t snapshot2, size_t size)
196 {
197   mc_mem_region_t region1 = mc_get_snapshot_region(addr1, snapshot1);
198   mc_mem_region_t region2 = mc_get_snapshot_region(addr2, snapshot2);
199   return mc_snapshot_region_memcp(addr1, region1, addr2, region2, size);
200 }