Ejemplo n.º 1
0
/* Rebase r_address in the relocation table.  */
static void
rebase_reloc_address (off_t reloff, int nrel, long linkedit_delta, long diff)
{
  int i;
  struct relocation_info reloc_info;
  struct scattered_relocation_info *sc_reloc_info
    = (struct scattered_relocation_info *) &reloc_info;

  for (i = 0; i < nrel; i++, reloff += sizeof (reloc_info))
    {
      if (lseek (infd, reloff - linkedit_delta, L_SET)
	  != reloff - linkedit_delta)
	unexec_error ("rebase_reloc_table: cannot seek to reloc_info");
      if (!unexec_read (&reloc_info, sizeof (reloc_info)))
	unexec_error ("rebase_reloc_table: cannot read reloc_info");

      if (sc_reloc_info->r_scattered == 0
	  && reloc_info.r_type == GENERIC_RELOC_VANILLA)
	{
	  reloc_info.r_address -= diff;
	  if (!unexec_write (reloff, &reloc_info, sizeof (reloc_info)))
	    unexec_error ("rebase_reloc_table: cannot write reloc_info");
	}
    }
}
Ejemplo n.º 2
0
/* Fix up relocation entries. */
static void
unrelocate (const char *name, off_t reloff, int nrel, vm_address_t base)
{
  int i, unreloc_count;
  struct relocation_info reloc_info;
  struct scattered_relocation_info *sc_reloc_info
    = (struct scattered_relocation_info *) &reloc_info;
  vm_address_t location;

  for (unreloc_count = 0, i = 0; i < nrel; i++)
    {
      if (lseek (infd, reloff, L_SET) != reloff)
	unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i);
      if (!unexec_read (&reloc_info, sizeof (reloc_info)))
	unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i);
      reloff += sizeof (reloc_info);

      if (sc_reloc_info->r_scattered == 0)
	switch (reloc_info.r_type)
	  {
	  case GENERIC_RELOC_VANILLA:
	    location = base + reloc_info.r_address;
	    if (location >= data_segment_scp->vmaddr
		&& location < (data_segment_scp->vmaddr
			       + data_segment_scp->vmsize))
	      {
		off_t src_off = data_segment_old_fileoff
		  + (location - data_segment_scp->vmaddr);
		off_t dst_off = data_segment_scp->fileoff
		  + (location - data_segment_scp->vmaddr);

		if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length))
		  unexec_error ("unrelocate: %s:%d cannot copy original value",
				name, i);
		unreloc_count++;
	      }
	    break;
	  default:
	    unexec_error ("unrelocate: %s:%d cannot handle type = %d",
			  name, i, reloc_info.r_type);
	  }
      else
	switch (sc_reloc_info->r_type)
	  {
#if defined (__ppc__)
	  case PPC_RELOC_PB_LA_PTR:
	    /* nothing to do for prebound lazy pointer */
	    break;
#endif
	  default:
	    unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d",
			  name, i, sc_reloc_info->r_type);
	  }
    }

  if (nrel > 0)
    printf ("Fixed up %d/%d %s relocation entries in data segment.\n",
	    unreloc_count, nrel, name);
}
Ejemplo n.º 3
0
static void
unexec_copy (int new_fd, int old_fd, long old_pos, long new_pos, int bytes)
{
    int remains = bytes;        
    char buf[128];

    while (remains > 0)
      {
          int n_to_copy = remains > sizeof(buf) ? sizeof(buf) : remains;

          unexec_read (old_fd, old_pos, buf, n_to_copy);
          unexec_write (new_fd, new_pos, buf, n_to_copy);

          old_pos += n_to_copy;
          new_pos += n_to_copy;
          remains -= n_to_copy;
      }

    return;
}
Ejemplo n.º 4
0
/* Read header and load commands from input file.  Store the latter in
   the global array lca.  Store the total number of load commands in
   global variable nlc.  */
static void
read_load_commands (void)
{
  int i;

  if (!unexec_read (&mh, sizeof (struct mach_header)))
    unexec_error ("cannot read mach-o header");

  if (mh.magic != MH_MAGIC)
    unexec_error ("input file not in Mach-O format");

  if (mh.filetype != MH_EXECUTE)
    unexec_error ("input Mach-O file is not an executable object file");

#if VERBOSE
  printf ("--- Header Information ---\n");
  printf ("Magic = 0x%08x\n", mh.magic);
  printf ("CPUType = %d\n", mh.cputype);
  printf ("CPUSubType = %d\n", mh.cpusubtype);
  printf ("FileType = 0x%x\n", mh.filetype);
  printf ("NCmds = %d\n", mh.ncmds);
  printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
  printf ("Flags = 0x%08x\n", mh.flags);
#endif

  nlc = mh.ncmds;
  lca = malloc (nlc * sizeof *lca);

  for (i = 0; i < nlc; i++)
    {
      struct load_command lc;
      /* Load commands are variable-size: so read the command type and
	 size first and then read the rest.  */
      if (!unexec_read (&lc, sizeof (struct load_command)))
        unexec_error ("cannot read load command");
      lca[i] = malloc (lc.cmdsize);
      memcpy (lca[i], &lc, sizeof (struct load_command));
      if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
        unexec_error ("cannot read content of load command");
      if (lc.cmd == LC_SEGMENT)
	{
	  struct segment_command *scp = (struct segment_command *) lca[i];

	  if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
	    infile_lc_highest_addr = scp->vmaddr + scp->vmsize;

	  if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
	    {
	      struct section *sectp = (struct section *) (scp + 1);
	      int j;

	      for (j = 0; j < scp->nsects; j++)
		if (sectp->offset < text_seg_lowest_offset)
		  text_seg_lowest_offset = sectp->offset;
	    }
	}
    }

  printf ("Highest address of load commands in input file: %#8lx\n",
	  (unsigned long)infile_lc_highest_addr);

  printf ("Lowest offset of all sections in __TEXT segment: %#8lx\n",
	  text_seg_lowest_offset);

  printf ("--- List of Load Commands in Input File ---\n");
  printf ("# cmd              cmdsize name                address     size\n");

  for (i = 0; i < nlc; i++)
    {
      printf ("%1d ", i);
      print_load_command (lca[i]);
    }
}
Ejemplo n.º 5
0
int
unexec (char *new_name, char *old_name,
        unsigned int emacs_edata, unsigned int dummy1, unsigned int dummy2)
{
  /* /dld.sl data */
  struct dynamic *ld = 0;
  /* old and new state */
  int old_fd;
  int new_fd;
  struct exec old_hdr;
  struct exec new_hdr;
  struct stat old_buf;
  /* some process specific "constants" */
  unsigned long n_pagsiz;
  caddr_t dynamic_beg;
  caddr_t current_break = (caddr_t) sbrk (0);

  /* dynamically linked image? -- if so, find dld.sl structures */
  if (dynamic_addr)
    {
      ld = (struct dynamic *) dynamic_addr;
#ifdef DEBUG
      printf ("dl_text = %#x\n", ld->text);
      printf ("dl_data = %#x\n", ld->data);
      printf ("dl_bss = %#x\n", ld->bss);
      printf ("dl_end = %#x\n", ld->end);
      printf ("dl_dmodule = %#x\n", ld->dmodule);
      printf ("dl_dlt = %#x\n", ld->dlt);
      printf ("dl_plt = %#x\n", ld->plt);
#endif
    }

  /* open the old and new files, figuring out how big the old one is
     so that we can map it in */
  old_fd = unexec_open (old_name, O_RDONLY, 0);
  new_fd = unexec_open (new_name, O_RDWR | O_CREAT | O_TRUNC, 0666);

  /* setup the header and the statbuf for old_fd */
  unexec_read (old_fd, 0, (char *) &old_hdr, sizeof (old_hdr));
  unexec_fstat (old_fd, &old_buf);

  /* set up some important constants */
  n_pagsiz = EXEC_PAGESIZE;

  /* setup beginning of data to copy from executable */
  if (ld)
      dynamic_beg = ld->dmodule;
  else
      dynamic_beg = (caddr_t)EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data;

  /* set up the new exec */
  new_hdr = old_hdr;
  new_hdr.a_text = MASK_DOWN (emacs_edata, n_pagsiz);
  new_hdr.a_data = MASK_UP (current_break, n_pagsiz)
      - EXEC_ALIGN(new_hdr.a_text);
  new_hdr.a_bss  = 0;

#ifdef DEBUG
  printf ("old text %#x\n", old_hdr.a_text);
  printf ("new text %#x\n", new_hdr.a_text);
  printf ("old data %#x\n", old_hdr.a_data);
  printf ("new data %#x\n", new_hdr.a_data);
  printf ("old bss %#x\n", old_hdr.a_bss);
  printf ("new bss %#x\n", new_hdr.a_bss);
#endif

  /* set up this variable, in case we want to reset "the break" 
     when restarting */
  sbrk_of_0_at_unexec = ((unsigned long) MASK_UP (current_break, n_pagsiz));
     
  /* Write out the first approximation to the new file. The sizes of
     each section will be correct, but there will be a number of 
     corrections that will need to be made. */
  {
    long old_datoff = DATA_OFFSET (old_hdr);
    long new_datoff = DATA_OFFSET (new_hdr);
    long old_dataddr = EXEC_ALIGN (old_hdr.a_text);
    long new_dataddr = EXEC_ALIGN (new_hdr.a_text);
    long new_mcaloff = MODCAL_OFFSET (new_hdr);
    long old_mcaloff = MODCAL_OFFSET (old_hdr);
    long newtext_size = new_hdr.a_text - old_dataddr;
    long newdata1_size = (unsigned long)dynamic_beg - new_dataddr;
    long dyn_size = (EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data)
        - (unsigned long)dynamic_beg;
    long newdata2_size = (unsigned long)current_break
        - ((unsigned long)dynamic_beg + dyn_size);
    long pad_size = 
      MASK_UP (current_break, n_pagsiz) - ((unsigned long) current_break);

#ifdef DEBUG
    printf ("current break is %#lx\n", current_break);

    printf ("old_dataddr = %#lx, dynamic_beg = %#lx\n",
            old_dataddr, dynamic_beg);
#endif

    /*
     * First, write the text segment with new header -- copy
     * everything until the start of the data segment from the old
     * file
     */
#ifdef DEBUG
    printf ("copying %#lx bytes of text from 0\n", old_datoff);
#endif
    unexec_copy (new_fd, old_fd, 0, 0, old_datoff);
    /* pad out the text segment */
#ifdef DEBUG
    printf ( "text pad size is %#x\n", old_dataddr - old_hdr.a_text);
#endif
    unexec_pad (new_fd, old_dataddr - old_hdr.a_text);

    /*
     * Update debug header spoo
     */
    if (new_hdr.a_extension > 0)
    {
	new_hdr.a_extension += LESYM_OFFSET(new_hdr) - LESYM_OFFSET(old_hdr);
    }

    /*
     * go back and write the new header.
     */
    unexec_write (new_fd, 0, (char *) &new_hdr, sizeof (new_hdr));

    
    /*
     * Copy the part of the data segment which becomes text from the
     * running image.
     */
#ifdef DEBUG
    printf ("copying %#lx bytes of new text from %#lx to position %#lx\n",
            newtext_size, old_dataddr, TEXT_OFFSET(new_hdr) + old_dataddr);
#endif
    unexec_write (new_fd, TEXT_OFFSET(new_hdr) + old_dataddr,
                  (caddr_t)old_dataddr, newtext_size);

#ifdef DEBUG
    printf ("new DATA_OFFSET is %#lx\n", new_datoff);
#endif

    /*
     * Copy the part of the old data segment which will be data
     * in the new executable (before the dynamic stuff)
     * from the running image.
     */
#ifdef DEBUG
    printf ("copying %#lx bytes of data from %#lx to position %#lx\n",
            newdata1_size, new_dataddr, new_datoff);
#endif
    unexec_write (new_fd, new_datoff, (caddr_t)new_dataddr, newdata1_size);

    /* copy the dynamic part of the data segment from the old executable */
    if (dyn_size)
      {
#ifdef DEBUG
        printf ("copying %#lx bytes of dyn data from executable"
                " at address %#lx to position %#lx\n", 
                dyn_size, dynamic_beg, new_datoff + newdata1_size);
#endif
        unexec_copy (new_fd, old_fd, old_datoff + newtext_size + newdata1_size,
                     new_datoff + newdata1_size, dyn_size);
      }

    /* copy remaining data (old bss) from the running image */
#ifdef DEBUG
    printf ("copying %#lx bytes of data from %#lx to position %#lx\n",
            newdata2_size, new_dataddr + newdata1_size + dyn_size,
            new_datoff + newdata1_size + dyn_size);
#endif
    unexec_write (new_fd, new_datoff + newdata1_size + dyn_size,
                  (caddr_t)(new_dataddr + newdata1_size + dyn_size),
                  newdata2_size);

    /* pad out the data segment */
#ifdef DEBUG
    printf ( "pad size is %#x\n", pad_size);
#endif
    unexec_pad (new_fd, pad_size);
    
    /* Finally, copy the rest of the junk from the old file. */
#ifdef DEBUG
    printf ("Copying %#lx bytes of junk from %#lx (old) to %#lx (new)\n",
            old_buf.st_size - old_mcaloff, old_mcaloff, new_mcaloff);
#endif
    unexec_copy (new_fd, old_fd, old_mcaloff, new_mcaloff,
                 old_buf.st_size - old_mcaloff);

    {
	long			curpos, offset;
	struct _debug_header	dhdr;
	int			new_header_delta;

	new_header_delta = LESYM_OFFSET(new_hdr) - LESYM_OFFSET(old_hdr);
	if ((new_header_delta > 0) &&
	    ((offset = EXT_OFFSET(old_hdr)) > 0))
	{
	    curpos = lseek(new_fd, 0, SEEK_CUR);
	    lseek(old_fd, offset, 0);
	    if (read(old_fd, &dhdr, sizeof(dhdr)) == sizeof(dhdr))
	    {
		dhdr.header_offset += new_header_delta;
		dhdr.gntt_offset += new_header_delta;
		dhdr.lntt_offset += new_header_delta;
		dhdr.slt_offset += new_header_delta;
		dhdr.vt_offset += new_header_delta;
		dhdr.xt_offset += new_header_delta;
		lseek(new_fd, EXT_OFFSET(new_hdr), SEEK_SET);
		if (write(new_fd, &dhdr, sizeof(dhdr)) != sizeof(dhdr))
		{
		    unexec_error("Unable to write debug information to \"%s\"\n",
				 1, new_name);
		}
		lseek(new_fd, curpos, SEEK_SET);
	    }
	    else
	    {
		unexec_error("Unable to read debug information from \"%s\"\n",
			     1, old_name);
	    }
	}
    }
  }
  
     
  /* make the output file executable -- then quit */
  unexec_fchmod (new_fd, 0755);
  close (old_fd);
  close (new_fd);
  return 0;
}