Logo AND Algorithmique Numérique Distribuée

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