Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Implement remote support for MC_ignore
[simgrid.git] / src / mc / mc_process.c
1 #include <assert.h>
2 #include <stddef.h>
3 #include <stdbool.h>
4 #include <stdint.h>
5 #include <errno.h>
6
7 #include <sys/types.h>
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <regex.h>
11 #include <sys/mman.h> // PROT_*
12
13 #include <pthread.h>
14
15 #include <libgen.h>
16
17 #include <libunwind.h>
18 #include <libunwind-ptrace.h>
19
20 #include "mc_process.h"
21 #include "mc_object_info.h"
22 #include "mc_address_space.h"
23 #include "mc_unw.h"
24 #include "mc_snapshot.h"
25 #include "mc_ignore.h"
26
27 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc,
28                                 "MC process information");
29
30 static void MC_process_init_memory_map_info(mc_process_t process);
31 static void MC_process_open_memory_file(mc_process_t process);
32
33 // ***** Destructor callbacks
34
35 // ***** mc_address_space methods for mc_process
36
37 static mc_process_t MC_process_get_process(mc_process_t p) {
38   return p;
39 }
40
41 static const s_mc_address_space_class_t mc_process_class = {
42   .read = (void*) &MC_process_read,
43   .get_process = (void*) MC_process_get_process
44 };
45
46 bool MC_is_process(mc_address_space_t p)
47 {
48   return p->address_space_class == &mc_process_class;
49 }
50
51 // ***** mc_process
52
53 void MC_process_init(mc_process_t process, pid_t pid, int sockfd)
54 {
55   process->address_space.address_space_class = &mc_process_class;
56   process->process_flags = MC_PROCESS_NO_FLAG;
57   process->socket = sockfd;
58   process->pid = pid;
59   if (pid==getpid())
60     process->process_flags |= MC_PROCESS_SELF_FLAG;
61   process->running = true;
62   process->status = 0;
63   process->memory_map = MC_get_memory_map(pid);
64   process->memory_file = -1;
65   process->cache_flags = 0;
66   process->heap = NULL;
67   process->heap_info = NULL;
68   MC_process_init_memory_map_info(process);
69   MC_process_open_memory_file(process);
70
71   // Read std_heap (is a struct mdesc*):
72   dw_variable_t std_heap_var = MC_process_find_variable_by_name(process, "std_heap");
73   if (!std_heap_var)
74     xbt_die("No heap information in the target process");
75   if(!std_heap_var->address)
76     xbt_die("No constant address for this variable");
77   MC_process_read(process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
78     &process->heap_address, std_heap_var->address, sizeof(struct mdesc*),
79     MC_PROCESS_INDEX_DISABLED);
80
81   process->checkpoint_ignore = MC_checkpoint_ignore_new();
82
83   process->unw_addr_space = unw_create_addr_space(&mc_unw_accessors  , __BYTE_ORDER);
84   if (process->process_flags & MC_PROCESS_SELF_FLAG) {
85     process->unw_underlying_addr_space = unw_local_addr_space;
86     process->unw_underlying_context = NULL;
87   } else {
88     process->unw_underlying_addr_space = unw_create_addr_space(&mc_unw_vmread_accessors, __BYTE_ORDER);
89     process->unw_underlying_context = _UPT_create(pid);
90   }
91 }
92
93 void MC_process_clear(mc_process_t process)
94 {
95   process->address_space.address_space_class = NULL;
96   process->process_flags = MC_PROCESS_NO_FLAG;
97   process->pid = 0;
98
99   MC_free_memory_map(process->memory_map);
100   process->memory_map = NULL;
101
102   process->maestro_stack_start = NULL;
103   process->maestro_stack_end = NULL;
104
105   xbt_dynar_free(&process->checkpoint_ignore);
106
107   size_t i;
108   for (i=0; i!=process->object_infos_size; ++i) {
109     MC_free_object_info(&process->object_infos[i]);
110   }
111   free(process->object_infos);
112   process->object_infos = NULL;
113   process->object_infos_size = 0;
114   if (process->memory_file >= 0) {
115     close(process->memory_file);
116   }
117
118   if (process->unw_underlying_addr_space != unw_local_addr_space) {
119     unw_destroy_addr_space(process->unw_underlying_addr_space);
120     _UPT_destroy(process->unw_underlying_context);
121   }
122   process->unw_underlying_context = NULL;
123   process->unw_underlying_addr_space = NULL;
124
125   unw_destroy_addr_space(process->unw_addr_space);
126   process->unw_addr_space = NULL;
127
128   process->cache_flags = 0;
129
130   free(process->heap);
131   process->heap = NULL;
132
133   free(process->heap_info);
134   process->heap_info = NULL;
135 }
136
137 void MC_process_refresh_heap(mc_process_t process)
138 {
139   assert(!MC_process_is_self(process));
140   // Read/dereference/refresh the std_heap pointer:
141   if (!process->heap) {
142     xbt_mheap_t oldheap  = mmalloc_get_current_heap();
143     MC_SET_MC_HEAP;
144     process->heap = malloc(sizeof(struct mdesc));
145     mmalloc_set_current_heap(oldheap);
146   }
147   MC_process_read(process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
148     process->heap, process->heap_address, sizeof(struct mdesc),
149     MC_PROCESS_INDEX_DISABLED
150     );
151 }
152
153 void MC_process_refresh_malloc_info(mc_process_t process)
154 {
155   assert(!MC_process_is_self(process));
156   if (!process->cache_flags & MC_PROCESS_CACHE_FLAG_HEAP)
157     MC_process_refresh_heap(process);
158   // Refresh process->heapinfo:
159   size_t malloc_info_bytesize = process->heap->heaplimit * sizeof(malloc_info);
160
161   xbt_mheap_t oldheap  = mmalloc_get_current_heap();
162   MC_SET_MC_HEAP;
163   process->heap_info = (malloc_info*) realloc(process->heap_info,
164     malloc_info_bytesize);
165   mmalloc_set_current_heap(oldheap);
166
167   MC_process_read(process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
168     process->heap_info,
169     process->heap->heapinfo, malloc_info_bytesize,
170     MC_PROCESS_INDEX_DISABLED);
171 }
172
173 #define SO_RE "\\.so[\\.0-9]*$"
174 #define VERSION_RE "-[\\.0-9]*$"
175
176 const char* FILTERED_LIBS[] = {
177   "libstdc++",
178   "libc++",
179   "libm",
180   "libgcc_s",
181   "libpthread",
182   "libunwind",
183   "libunwind-x86_64",
184   "libunwind-x86",
185   "libunwind-ptrace",
186   "libdw",
187   "libdl",
188   "librt",
189   "liblzma",
190   "libelf",
191   "libbz2",
192   "libz",
193   "libelf",
194   "libc",
195   "ld"
196 };
197
198 static bool MC_is_simgrid_lib(const char* libname)
199 {
200   return !strcmp(libname, "libsimgrid");
201 }
202
203 static bool MC_is_filtered_lib(const char* libname)
204 {
205   const size_t n = sizeof(FILTERED_LIBS) / sizeof(const char*);
206   size_t i;
207   for (i=0; i!=n; ++i)
208     if (strcmp(libname, FILTERED_LIBS[i])==0)
209       return true;
210   return false;
211 }
212
213 struct s_mc_memory_map_re {
214   regex_t so_re;
215   regex_t version_re;
216 };
217
218 static char* MC_get_lib_name(const char* pathname, struct s_mc_memory_map_re* res) {
219   const char* map_basename = basename((char*) pathname);
220
221   regmatch_t match;
222   if(regexec(&res->so_re, map_basename, 1, &match, 0))
223     return NULL;
224
225   char* libname = strndup(map_basename, match.rm_so);
226
227   // Strip the version suffix:
228   if(libname && !regexec(&res->version_re, libname, 1, &match, 0)) {
229     char* temp = libname;
230     libname = strndup(temp, match.rm_so);
231     free(temp);
232   }
233
234   return libname;
235 }
236
237 /** @brief Finds the range of the different memory segments and binary paths */
238 static void MC_process_init_memory_map_info(mc_process_t process)
239 {
240   XBT_DEBUG("Get debug information ...");
241   process->maestro_stack_start = NULL;
242   process->maestro_stack_end = NULL;
243   process->object_infos = NULL;
244   process->object_infos_size = 0;
245   process->binary_info = NULL;
246   process->libsimgrid_info = NULL;
247
248   struct s_mc_memory_map_re res;
249
250   if(regcomp(&res.so_re, SO_RE, 0) || regcomp(&res.version_re, VERSION_RE, 0))
251     xbt_die(".so regexp did not compile");
252
253   memory_map_t maps = process->memory_map;
254
255   const char* current_name = NULL;
256
257   size_t i = 0;
258   for (i=0; i < maps->mapsize; i++) {
259     map_region_t reg = &(maps->regions[i]);
260     const char* pathname = maps->regions[i].pathname;
261
262     // Nothing to do
263     if (maps->regions[i].pathname == NULL) {
264       current_name = NULL;
265       continue;
266     }
267
268     // [stack], [vvar], [vsyscall], [vdso] ...
269     if (pathname[0] == '[') {
270       if ((reg->prot & PROT_WRITE) && !memcmp(pathname, "[stack]", 7)) {
271         process->maestro_stack_start = reg->start_addr;
272         process->maestro_stack_end = reg->end_addr;
273       }
274       current_name = NULL;
275       continue;
276     }
277
278     if (current_name && strcmp(current_name, pathname)==0)
279       continue;
280
281     current_name = pathname;
282     if (!(reg->prot & PROT_READ) && (reg->prot & PROT_EXEC))
283       continue;
284
285     const bool is_executable = !i;
286     char* libname = NULL;
287     if (!is_executable) {
288       libname = MC_get_lib_name(pathname, &res);
289       if(!libname)
290         continue;
291       if (MC_is_filtered_lib(libname)) {
292         free(libname);
293         continue;
294       }
295     }
296
297     mc_object_info_t info =
298       MC_find_object_info(process->memory_map, pathname, is_executable);
299     process->object_infos = (mc_object_info_t*) realloc(process->object_infos,
300       (process->object_infos_size+1) * sizeof(mc_object_info_t*));
301     process->object_infos[process->object_infos_size] = info;
302     process->object_infos_size++;
303     if (is_executable)
304       process->binary_info = info;
305     else if (libname && MC_is_simgrid_lib(libname))
306       process->libsimgrid_info = info;
307     free(libname);
308   }
309
310   regfree(&res.so_re);
311   regfree(&res.version_re);
312
313   // Resolve time (including accress differents objects):
314   for (i=0; i!=process->object_infos_size; ++i)
315     MC_post_process_object_info(process, process->object_infos[i]);
316
317   xbt_assert(process->maestro_stack_start, "Did not find maestro_stack_start");
318   xbt_assert(process->maestro_stack_end, "Did not find maestro_stack_end");
319
320   XBT_DEBUG("Get debug information done !");
321 }
322
323 mc_object_info_t MC_process_find_object_info(mc_process_t process, const void *addr)
324 {
325   size_t i;
326   for (i = 0; i != process->object_infos_size; ++i) {
327     if (addr >= (void *) process->object_infos[i]->start
328         && addr <= (void *) process->object_infos[i]->end) {
329       return process->object_infos[i];
330     }
331   }
332   return NULL;
333 }
334
335 mc_object_info_t MC_process_find_object_info_exec(mc_process_t process, const void *addr)
336 {
337   size_t i;
338   for (i = 0; i != process->object_infos_size; ++i) {
339     if (addr >= (void *) process->object_infos[i]->start_exec
340         && addr <= (void *) process->object_infos[i]->end_exec) {
341       return process->object_infos[i];
342     }
343   }
344   return NULL;
345 }
346
347 mc_object_info_t MC_process_find_object_info_rw(mc_process_t process, const void *addr)
348 {
349   size_t i;
350   for (i = 0; i != process->object_infos_size; ++i) {
351     if (addr >= (void *) process->object_infos[i]->start_rw
352         && addr <= (void *) process->object_infos[i]->end_rw) {
353       return process->object_infos[i];
354     }
355   }
356   return NULL;
357 }
358
359 // Functions, variables…
360
361 dw_frame_t MC_process_find_function(mc_process_t process, const void *ip)
362 {
363   mc_object_info_t info = MC_process_find_object_info_exec(process, ip);
364   if (info == NULL)
365     return NULL;
366   else
367     return MC_file_object_info_find_function(info, ip);
368 }
369
370 dw_variable_t MC_process_find_variable_by_name(mc_process_t process, const char* name)
371 {
372   const size_t n = process->object_infos_size;
373   size_t i;
374   for (i=0; i!=n; ++i) {
375     mc_object_info_t info =process->object_infos[i];
376     dw_variable_t var = MC_file_object_info_find_variable_by_name(info, name);
377     if (var)
378       return var;
379   }
380   return NULL;
381 }
382
383 // ***** Memory access
384
385 int MC_process_vm_open(pid_t pid, int flags)
386 {
387   const size_t buffer_size = 30;
388   char buffer[buffer_size];
389   int res = snprintf(buffer, buffer_size, "/proc/%lli/mem", (long long) pid);
390   if (res < 0 || res >= buffer_size) {
391     errno = ENAMETOOLONG;
392     return -1;
393   }
394   return open(buffer, flags);
395 }
396
397 static void MC_process_open_memory_file(mc_process_t process)
398 {
399   if (MC_process_is_self(process) || process->memory_file >= 0)
400     return;
401
402   int fd = MC_process_vm_open(process->pid, O_RDWR);
403   if (fd<0)
404     xbt_die("Could not open file for process virtual address space");
405   process->memory_file = fd;
406 }
407
408 static ssize_t pread_whole(int fd, void *buf, size_t count, off_t offset)
409 {
410   char* buffer = (char*) buf;
411   ssize_t real_count = count;
412   while (count) {
413     ssize_t res = pread(fd, buffer, count, offset);
414     if (res > 0) {
415       count  -= res;
416       buffer += res;
417       offset += res;
418     } else if (res==0) {
419       return -1;
420     } else if (errno != EINTR) {
421       return -1;
422     }
423   }
424   return real_count;
425 }
426
427 static ssize_t pwrite_whole(int fd, const void *buf, size_t count, off_t offset)
428 {
429   const char* buffer = (const char*) buf;
430   ssize_t real_count = count;
431   while (count) {
432     ssize_t res = pwrite(fd, buffer, count, offset);
433     if (res > 0) {
434       count  -= res;
435       buffer += res;
436       offset += res;
437     } else if (res==0) {
438       return -1;
439     } else if (errno != EINTR) {
440       return -1;
441     }
442   }
443   return real_count;
444 }
445
446 const void* MC_process_read(mc_process_t process, e_adress_space_read_flags_t flags,
447   void* local, const void* remote, size_t len,
448   int process_index)
449 {
450   if (process_index != MC_PROCESS_INDEX_DISABLED) {
451     mc_object_info_t info = MC_process_find_object_info_rw(process, remote);
452     // Segment overlap is not handled.
453     if (MC_object_info_is_privatized(info)) {
454       if (process_index < 0)
455         xbt_die("Missing process index");
456       // Address translation in the privaization segment:
457       size_t offset = (const char*) remote - info->start_rw;
458       remote = (const char*) remote - offset;
459     }
460   }
461
462   if (MC_process_is_self(process)) {
463     if (flags & MC_ADDRESS_SPACE_READ_FLAGS_LAZY)
464       return remote;
465     else {
466       memcpy(local, remote, len);
467       return local;
468     }
469   } else {
470     if (pread_whole(process->memory_file, local, len, (off_t) remote) < 0)
471       xbt_die("Read from process %lli failed", (long long) process->pid);
472     return local;
473   }
474 }
475
476 void MC_process_write(mc_process_t process, const void* local, void* remote, size_t len)
477 {
478   if (MC_process_is_self(process)) {
479     memcpy(remote, local, len);
480   } else {
481     if (pwrite_whole(process->memory_file, local, len, (off_t) remote) < 0)
482       xbt_die("Write to process %lli failed", (long long) process->pid);
483   }
484 }
485
486 static pthread_once_t zero_buffer_flag = PTHREAD_ONCE_INIT;
487 static const void* zero_buffer;
488 static const int zero_buffer_size = 10 * 4096;
489
490 static void MC_zero_buffer_init(void)
491 {
492   int fd = open("/dev/zero", O_RDONLY);
493   if (fd<0)
494     xbt_die("Could not open /dev/zero");
495   zero_buffer = mmap(NULL, zero_buffer_size, PROT_READ, MAP_SHARED, fd, 0);
496   if (zero_buffer == MAP_FAILED)
497     xbt_die("Could not map the zero buffer");
498   close(fd);
499 }
500
501 void MC_process_clear_memory(mc_process_t process, void* remote, size_t len)
502 {
503   if (MC_process_is_self(process)) {
504     memset(remote, 0, len);
505   } else {
506     pthread_once(&zero_buffer_flag, MC_zero_buffer_init);
507     while (len) {
508       size_t s = len > zero_buffer_size ? zero_buffer_size : len;
509       MC_process_write(process, zero_buffer, remote, s);
510       remote = (char*) remote + s;
511       len -= s;
512     }
513   }
514 }