root/miscwrappers.cpp
/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- exit
- close
- fclose
- closedir
- pipe
- pipe2
- wait
- waitpid
- wait3
- wait4
- waitid
- syscall
- pthread_cond_broadcast
- pthread_cond_destroy
- pthread_cond_init
- pthread_cond_signal
- pthread_cond_timedwait
- pthread_cond_wait
- pthread_mutex_lock
- pthread_mutex_unlock
1 /****************************************************************************
2 * Copyright (C) 2006-2013 by Jason Ansel, Kapil Arya, and Gene Cooperman *
3 * jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu *
4 * *
5 * This file is part of DMTCP. *
6 * *
7 * DMTCP is free software: you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * DMTCP is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with DMTCP:dmtcp/src. If not, see *
19 * <http://www.gnu.org/licenses/>. *
20 ****************************************************************************/
21
22 #include "dmtcpworker.h"
23 #include "threadsync.h"
24 #include "protectedfds.h"
25 #include "constants.h"
26 #include "syscallwrappers.h"
27 #include "../jalib/jassert.h"
28 #include "../jalib/jconvert.h"
29 #include "processinfo.h"
30 #include <sys/syscall.h>
31
32 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) && __GLIBC_PREREQ(2,4)
33 #include <sys/inotify.h>
34 #endif
35 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) && __GLIBC_PREREQ(2,8)
36 #include <sys/eventfd.h>
37 #include <sys/signalfd.h>
38 #endif
39
40 #ifdef __aarch64__
41 // We must support all deprecated syscalls in case the end user code uses it.
42 # define __ARCH_WANT_SYSCALL_DEPRECATED
43 # define __ARCH_WANT_SYSCALL_NO_AT
44 # define __ARCH_WANT_SYSCALL_NO_FLAGS
45 // SYS_fork is a deprecated kernel call in aarch64; in favor of SYS_clone?
46 # include <asm-generic/unistd.h>
47 // SYS_fork undefined in aarch64, but add extra insurance
48 # undef SYS_fork
49 # undef SYS_open
50 # undef SYS_pipe
51 # undef SYS_poll
52 # define SYS_fork __NR_fork
53 # define SYS_open __NR_open
54 # define SYS_pipe __NR_pipe
55 # define SYS_poll __NR_poll
56 // These kernel calls are not deprecated. But SYS_XXX is not defined for them.
57 # define SYS_epoll_create __NR_epoll_create
58 # define SYS_inotify_init __NR_inotify_init
59 # define SYS_signalfd __NR_signalfd
60 # define SYS_eventfd __NR_eventfd
61 #endif
62
63 using namespace dmtcp;
64
65 EXTERNC int dmtcp_is_popen_fp(FILE *fp) __attribute((weak));
66
67 extern "C" void exit ( int status )
68 {
69 /*
70 * NOTE: This sets the _exitInProgress flag to true which results in
71 * a call to tgkill(SIGUSR2) for the ckpt thread.
72 * Refer to the comment in: DmtcpWorker::~DmtcpWorker()
73 */
74 DmtcpWorker::setExitInProgress();
75 _real_exit ( status );
76 for (;;); // Without this, gcc emits warning: `noreturn' fnc does return
77 }
78
79 extern "C" int close(int fd)
80 {
81 if (DMTCP_IS_PROTECTED_FD(fd)) {
82 JTRACE("blocked attempt to close protected fd") (fd);
83 errno = EBADF;
84 return -1;
85 }
86 return _real_close(fd);
87 }
88
89 extern "C" int fclose(FILE *fp)
90 {
91 // If this fp was obtained using popen(), we must pclose it
92 if (dmtcp_is_popen_fp(fp)) {
93 return pclose(fp);
94 }
95 int fd = fileno(fp);
96 if (DMTCP_IS_PROTECTED_FD(fd)) {
97 JTRACE("blocked attempt to fclose protected fd") (fd);
98 errno = EBADF;
99 return -1;
100 }
101 return _real_fclose(fp);
102 }
103
104 extern "C" int closedir(DIR *dir)
105 {
106 int fd = dirfd(dir);
107 if (DMTCP_IS_PROTECTED_FD(fd)) {
108 JTRACE("blocked attempt to closedir protected fd") (fd);
109 errno = EBADF;
110 return -1;
111 }
112 return _real_closedir(dir);
113 }
114
115 /*
116 * FIXME: Add wrapper for dup2 and dup3 to detect if the newfd is a protected fd.
117 extern "C" int dup2(int oldfd, int newfd)
118 {
119 if (DMTCP_IS_PROTECTED_FD(newfd)) {
120 }
121 return _real_dup2(oldfd, newfd);
122 }
123 */
124
125 extern "C" int pipe ( int fds[2] )
126 {
127 JTRACE ( "promoting pipe() to socketpair()" );
128 //just promote pipes to socketpairs
129 return socketpair ( AF_UNIX, SOCK_STREAM, 0, fds );
130 }
131
132 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) && __GLIBC_PREREQ(2,9)
133 // pipe2 appeared in Linux 2.6.27
134 extern "C" int pipe2 ( int fds[2], int flags )
135 {
136 JTRACE ( "promoting pipe2() to socketpair()" );
137 //just promote pipes to socketpairs
138 int newFlags = 0;
139 if ((flags & O_NONBLOCK) != 0) newFlags |= SOCK_NONBLOCK;
140 if ((flags & O_CLOEXEC) != 0) newFlags |= SOCK_CLOEXEC;
141 return socketpair ( AF_UNIX, SOCK_STREAM | newFlags, 0, fds );
142 }
143 #endif
144
145
146 // extern "C" pid_t getpid()
147 // {
148 // return ProcessInfo::instance().pid();
149 // }
150
151 // extern "C" pid_t getppid()
152 // {
153 // pid_t ppid = _real_getppid();
154 // if (ppid == 1 ) {
155 // ProcessInfo::instance().setppid( 1 );
156 // }
157 //
158 // return origPpid;
159 // }
160
161 // extern "C" pid_t setsid(void)
162 // {
163 // pid_t pid = _real_setsid();
164 // ProcessInfo::instance().setsid(origPid);
165 // return origPid;
166 // }
167
168 #if 1
169 extern "C" pid_t wait (__WAIT_STATUS stat_loc)
170 {
171 return waitpid(-1, (int*)stat_loc, 0);
172 }
173
174 extern "C" pid_t waitpid(pid_t pid, int *stat_loc, int options)
175 {
176 return wait4(pid, stat_loc, options, NULL);
177 }
178
179 extern "C" pid_t wait3(__WAIT_STATUS status, int options, struct rusage *rusage)
180 {
181 return wait4(-1, status, options, rusage);
182 }
183
184 extern "C"
185 pid_t wait4(pid_t pid, __WAIT_STATUS status, int options, struct rusage *rusage)
186 {
187 int stat;
188 int saved_errno = errno;
189 pid_t retval = 0;
190
191 if (status == NULL) {
192 status = (__WAIT_STATUS) &stat;
193 }
194
195 retval = _real_wait4(pid, status, options, rusage);
196 saved_errno = errno;
197
198 if (retval > 0 &&
199 (WIFEXITED(*(int*)status) || WIFSIGNALED(*(int*)status))) {
200 ProcessInfo::instance().eraseChild(retval);
201 }
202 errno = saved_errno;
203 return retval;
204 }
205
206 extern "C" int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options)
207 {
208 siginfo_t siginfop;
209 memset(&siginfop, 0, sizeof(siginfop));
210
211 int retval = _real_waitid (idtype, id, &siginfop, options);
212
213 if (retval != -1) {
214 if ( siginfop.si_code == CLD_EXITED || siginfop.si_code == CLD_KILLED )
215 ProcessInfo::instance().eraseChild ( siginfop.si_pid );
216 }
217
218 if (retval == 0 && infop != NULL) {
219 *infop = siginfop;
220 }
221
222 return retval;
223 }
224 #endif
225
226 extern "C" int __clone ( int ( *fn ) ( void *arg ), void *child_stack, int flags, void *arg, int *parent_tidptr, struct user_desc *newtls, int *child_tidptr );
227
228 #define SYSCALL_VA_START() \
229 va_list ap; \
230 va_start(ap, sys_num)
231
232 #define SYSCALL_VA_END() \
233 va_end(ap)
234
235 #define SYSCALL_GET_ARG(type,arg) type arg = va_arg(ap, type)
236
237 #define SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2) \
238 SYSCALL_GET_ARG(type1,arg1); \
239 SYSCALL_GET_ARG(type2,arg2)
240
241 #define SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3) \
242 SYSCALL_GET_ARGS_2(type1,arg1,type2,arg2); \
243 SYSCALL_GET_ARG(type3,arg3)
244
245 #define SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
246 SYSCALL_GET_ARGS_3(type1,arg1,type2,arg2,type3,arg3); \
247 SYSCALL_GET_ARG(type4,arg4)
248
249 #define SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
250 type5,arg5) \
251 SYSCALL_GET_ARGS_4(type1,arg1,type2,arg2,type3,arg3,type4,arg4); \
252 SYSCALL_GET_ARG(type5,arg5)
253
254 #define SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
255 type5,arg5,type6,arg6) \
256 SYSCALL_GET_ARGS_5(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
257 type5,arg5); \
258 SYSCALL_GET_ARG(type6,arg6)
259
260 #define SYSCALL_GET_ARGS_7(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
261 type5,arg5,type6,arg6,type7,arg7) \
262 SYSCALL_GET_ARGS_6(type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
263 type5,arg5,type6,arg6); \
264 SYSCALL_GET_ARG(type7,arg7)
265
266 /* Comments by Gene:
267 * Here, syscall is the wrapper, and the call to syscall would be _real_syscall
268 * We would add a special case for SYS_gettid, while all others default as below
269 * It depends on the idea that arguments are stored in registers, whose
270 * natural size is: sizeof(void*)
271 * So, we pass six arguments to syscall, and it will ignore any extra arguments
272 * I believe that all Linux system calls have no more than 7 args.
273 * clone() is an example of one with 7 arguments.
274 * If we discover system calls for which the 7 args strategy doesn't work,
275 * we can special case them.
276 *
277 * XXX: DO NOT USE JTRACE/JNOTE/JASSERT in this function; even better, do not
278 * use any STL here. (--Kapil)
279 */
280 extern "C" long syscall(long sys_num, ... )
281 {
282 long int ret;
283 va_list ap;
284
285 va_start(ap, sys_num);
286
287 switch ( sys_num ) {
288
289 case SYS_clone:
290 {
291 typedef int (*fnc) (void*);
292 SYSCALL_GET_ARGS_7(fnc, fn, void*, child_stack, int, flags, void*, arg,
293 pid_t*, pid, struct user_desc*, tls, pid_t*, ctid);
294 ret = __clone(fn, child_stack, flags, arg, pid, tls, ctid);
295 break;
296 }
297
298 case SYS_execve:
299 {
300 SYSCALL_GET_ARGS_3(const char*,filename,char* const *,argv,char* const *,envp);
301 ret = execve(filename,argv,envp);
302 break;
303 }
304
305 case SYS_fork:
306 {
307 ret = fork();
308 break;
309 }
310 case SYS_exit:
311 {
312 SYSCALL_GET_ARG(int,status);
313 exit(status);
314 break;
315 }
316 case SYS_open:
317 {
318 SYSCALL_GET_ARGS_3(const char*,pathname,int,flags,mode_t,mode);
319 ret = open(pathname, flags, mode);
320 break;
321 }
322 case SYS_close:
323 {
324 SYSCALL_GET_ARG(int,fd);
325 ret = close(fd);
326 break;
327 }
328
329 case SYS_rt_sigaction:
330 {
331 SYSCALL_GET_ARGS_3(int,signum,const struct sigaction*,act,struct sigaction*,oldact);
332 ret = sigaction(signum, act, oldact);
333 break;
334 }
335 case SYS_rt_sigprocmask:
336 {
337 SYSCALL_GET_ARGS_3(int,how,const sigset_t*,set,sigset_t*,oldset);
338 ret = sigprocmask(how, set, oldset);
339 break;
340 }
341 case SYS_rt_sigtimedwait:
342 {
343 SYSCALL_GET_ARGS_3(const sigset_t*,set,siginfo_t*,info,
344 const struct timespec*, timeout);
345 ret = sigtimedwait(set, info, timeout);
346 break;
347 }
348
349 #ifdef __i386__
350 case SYS_sigaction:
351 {
352 SYSCALL_GET_ARGS_3(int,signum,const struct sigaction*,act,struct sigaction*,oldact);
353 ret = sigaction(signum, act, oldact);
354 break;
355 }
356 case SYS_signal:
357 {
358 typedef void (*sighandler_t)(int);
359 SYSCALL_GET_ARGS_2(int,signum,sighandler_t,handler);
360 // Cast needed: signal returns sighandler_t
361 ret = (long int)signal(signum, handler);
362 break;
363 }
364 case SYS_sigprocmask:
365 {
366 SYSCALL_GET_ARGS_3(int,how,const sigset_t*,set,sigset_t*,oldset);
367 ret = sigprocmask(how, set, oldset);
368 break;
369 }
370 #endif
371
372 #ifdef __x86_64__
373 // These SYS_xxx are only defined for 64-bit Linux
374 case SYS_socket:
375 {
376 SYSCALL_GET_ARGS_3(int,domain,int,type,int,protocol);
377 ret = socket(domain,type,protocol);
378 break;
379 }
380 case SYS_connect:
381 {
382 SYSCALL_GET_ARGS_3(int,sockfd,const struct sockaddr*,addr,socklen_t,addrlen);
383 ret = connect(sockfd, addr, addrlen);
384 break;
385 }
386 case SYS_bind:
387 {
388 SYSCALL_GET_ARGS_3(int,sockfd,const struct sockaddr*,addr,socklen_t,addrlen);
389 ret = bind(sockfd,addr,addrlen);
390 break;
391 }
392 case SYS_listen:
393 {
394 SYSCALL_GET_ARGS_2(int,sockfd,int,backlog);
395 ret = listen(sockfd,backlog);
396 break;
397 }
398 case SYS_accept:
399 {
400 SYSCALL_GET_ARGS_3(int,sockfd,struct sockaddr*,addr,socklen_t*,addrlen);
401 ret = accept(sockfd, addr, addrlen);
402 break;
403 }
404 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) && __GLIBC_PREREQ(2,10)
405 case SYS_accept4:
406 {
407 SYSCALL_GET_ARGS_4(int,sockfd,struct sockaddr*,addr,socklen_t*,addrlen,int,flags);
408 ret = accept4(sockfd, addr, addrlen, flags);
409 break;
410 }
411 #endif
412 case SYS_setsockopt:
413 {
414 SYSCALL_GET_ARGS_5(int,s,int,level,int,optname,const void*,optval,socklen_t,optlen);
415 ret = setsockopt(s, level, optname, optval, optlen);
416 break;
417 }
418
419 case SYS_socketpair:
420 {
421 SYSCALL_GET_ARGS_4(int,d,int,type,int,protocol,int*,sv);
422 ret = socketpair(d,type,protocol,sv);
423 break;
424 }
425 #endif
426
427 case SYS_pipe:
428 {
429 SYSCALL_GET_ARG(int*,fds);
430 ret = pipe(fds);
431 break;
432 }
433 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)) && __GLIBC_PREREQ(2,9)
434 case SYS_pipe2:
435 {
436 SYSCALL_GET_ARGS_2(int*,fds,int,flags);
437 ret = pipe2(fds, flags);
438 break;
439 }
440 #endif
441
442 case SYS_setsid:
443 {
444 ret = setsid();
445 break;
446 }
447
448 #ifndef DISABLE_SYS_V_IPC
449 # ifdef __x86_64__
450 // These SYS_xxx are only defined for 64-bit Linux
451 case SYS_shmget:
452 {
453 SYSCALL_GET_ARGS_3(key_t,key,size_t,size,int,shmflg);
454 ret = shmget(key, size, shmflg);
455 break;
456 }
457 case SYS_shmat:
458 {
459 SYSCALL_GET_ARGS_3(int,shmid,const void*,shmaddr,int,shmflg);
460 ret = (unsigned long) shmat(shmid, shmaddr, shmflg);
461 break;
462 }
463 case SYS_shmdt:
464 {
465 SYSCALL_GET_ARG(const void*,shmaddr);
466 ret = shmdt(shmaddr);
467 break;
468 }
469 case SYS_shmctl:
470 {
471 SYSCALL_GET_ARGS_3(int,shmid,int,cmd,struct shmid_ds*,buf);
472 ret = shmctl(shmid, cmd, buf);
473 break;
474 }
475 # endif
476 #endif
477 case SYS_poll:
478 {
479 SYSCALL_GET_ARGS_3(struct pollfd *,fds,nfds_t,nfds,int,timeout);
480 ret = poll(fds, nfds, timeout);
481 break;
482 }
483 case SYS_epoll_create:
484 {
485 SYSCALL_GET_ARG(int,size);
486 ret = epoll_create(size);
487 break;
488 }
489 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) && __GLIBC_PREREQ(2,4)
490 case SYS_inotify_init:
491 {
492 ret = inotify_init();
493 break;
494 }
495 #endif
496 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) && __GLIBC_PREREQ(2,8)
497 case SYS_signalfd:
498 {
499 SYSCALL_GET_ARGS_3(int,fd,sigset_t *,mask,int,flags);
500 ret = signalfd(fd, mask, flags);
501 break;
502 }
503 #endif
504 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && __GLIBC_PREREQ(2,8)
505 case SYS_signalfd4:
506 {
507 SYSCALL_GET_ARGS_3(int,fd,sigset_t *,mask,int,flags);
508 ret = signalfd(fd, mask, flags);
509 break;
510 }
511 #endif
512 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) && __GLIBC_PREREQ(2,8)
513 case SYS_eventfd:
514 {
515 SYSCALL_GET_ARGS_2(unsigned int,initval,int,flags);
516 ret = eventfd(initval, flags);
517 break;
518 }
519 #endif
520 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && __GLIBC_PREREQ(2,8)
521 case SYS_eventfd2:
522 {
523 SYSCALL_GET_ARGS_2(unsigned int,initval,int,flags);
524 ret = eventfd(initval, flags);
525 break;
526 }
527 #endif
528 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) && __GLIBC_PREREQ(2,9)
529 case SYS_epoll_create1:
530 {
531 SYSCALL_GET_ARG(int,flags);
532 ret = epoll_create(flags);
533 break;
534 }
535 case SYS_inotify_init1:
536 {
537 SYSCALL_GET_ARG(int,flags);
538 ret = inotify_init1(flags);
539 break;
540 }
541 #endif
542
543 default:
544 {
545 SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4,
546 void*, arg5, void*, arg6, void*, arg7);
547 ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
548 break;
549 }
550 }
551 va_end(ap);
552 return ret;
553 }
554
555 // TODO: Move these to a separate pthreadwrappers.cpp file.
556 extern "C" int
557 pthread_cond_broadcast(pthread_cond_t *cond)
558 {
559 return _real_pthread_cond_broadcast(cond);
560 }
561
562 extern "C" int
563 pthread_cond_destroy(pthread_cond_t *cond)
564 {
565 return _real_pthread_cond_destroy(cond);
566 }
567
568 extern "C" int
569 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
570 {
571 return _real_pthread_cond_init(cond, attr);
572 }
573
574 extern "C" int
575 pthread_cond_signal(pthread_cond_t *cond)
576 {
577 return _real_pthread_cond_signal(cond);
578 }
579
580 extern "C" int
581 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
582 const struct timespec *abstime)
583 {
584 return _real_pthread_cond_timedwait(cond, mutex, abstime);
585 }
586
587 extern "C" int
588 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
589 {
590 return _real_pthread_cond_wait(cond, mutex);
591 }
592
593
594 extern "C" int
595 pthread_mutex_lock(pthread_mutex_t *mutex)
596 {
597 return _real_pthread_mutex_lock(mutex);
598 }
599
600 extern "C" int
601 pthread_mutex_unlock(pthread_mutex_t *mutex)
602 {
603 return _real_pthread_mutex_unlock(mutex);
604 }
605
606 /*
607 extern "C" int
608 printf (const char *format, ...)
609 {
610 va_list arg;
611 int done;
612
613 va_start (arg, format);
614 done = vfprintf (stdout, format, arg);
615 va_end (arg);
616
617 return done;
618 }
619
620 extern "C" int
621 fprintf (FILE *stream, const char *format, ...)
622 {
623 va_list arg;
624 int done;
625
626 va_start (arg, format);
627 done = vfprintf (stream, format, arg);
628 va_end (arg);
629
630 return done;
631 }
632
633 extern "C" int
634 vprintf (const char *format, __gnuc_va_list arg)
635 {
636 return vfprintf (stdout, format, arg);
637 }
638
639 extern "C" int
640 vfprintf (FILE *s, const char *format, va_list ap)
641 {
642 WRAPPER_EXECUTION_DISABLE_CKPT();
643 int retVal = _real_vfprintf ( s, format, ap );
644 WRAPPER_EXECUTION_ENABLE_CKPT();
645 return retVal;
646 }
647
648
649 extern "C" int
650 sprintf (char *s, const char *format, ...)
651 {
652 va_list arg;
653 int done;
654
655 va_start (arg, format);
656 done = vsprintf (s, format, arg);
657 va_end (arg);
658
659 return done;
660 }
661
662
663 extern "C" int
664 snprintf (char *s, size_t maxlen, const char *format, ...)
665 {
666 va_list arg;
667 int done;
668
669 va_start (arg, format);
670 done = vsnprintf (s, maxlen, format, arg);
671 va_end (arg);
672
673 return done;
674 }
675
676
677 extern "C" int vsprintf(char *str, const char *format, va_list ap);
678 extern "C" int vsnprintf(char *str, size_t size, const char *format, va_list ap);
679 */