1 /* Copyright (c) 2015. The SimGrid Team.
2 * All rights reserved. */
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. */
8 #include <system_error>
11 #include <sys/types.h>
13 #include <sys/socket.h>
14 #include <sys/signalfd.h>
15 #include <sys/ptrace.h>
18 #include <xbt/automaton.h>
19 #include <xbt/automaton.hpp>
21 #include "ModelChecker.hpp"
22 #include "mc_protocol.h"
23 #include "src/mc/Server.hpp"
24 #include "mc_private.h"
25 #include "mc_ignore.h"
26 #include "mcer_ignore.h"
28 #include "src/mc/mc_liveness.h"
30 using simgrid::mc::remote;
34 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_Server, mc, "MC server logic");
38 // HArdcoded index for now:
39 #define SOCKET_FD_INDEX 0
40 #define SIGNAL_FD_INDEX 1
45 Server* server = nullptr;
47 Server::Server(pid_t pid_, int socket_)
48 : pid(pid_), socket(socket_) {}
52 // Block SIGCHLD (this will be handled with accept/signalfd):
55 sigaddset(&set, SIGCHLD);
56 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
57 throw std::system_error(errno, std::system_category());
60 sigfillset(&full_set);
62 // Prepare data for poll:
64 struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
65 socket_pollfd->fd = socket;
66 socket_pollfd->events = POLLIN;
67 socket_pollfd->revents = 0;
69 int signal_fd = signalfd(-1, &set, 0);
71 throw std::system_error(errno, std::system_category());
73 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
74 signalfd_pollfd->fd = signal_fd;
75 signalfd_pollfd->events = POLLIN;
76 signalfd_pollfd->revents = 0;
78 XBT_DEBUG("Waiting for the model-checked process");
81 // The model-checked process SIGSTOP itself to signal it's ready:
82 pid_t res = waitpid(pid, &status, __WALL);
83 if (res < 0 || !WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP)
84 xbt_die("Could not wait model-checked process");
86 // The model-checked process is ready, we can read its memory layout:
87 MC_init_model_checker(pid, socket);
89 ptrace(PTRACE_SETOPTIONS, pid, nullptr, PTRACE_O_TRACEEXIT);
90 ptrace(PTRACE_CONT, pid, 0, 0);
93 void Server::shutdown()
95 XBT_DEBUG("Shuting down model-checker");
97 simgrid::mc::Process* process = &mc_model_checker->process();
98 int status = process->status();
99 if (process->running()) {
100 XBT_DEBUG("Killing process");
101 kill(process->pid(), SIGTERM);
102 if (waitpid(process->pid(), &status, 0) == -1)
103 throw std::system_error(errno, std::system_category());
104 // TODO, handle the case when the process does not want to die with a timeout
105 process->terminate(status);
109 void Server::resume(simgrid::mc::Process& process)
111 int res = process.send_message(MC_MESSAGE_CONTINUE);
113 throw std::system_error(res, std::system_category());
114 process.cache_flags = (mc_process_cache_flags_t) 0;
118 void throw_socket_error(int fd)
121 socklen_t errlen = sizeof(error);
122 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
124 throw std::system_error(error, std::system_category());
127 bool Server::handle_message(char* buffer, ssize_t size)
129 s_mc_message_t base_message;
130 if (size < (ssize_t) sizeof(base_message))
131 xbt_die("Broken message");
132 memcpy(&base_message, buffer, sizeof(base_message));
134 switch(base_message.type) {
136 case MC_MESSAGE_IGNORE_HEAP:
138 s_mc_ignore_heap_message_t message;
139 if (size != sizeof(message))
140 xbt_die("Broken messsage");
141 memcpy(&message, buffer, sizeof(message));
142 mc_heap_ignore_region_t region = xbt_new(s_mc_heap_ignore_region_t, 1);
143 *region = message.region;
144 MC_heap_region_ignore_insert(region);
148 case MC_MESSAGE_UNIGNORE_HEAP:
150 s_mc_ignore_memory_message_t message;
151 if (size != sizeof(message))
152 xbt_die("Broken messsage");
153 memcpy(&message, buffer, sizeof(message));
154 MC_heap_region_ignore_remove(
155 (void *)(std::uintptr_t) message.addr, message.size);
159 case MC_MESSAGE_IGNORE_MEMORY:
161 s_mc_ignore_memory_message_t message;
162 if (size != sizeof(message))
163 xbt_die("Broken messsage");
164 memcpy(&message, buffer, sizeof(message));
165 mc_model_checker->process().ignore_region(
166 message.addr, message.size);
170 case MC_MESSAGE_STACK_REGION:
172 s_mc_stack_region_message_t message;
173 if (size != sizeof(message))
174 xbt_die("Broken messsage");
175 memcpy(&message, buffer, sizeof(message));
176 stack_region_t stack_region = xbt_new(s_stack_region_t, 1);
177 *stack_region = message.stack_region;
178 MC_stack_area_add(stack_region);
182 case MC_MESSAGE_REGISTER_SYMBOL:
184 s_mc_register_symbol_message_t message;
185 if (size != sizeof(message))
186 xbt_die("Broken message");
187 memcpy(&message, buffer, sizeof(message));
188 if (message.callback)
189 xbt_die("Support for client-side function proposition is not implemented.");
190 XBT_DEBUG("Received symbol: %s", message.name);
192 if (_mc_property_automaton == NULL)
193 _mc_property_automaton = xbt_automaton_new();
195 simgrid::mc::Process* process = &mc_model_checker->process();
196 simgrid::mc::remote_ptr<int> address
197 = simgrid::mc::remote((int*) message.data);
198 simgrid::xbt::add_proposition(_mc_property_automaton,
200 [process, address]() { return process->read(address); }
206 case MC_MESSAGE_WAITING:
209 case MC_MESSAGE_ASSERTION_FAILED:
210 MC_report_assertion_error();
211 ::exit(SIMGRID_MC_EXIT_SAFETY);
215 xbt_die("Unexpected message from model-checked application");
221 bool Server::handle_events()
223 char buffer[MC_MESSAGE_LENGTH];
224 struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
225 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
227 while(poll(fds, 2, -1) == -1) {
232 throw std::system_error(errno, std::system_category());
236 if (socket_pollfd->revents) {
237 if (socket_pollfd->revents & POLLIN) {
238 ssize_t size = MC_receive_message(socket_pollfd->fd, buffer, sizeof(buffer), MSG_DONTWAIT);
239 if (size == -1 && errno != EAGAIN)
240 throw std::system_error(errno, std::system_category());
241 return handle_message(buffer, size);
243 if (socket_pollfd->revents & POLLERR) {
244 throw_socket_error(socket_pollfd->fd);
246 if (socket_pollfd->revents & POLLHUP)
247 xbt_die("Socket hang up?");
250 if (signalfd_pollfd->revents) {
251 if (signalfd_pollfd->revents & POLLIN) {
252 this->handle_signals();
255 if (signalfd_pollfd->revents & POLLERR) {
256 throw_socket_error(signalfd_pollfd->fd);
258 if (signalfd_pollfd->revents & POLLHUP)
259 xbt_die("Signalfd hang up?");
267 while (mc_model_checker->process().running())
268 this->handle_events();
271 void Server::handle_signals()
273 struct signalfd_siginfo info;
274 struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
276 ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
281 throw std::system_error(errno, std::system_category());
282 } else if (size != sizeof(info))
283 return throw std::runtime_error(
284 "Bad communication with model-checked application");
288 this->on_signal(&info);
291 void Server::handle_waitpid()
293 XBT_DEBUG("Check for wait event");
296 while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
298 if (errno == ECHILD) {
300 if (mc_model_checker->process().running())
301 xbt_die("Inconsistent state");
305 XBT_ERROR("Could not wait for pid");
306 throw std::system_error(errno, std::system_category());
310 if (pid == mc_model_checker->process().pid()) {
312 // From PTRACE_O_TRACEEXIT:
313 if (status>>8 == (SIGTRAP | (PTRACE_EVENT_EXIT<<8))) {
314 if (ptrace(PTRACE_GETEVENTMSG, pid, 0, &status) == -1)
315 xbt_die("Could not get exit status");
316 if (WIFSIGNALED(status)) {
317 MC_report_crash(status);
318 ::exit(SIMGRID_MC_EXIT_PROGRAM_CRASH);
322 // We don't care about signals, just reinject them:
323 if (WIFSTOPPED(status)) {
324 XBT_DEBUG("Stopped with signal %i", (int) WSTOPSIG(status));
325 if (ptrace(PTRACE_CONT, pid, 0, WSTOPSIG(status)) == -1)
326 xbt_die("Could not PTRACE_CONT");
329 else if (WIFEXITED(status) || WIFSIGNALED(status)) {
330 XBT_DEBUG("Child process is over");
331 mc_model_checker->process().terminate(status);
337 void Server::on_signal(const struct signalfd_siginfo* info)
339 switch(info->ssi_signo) {
341 this->handle_waitpid();
348 void Server::wait_client(simgrid::mc::Process& process)
350 this->resume(process);
351 while (mc_model_checker->process().running()) {
352 if (!simgrid::mc::server->handle_events())
357 void Server::simcall_handle(simgrid::mc::Process& process, unsigned long pid, int value)
359 s_mc_simcall_handle_message m;
360 memset(&m, 0, sizeof(m));
361 m.type = MC_MESSAGE_SIMCALL_HANDLE;
364 process.send_message(m);
365 process.cache_flags = (mc_process_cache_flags_t) 0;
366 while (process.running()) {
367 if (!simgrid::mc::server->handle_events())