changeset 73613:fd7f97a75198

2006-11-02 Nozomu Ando <nand@mac.com> * unexmacosx.c (mach_header, segment_command, vm_region, section) [_LP64]: New defines. (VM_REGION_BASIC_INFO_COUNT, VM_REGION_BASIC_INFO, LC_SEGMENT) (MH_MAGIC) [_LP64]: Redefine. (delta): Remove variable. (curr_file_offset, pagesize): New variables. (ROUNDUP_TO_PAGE_BOUNDARY): New macro. (data_segment_old_fileoff): Initialize explicitly. (print_region, unexec_regions_recorder, print_load_command_name) (copy_segment, copy_data_segment): Use long format in printf. (MAX_UNEXEC_REGIONS): Increase to 400. (unexec_regions_recorder): Don't warn too many regions here. (find_emacs_zone_regions): Warn too many regions here. (print_load_command_name) [_LP64]: Show correct load command name. (copy_segment, copy_data_segment): Use variable `curr_file_offset'. Show starting virtual memory address. Don't show ending file offset. (copy_symtab, copy_dysymtab, copy_twolevelhints): New argument DELTA. (dump_it): Use new local variable `linkedit_delta' and pass to them. Error if trying to handle multiple DATA segments. (unexec): Initialize variable `pagesize'.
author YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
date Thu, 02 Nov 2006 04:37:26 +0000
parents 0dc9329d69be
children 1d0c4864fdee
files src/unexmacosx.c
diffstat 1 files changed, 75 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/src/unexmacosx.c	Thu Nov 02 01:31:39 2006 +0000
+++ b/src/unexmacosx.c	Thu Nov 02 04:37:26 2006 +0000
@@ -112,6 +112,20 @@
 
 #include <assert.h>
 
+#ifdef _LP64
+#define mach_header			mach_header_64
+#define segment_command			segment_command_64
+#undef  VM_REGION_BASIC_INFO_COUNT
+#define VM_REGION_BASIC_INFO_COUNT	VM_REGION_BASIC_INFO_COUNT_64
+#undef  VM_REGION_BASIC_INFO
+#define VM_REGION_BASIC_INFO		VM_REGION_BASIC_INFO_64
+#undef  LC_SEGMENT
+#define LC_SEGMENT			LC_SEGMENT_64
+#define vm_region			vm_region_64
+#define section				section_64
+#undef MH_MAGIC
+#define MH_MAGIC			MH_MAGIC_64
+#endif
 
 #define VERBOSE 1
 
@@ -164,9 +178,11 @@
 /* Offset at which the next load command should be written.  */
 unsigned long curr_header_offset = sizeof (struct mach_header);
 
-/* Current adjustment that needs to be made to offset values because
-   of additional data segments.  */
-unsigned long delta = 0;
+/* Offset at which the next segment should be written.  */
+static unsigned long curr_file_offset = 0;
+
+static unsigned long pagesize;
+#define ROUNDUP_TO_PAGE_BOUNDARY(x)	(((x) + pagesize - 1) & ~(pagesize - 1))
 
 int infd, outfd;
 
@@ -175,7 +191,7 @@
 malloc_zone_t *emacs_zone;
 
 /* file offset of input file's data segment */
-off_t data_segment_old_fileoff;
+off_t data_segment_old_fileoff = 0;
 
 struct segment_command *data_segment_scp;
 
@@ -286,7 +302,7 @@
 print_region (vm_address_t address, vm_size_t size, vm_prot_t prot,
 	      vm_prot_t max_prot)
 {
-  printf ("%#10x %#8x ", address, size);
+  printf ("%#10lx %#8lx ", (long) address, (long) size);
   print_prot (prot);
   putchar (' ');
   print_prot (max_prot);
@@ -412,7 +428,7 @@
 }
 
 
-#define MAX_UNEXEC_REGIONS 200
+#define MAX_UNEXEC_REGIONS 400
 
 int num_unexec_regions;
 vm_range_t unexec_regions[MAX_UNEXEC_REGIONS];
@@ -424,11 +440,10 @@
   while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
     {
       unexec_regions[num_unexec_regions++] = *ranges;
-      printf ("%#8x (sz: %#8x)\n", ranges->address, ranges->size);
+      printf ("%#8lx (sz: %#8lx)\n",
+	      (long) (ranges->address), (long) (ranges->size));
       ranges++; num--;
     }
-  if (num_unexec_regions == MAX_UNEXEC_REGIONS)
-    fprintf (stderr, "malloc_freezedry_recorder: too many regions\n");
 }
 
 static kern_return_t
@@ -449,6 +464,9 @@
 				      (vm_address_t) emacs_zone,
 				      unexec_reader,
 				      unexec_regions_recorder);
+
+  if (num_unexec_regions == MAX_UNEXEC_REGIONS)
+    unexec_error ("find_emacs_zone_regions: too many regions");
 }
 
 static int
@@ -500,7 +518,11 @@
   switch (lc)
     {
     case LC_SEGMENT:
+#ifndef _LP64
       printf ("LC_SEGMENT       ");
+#else
+      printf ("LC_SEGMENT_64    ");
+#endif
       break;
     case LC_LOAD_DYLINKER:
       printf ("LC_LOAD_DYLINKER ");
@@ -541,14 +563,14 @@
       int j;
 
       scp = (struct segment_command *) lc;
-      printf (" %-16.16s %#10x %#8x\n",
-	      scp->segname, scp->vmaddr, scp->vmsize);
+      printf (" %-16.16s %#10lx %#8lx\n",
+	      scp->segname, (long) (scp->vmaddr), (long) (scp->vmsize));
 
       sectp = (struct section *) (scp + 1);
       for (j = 0; j < scp->nsects; j++)
 	{
-	  printf ("                           %-16.16s %#10x %#8x\n",
-		  sectp->sectname, sectp->addr, sectp->size);
+	  printf ("                           %-16.16s %#10lx %#8lx\n",
+		  sectp->sectname, (long) (sectp->addr), (long) (sectp->size));
 	  sectp++;
 	}
     }
@@ -644,21 +666,23 @@
   struct section *sectp;
   int j;
 
-  scp->fileoff += delta;
+  scp->fileoff = curr_file_offset;
 
   sectp = (struct section *) (scp + 1);
   for (j = 0; j < scp->nsects; j++)
     {
-      sectp->offset += delta;
+      sectp->offset += curr_file_offset - old_fileoff;
       sectp++;
     }
 
-  printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
-	  scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
-	  scp->filesize);
+  printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
+	  scp->segname, (long) (scp->fileoff), (long) (scp->vmsize),
+	  (long) (scp->vmaddr));
 
   if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
     unexec_error ("cannot copy segment from input to output file");
+  curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
+
   if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
     unexec_error ("cannot write load command to header");
 
@@ -685,12 +709,9 @@
   int j;
   unsigned long header_offset, file_offset, old_file_offset;
 
-  printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
-	  scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
-	  scp->filesize);
-
-  if (delta != 0)
-    unexec_error ("cannot handle multiple DATA segments in input file");
+  printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
+	  scp->segname, curr_file_offset, (long)(scp->vmsize),
+	  (long) (scp->vmaddr));
 
   /* Offsets in the output file for writing the next section structure
      and segment data block, respectively.  */
@@ -700,7 +721,7 @@
   for (j = 0; j < scp->nsects; j++)
     {
       old_file_offset = sectp->offset;
-      sectp->offset = sectp->addr - scp->vmaddr + scp->fileoff;
+      sectp->offset = sectp->addr - scp->vmaddr + curr_file_offset;
       /* The __data section is dumped from memory.  The __bss and
 	 __common sections are also dumped from memory but their flag
 	 fields require changing (from S_ZEROFILL to S_REGULAR).  The
@@ -762,9 +783,9 @@
       else
 	unexec_error ("unrecognized section name in __DATA segment");
 
-      printf ("        section %-16.16s at %#8x - %#8x (sz: %#8x)\n",
-	      sectp->sectname, sectp->offset, sectp->offset + sectp->size,
-	      sectp->size);
+      printf ("        section %-16.16s at %#8lx - %#8lx (sz: %#8lx)\n",
+	      sectp->sectname, (long) (sectp->offset),
+	      (long) (sectp->offset + sectp->size), (long) (sectp->size));
 
       header_offset += sizeof (struct section);
       sectp++;
@@ -775,17 +796,16 @@
      this may leave unused locations at the end of the segment data
      block because the total of the sizes of all sections in the
      segment is generally smaller than vmsize.  */
-  delta = scp->vmsize - scp->filesize;
   scp->filesize = scp->vmsize;
   if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
     unexec_error ("cannot write header of __DATA segment");
   curr_header_offset += lc->cmdsize;
+  curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
 
   /* Create new __DATA segment load commands for regions on the region
      list that do not corresponding to any segment load commands in
      the input file.
-     */
-  file_offset = scp->fileoff + scp->filesize;
+  */
   for (j = 0; j < num_unexec_regions; j++)
     {
       struct segment_command sc;
@@ -795,21 +815,20 @@
       strncpy (sc.segname, SEG_DATA, 16);
       sc.vmaddr = unexec_regions[j].address;
       sc.vmsize = unexec_regions[j].size;
-      sc.fileoff = file_offset;
+      sc.fileoff = curr_file_offset;
       sc.filesize = unexec_regions[j].size;
       sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
       sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
       sc.nsects = 0;
       sc.flags = 0;
 
-      printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
-	      sc.segname, sc.fileoff, sc.fileoff + sc.filesize,
-	      sc.filesize);
+      printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
+	      sc.segname, (long) (sc.fileoff), (long) (sc.vmsize),
+	      (long) (sc.vmaddr));
 
       if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize))
 	unexec_error ("cannot write new __DATA segment");
-      delta += sc.filesize;
-      file_offset += sc.filesize;
+      curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize);
 
       if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
 	unexec_error ("cannot write new __DATA segment's header");
@@ -821,7 +840,7 @@
 /* Copy a LC_SYMTAB load command from the input file to the output
    file, adjusting the file offset fields.  */
 static void
-copy_symtab (struct load_command *lc)
+copy_symtab (struct load_command *lc, long delta)
 {
   struct symtab_command *stp = (struct symtab_command *) lc;
 
@@ -898,7 +917,7 @@
 /* Copy a LC_DYSYMTAB load command from the input file to the output
    file, adjusting the file offset fields.  */
 static void
-copy_dysymtab (struct load_command *lc)
+copy_dysymtab (struct load_command *lc, long delta)
 {
   struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
 
@@ -927,7 +946,7 @@
 /* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
    file, adjusting the file offset fields.  */
 static void
-copy_twolevelhints (struct load_command *lc)
+copy_twolevelhints (struct load_command *lc, long delta)
 {
   struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
 
@@ -964,6 +983,7 @@
 dump_it ()
 {
   int i;
+  long linkedit_delta = 0;
 
   printf ("--- Load Commands written to Output File ---\n");
 
@@ -977,6 +997,9 @@
 	    {
 	      /* save data segment file offset and segment_command for
 		 unrelocate */
+	      if (data_segment_old_fileoff)
+		unexec_error ("cannot handle multiple DATA segments"
+			      " in input file");
 	      data_segment_old_fileoff = scp->fileoff;
 	      data_segment_scp = scp;
 
@@ -984,18 +1007,26 @@
 	    }
 	  else
 	    {
+	      if (strncmp (scp->segname, SEG_LINKEDIT, 16) == 0)
+		{
+		  if (linkedit_delta)
+		    unexec_error ("cannot handle multiple LINKEDIT segments"
+				  " in input file");
+		  linkedit_delta = curr_file_offset - scp->fileoff;
+		}
+
 	      copy_segment (lca[i]);
 	    }
 	}
 	break;
       case LC_SYMTAB:
-	copy_symtab (lca[i]);
+	copy_symtab (lca[i], linkedit_delta);
 	break;
       case LC_DYSYMTAB:
-	copy_dysymtab (lca[i]);
+	copy_dysymtab (lca[i], linkedit_delta);
 	break;
       case LC_TWOLEVEL_HINTS:
-	copy_twolevelhints (lca[i]);
+	copy_twolevelhints (lca[i], linkedit_delta);
 	break;
       default:
 	copy_other (lca[i]);
@@ -1024,6 +1055,7 @@
   if (in_dumped_exec)
     unexec_error ("Unexec from a dumped executable is not supported.");
 
+  pagesize = getpagesize ();
   infd = open (infile, O_RDONLY, 0);
   if (infd < 0)
     {