Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
7f3629145b3e904610155a992ef65ca9061e4198
[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 static inline __attribute__((always_inline))
29 void* mc_translate_address_region(uintptr_t addr, mc_mem_region_t region)
30 {
31     size_t pageno = mc_page_number(region->start_addr, (void*) addr);
32     size_t snapshot_pageno = region->page_numbers[pageno];
33     const void* snapshot_page = mc_page_store_get_page(mc_model_checker->pages, snapshot_pageno);
34     return (char*) snapshot_page + mc_page_offset((void*) addr);
35 }
36
37 /** \brief Translate a pointer from process address space to snapshot address space
38  *
39  *  The address space contains snapshot of the main/application memory:
40  *  this function finds the address in a given snaphot for a given
41  *  real/application address.
42  *
43  *  For read only memory regions and other regions which are not int the
44  *  snapshot, the address is not changed.
45  *
46  *  \param addr     Application address
47  *  \param snapshot The snapshot of interest (if NULL no translation is done)
48  *  \return         Translated address in the snapshot address space
49  * */
50 static inline __attribute__((always_inline))
51 void* mc_translate_address(uintptr_t addr, mc_snapshot_t snapshot)
52 {
53
54   // If not in a process state/clone:
55   if (!snapshot) {
56     return (uintptr_t *) addr;
57   }
58
59   mc_mem_region_t region = mc_get_snapshot_region((void*) addr, snapshot);
60
61   xbt_assert(mc_region_contain(region, (void*) addr), "Trying to read out of the region boundary.");
62
63   if (!region) {
64     return (void *) addr;
65   }
66
67   // Flat snapshot:
68   else if (region->data) {
69     uintptr_t offset = addr - (uintptr_t) region->start_addr;
70     return (void *) ((uintptr_t) region->data + offset);
71   }
72
73   // Per-page snapshot:
74   else if (region->page_numbers) {
75     return mc_translate_address_region(addr, region);
76   }
77
78   else {
79     xbt_die("No data for this memory region");
80   }
81 }
82
83 /** @brief Read memory from a snapshot region broken across fragmented pages
84  *
85  *  @param addr    Process (non-snapshot) address of the data
86  *  @param region  Snapshot memory region where the data is located
87  *  @param target  Buffer to store the value
88  *  @param size    Size of the data to read in bytes
89  *  @return Pointer where the data is located (target buffer of original location)
90  */
91 static void* mc_snapshot_read_fragmented(void* addr, mc_mem_region_t region, void* target, size_t size)
92 {
93   void* end = (char*) addr + size - 1;
94   size_t page_end = mc_page_number(NULL, end);
95   void* dest = target;
96
97   // Read each page:
98   while (mc_page_number(NULL, addr) != page_end) {
99     void* snapshot_addr = mc_translate_address_region((uintptr_t) addr, region);
100     void* next_page = mc_page_from_number(NULL, mc_page_number(NULL, addr) + 1);
101     size_t readable = (char*) next_page - (char*) addr;
102     memcpy(dest, snapshot_addr, readable);
103     addr = (char*) addr + readable;
104     dest = (char*) dest + readable;
105     size -= readable;
106   }
107
108   // Read the end:
109   void* snapshot_addr = mc_translate_address_region((uintptr_t)addr, region);
110   memcpy(dest, snapshot_addr, size);
111
112   return target;
113 }
114
115 /** @brief Read memory from a snapshot region
116  *
117  *  @param addr    Process (non-snapshot) address of the data
118  *  @param region  Snapshot memory region where the data is located
119  *  @param target  Buffer to store the value
120  *  @param size    Size of the data to read in bytes
121  *  @return Pointer where the data is located (target buffer of original location)
122  */
123 void* mc_snapshot_read_region(void* addr, mc_mem_region_t region, void* target, size_t size)
124 {
125   uintptr_t offset = (uintptr_t) addr - (uintptr_t) region->start_addr;
126
127   xbt_assert(addr >= region->start_addr && (char*) addr+size < (char*)region->start_addr+region->size,
128     "Trying to read out of the region boundary.");
129
130   // Linear memory region:
131   if (region->data) {
132     return (void*) ((uintptr_t) region->data + offset);
133   }
134
135   // Fragmented memory region:
136   else if (region->page_numbers) {
137     void* end = (char*) addr + size - 1;
138     if( mc_same_page(addr, end) ) {
139       // The memory is contained in a single page:
140       return mc_translate_address_region((uintptr_t) addr, region);
141     } else {
142       // The memory spans several pages:
143       return mc_snapshot_read_fragmented(addr, region, target, size);
144     }
145   }
146
147   else {
148     xbt_die("No data available for this region");
149   }
150 }
151
152 /** @brief Read memory from a snapshot
153  *
154  *  @param addr     Process (non-snapshot) address of the data
155  *  @param snapshot Snapshot (or NULL is no snapshot)
156  *  @param target   Buffer to store the value
157  *  @param size     Size of the data to read in bytes
158  *  @return Pointer where the data is located (target buffer of original location)
159  */
160 void* mc_snapshot_read(void* addr, mc_snapshot_t snapshot, void* target, size_t size)
161 {
162   if (snapshot) {
163     mc_mem_region_t region = mc_get_snapshot_region(addr, snapshot);
164     return mc_snapshot_read_region(addr, region, target, size);
165   } else {
166     return addr;
167   }
168 }
169
170 /** Compare memory between snapshots (with known regions)
171  *
172  * @param addr1 Address in the first snapshot
173  * @param snapshot2 Region of the address in the first snapshot
174  * @param addr2 Address in the second snapshot
175  * @param snapshot2 Region of the address in the second snapshot
176  * @return same as memcmp
177  * */
178 int mc_snapshot_region_memcp(
179   void* addr1, mc_mem_region_t region1,
180   void* addr2, mc_mem_region_t region2, size_t size)
181 {
182   // Using alloca() for large allocations may trigger stack overflow:
183   // use malloc if the buffer is too big.
184
185   bool stack_alloc = size < 64;
186   void* buffer = stack_alloc ? alloca(2*size) : malloc(2*size);
187   void* buffer1 = mc_snapshot_read_region(addr1, region1, buffer, size);
188   void* buffer2 = mc_snapshot_read_region(addr2, region2, (char*) buffer + size, size);
189   int res;
190   if (buffer1 == buffer2) {
191     res =  0;
192   } else {
193     res = memcmp(buffer1, buffer2, size);
194   }
195   if (!stack_alloc) {
196     free(buffer);
197   }
198   return res;
199 }
200
201 /** Compare memory between snapshots
202  *
203  * @param addr1 Address in the first snapshot
204  * @param snapshot1 First snapshot
205  * @param addr2 Address in the second snapshot
206  * @param snapshot2 Second snapshot
207  * @return same as memcmp
208  * */
209 int mc_snapshot_memcp(
210   void* addr1, mc_snapshot_t snapshot1,
211   void* addr2, mc_snapshot_t snapshot2, size_t size)
212 {
213   mc_mem_region_t region1 = mc_get_snapshot_region(addr1, snapshot1);
214   mc_mem_region_t region2 = mc_get_snapshot_region(addr2, snapshot2);
215   return mc_snapshot_region_memcp(addr1, region1, addr2, region2, size);
216 }