Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Fix build with mc
[simgrid.git] / src / mc / Process.cpp
1 /* Copyright (c) 2014-2015. 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 #define _FILE_OFFSET_BITS 64
8
9 #include <assert.h>
10 #include <stddef.h>
11 #include <stdbool.h>
12 #include <stdint.h>
13 #include <errno.h>
14
15 #include <sys/types.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <regex.h>
19 #include <sys/mman.h> // PROT_*
20
21 #include <pthread.h>
22
23 #include <libgen.h>
24
25 #include <libunwind.h>
26 #include <libunwind-ptrace.h>
27
28 #include <xbt/mmalloc.h>
29
30 #include "src/mc/mc_object_info.h"
31 #include "src/mc/mc_unw.h"
32 #include "src/mc/mc_snapshot.h"
33 #include "src/mc/mc_ignore.h"
34 #include "src/mc/mc_smx.h"
35
36 #include "src/mc/Process.hpp"
37 #include "src/mc/AddressSpace.hpp"
38 #include "src/mc/ObjectInformation.hpp"
39 #include "src/mc/Variable.hpp"
40
41 using simgrid::mc::remote;
42
43 extern "C" {
44
45 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc,
46                                 "MC process information");
47
48 // ***** Helper stuff
49
50 #define SO_RE "\\.so[\\.0-9]*$"
51 #define VERSION_RE "-[\\.0-9-]*$"
52
53 static const char *const FILTERED_LIBS[] = {
54   "ld",
55   "libbz2",
56   "libboost_chrono",
57   "libboost_context",
58   "libboost_system",
59   "libboost_thread",
60   "libc",
61   "libc++",
62   "libcdt",
63   "libcgraph",
64   "libdl",
65   "libdw",
66   "libelf",
67   "libgcc_s",
68   "liblua5.1",
69   "liblua5.3",
70   "liblzma",
71   "libm",
72   "libpthread",
73   "librt",
74   "libsigc",
75   "libstdc++",
76   "libunwind",
77   "libunwind-x86_64",
78   "libunwind-x86",
79   "libunwind-ptrace",
80   "libz"
81 };
82
83 static bool MC_is_simgrid_lib(const char* libname)
84 {
85   return !strcmp(libname, "libsimgrid");
86 }
87
88 static bool MC_is_filtered_lib(const char* libname)
89 {
90   for (const char* filtered_lib : FILTERED_LIBS)
91     if (strcmp(libname, filtered_lib)==0)
92       return true;
93   return false;
94 }
95
96 struct s_mc_memory_map_re {
97   regex_t so_re;
98   regex_t version_re;
99 };
100
101 static char* MC_get_lib_name(const char* pathname, struct s_mc_memory_map_re* res)
102 {
103   const char* map_basename = xbt_basename((char*) pathname);
104
105   regmatch_t match;
106   if(regexec(&res->so_re, map_basename, 1, &match, 0))
107     return NULL;
108
109   char* libname = strndup(map_basename, match.rm_so);
110
111   // Strip the version suffix:
112   if(libname && !regexec(&res->version_re, libname, 1, &match, 0)) {
113     char* temp = libname;
114     libname = strndup(temp, match.rm_so);
115     free(temp);
116   }
117
118   return libname;
119 }
120
121 static ssize_t pread_whole(int fd, void *buf, size_t count, std::uint64_t offset)
122 {
123   char* buffer = (char*) buf;
124   ssize_t real_count = count;
125   while (count) {
126     ssize_t res = pread(fd, buffer, count, (std::int64_t) offset);
127     if (res > 0) {
128       count  -= res;
129       buffer += res;
130       offset += res;
131     } else if (res==0) {
132       return -1;
133     } else if (errno != EINTR) {
134       perror("pread_whole");
135       return -1;
136     }
137   }
138   return real_count;
139 }
140
141 static ssize_t pwrite_whole(int fd, const void *buf, size_t count, off_t offset)
142 {
143   const char* buffer = (const char*) buf;
144   ssize_t real_count = count;
145   while (count) {
146     ssize_t res = pwrite(fd, buffer, count, offset);
147     if (res > 0) {
148       count  -= res;
149       buffer += res;
150       offset += res;
151     } else if (res==0) {
152       return -1;
153     } else if (errno != EINTR) {
154       return -1;
155     }
156   }
157   return real_count;
158 }
159
160 static pthread_once_t zero_buffer_flag = PTHREAD_ONCE_INIT;
161 static const void* zero_buffer;
162 static const size_t zero_buffer_size = 10 * 4096;
163
164 static void MC_zero_buffer_init(void)
165 {
166   int fd = open("/dev/zero", O_RDONLY);
167   if (fd<0)
168     xbt_die("Could not open /dev/zero");
169   zero_buffer = mmap(NULL, zero_buffer_size, PROT_READ, MAP_SHARED, fd, 0);
170   if (zero_buffer == MAP_FAILED)
171     xbt_die("Could not map the zero buffer");
172   close(fd);
173 }
174
175 static
176 int open_process_file(pid_t pid, const char* file, int flags)
177 {
178   char buff[50];
179   snprintf(buff, sizeof(buff), "/proc/%li/%s", (long) pid, file);
180   return open(buff, flags);
181 }
182
183 }
184
185 namespace simgrid {
186 namespace mc {
187
188 int open_vm(pid_t pid, int flags)
189 {
190   const size_t buffer_size = 30;
191   char buffer[buffer_size];
192   int res = snprintf(buffer, buffer_size, "/proc/%lli/mem", (long long) pid);
193   if (res < 0 || (size_t) res >= buffer_size) {
194     errno = ENAMETOOLONG;
195     return -1;
196   }
197   return open(buffer, flags);
198 }
199
200   
201 }
202 }
203
204 // ***** Process
205
206 namespace simgrid {
207 namespace mc {
208
209 Process::Process(pid_t pid, int sockfd) :
210    AddressSpace(this),pid_(pid), socket_(sockfd), running_(true)
211 {}
212
213 void Process::init()
214 {
215   this->memory_map_ = simgrid::xbt::get_memory_map(this->pid_);
216   this->init_memory_map_info();
217
218   int fd = open_vm(this->pid_, O_RDWR);
219   if (fd<0)
220     xbt_die("Could not open file for process virtual address space");
221   this->memory_file = fd;
222
223   // Read std_heap (is a struct mdesc*):
224   simgrid::mc::Variable* std_heap_var = this->find_variable("__mmalloc_default_mdp");
225   if (!std_heap_var)
226     xbt_die("No heap information in the target process");
227   if(!std_heap_var->address)
228     xbt_die("No constant address for this variable");
229   this->read_bytes(&this->heap_address, sizeof(struct mdesc*),
230     remote(std_heap_var->address),
231     simgrid::mc::ProcessIndexDisabled);
232
233   this->smx_process_infos = MC_smx_process_info_list_new();
234   this->smx_old_process_infos = MC_smx_process_info_list_new();
235   this->unw_addr_space = unw_create_addr_space(&mc_unw_accessors  , __BYTE_ORDER);
236   this->unw_underlying_addr_space = unw_create_addr_space(&mc_unw_vmread_accessors, __BYTE_ORDER);
237   this->unw_underlying_context = _UPT_create(this->pid_);
238 }
239
240 Process::~Process()
241 {
242   if (this->socket_ >= 0 && close(this->socket_) < 0)
243     xbt_die("Could not close communication socket");
244
245   this->maestro_stack_start_ = nullptr;
246   this->maestro_stack_end_ = nullptr;
247
248   xbt_dynar_free(&this->smx_process_infos);
249   xbt_dynar_free(&this->smx_old_process_infos);
250
251   if (this->memory_file >= 0) {
252     close(this->memory_file);
253   }
254
255   if (this->unw_underlying_addr_space != unw_local_addr_space) {
256     unw_destroy_addr_space(this->unw_underlying_addr_space);
257     _UPT_destroy(this->unw_underlying_context);
258   }
259   this->unw_underlying_context = NULL;
260   this->unw_underlying_addr_space = NULL;
261
262   unw_destroy_addr_space(this->unw_addr_space);
263   this->unw_addr_space = NULL;
264
265   this->cache_flags = MC_PROCESS_CACHE_FLAG_NONE;
266
267   if (this->clear_refs_fd_ >= 0)
268     close(this->clear_refs_fd_);
269   if (this->pagemap_fd_ >= 0)
270     close(this->pagemap_fd_);
271 }
272
273 /** Refresh the information about the process
274  *
275  *  Do not use direclty, this is used by the getters when appropriate
276  *  in order to have fresh data.
277  */
278 void Process::refresh_heap()
279 {
280   xbt_assert(mc_mode == MC_MODE_SERVER);
281   // Read/dereference/refresh the std_heap pointer:
282   if (!this->heap)
283     this->heap = std::unique_ptr<s_xbt_mheap_t>(new s_xbt_mheap_t());
284   this->read_bytes(this->heap.get(), sizeof(struct mdesc),
285     remote(this->heap_address), simgrid::mc::ProcessIndexDisabled);
286   this->cache_flags |= MC_PROCESS_CACHE_FLAG_HEAP;
287 }
288
289 /** Refresh the information about the process
290  *
291  *  Do not use direclty, this is used by the getters when appropriate
292  *  in order to have fresh data.
293  * */
294 void Process::refresh_malloc_info()
295 {
296   xbt_assert(mc_mode == MC_MODE_SERVER);
297   if (!(this->cache_flags & MC_PROCESS_CACHE_FLAG_HEAP))
298     this->refresh_heap();
299   // Refresh process->heapinfo:
300   size_t count = this->heap->heaplimit + 1;
301   if (this->heap_info.size() < count)
302     this->heap_info.resize(count);
303   this->read_bytes(this->heap_info.data(), count * sizeof(malloc_info),
304     remote(this->heap->heapinfo), simgrid::mc::ProcessIndexDisabled);
305   this->cache_flags |= MC_PROCESS_CACHE_FLAG_MALLOC_INFO;
306 }
307
308 /** @brief Finds the range of the different memory segments and binary paths */
309 void Process::init_memory_map_info()
310 {
311   XBT_DEBUG("Get debug information ...");
312   this->maestro_stack_start_ = nullptr;
313   this->maestro_stack_end_ = nullptr;
314   this->object_infos.resize(0);
315   this->binary_info = NULL;
316   this->libsimgrid_info = NULL;
317
318   struct s_mc_memory_map_re res;
319
320   if(regcomp(&res.so_re, SO_RE, 0) || regcomp(&res.version_re, VERSION_RE, 0))
321     xbt_die(".so regexp did not compile");
322
323   std::vector<simgrid::xbt::VmMap> const& maps = this->memory_map_;
324
325   const char* current_name = NULL;
326
327   this->object_infos.resize(0);
328
329   for (size_t i=0; i < maps.size(); i++) {
330     simgrid::xbt::VmMap const& reg = maps[i];
331     const char* pathname = maps[i].pathname.c_str();
332
333     // Nothing to do
334     if (maps[i].pathname.empty()) {
335       current_name = NULL;
336       continue;
337     }
338
339     // [stack], [vvar], [vsyscall], [vdso] ...
340     if (pathname[0] == '[') {
341       if ((reg.prot & PROT_WRITE) && !memcmp(pathname, "[stack]", 7)) {
342         this->maestro_stack_start_ = remote(reg.start_addr);
343         this->maestro_stack_end_ = remote(reg.end_addr);
344       }
345       current_name = NULL;
346       continue;
347     }
348
349     if (current_name && strcmp(current_name, pathname)==0)
350       continue;
351
352     current_name = pathname;
353     if (!(reg.prot & PROT_READ) && (reg.prot & PROT_EXEC))
354       continue;
355
356     const bool is_executable = !i;
357     char* libname = NULL;
358     if (!is_executable) {
359       libname = MC_get_lib_name(pathname, &res);
360       if(!libname)
361         continue;
362       if (MC_is_filtered_lib(libname)) {
363         free(libname);
364         continue;
365       }
366     }
367
368     std::shared_ptr<simgrid::mc::ObjectInformation> info =
369       MC_find_object_info(this->memory_map_, pathname);
370     this->object_infos.push_back(info);
371     if (is_executable)
372       this->binary_info = info;
373     else if (libname && MC_is_simgrid_lib(libname))
374       this->libsimgrid_info = info;
375     free(libname);
376   }
377
378   regfree(&res.so_re);
379   regfree(&res.version_re);
380
381   // Resolve time (including accross differents objects):
382   for (auto const& object_info : this->object_infos)
383     MC_post_process_object_info(this, object_info.get());
384
385   xbt_assert(this->maestro_stack_start_, "Did not find maestro_stack_start");
386   xbt_assert(this->maestro_stack_end_, "Did not find maestro_stack_end");
387
388   XBT_DEBUG("Get debug information done !");
389 }
390
391 std::shared_ptr<simgrid::mc::ObjectInformation> Process::find_object_info(remote_ptr<void> addr) const
392 {
393   for (auto const& object_info : this->object_infos) {
394     if (addr.address() >= (std::uint64_t)object_info->start
395         && addr.address() <= (std::uint64_t)object_info->end) {
396       return object_info;
397     }
398   }
399   return NULL;
400 }
401
402 std::shared_ptr<ObjectInformation> Process::find_object_info_exec(remote_ptr<void> addr) const
403 {
404   for (std::shared_ptr<ObjectInformation> const& info : this->object_infos) {
405     if (addr.address() >= (std::uint64_t) info->start_exec
406         && addr.address() <= (std::uint64_t) info->end_exec) {
407       return info;
408     }
409   }
410   return nullptr;
411 }
412
413 std::shared_ptr<ObjectInformation> Process::find_object_info_rw(remote_ptr<void> addr) const
414 {
415   for (std::shared_ptr<ObjectInformation> const& info : this->object_infos) {
416     if (addr.address() >= (std::uint64_t)info->start_rw
417         && addr.address() <= (std::uint64_t)info->end_rw) {
418       return info;
419     }
420   }
421   return nullptr;
422 }
423
424 simgrid::mc::Frame* Process::find_function(remote_ptr<void> ip) const
425 {
426   std::shared_ptr<simgrid::mc::ObjectInformation> info = this->find_object_info_exec(ip);
427   return info ? info->find_function((void*) ip.address()) : nullptr;
428 }
429
430 /** Find (one occurence of) the named variable definition
431  */
432 simgrid::mc::Variable* Process::find_variable(const char* name) const
433 {
434   // First lookup the variable in the executable shared object.
435   // A global variable used directly by the executable code from a library
436   // is reinstanciated in the executable memory .data/.bss.
437   // We need to look up the variable in the execvutable first.
438   if (this->binary_info) {
439     std::shared_ptr<simgrid::mc::ObjectInformation> const& info = this->binary_info;
440     simgrid::mc::Variable* var = info->find_variable(name);
441     if (var)
442       return var;
443   }
444
445   for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info : this->object_infos) {
446     simgrid::mc::Variable* var = info->find_variable(name);
447     if (var)
448       return var;
449   }
450
451   return NULL;
452 }
453
454 void Process::read_variable(const char* name, void* target, size_t size) const
455 {
456   simgrid::mc::Variable* var = this->find_variable(name);
457   if (!var->address)
458     xbt_die("No simple location for this variable");
459   if (!var->type->full_type)
460     xbt_die("Partial type for %s, cannot check size", name);
461   if ((size_t) var->type->full_type->byte_size != size)
462     xbt_die("Unexpected size for %s (expected %zi, was %zi)",
463       name, size, (size_t) var->type->full_type->byte_size);
464   this->read_bytes(target, size, remote(var->address));
465 }
466
467 char* Process::read_string(remote_ptr<void> address) const
468 {
469   if (!address)
470     return NULL;
471
472   off_t len = 128;
473   char* res = (char*) malloc(len);
474   off_t off = 0;
475
476   while (1) {
477     ssize_t c = pread(this->memory_file, res + off, len - off, (off_t) address.address() + off);
478     if (c == -1) {
479       if (errno == EINTR)
480         continue;
481       else
482         xbt_die("Could not read from from remote process");
483     }
484     if (c==0)
485       xbt_die("Could not read string from remote process");
486
487     void* p = memchr(res + off, '\0', c);
488     if (p)
489       return res;
490
491     off += c;
492     if (off == len) {
493       len *= 2;
494       res = (char*) realloc(res, len);
495     }
496   }
497 }
498
499 const void *Process::read_bytes(void* buffer, std::size_t size,
500   remote_ptr<void> address, int process_index,
501   ReadOptions options) const
502 {
503   if (process_index != simgrid::mc::ProcessIndexDisabled) {
504     std::shared_ptr<simgrid::mc::ObjectInformation> const& info =
505       this->find_object_info_rw((void*)address.address());
506     // Segment overlap is not handled.
507 #ifdef HAVE_SMPI
508     if (info.get() && this->privatized(*info)) {
509       if (process_index < 0)
510         xbt_die("Missing process index");
511       if (process_index >= (int) MC_smpi_process_count())
512         xbt_die("Invalid process index");
513
514       // Read smpi_privatisation_regions from MCed:
515       smpi_privatisation_region_t remote_smpi_privatisation_regions =
516         mc_model_checker->process().read_variable<smpi_privatisation_region_t>(
517           "smpi_privatisation_regions");
518
519       s_smpi_privatisation_region_t privatisation_region =
520         mc_model_checker->process().read<s_smpi_privatisation_region_t>(
521           remote(remote_smpi_privatisation_regions + process_index));
522
523       // Address translation in the privaization segment:
524       size_t offset = address.address() - (std::uint64_t)info->start_rw;
525       address = remote((char*)privatisation_region.address + offset);
526     }
527 #endif
528   }
529
530   if (pread_whole(this->memory_file, buffer, size, address.address()) < 0)
531     xbt_die("Read from process %lli failed", (long long) this->pid_);
532   return buffer;
533 }
534
535 /** Write data to a process memory
536  *
537  *  @param process the process
538  *  @param local   local memory address (source)
539  *  @param remote  target process memory address (target)
540  *  @param len     data size
541  */
542 void Process::write_bytes(const void* buffer, size_t len, remote_ptr<void> address)
543 {
544   if (pwrite_whole(this->memory_file, buffer, len, address.address()) < 0)
545     xbt_die("Write to process %lli failed", (long long) this->pid_);
546 }
547
548 void Process::clear_bytes(remote_ptr<void> address, size_t len)
549 {
550   pthread_once(&zero_buffer_flag, MC_zero_buffer_init);
551   while (len) {
552     size_t s = len > zero_buffer_size ? zero_buffer_size : len;
553     this->write_bytes(zero_buffer, s, address);
554     address = remote((char*) address.address() + s);
555     len -= s;
556   }
557 }
558
559 void Process::ignore_region(std::uint64_t addr, std::size_t size)
560 {
561   IgnoredRegion region;
562   region.addr = addr;
563   region.size = size;
564
565   if (ignored_regions_.empty()) {
566     ignored_regions_.push_back(region);
567     return;
568   }
569
570   unsigned int cursor = 0;
571   IgnoredRegion* current_region = nullptr;
572
573   int start = 0;
574   int end = ignored_regions_.size() - 1;
575   while (start <= end) {
576     cursor = (start + end) / 2;
577     current_region = &ignored_regions_[cursor];
578     if (current_region->addr == addr) {
579       if (current_region->size == size)
580         return;
581       else if (current_region->size < size)
582         start = cursor + 1;
583       else
584         end = cursor - 1;
585     } else if (current_region->addr < addr)
586       start = cursor + 1;
587     else
588       end = cursor - 1;
589   }
590
591   std::size_t position;
592   if (current_region->addr == addr) {
593     if (current_region->size < size) {
594       position = cursor + 1;
595     } else {
596       position = cursor;
597     }
598   } else if (current_region->addr < addr) {
599     position = cursor + 1;
600   } else {
601     position = cursor;
602   }
603   ignored_regions_.insert(
604     ignored_regions_.begin() + position, region);
605 }
606
607 void Process::reset_soft_dirty()
608 {
609   if (this->clear_refs_fd_ < 0) {
610     this->clear_refs_fd_ = open_process_file(pid_, "clear_refs", O_WRONLY|O_CLOEXEC);
611     if (this->clear_refs_fd_ < 0)
612       xbt_die("Could not open clear_refs file for soft-dirty tracking. Run as root?");
613   }
614   if(::write(this->clear_refs_fd_, "4\n", 2) != 2)
615     xbt_die("Could not reset softdirty bits");
616 }
617
618 void Process::read_pagemap(uint64_t* pagemap, size_t page_start, size_t page_count)
619 {
620   if (pagemap_fd_ < 0) {
621     pagemap_fd_ = open_process_file(pid_, "pagemap", O_RDONLY|O_CLOEXEC);
622     if (pagemap_fd_ < 0)
623       xbt_die("Could not open pagemap file for soft-dirty tracking. Run as root?");
624   }
625   ssize_t bytesize = sizeof(uint64_t) * page_count;
626   off_t offset = sizeof(uint64_t) * page_start;
627   if (pread_whole(pagemap_fd_, pagemap, bytesize, offset) != bytesize)
628     xbt_die("Could not read pagemap");
629 }
630
631 void Process::ignore_heap(IgnoredHeapRegion const& region)
632 {
633   if (ignored_heap_.empty()) {
634     ignored_heap_.push_back(std::move(region));
635     return;
636   }
637
638   typedef std::vector<IgnoredHeapRegion>::size_type size_type;
639
640   size_type start = 0;
641   size_type end = ignored_heap_.size() - 1;
642
643   // Binary search the position of insertion:
644   size_type cursor;
645   while (start <= end) {
646     cursor = start + (end - start) / 2;
647     auto& current_region = ignored_heap_[cursor];
648     if (current_region.address == region.address)
649       return;
650     else if (current_region.address < region.address)
651       start = cursor + 1;
652     else if (cursor != 0)
653       end = cursor - 1;
654     // Avoid underflow:
655     else
656       break;
657   }
658
659   // Insert it mc_heap_ignore_region_t:
660   if (ignored_heap_[cursor].address < region.address)
661     ++cursor;
662   ignored_heap_.insert( ignored_heap_.begin() + cursor, region);
663 }
664
665 void Process::unignore_heap(void *address, size_t size)
666 {
667   typedef std::vector<IgnoredHeapRegion>::size_type size_type;
668
669   size_type start = 0;
670   size_type end = ignored_heap_.size() - 1;
671
672   // Binary search:
673   size_type cursor;
674   while (start <= end) {
675     cursor = (start + end) / 2;
676     auto& region = ignored_heap_[cursor];
677     if (region.address == address) {
678       ignored_heap_.erase(ignored_heap_.begin() + cursor);
679       return;
680     } else if (region.address < address)
681       start = cursor + 1;
682     else if ((char *) region.address <= ((char *) address + size)) {
683       ignored_heap_.erase(ignored_heap_.begin() + cursor);
684       return;
685     } else if (cursor != 0)
686       end = cursor - 1;
687     // Avoid underflow:
688     else
689       break;
690   }
691 }
692
693 void Process::ignore_local_variable(const char *var_name, const char *frame_name)
694 {
695   if (frame_name != nullptr && strcmp(frame_name, "*") == 0)
696     frame_name = nullptr;
697   for (std::shared_ptr<simgrid::mc::ObjectInformation> const& info :
698       this->object_infos)
699     info->remove_local_variable(var_name, frame_name);
700 }
701
702 }
703 }