Esempio n. 1
0
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 ();
    }
  }
}
Esempio n. 2
0
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
    }
Esempio n. 3
0
// 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);
  }
}
Esempio n. 4
0
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();
  }
}
Esempio n. 5
0
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;)
Esempio n. 6
0
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 ();
  }
}
Esempio n. 8
0
/**
 * 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;
  }
}
Esempio n. 11
0
void __stack_chk_fail_local(void)
{
  MTCP_PRINTF("ERROR: Stack Overflow detected.\n");
  mtcp_abort();
}
Esempio n. 12
0
void __stack_chk_guard(void)
{
  MTCP_PRINTF("ERROR: Stack Overflow detected.\n");
  mtcp_abort();
}
Esempio n. 13
0
void _Unwind_Resume(void)
{
  MTCP_PRINTF("MTCP Internal Error: %s Not Implemented.\n", __FUNCTION__);
  mtcp_abort();
}
Esempio n. 14
0
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 */
}
Esempio n. 15
0
/**
 * 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();
  }
}
Esempio n. 16
0
void __gcc_personality_v0(void)
{
  MTCP_PRINTF("MTCP Internal Error: %s Not Implemented.\n", __FUNCTION__);
  mtcp_abort();
}
Esempio n. 17
0
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);
}