NO_OPTIMIZE static void restore_brk(VA saved_brk, VA restore_begin, VA restore_end) { int mtcp_sys_errno; VA current_brk; VA new_brk; /* The kernel (2.6.9 anyway) has a variable mm->brk that we should restore. * The only access we have is brk() which basically sets mm->brk to the new * value, but also has a nasty side-effect (as far as we're concerned) of * mmapping an anonymous section between the old value of mm->brk and the * value being passed to brk(). It will munmap the bracketed memory if the * value being passed is lower than the old value. But if zero, it will * return the current mm->brk value. * * So we're going to restore the brk here. As long as the current mm->brk * value is below the static restore region, we're ok because we 'know' the * restored brk can't be in the static restore region, and we don't care if * the kernel mmaps something or munmaps something because we're going to wipe * it all out anyway. */ current_brk = mtcp_sys_brk (NULL); if ((current_brk > restore_begin) && (saved_brk < restore_end)) { MTCP_PRINTF("current_brk %p, saved_brk %p, restore_begin %p," " restore_end %p\n", current_brk, saved_brk, restore_begin, restore_end); mtcp_abort (); } new_brk = mtcp_sys_brk (saved_brk); if (new_brk == (VA)-1) { MTCP_PRINTF("sbrk(%p): errno: %d (bad heap)\n", saved_brk, mtcp_sys_errno ); mtcp_abort(); } else if (new_brk > current_brk) { // Now unmap the just mapped extended heap. This is to ensure that we don't // have overlap with the restore region. if (mtcp_sys_munmap(current_brk, new_brk - current_brk) == -1) { MTCP_PRINTF("***WARNING: munmap failed; errno: %d\n", mtcp_sys_errno); } } if (new_brk != saved_brk) { if (new_brk == current_brk && new_brk > saved_brk) DPRINTF("new_brk == current_brk == %p\n; saved_break, %p," " is strictly smaller;\n data segment not extended.\n", new_brk, saved_brk); else { if (new_brk == current_brk) MTCP_PRINTF("error: new/current break (%p) != saved break (%p)\n", current_brk, saved_brk); else MTCP_PRINTF("error: new break (%p) != current break (%p)\n", new_brk, current_brk); //mtcp_abort (); } } }
NO_OPTIMIZE static void restorememoryareas(RestoreInfo *rinfo_ptr) { int mtcp_sys_errno; DPRINTF("Entering copy of restorememoryareas(). Will now unmap old memory" "\n and restore memory sections from the checkpoint image.\n"); DPRINTF("DPRINTF may fail when we unmap, since strings are in rodata.\n" "But we may be lucky if the strings have been cached by the O/S\n" "or if compiler uses relative addressing for rodata with -fPIC\n"); if (rinfo_ptr->use_gdb) { MTCP_PRINTF("Called with --use-gdb. A useful command is:\n" " (gdb) info proc mapping"); if (rinfo_ptr->text_offset != -1) { MTCP_PRINTF("Called with --text-offset 0x%x. A useful command is:\n" "(gdb) add-symbol-file ../../bin/mtcp_restart %p\n", rinfo_ptr->text_offset, rinfo_ptr->restore_addr + rinfo_ptr->text_offset); #if defined(__i386__) || defined(__x86_64__) asm volatile ("int3"); // Do breakpoint; send SIGTRAP, caught by gdb #else MTCP_PRINTF("IN GDB: interrupt (^C); add-symbol-file ...; (gdb) print x=0\n"); { int x = 1; while (x); } // Stop execution for user to type command. #endif }
// Used by util/readdmtcp.sh // So, we use mtcp_printf to stdout instead of MTCP_PRINTF (diagnosis for DMTCP) static void mtcp_simulateread(int fd, MtcpHeader *mtcpHdr) { int mtcp_sys_errno; // Print miscellaneous information: char buf[MTCP_SIGNATURE_LEN+1]; mtcp_memcpy(buf, mtcpHdr->signature, MTCP_SIGNATURE_LEN); buf[MTCP_SIGNATURE_LEN] = '\0'; mtcp_printf("\nMTCP: %s", buf); mtcp_printf("**** mtcp_restart (will be copied here): %p-%p\n", mtcpHdr->restore_addr, mtcpHdr->restore_addr + mtcpHdr->restore_size); mtcp_printf("**** DMTCP entry point (ThreadList::postRestart()): %p\n", mtcpHdr->post_restart); mtcp_printf("**** brk (sbrk(0)): %p\n", mtcpHdr->saved_brk); mtcp_printf("**** vdso: %p-%p\n", mtcpHdr->vdsoStart, mtcpHdr->vdsoEnd); mtcp_printf("**** vvar: %p-%p\n", mtcpHdr->vvarStart, mtcpHdr->vvarEnd); Area area; mtcp_printf("\n**** Listing ckpt image area:\n"); while(1) { mtcp_readfile(fd, &area, sizeof area); if (area.size == -1) break; if ((area.properties & DMTCP_ZERO_PAGE) == 0 && (area.properties & DMTCP_SKIP_WRITING_TEXT_SEGMENTS) == 0) { void *addr = mtcp_sys_mmap(0, area.size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) { MTCP_PRINTF("***Error: mmap failed; errno: %d\n", mtcp_sys_errno); mtcp_abort(); } mtcp_readfile(fd, addr, area.size); if (mtcp_sys_munmap(addr, area.size) == -1) { MTCP_PRINTF("***Error: munmap failed; errno: %d\n", mtcp_sys_errno); mtcp_abort(); } } mtcp_printf("%p-%p %c%c%c%c " // "%x %u:%u %u" " %s\n", area.addr, area.addr + area.size, ( area.prot & PROT_READ ? 'r' : '-' ), ( area.prot & PROT_WRITE ? 'w' : '-' ), ( area.prot & PROT_EXEC ? 'x' : '-' ), ( area.flags & MAP_SHARED ? 's' : ( area.flags & MAP_ANONYMOUS ? 'p' : '-' ) ), //area.offset, area.devmajor, area.devminor, area.inodenum, area.name); } }
void mtcp_skipfile(int fd, size_t size) { VA tmp_addr = mtcp_sys_mmap(0, size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (tmp_addr == MAP_FAILED) { MTCP_PRINTF("mtcp_sys_mmap() failed with error: %d", mtcp_sys_errno); mtcp_abort(); } mtcp_readfile(fd, tmp_addr, size); if (mtcp_sys_munmap(tmp_addr, size) == -1) { MTCP_PRINTF("mtcp_sys_munmap() failed with error: %d", mtcp_sys_errno); mtcp_abort(); } }
NO_OPTIMIZE static void restart_fast_path() { int mtcp_sys_errno; void *addr = mtcp_sys_mmap(rinfo.restore_addr, rinfo.restore_size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) { MTCP_PRINTF("mmap failed with error; errno: %d\n", mtcp_sys_errno); mtcp_abort(); } size_t offset = (char*)&restorememoryareas - rinfo.text_addr; rinfo.restorememoryareas_fptr = (fnptr_t)(rinfo.restore_addr + offset); /* For __arm__ * should be able to use kernel call: __ARM_NR_cacheflush(start, end, flag) * followed by copying new text below, followed by DSB and ISB, * to eliminstate need for delay loop. But this needs more testing. */ mtcp_memcpy(rinfo.restore_addr, rinfo.text_addr, rinfo.text_size); mtcp_memcpy(rinfo.restore_addr + rinfo.text_size, &rinfo, sizeof(rinfo)); void *stack_ptr = rinfo.restore_addr + rinfo.restore_size - MB; #if defined(__INTEL_COMPILER) && defined(__x86_64__) memfence(); asm volatile (CLEAN_FOR_64_BIT(mov %0,%%esp;)
void mtcp_rename_ckptfile(const char *tempckpt, const char *permckpt) { if (mtcp_sys_rename(tempckpt, permckpt) < 0) { MTCP_PRINTF("error %d renaming %s to %s\n", mtcp_sys_errno, tempckpt, permckpt); mtcp_abort (); } }
void mtcp_readcs(int fd, char cs) { char xcs; mtcp_readfile (fd, &xcs, sizeof xcs); if (xcs != cs) { MTCP_PRINTF("checkpoint section %d next, expected %d\n", xcs, cs); mtcp_abort (); } }
/** * This function will return the first character of the given file. If the * file is not readable, we will abort. * * @param filename the name of the file to read * @return the first character of the given file */ static char first_char(char *filename) { int fd, rc; char c; fd = mtcp_sys_open(filename, O_RDONLY, 0); if(fd < 0) { MTCP_PRINTF("ERROR: Cannot open file %s\n", filename); mtcp_abort(); } rc = mtcp_sys_read(fd, &c, 1); if(rc != 1) { MTCP_PRINTF("ERROR: Error reading from file %s\n", filename); mtcp_abort(); } mtcp_sys_close(fd); return c; }
void mtcp_readfile(int fd, void *buf, size_t size) { ssize_t rc; size_t ar = 0; int tries = 0; while(ar != size) { rc = mtcp_sys_read(fd, (char*)buf + ar, size - ar); if (rc < 0 && rc > -4096) { /* kernel could return large unsigned int */ MTCP_PRINTF("error %d reading checkpoint\n", mtcp_sys_errno); mtcp_abort(); } else if (rc == 0) { MTCP_PRINTF("only read %u bytes instead of %u from checkpoint file\n", (unsigned)ar, (unsigned)size); if (tries++ >= 10) { MTCP_PRINTF(" failed to read after 10 tries in a row.\n"); mtcp_abort(); } } ar += rc; } }
void mtcp_writefile (int fd, void const *buff, size_t size) { char const *bf; ssize_t rc; size_t sz, wt; static char zeroes[MTCP_PAGE_SIZE] = { 0 }; //checkpointsize += size; bf = buff; sz = size; while (sz > 0) { for (wt = sz; wt > 0; wt /= 2) { rc = mtcp_sys_write (fd, bf, wt); if ((rc >= 0) || (mtcp_sys_errno != EFAULT)) break; } /* Sometimes image page alignment will leave a hole in the middle of an * image ... but the idiot proc/self/maps will include it anyway */ if (wt == 0) { rc = (sz > sizeof zeroes ? sizeof zeroes : sz); //checkpointsize -= rc; /* Correct now, since mtcp_writefile will add rc // back */ mtcp_writefile (fd, zeroes, rc); } /* Otherwise, check for real error */ else { if (rc == 0) mtcp_sys_errno = EPIPE; if (rc <= 0) { MTCP_PRINTF("Error %d writing from %p to checkpoint file.\n", mtcp_sys_errno, bf); mtcp_abort (); } } /* It's ok, we're on to next part */ sz -= rc; bf += rc; } }
void __stack_chk_fail_local(void) { MTCP_PRINTF("ERROR: Stack Overflow detected.\n"); mtcp_abort(); }
void __stack_chk_guard(void) { MTCP_PRINTF("ERROR: Stack Overflow detected.\n"); mtcp_abort(); }
void _Unwind_Resume(void) { MTCP_PRINTF("MTCP Internal Error: %s Not Implemented.\n", __FUNCTION__); mtcp_abort(); }
NO_OPTIMIZE int main(int argc, char *argv[], char **environ) { char *ckptImage = NULL; MtcpHeader mtcpHdr; int mtcp_sys_errno; int simulate = 0; if (argc == 1) { MTCP_PRINTF("***ERROR: This program should not be used directly.\n"); mtcp_sys_exit(1); } #if 0 MTCP_PRINTF("Attach for debugging."); {int x=1; while(x);} #endif // TODO(karya0): Remove vDSO checks after 2.4.0-rc3 release, and after testing. // Without mtcp_check_vdso, CentOS 7 fails on dmtcp3, dmtcp5, others. #define ENABLE_VDSO_CHECK // TODO(karya0): Remove this block and the corresponding file after sufficient // testing: including testing for __i386__, __arm__ and __aarch64__ #ifdef ENABLE_VDSO_CHECK /* i386 uses random addresses for vdso. Make sure that its location * will not conflict with other memory regions. * (Other arch's may also need this in the future. So, we do it for all.) * Note that we may need to keep the old and the new vdso. We may * have checkpointed inside gettimeofday inside the old vdso, and the * kernel, on restart, knows only the new vdso. */ mtcp_check_vdso(environ); #endif rinfo.fd = -1; rinfo.use_gdb = 0; rinfo.text_offset = -1; shift; while (argc > 0) { // Flags for standalone debugging if (argc == 1) { // We would use MTCP_PRINTF, but it's also for output of util/readdmtcp.sh mtcp_printf("Considering '%s' as a ckpt image.\n", argv[0]); ckptImage = argv[0]; break; } else if (mtcp_strcmp(argv[0], "--use-gdb") == 0) { rinfo.use_gdb = 1; shift; } else if (mtcp_strcmp(argv[0], "--text-offset") == 0) { rinfo.text_offset = mtcp_strtol(argv[1]); shift; shift; // Flags for call by dmtcp_restart follow here: } else if (mtcp_strcmp(argv[0], "--fd") == 0) { rinfo.fd = mtcp_strtol(argv[1]); shift; shift; } else if (mtcp_strcmp(argv[0], "--stderr-fd") == 0) { rinfo.stderr_fd = mtcp_strtol(argv[1]); shift; shift; } else if (mtcp_strcmp(argv[0], "--simulate") == 0) { simulate = 1; shift; } else { MTCP_PRINTF("MTCP Internal Error\n"); return -1; } } if ((rinfo.fd != -1) ^ (ckptImage == NULL)) { MTCP_PRINTF("***MTCP Internal Error\n"); mtcp_abort(); } if (rinfo.fd != -1) { mtcp_readfile(rinfo.fd, &mtcpHdr, sizeof mtcpHdr); } else { int rc = -1; rinfo.fd = mtcp_sys_open2(ckptImage, O_RDONLY); if (rinfo.fd == -1) { MTCP_PRINTF("***ERROR opening ckpt image (%s); errno: %d\n", ckptImage, mtcp_sys_errno); mtcp_abort(); } // This assumes that the MTCP header signature is unique. // We repeatedly look for mtcpHdr because the first header will be // for DMTCP. So, we look deeper for the MTCP header. The MTCP // header is guaranteed to start on an offset that's an integer // multiple of sizeof(mtcpHdr), which is currently 4096 bytes. do { rc = mtcp_readfile(rinfo.fd, &mtcpHdr, sizeof mtcpHdr); } while (rc > 0 && mtcp_strcmp(mtcpHdr.signature, MTCP_SIGNATURE) != 0); if (rc == 0) { /* if end of file */ MTCP_PRINTF("***ERROR: ckpt image doesn't match MTCP_SIGNATURE\n"); return 1; /* exit with error code 1 */ } } DPRINTF("For debugging:\n" " (gdb) add-symbol-file ../../bin/mtcp_restart %p\n", mtcpHdr.restore_addr + rinfo.text_offset); if (rinfo.text_offset == -1) DPRINTF("... but add to the above the result, 1 +" " `text_offset.sh mtcp_restart`\n in the mtcp subdirectory.\n"); if (simulate) { mtcp_simulateread(rinfo.fd, &mtcpHdr); return 0; } rinfo.saved_brk = mtcpHdr.saved_brk; rinfo.restore_addr = mtcpHdr.restore_addr; rinfo.restore_end = mtcpHdr.restore_addr + mtcpHdr.restore_size; rinfo.restore_size = mtcpHdr.restore_size; rinfo.vdsoStart = mtcpHdr.vdsoStart; rinfo.vdsoEnd = mtcpHdr.vdsoEnd; rinfo.vvarStart = mtcpHdr.vvarStart; rinfo.vvarEnd = mtcpHdr.vvarEnd; rinfo.post_restart = mtcpHdr.post_restart; rinfo.motherofall_tls_info = mtcpHdr.motherofall_tls_info; rinfo.tls_pid_offset = mtcpHdr.tls_pid_offset; rinfo.tls_tid_offset = mtcpHdr.tls_tid_offset; rinfo.myinfo_gs = mtcpHdr.myinfo_gs; restore_brk(rinfo.saved_brk, rinfo.restore_addr, rinfo.restore_addr + rinfo.restore_size); getTextAddr(&rinfo.text_addr, &rinfo.text_size); if (hasOverlappingMapping(rinfo.restore_addr, rinfo.restore_size)) { MTCP_PRINTF("*** Not Implemented.\n\n"); mtcp_abort(); restart_slow_path(); } else { restart_fast_path(); } return 0; /* Will not reach here, but need to satisfy the compiler */ }
/** * This function will open the checkpoint file stored at the given filename. * It will check the magic number and take the appropriate action. If the * magic number is unknown, we will abort. The fd returned points to the * beginning of the uncompressed data. * NOTE: related code in ../dmtcp/src/connectionmanager.cpp:open_ckpt_to_read() * * @param filename the name of the checkpoint file * @return the fd to use */ static int open_ckpt_to_read(char *filename, char *envp[]) { int fd; int fds[2]; char fc; char *gzip_cmd = "gzip"; static char *gzip_args[] = { "gzip", "-d", "-", NULL }; #ifdef HBICT_DELTACOMP char *hbict_cmd = "hbict"; static char *hbict_args[] = { "hbict", "-r", NULL }; #endif char decomp_path[PATH_MAX]; static char **decomp_args; pid_t cpid; fc = first_char(filename); fd = mtcp_sys_open(filename, O_RDONLY, 0); if(fd < 0) { MTCP_PRINTF("ERROR: Cannot open checkpoint file %s\n", filename); mtcp_abort(); } if (fc == MAGIC_FIRST || fc == 'D') /* no compression ('D' from DMTCP) */ return fd; else if (fc == GZIP_FIRST #ifdef HBICT_DELTACOMP || fc == HBICT_FIRST #endif ) { /* Set prog_path */ if( fc == GZIP_FIRST ){ decomp_args = gzip_args; if( mtcp_find_executable(gzip_cmd, getenv("PATH"), decomp_path) == NULL ) { MTCP_PRINTF("ERROR: Cannot find gunzip to decompress ckpt file!\n"); mtcp_abort(); } } #ifdef HBICT_DELTACOMP if( fc == HBICT_FIRST ){ decomp_args = hbict_args; if( mtcp_find_executable(hbict_cmd, getenv("PATH"), decomp_path) == NULL ) { MTCP_PRINTF("ERROR: Cannot find hbict to decompress ckpt file!\n"); mtcp_abort(); } } #endif if (mtcp_sys_pipe(fds) == -1) { MTCP_PRINTF("ERROR: Cannot create pipe to execute gunzip to decompress" " checkpoint file!\n"); mtcp_abort(); } cpid = mtcp_sys_fork(); if(cpid == -1) { MTCP_PRINTF("ERROR: Cannot fork to execute gunzip to decompress" " checkpoint file!\n"); mtcp_abort(); } else if(cpid > 0) /* parent process */ { decomp_child_pid = cpid; mtcp_sys_close(fd); mtcp_sys_close(fds[1]); return fds[0]; } else /* child process */ { fd = mtcp_sys_dup(mtcp_sys_dup(mtcp_sys_dup(fd))); if (fd == -1) { MTCP_PRINTF("ERROR: dup() failed! No restoration will be performed!" " Cancel now!\n"); mtcp_abort(); } fds[1] = mtcp_sys_dup(fds[1]); mtcp_sys_close(fds[0]); if (mtcp_sys_dup2(fd, STDIN_FILENO) != STDIN_FILENO) { MTCP_PRINTF("ERROR: dup2() failed! No restoration will be performed!" " Cancel now!\n"); mtcp_abort(); } mtcp_sys_close(fd); mtcp_sys_dup2(fds[1], STDOUT_FILENO); mtcp_sys_close(fds[1]); mtcp_sys_execve(decomp_path, decomp_args, envp); /* should not get here */ MTCP_PRINTF("ERROR: Decompression failed! No restoration will be" " performed! Cancel now!\n"); mtcp_abort(); } } else /* invalid magic number */ { MTCP_PRINTF("ERROR: Invalid magic number in this checkpoint file!\n"); mtcp_abort(); } }
void __gcc_personality_v0(void) { MTCP_PRINTF("MTCP Internal Error: %s Not Implemented.\n", __FUNCTION__); mtcp_abort(); }
int main (int argc, char *argv[], char *envp[]) { char magicbuf[MAGIC_LEN], *restorename; int fd, verify; size_t restore_size, offset=0; void *restore_begin, *restore_mmap; void (*restore_start) (int fd, int verify, pid_t decomp_child_pid, char *ckpt_newname, char *cmd_file, char *argv[], char *envp[]); char cmd_file[PATH_MAX+1]; char ckpt_newname[PATH_MAX+1] = ""; char **orig_argv = argv; int orig_argc = argc; environ = envp; if (mtcp_sys_getuid() == 0 || mtcp_sys_geteuid() == 0) { mtcp_printf("Running mtcp_restart as root is dangerous. Aborting.\n" \ "If you still want to do this (at your own risk)," \ " then modify mtcp/%s:%d and re-compile.\n", __FILE__, __LINE__ - 4); mtcp_abort(); } // Turn off randomize_va (by re-exec'ing) or warn user if vdso_enabled is on. mtcp_check_vdso_enabled(); fd = decomp_child_pid = -1; verify = 0; shift; while (1) { if (argc == 0 || (mtcp_strcmp(argv[0], "--help") == 0 && argc == 1)) { mtcp_printf("%s", theUsage); return (-1); } else if (mtcp_strcmp (argv[0], "--version") == 0 && argc == 1) { mtcp_printf("%s", VERSION_AND_COPYRIGHT_INFO); return (-1); } else if (mtcp_strcmp (argv[0], "--verify") == 0 && argc == 2) { verify = 1; restorename = argv[1]; break; } else if (mtcp_strcmp (argv[0], "--offset") == 0 && argc >= 3) { offset = mtcp_atoi(argv[1]); shift; shift; } else if (mtcp_strcmp (argv[0], "--fd") == 0 && argc >= 2) { fd = mtcp_atoi(argv[1]); shift; shift; } else if (mtcp_strcmp (argv[0], "--gzip-child-pid") == 0 && argc >= 2) { decomp_child_pid = mtcp_atoi(argv[1]); shift; shift; } else if (mtcp_strcmp (argv[0], "--rename-ckpt") == 0 && argc >= 2) { mtcp_strncpy(ckpt_newname, argv[1], PATH_MAX); shift; shift; } else if (mtcp_strcmp (argv[0], "--stderr-fd") == 0 && argc >= 2) { // If using with DMTCP/jassert, Pass in a non-standard stderr dmtcp_info_stderr_fd = mtcp_atoi(argv[1]); shift; shift; } else if (mtcp_strcmp (argv[0], "--") == 0 && argc == 2) { restorename = argv[1]; break; } else if (argc == 1) { restorename = argv[0]; break; } else { mtcp_printf("%s", theUsage); return (-1); } } // Restore argc and argv pointer argv = orig_argv; argc = orig_argc; /* XXX XXX XXX: * DO NOT USE mtcp_printf OR DPRINTF BEFORE THIS BLOCK, IT'S DANGEROUS AND * CAN MESS UP YOUR PROCESSES BY WRITING GARBAGE TO THEIR STDERR FD, * IF THEY ARE NOT USING IT AS STDERR. * --Kapil */ if (fd != -1 && decomp_child_pid != -1) { restorename = NULL; } else if ((fd == -1 && decomp_child_pid != -1) || (offset != 0 && fd != -1)) { mtcp_printf("%s", theUsage); return (-1); } if (restorename) { #if 1 if (mtcp_sys_access(restorename, R_OK) != 0 && mtcp_sys_errno == EACCES) { MTCP_PRINTF("\nProcess does not have read permission for\n" \ " checkpoint image (%s).\n" \ " (Check file permissions, UIDs etc.)\n", restorename); mtcp_abort(); } #else struct stat buf; int rc = mtcp_sys_stat(restorename, &buf); if (rc == -1) { MTCP_PRINTF("Error %d stat()'ing ckpt image %s.", mtcp_sys_errno, restorename); mtcp_abort(); } else if (buf.st_uid != mtcp_sys_getuid()) { /*Could also run if geteuid() matches*/ MTCP_PRINTF("\nProcess uid (%d) doesn't match uid (%d) of\n" \ " checkpoint image (%s).\n" \ "This is dangerous. Aborting for security reasons.\n" \ "If you still want to do this, modify mtcp/%s:%d and" " re-compile.\n", mtcp_sys_getuid(), buf.st_uid, restorename, __FILE__, __LINE__ - 5); mtcp_abort(); } #endif } if (mtcp_strlen(ckpt_newname) == 0 && restorename != NULL && offset != 0) { mtcp_strncpy(ckpt_newname, restorename, PATH_MAX); } if (restorename!=NULL) fd = open_ckpt_to_read(restorename, envp); if (offset>0) { //skip into the file a bit VA addr = (VA) mtcp_sys_mmap(0, offset, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) { MTCP_PRINTF("mmap failed with error %d\n", mtcp_sys_errno); mtcp_abort(); } mtcp_readfile(fd, addr, offset); if (mtcp_sys_munmap(addr, offset) == -1) { MTCP_PRINTF("munmap failed with error %d\n", mtcp_sys_errno); mtcp_abort(); } } mtcp_memset(magicbuf, 0, sizeof magicbuf); mtcp_readfile (fd, magicbuf, MAGIC_LEN); if (mtcp_memcmp (magicbuf, MAGIC, MAGIC_LEN) != 0) { MTCP_PRINTF("'%s' is '%s', but this restore is '%s' (fd=%d)\n", restorename, magicbuf, MAGIC, fd); return (-1); } /* Set the resource limits for stack from saved values */ struct rlimit stack_rlimit; #ifdef FAST_CKPT_RST_VIA_MMAP Area area; fastckpt_read_header(fd, &stack_rlimit, &area, (VA*) &restore_start); restore_begin = area.addr; restore_size = area.size; #else mtcp_readcs (fd, CS_STACKRLIMIT); /* resource limit for stack */ mtcp_readfile (fd, &stack_rlimit, sizeof stack_rlimit); /* Find where the restore image goes */ mtcp_readcs (fd, CS_RESTOREBEGIN); /* beginning of checkpointed libmtcp.so image */ mtcp_readfile (fd, &restore_begin, sizeof restore_begin); mtcp_readcs (fd, CS_RESTORESIZE); /* size of checkpointed libmtcp.so image */ mtcp_readfile (fd, &restore_size, sizeof restore_size); mtcp_readcs (fd, CS_RESTORESTART); mtcp_readfile (fd, &restore_start, sizeof restore_start); DPRINTF("saved stack resource limit: soft_lim:%p, hard_lim:%p\n", stack_rlimit.rlim_cur, stack_rlimit.rlim_max); #endif // FAST_CKPT_RST_VIA_MMAP mtcp_sys_setrlimit(RLIMIT_STACK, &stack_rlimit); /* Read in the restore image to same address where it was loaded at time * of checkpoint. This is libmtcp.so, including both text and data sections * as a single section. Hence, we need both write and exec permission, * and MAP_ANONYMOUS, since the data could have changed. */ DPRINTF("restoring anonymous area %p at %p\n", restore_size, restore_begin); if (mtcp_sys_munmap(restore_begin, restore_size) < 0) { MTCP_PRINTF("failed to unmap region at %p\n", restore_begin); mtcp_abort (); } #ifdef FAST_CKPT_RST_VIA_MMAP fastckpt_load_restore_image(fd, &area); #else restore_mmap = mtcp_safemmap (restore_begin, restore_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_FIXED | MAP_PRIVATE, -1, 0); if (restore_mmap == MAP_FAILED) { #ifndef _XOPEN_UNIX MTCP_PRINTF("Does mmap here support MAP_FIXED?\n"); #endif if (mtcp_sys_errno != EBUSY) { MTCP_PRINTF("Error %d creating %p byte restore region at %p.\n", mtcp_sys_errno, restore_size, restore_begin); mtcp_abort (); } else { MTCP_PRINTF("restarting due to address conflict...\n"); mtcp_sys_close (fd); mtcp_sys_execve (argv[0], argv, envp); } } if (restore_mmap != restore_begin) { MTCP_PRINTF("%p byte restore region at %p got mapped at %p\n", restore_size, restore_begin, restore_mmap); mtcp_abort (); } mtcp_readcs (fd, CS_RESTOREIMAGE); mtcp_readfile (fd, restore_begin, restore_size); #endif #ifndef __x86_64__ // Copy command line to libmtcp.so, so that we can re-exec if randomized vdso // steps on us. This won't be needed when we use the linker to map areas. cmd_file[0] = '\0'; { int cmd_len = mtcp_sys_readlink("/proc/self/exe", cmd_file, PATH_MAX); if (cmd_len == -1) MTCP_PRINTF("WARNING: Couldn't find /proc/self/exe." " Trying to continue anyway.\n"); else cmd_file[cmd_len] = '\0'; } #endif #ifdef LIBC_STATIC_AVAILABLE /******************************************************************** * Apparently, there is no consistent way to define LIBC_STATIC_AVAILABLE. * The purpose of the code below is to be able to use a symbolic debugger * like gdb when dmtcp_restart calls MTCP. It would print a command that * you can paste into gdb to allow debugging inside the function restore_start. * When "ifdef LIBC_STATIC_AVAILABLE" was added, mtcp/Makefile was modified * to forbid using functions from libc.a like popen. If you want to debug * restore_start(), you should read the code below and manually calculate * by hand what this used to automatically calculate. For a semi-automated * substitute, when you reach restore_start(), call it with (gdb) si * Then try: (gdb) shell ../utils/gdb-add-libmtcp-symbol-file.py * where ADDR will be restore_start or an arb. address in restore_start() ********************************************************************/ # ifdef DEBUG char *p, symbolbuff[256]; FILE *symbolfile; long textbase; /* offset */ MTCP_PRINTF("restore_begin=%p, restore_start=%p\n", restore_begin, restore_start); textbase = 0; symbolfile = popen ("readelf -S libmtcp.so", "r"); if (symbolfile != NULL) { while (fgets (symbolbuff, sizeof symbolbuff, symbolfile) != NULL) { if (memcmp (symbolbuff + 5, "] .text ", 8) == 0) { textbase = strtoul (symbolbuff + 41, &p, 16); } } pclose (symbolfile); if (textbase != 0) { mtcp_printf("\n**********\nmtcp_restart*: The symbol table of the" " checkpointed file can be\nmade available to gdb." " Just type the command below in gdb:\n"); mtcp_printf(" add-symbol-file libmtcp.so %p\n", restore_begin + textbase); mtcp_printf("Then type \"continue\" to continue debugging.\n"); mtcp_printf("**********\n"); } } mtcp_maybebpt (); # endif #endif /* Now call it - it shouldn't return */ (*restore_start) (fd, verify, decomp_child_pid, ckpt_newname, cmd_file, argv, envp); MTCP_PRINTF("restore routine returned (it should never do this!)\n"); mtcp_abort (); return (0); }