changeset 73690:04b7851d50f8

(malloc_cookie): Remove unused variable. (region_list_head, region_list_tail, lca, nlc, infile_lc_highest_addr) (text_seg_lowest_offset, mh, curr_header_offset, infd, outfd) (emacs_zone, data_segment_old_fileoff, data_segment_scp) (num_unexec_regions, unexec_regions): Make variables static. (print_regions, find_emacs_zone_regions): Make static. (unexec_region_info): New typedef. (unexec_regions): Change type from vm_range_t[] to unexec_region_info[]. All uses changed. (unexec_regions_recorder): Subtract size of trailing null pages from filesize. Show filesize. (unexec_regions_merge): Don't merge if null pages of preceding region is not too small. Use long format in printf. (copy_segment, copy_data_segment): Show filesize. (copy_data_segment): Write filesize bytes of region data. Adjust filesize in segment command accordingly. (dump_it): Use long format in printf.
author YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
date Sun, 05 Nov 2006 06:11:54 +0000
parents cd0ac1c9a67c
children 292fa2a0b5f2
files src/unexmacosx.c
diffstat 1 files changed, 76 insertions(+), 57 deletions(-) [+]
line wrap: on
line diff
--- a/src/unexmacosx.c	Sun Nov 05 04:11:47 2006 +0000
+++ b/src/unexmacosx.c	Sun Nov 05 06:11:54 2006 +0000
@@ -69,10 +69,10 @@
    fact, the earliest one starts a few hundred bytes beyond the end of
    the last load command.  The linker option -headerpad controls the
    minimum size of this padding.  Its setting can be changed in
-   s/darwin.h.  A value of 0x300, e.g., leaves room for about 15
-   additional load commands for the newly created __DATA segments (at
-   56 bytes each).  Unexec fails if there is not enough room for these
-   new segments.
+   s/darwin.h.  A value of 0x690, e.g., leaves room for 30 additional
+   load commands for the newly created __DATA segments (at 56 bytes
+   each).  Unexec fails if there is not enough room for these new
+   segments.
 
    The __TEXT segment contains the sections __text, __cstring,
    __picsymbol_stub, and __const and the __DATA segment contains the
@@ -137,9 +137,6 @@
    mapped to dynamically loaded libraries and will not be dumped.  */
 #define VM_DATA_TOP (20 * 1024 * 1024)
 
-/* Used by malloc_freezedry and malloc_jumpstart.  */
-int malloc_cookie;
-
 /* Type of an element on the list of regions to be dumped.  */
 struct region_t {
   vm_address_t address;
@@ -151,32 +148,32 @@
 };
 
 /* Head and tail of the list of regions to be dumped.  */
-struct region_t *region_list_head = 0;
-struct region_t *region_list_tail = 0;
+static struct region_t *region_list_head = 0;
+static struct region_t *region_list_tail = 0;
 
 /* Pointer to array of load commands.  */
-struct load_command **lca;
+static struct load_command **lca;
 
 /* Number of load commands.  */
-int nlc;
+static int nlc;
 
 /* The highest VM address of segments loaded by the input file.
    Regions with addresses beyond this are assumed to be allocated
    dynamically and thus require dumping.  */
-vm_address_t infile_lc_highest_addr = 0;
+static vm_address_t infile_lc_highest_addr = 0;
 
 /* The lowest file offset used by the all sections in the __TEXT
    segments.  This leaves room at the beginning of the file to store
    the Mach-O header.  Check this value against header size to ensure
    the added load commands for the new __DATA segments did not
    overwrite any of the sections in the __TEXT segment.  */
-unsigned long text_seg_lowest_offset = 0x10000000;
+static unsigned long text_seg_lowest_offset = 0x10000000;
 
 /* Mach header.  */
-struct mach_header mh;
+static struct mach_header mh;
 
 /* Offset at which the next load command should be written.  */
-unsigned long curr_header_offset = sizeof (struct mach_header);
+static unsigned long curr_header_offset = sizeof (struct mach_header);
 
 /* Offset at which the next segment should be written.  */
 static unsigned long curr_file_offset = 0;
@@ -184,16 +181,16 @@
 static unsigned long pagesize;
 #define ROUNDUP_TO_PAGE_BOUNDARY(x)	(((x) + pagesize - 1) & ~(pagesize - 1))
 
-int infd, outfd;
+static int infd, outfd;
 
-int in_dumped_exec = 0;
+static int in_dumped_exec = 0;
 
-malloc_zone_t *emacs_zone;
+static malloc_zone_t *emacs_zone;
 
 /* file offset of input file's data segment */
-off_t data_segment_old_fileoff = 0;
+static off_t data_segment_old_fileoff = 0;
 
-struct segment_command *data_segment_scp;
+static struct segment_command *data_segment_scp;
 
 /* Read N bytes from infd into memory starting at address DEST.
    Return true if successful, false otherwise.  */
@@ -320,7 +317,7 @@
     print_region (r->address, r->size, r->protection, r->max_protection);
 }
 
-void
+static void
 print_regions ()
 {
   task_t target_task = mach_task_self ();
@@ -430,18 +427,36 @@
 
 #define MAX_UNEXEC_REGIONS 400
 
-int num_unexec_regions;
-vm_range_t unexec_regions[MAX_UNEXEC_REGIONS];
+static int num_unexec_regions;
+typedef struct {
+  vm_range_t range;
+  vm_size_t filesize;
+} unexec_region_info;
+static unexec_region_info unexec_regions[MAX_UNEXEC_REGIONS];
 
 static void
 unexec_regions_recorder (task_t task, void *rr, unsigned type,
 			 vm_range_t *ranges, unsigned num)
 {
+  vm_address_t p;
+  vm_size_t filesize;
+
   while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
     {
-      unexec_regions[num_unexec_regions++] = *ranges;
-      printf ("%#8lx (sz: %#8lx)\n",
-	      (long) (ranges->address), (long) (ranges->size));
+      /* Subtract the size of trailing null pages from filesize.  It
+	 can be smaller than vmsize in segment commands.  In such a
+	 case, trailing pages are initialized with zeros.  */
+      for (p = ranges->address + ranges->size; p > ranges->address;
+	   p -= sizeof (int))
+	if (*(((int *) p)-1))
+	  break;
+      filesize = ROUNDUP_TO_PAGE_BOUNDARY (p - ranges->address);
+      assert (filesize <= ranges->size);
+
+      unexec_regions[num_unexec_regions].filesize = filesize;
+      unexec_regions[num_unexec_regions++].range = *ranges;
+      printf ("%#10lx (sz: %#8lx/%#8lx)\n", (long) (ranges->address),
+	      (long) filesize, (long) (ranges->size));
       ranges++; num--;
     }
 }
@@ -453,7 +468,7 @@
   return KERN_SUCCESS;
 }
 
-void
+static void
 find_emacs_zone_regions ()
 {
   num_unexec_regions = 0;
@@ -472,8 +487,8 @@
 static int
 unexec_regions_sort_compare (const void *a, const void *b)
 {
-  vm_address_t aa = ((vm_range_t *) a)->address;
-  vm_address_t bb = ((vm_range_t *) b)->address;
+  vm_address_t aa = ((unexec_region_info *) a)->range.address;
+  vm_address_t bb = ((unexec_region_info *) b)->range.address;
 
   if (aa < bb)
     return -1;
@@ -487,7 +502,7 @@
 unexec_regions_merge ()
 {
   int i, n;
-  vm_range_t r;
+  unexec_region_info r;
 
   qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]),
 	 &unexec_regions_sort_compare);
@@ -495,9 +510,11 @@
   r = unexec_regions[0];
   for (i = 1; i < num_unexec_regions; i++)
     {
-      if (r.address + r.size == unexec_regions[i].address)
+      if (r.range.address + r.range.size == unexec_regions[i].range.address
+	  && r.range.size - r.filesize < 2 * pagesize)
 	{
-	  r.size += unexec_regions[i].size;
+	  r.filesize = r.range.size + unexec_regions[i].filesize;
+	  r.range.size += unexec_regions[i].range.size;
 	}
       else
 	{
@@ -642,7 +659,7 @@
   printf ("Highest address of load commands in input file: %#8x\n",
 	  infile_lc_highest_addr);
 
-  printf ("Lowest offset of all sections in __TEXT segment: %#8x\n",
+  printf ("Lowest offset of all sections in __TEXT segment: %#8lx\n",
 	  text_seg_lowest_offset);
 
   printf ("--- List of Load Commands in Input File ---\n");
@@ -675,9 +692,9 @@
       sectp++;
     }
 
-  printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
-	  scp->segname, (long) (scp->fileoff), (long) (scp->vmsize),
-	  (long) (scp->vmaddr));
+  printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
+	  scp->segname, (long) (scp->fileoff), (long) (scp->filesize),
+	  (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");
@@ -707,11 +724,18 @@
   struct segment_command *scp = (struct segment_command *) lc;
   struct section *sectp;
   int j;
-  unsigned long header_offset, file_offset, old_file_offset;
+  unsigned long header_offset, old_file_offset;
 
-  printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
-	  scp->segname, curr_file_offset, (long)(scp->vmsize),
-	  (long) (scp->vmaddr));
+  /* The new filesize of the segment is set to its vmsize because data
+     blocks for segments must start at region boundaries.  Note that
+     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.  */
+  scp->filesize = scp->vmsize;
+
+  printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
+	  scp->segname, curr_file_offset, (long)(scp->filesize),
+	  (long)(scp->vmsize), (long) (scp->vmaddr));
 
   /* Offsets in the output file for writing the next section structure
      and segment data block, respectively.  */
@@ -791,16 +815,11 @@
       sectp++;
     }
 
-  /* The new filesize of the segment is set to its vmsize because data
-     blocks for segments must start at region boundaries.  Note that
-     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.  */
-  scp->filesize = scp->vmsize;
+  curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
+
   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
@@ -813,20 +832,20 @@
       sc.cmd = LC_SEGMENT;
       sc.cmdsize = sizeof (struct segment_command);
       strncpy (sc.segname, SEG_DATA, 16);
-      sc.vmaddr = unexec_regions[j].address;
-      sc.vmsize = unexec_regions[j].size;
+      sc.vmaddr = unexec_regions[j].range.address;
+      sc.vmsize = unexec_regions[j].range.size;
       sc.fileoff = curr_file_offset;
-      sc.filesize = unexec_regions[j].size;
+      sc.filesize = unexec_regions[j].filesize;
       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 @ %#8lx (%#8lx @ %#8lx)\n",
-	      sc.segname, (long) (sc.fileoff), (long) (sc.vmsize),
-	      (long) (sc.vmaddr));
+      printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
+	      sc.segname, (long) (sc.fileoff), (long) (sc.filesize),
+	      (long) (sc.vmsize), (long) (sc.vmaddr));
 
-      if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize))
+      if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.filesize))
 	unexec_error ("cannot write new __DATA segment");
       curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize);
 
@@ -1036,7 +1055,7 @@
   if (curr_header_offset > text_seg_lowest_offset)
     unexec_error ("not enough room for load commands for new __DATA segments");
 
-  printf ("%d unused bytes follow Mach-O header\n",
+  printf ("%ld unused bytes follow Mach-O header\n",
 	  text_seg_lowest_offset - curr_header_offset);
 
   mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
@@ -1113,8 +1132,8 @@
   int i;
 
   for (i = 0; i < num_unexec_regions; i++)
-    if ((vm_address_t) ptr - unexec_regions[i].address
-	< unexec_regions[i].size)
+    if ((vm_address_t) ptr - unexec_regions[i].range.address
+	< unexec_regions[i].range.size)
       return 1;
 
   return 0;