Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
900a6f8d50075b2eef454861205133465a6ba499
[simgrid.git] / src / mc / mc_process.c
1 #include <stddef.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <errno.h>
5
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include <unistd.h>
9 #include <regex.h>
10 #include <sys/mman.h> // PROT_*
11
12 #include <libgen.h>
13
14 #include "mc_process.h"
15 #include "mc_object_info.h"
16
17 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc,
18                                 "MC process information");
19
20 static void MC_process_init_memory_map_info(mc_process_t process);
21 static void MC_process_open_memory_file(mc_process_t process);
22
23
24 void MC_process_init(mc_process_t process, pid_t pid)
25 {
26   process->process_flags = MC_PROCESS_NO_FLAG;
27   process->pid = pid;
28   if (pid==getpid())
29     process->process_flags |= MC_PROCESS_SELF_FLAG;
30   process->memory_map = MC_get_memory_map(pid);
31   process->memory_file = -1;
32   MC_process_init_memory_map_info(process);
33   MC_process_open_memory_file(process);
34 }
35
36 void MC_process_clear(mc_process_t process)
37 {
38   process->process_flags = MC_PROCESS_NO_FLAG;
39   process->pid = 0;
40
41   MC_free_memory_map(process->memory_map);
42   process->memory_map = NULL;
43
44   process->maestro_stack_start = NULL;
45   process->maestro_stack_end = NULL;
46
47   size_t i;
48   for (i=0; i!=process->object_infos_size; ++i) {
49     MC_free_object_info(&process->object_infos[i]);
50   }
51   free(process->object_infos);
52   process->object_infos = NULL;
53   process->object_infos_size = 0;
54   if (process->memory_file >= 0) {
55     close(process->memory_file);
56   }
57 }
58
59 #define SO_RE "\\.so[\\.0-9]*$"
60 #define VERSION_RE "-[\\.0-9]*$"
61
62 const char* FILTERED_LIBS[] = {
63   "libstdc++",
64   "libc++",
65   "libm",
66   "libgcc_s",
67   "libpthread",
68   "libunwind",
69   "libunwind-x86_64",
70   "libunwind-x86",
71   "libdw",
72   "libdl",
73   "librt",
74   "liblzma",
75   "libelf",
76   "libbz2",
77   "libz",
78   "libelf",
79   "libc",
80   "ld"
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   const size_t n = sizeof(FILTERED_LIBS) / sizeof(const char*);
91   size_t i;
92   for (i=0; i!=n; ++i)
93     if (strcmp(libname, FILTERED_LIBS[i])==0)
94       return true;
95   return false;
96 }
97
98 struct s_mc_memory_map_re {
99   regex_t so_re;
100   regex_t version_re;
101 };
102
103 static char* MC_get_lib_name(const char* pathname, struct s_mc_memory_map_re* res) {
104   const char* map_basename = basename((char*) pathname);
105
106   regmatch_t match;
107   if(regexec(&res->so_re, map_basename, 1, &match, 0))
108     return NULL;
109
110   char* libname = strndup(map_basename, match.rm_so);
111
112   // Strip the version suffix:
113   if(libname && !regexec(&res->version_re, libname, 1, &match, 0)) {
114     char* temp = libname;
115     libname = strndup(temp, match.rm_so);
116     free(temp);
117   }
118
119   return libname;
120 }
121
122 /** @brief Finds the range of the different memory segments and binary paths */
123 static void MC_process_init_memory_map_info(mc_process_t process)
124 {
125   XBT_INFO("Get debug information ...");
126   process->maestro_stack_start = NULL;
127   process->maestro_stack_end = NULL;
128   process->object_infos = NULL;
129   process->object_infos_size = 0;
130   process->binary_info = NULL;
131   process->libsimgrid_info = NULL;
132
133   struct s_mc_memory_map_re res;
134
135   if(regcomp(&res.so_re, SO_RE, 0) || regcomp(&res.version_re, VERSION_RE, 0))
136     xbt_die(".so regexp did not compile");
137
138   memory_map_t maps = process->memory_map;
139
140   const char* current_name = NULL;
141
142   size_t i = 0;
143   for (i=0; i < maps->mapsize; i++) {
144     map_region_t reg = &(maps->regions[i]);
145     const char* pathname = maps->regions[i].pathname;
146
147     // Nothing to do
148     if (maps->regions[i].pathname == NULL) {
149       current_name = NULL;
150       continue;
151     }
152
153     // [stack], [vvar], [vsyscall], [vdso] ...
154     if (pathname[0] == '[') {
155       if ((reg->prot & PROT_WRITE) && !memcmp(pathname, "[stack]", 7)) {
156         process->maestro_stack_start = reg->start_addr;
157         process->maestro_stack_end = reg->end_addr;
158       }
159       current_name = NULL;
160       continue;
161     }
162
163     if (current_name && strcmp(current_name, pathname)==0)
164       continue;
165
166     current_name = pathname;
167     if (!(reg->prot & PROT_READ) && (reg->prot & PROT_EXEC))
168       continue;
169
170     const bool is_executable = !i;
171     char* libname = NULL;
172     if (!is_executable) {
173       libname = MC_get_lib_name(pathname, &res);
174       if(!libname)
175         continue;
176       if (MC_is_filtered_lib(libname)) {
177         free(libname);
178         continue;
179       }
180     }
181
182     mc_object_info_t info =
183       MC_find_object_info(process->memory_map, pathname, is_executable);
184     process->object_infos = (mc_object_info_t*) realloc(process->object_infos,
185       (process->object_infos_size+1) * sizeof(mc_object_info_t*));
186     process->object_infos[process->object_infos_size] = info;
187     process->object_infos_size++;
188     if (is_executable)
189       process->binary_info = info;
190     else if (libname && MC_is_simgrid_lib(libname))
191       process->libsimgrid_info = info;
192     free(libname);
193   }
194
195   regfree(&res.so_re);
196   regfree(&res.version_re);
197
198   // Resolve time (including accress differents objects):
199   for (i=0; i!=process->object_infos_size; ++i)
200     MC_post_process_object_info(process, process->object_infos[i]);
201
202   xbt_assert(process->maestro_stack_start, "maestro_stack_start");
203   xbt_assert(process->maestro_stack_end, "maestro_stack_end");
204
205   XBT_INFO("Get debug information done !");
206 }
207
208 mc_object_info_t MC_process_find_object_info(mc_process_t process, void *ip)
209 {
210   size_t i;
211   for (i = 0; i != process->object_infos_size; ++i) {
212     if (ip >= (void *) process->object_infos[i]->start_exec
213         && ip <= (void *) process->object_infos[i]->end_exec) {
214       return process->object_infos[i];
215     }
216   }
217   return NULL;
218 }
219
220 dw_frame_t MC_process_find_function(mc_process_t process, void *ip)
221 {
222   mc_object_info_t info = MC_process_find_object_info(process, ip);
223   if (info == NULL)
224     return NULL;
225   else
226     return MC_file_object_info_find_function(info, ip);
227 }
228
229 // ***** Memory access
230
231 static void MC_process_open_memory_file(mc_process_t process)
232 {
233   if (MC_process_is_self(process) || process->memory_file >= 0)
234     return;
235
236   const size_t buffer_size = 30;
237   char buffer[buffer_size];
238   int res = snprintf(buffer, buffer_size, "/proc/%lli/mem", (long long) process->pid);
239   if (res < 0 || res>= buffer_size) {
240     XBT_ERROR("Could not open memory file descriptor for process %lli",
241       (long long) process->pid);
242     return;
243   }
244
245   int fd = open(buffer, O_RDWR);
246   if (fd<0)
247     xbt_die("Could not initialise memory access for remote process");
248   process->memory_file = fd;
249 }
250
251 static ssize_t pread_whole(int fd, void *buf, size_t count, off_t offset)
252 {
253   char* buffer = (char*) buf;
254   ssize_t real_count = count;
255   while (count) {
256     ssize_t res = pread(fd, buffer, count, offset);
257     if (res >= 0) {
258       count  -= res;
259       buffer += res;
260       offset += res;
261     } else if (res==0) {
262       return -1;
263     } else if (errno != EINTR) {
264       return -1;
265     }
266   }
267   return real_count;
268 }
269
270 static ssize_t pwrite_whole(int fd, const void *buf, size_t count, off_t offset)
271 {
272   const char* buffer = (const char*) buf;
273   ssize_t real_count = count;
274   while (count) {
275     ssize_t res = pwrite(fd, buffer, count, offset);
276     if (res >= 0) {
277       count  -= res;
278       buffer += res;
279       offset += res;
280     } else if (res==0) {
281       return -1;
282     } else if (errno != EINTR) {
283       return -1;
284     }
285   }
286   return real_count;
287 }
288
289 void MC_process_read(mc_process_t process, void* local, const void* remote, size_t len)
290 {
291   if (MC_process_is_self(process)) {
292     memcpy(local, remote, len);
293   } else {
294     if (pread_whole(process->memory_file, local, len, (off_t) remote) < 0)
295       xbt_die("Read from process %lli failed", (long long) process->pid);
296   }
297 }
298
299 void MC_process_write(mc_process_t process, const void* local, void* remote, size_t len)
300 {
301   if (MC_process_is_self(process)) {
302     memcpy(remote, local, len);
303   } else {
304     if (pwrite_whole(process->memory_file, local, len, (off_t) remote) < 0)
305       xbt_die("Write to process %lli failed", (long long) process->pid);
306   }
307 }