1/* Dump Emacs in Mach-O format for use on Mac OS X.
2   Copyright (C) 2001, 2002, 2003, 2004, 2005,
3                 2006, 2007 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING.  If not, write to
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA.  */
21
22/* Contributed by Andrew Choi (akochoi@mac.com).  */
23
24/* Documentation note.
25
26   Consult the following documents/files for a description of the
27   Mach-O format: the file loader.h, man pages for Mach-O and ld, old
28   NEXTSTEP documents of the Mach-O format.  The tool otool dumps the
29   mach header (-h option) and the load commands (-l option) in a
30   Mach-O file.  The tool nm on Mac OS X displays the symbol table in
31   a Mach-O file.  For examples of unexec for the Mach-O format, see
32   the file unexnext.c in the GNU Emacs distribution, the file
33   unexdyld.c in the Darwin port of GNU Emacs 20.7, and unexdyld.c in
34   the Darwin port of XEmacs 21.1.  Also the Darwin Libc source
35   contains the source code for malloc_freezedry and malloc_jumpstart.
36   Read that to see what they do.  This file was written completely
37   from scratch, making use of information from the above sources.  */
38
39/* The Mac OS X implementation of unexec makes use of Darwin's `zone'
40   memory allocator.  All calls to malloc, realloc, and free in Emacs
41   are redirected to unexec_malloc, unexec_realloc, and unexec_free in
42   this file.  When temacs is run, all memory requests are handled in
43   the zone EmacsZone.  The Darwin memory allocator library calls
44   maintain the data structures to manage this zone.  Dumping writes
45   its contents to data segments of the executable file.  When emacs
46   is run, the loader recreates the contents of the zone in memory.
47   However since the initialization routine of the zone memory
48   allocator is run again, this `zone' can no longer be used as a
49   heap.  That is why emacs uses the ordinary malloc system call to
50   allocate memory.  Also, when a block of memory needs to be
51   reallocated and the new size is larger than the old one, a new
52   block must be obtained by malloc and the old contents copied to
53   it.  */
54
55/* Peculiarity of the Mach-O files generated by ld in Mac OS X
56   (possible causes of future bugs if changed).
57
58   The file offset of the start of the __TEXT segment is zero.  Since
59   the Mach header and load commands are located at the beginning of a
60   Mach-O file, copying the contents of the __TEXT segment from the
61   input file overwrites them in the output file.  Despite this,
62   unexec works fine as written below because the segment load command
63   for __TEXT appears, and is therefore processed, before all other
64   load commands except the segment load command for __PAGEZERO, which
65   remains unchanged.
66
67   Although the file offset of the start of the __TEXT segment is
68   zero, none of the sections it contains actually start there.  In
69   fact, the earliest one starts a few hundred bytes beyond the end of
70   the last load command.  The linker option -headerpad controls the
71   minimum size of this padding.  Its setting can be changed in
72   s/darwin.h.  A value of 0x690, e.g., leaves room for 30 additional
73   load commands for the newly created __DATA segments (at 56 bytes
74   each).  Unexec fails if there is not enough room for these new
75   segments.
76
77   The __TEXT segment contains the sections __text, __cstring,
78   __picsymbol_stub, and __const and the __DATA segment contains the
79   sections __data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __bss,
80   and __common.  The other segments do not contain any sections.
81   These sections are copied from the input file to the output file,
82   except for __data, __bss, and __common, which are dumped from
83   memory.  The types of the sections __bss and __common are changed
84   from S_ZEROFILL to S_REGULAR.  Note that the number of sections and
85   their relative order in the input and output files remain
86   unchanged.  Otherwise all n_sect fields in the nlist records in the
87   symbol table (specified by the LC_SYMTAB load command) will have to
88   be changed accordingly.
89*/
90
91#include <stdio.h>
92#include <stdlib.h>
93#include <fcntl.h>
94#include <stdarg.h>
95#include <sys/types.h>
96#include <unistd.h>
97#include <mach/mach.h>
98#include <mach-o/loader.h>
99#include <mach-o/reloc.h>
100#if defined (__ppc__)
101#include <mach-o/ppc/reloc.h>
102#endif
103#include <config.h>
104#undef malloc
105#undef realloc
106#undef free
107#ifdef HAVE_MALLOC_MALLOC_H
108#include <malloc/malloc.h>
109#else
110#include <objc/malloc.h>
111#endif
112
113#include <assert.h>
114#include "version.h"
115
116#if _LP64
117#define mach_header				mach_header_64
118#define segment_command				segment_command_64
119#define vm_region				vm_region_64
120#define section					section_64
121#define target_VM_REGION_BASIC_INFO_COUNT	VM_REGION_BASIC_INFO_COUNT_64
122#define target_VM_REGION_BASIC_INFO		VM_REGION_BASIC_INFO_64
123#define target_LC_SEGMENT			LC_SEGMENT_64
124#define target_MH_MAGIC				MH_MAGIC_64
125#else
126#define target_VM_REGION_BASIC_INFO_COUNT	VM_REGION_BASIC_INFO_COUNT
127#define target_VM_REGION_BASIC_INFO		VM_REGION_BASIC_INFO
128#define target_LC_SEGMENT			LC_SEGMENT
129#define target_MH_MAGIC				MH_MAGIC
130#endif
131
132#define VERBOSE 1
133
134/* Size of buffer used to copy data from the input file to the output
135   file in function unexec_copy.  */
136#define UNEXEC_COPY_BUFSZ 1024
137
138/* Regions with memory addresses above this value are assumed to be
139   mapped to dynamically loaded libraries and will not be dumped.  */
140#define VM_DATA_TOP (20 * 1024 * 1024)
141
142/* Type of an element on the list of regions to be dumped.  */
143struct region_t {
144  vm_address_t address;
145  vm_size_t size;
146  vm_prot_t protection;
147  vm_prot_t max_protection;
148
149  struct region_t *next;
150};
151
152/* Head and tail of the list of regions to be dumped.  */
153static struct region_t *region_list_head = 0;
154static struct region_t *region_list_tail = 0;
155
156/* Pointer to array of load commands.  */
157static struct load_command **lca;
158
159/* Number of load commands.  */
160static int nlc;
161
162/* The highest VM address of segments loaded by the input file.
163   Regions with addresses beyond this are assumed to be allocated
164   dynamically and thus require dumping.  */
165static vm_address_t infile_lc_highest_addr = 0;
166
167/* The lowest file offset used by the all sections in the __TEXT
168   segments.  This leaves room at the beginning of the file to store
169   the Mach-O header.  Check this value against header size to ensure
170   the added load commands for the new __DATA segments did not
171   overwrite any of the sections in the __TEXT segment.  */
172static unsigned long text_seg_lowest_offset = 0x10000000;
173
174/* Mach header.  */
175static struct mach_header mh;
176
177/* Offset at which the next load command should be written.  */
178static unsigned long curr_header_offset = sizeof (struct mach_header);
179
180/* Offset at which the next segment should be written.  */
181static unsigned long curr_file_offset = 0;
182
183static unsigned long pagesize;
184#define ROUNDUP_TO_PAGE_BOUNDARY(x)	(((x) + pagesize - 1) & ~(pagesize - 1))
185
186static int infd, outfd;
187
188static int in_dumped_exec = 0;
189
190static malloc_zone_t *emacs_zone;
191
192/* file offset of input file's data segment */
193static off_t data_segment_old_fileoff = 0;
194
195static struct segment_command *data_segment_scp;
196
197/* Read N bytes from infd into memory starting at address DEST.
198   Return true if successful, false otherwise.  */
199static int
200unexec_read (void *dest, size_t n)
201{
202  return n == read (infd, dest, n);
203}
204
205/* Write COUNT bytes from memory starting at address SRC to outfd
206   starting at offset DEST.  Return true if successful, false
207   otherwise.  */
208static int
209unexec_write (off_t dest, const void *src, size_t count)
210{
211  if (lseek (outfd, dest, SEEK_SET) != dest)
212    return 0;
213
214  return (count == write(outfd, src, count));
215}
216
217/* Write COUNT bytes of zeros to outfd starting at offset DEST.
218   Return true if successful, false otherwise.  */
219static int
220unexec_write_zero (off_t dest, size_t count)
221{
222  char buf[UNEXEC_COPY_BUFSZ];
223  ssize_t bytes;
224
225  bzero (buf, UNEXEC_COPY_BUFSZ);
226  if (lseek (outfd, dest, SEEK_SET) != dest)
227    return 0;
228
229  while (count > 0)
230    {
231      bytes = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count;
232      if (write (outfd, buf, bytes) != bytes)
233	return 0;
234      count -= bytes;
235    }
236
237  return 1;
238}
239
240/* Copy COUNT bytes from starting offset SRC in infd to starting
241   offset DEST in outfd.  Return true if successful, false
242   otherwise.  */
243static int
244unexec_copy (off_t dest, off_t src, ssize_t count)
245{
246  ssize_t bytes_read;
247  ssize_t bytes_to_read;
248
249  char buf[UNEXEC_COPY_BUFSZ];
250
251  if (lseek (infd, src, SEEK_SET) != src)
252    return 0;
253
254  if (lseek (outfd, dest, SEEK_SET) != dest)
255    return 0;
256
257  while (count > 0)
258    {
259      bytes_to_read = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count;
260      bytes_read = read (infd, buf, bytes_to_read);
261      if (bytes_read <= 0)
262	return 0;
263      if (write (outfd, buf, bytes_read) != bytes_read)
264	return 0;
265      count -= bytes_read;
266    }
267
268  return 1;
269}
270
271/* Debugging and informational messages routines.  */
272
273static void
274unexec_error (char *format, ...)
275{
276  va_list ap;
277
278  va_start (ap, format);
279  fprintf (stderr, "unexec: ");
280  vfprintf (stderr, format, ap);
281  fprintf (stderr, "\n");
282  va_end (ap);
283  exit (1);
284}
285
286static void
287print_prot (vm_prot_t prot)
288{
289  if (prot == VM_PROT_NONE)
290    printf ("none");
291  else
292    {
293      putchar (prot & VM_PROT_READ ? 'r' : ' ');
294      putchar (prot & VM_PROT_WRITE ? 'w' : ' ');
295      putchar (prot & VM_PROT_EXECUTE ? 'x' : ' ');
296      putchar (' ');
297    }
298}
299
300static void
301print_region (vm_address_t address, vm_size_t size, vm_prot_t prot,
302	      vm_prot_t max_prot)
303{
304  printf ("%#10lx %#8lx ", (long) address, (long) size);
305  print_prot (prot);
306  putchar (' ');
307  print_prot (max_prot);
308  putchar ('\n');
309}
310
311static void
312print_region_list ()
313{
314  struct region_t *r;
315
316  printf ("   address     size prot maxp\n");
317
318  for (r = region_list_head; r; r = r->next)
319    print_region (r->address, r->size, r->protection, r->max_protection);
320}
321
322static void
323print_regions ()
324{
325  task_t target_task = mach_task_self ();
326  vm_address_t address = (vm_address_t) 0;
327  vm_size_t size;
328  struct vm_region_basic_info info;
329  mach_msg_type_number_t info_count = target_VM_REGION_BASIC_INFO_COUNT;
330  mach_port_t object_name;
331
332  printf ("   address     size prot maxp\n");
333
334  while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
335		    (vm_region_info_t) &info, &info_count, &object_name)
336	 == KERN_SUCCESS && info_count == target_VM_REGION_BASIC_INFO_COUNT)
337    {
338      print_region (address, size, info.protection, info.max_protection);
339
340      if (object_name != MACH_PORT_NULL)
341	mach_port_deallocate (target_task, object_name);
342
343      address += size;
344    }
345}
346
347/* Build the list of regions that need to be dumped.  Regions with
348   addresses above VM_DATA_TOP are omitted.  Adjacent regions with
349   identical protection are merged.  Note that non-writable regions
350   cannot be omitted because they some regions created at run time are
351   read-only.  */
352static void
353build_region_list ()
354{
355  task_t target_task = mach_task_self ();
356  vm_address_t address = (vm_address_t) 0;
357  vm_size_t size;
358  struct vm_region_basic_info info;
359  mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
360  mach_port_t object_name;
361  struct region_t *r;
362
363#if VERBOSE
364  printf ("--- List of All Regions ---\n");
365  printf ("   address     size prot maxp\n");
366#endif
367
368  while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
369		    (vm_region_info_t) &info, &info_count, &object_name)
370	 == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
371    {
372      /* Done when we reach addresses of shared libraries, which are
373	 loaded in high memory.  */
374      if (address >= VM_DATA_TOP)
375	break;
376
377#if VERBOSE
378      print_region (address, size, info.protection, info.max_protection);
379#endif
380
381      /* If a region immediately follows the previous one (the one
382	 most recently added to the list) and has identical
383	 protection, merge it with the latter.  Otherwise create a
384	 new list element for it.  */
385      if (region_list_tail
386	  && info.protection == region_list_tail->protection
387	  && info.max_protection == region_list_tail->max_protection
388	  && region_list_tail->address + region_list_tail->size == address)
389	{
390	  region_list_tail->size += size;
391	}
392      else
393	{
394	  r = (struct region_t *) malloc (sizeof (struct region_t));
395
396	  if (!r)
397	    unexec_error ("cannot allocate region structure");
398
399	  r->address = address;
400	  r->size = size;
401	  r->protection = info.protection;
402	  r->max_protection = info.max_protection;
403
404	  r->next = 0;
405	  if (region_list_head == 0)
406	    {
407	      region_list_head = r;
408	      region_list_tail = r;
409	    }
410	  else
411	    {
412	      region_list_tail->next = r;
413	      region_list_tail = r;
414	    }
415
416	  /* Deallocate (unused) object name returned by
417	     vm_region.  */
418	  if (object_name != MACH_PORT_NULL)
419	    mach_port_deallocate (target_task, object_name);
420	}
421
422      address += size;
423    }
424
425  printf ("--- List of Regions to be Dumped ---\n");
426  print_region_list ();
427}
428
429
430#define MAX_UNEXEC_REGIONS 400
431
432static int num_unexec_regions;
433typedef struct {
434  vm_range_t range;
435  vm_size_t filesize;
436} unexec_region_info;
437static unexec_region_info unexec_regions[MAX_UNEXEC_REGIONS];
438
439static void
440unexec_regions_recorder (task_t task, void *rr, unsigned type,
441			 vm_range_t *ranges, unsigned num)
442{
443  while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
444    {
445      unexec_regions[num_unexec_regions].filesize = ranges->size;
446      unexec_regions[num_unexec_regions++].range = *ranges;
447      printf ("%#10lx (sz: %#8lx)\n", (long) (ranges->address),
448	      (long) (ranges->size));
449      ranges++; num--;
450    }
451}
452
453static kern_return_t
454unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr)
455{
456  *ptr = (void *) address;
457  return KERN_SUCCESS;
458}
459
460static void
461find_emacs_zone_regions ()
462{
463  num_unexec_regions = 0;
464
465  emacs_zone->introspect->enumerator (mach_task_self(), 0,
466				      MALLOC_PTR_REGION_RANGE_TYPE,
467				      (vm_address_t) emacs_zone,
468				      unexec_reader,
469				      unexec_regions_recorder);
470
471  if (num_unexec_regions == MAX_UNEXEC_REGIONS)
472    unexec_error ("find_emacs_zone_regions: too many regions");
473}
474
475static int
476unexec_regions_sort_compare (const void *a, const void *b)
477{
478  vm_address_t aa = ((unexec_region_info *) a)->range.address;
479  vm_address_t bb = ((unexec_region_info *) b)->range.address;
480
481  if (aa < bb)
482    return -1;
483  else if (aa > bb)
484    return 1;
485  else
486    return 0;
487}
488
489static void
490unexec_regions_merge ()
491{
492  int i, n;
493  vm_address_t begin, end;
494  unexec_region_info r;
495  long total = 0;
496  void *zeropage = calloc(1, pagesize);
497  long zerodBytes = 0;
498  qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]),
499	 &unexec_regions_sort_compare);
500  n = 0;
501  r = unexec_regions[0];
502  if (r.range.address & (pagesize-1L)) {
503	  begin = r.range.address;
504	  r.range.address = r.range.address & ~(pagesize-1L);
505	  r.range.size += begin - r.range.address;
506	  r.filesize += begin - r.range.address;
507  }
508  for (i = 1; i < num_unexec_regions; i++) {
509    if ((r.range.address + r.range.size) == unexec_regions[i].range.address) {
510	  r.filesize += unexec_regions[i].filesize;
511	  r.range.size += unexec_regions[i].range.size;
512    } else {	/* All segments must be a multiple of pagesize */
513	    end = r.range.address + r.range.size;
514	    if (end & (pagesize-1L)) {
515		    end = ROUNDUP_TO_PAGE_BOUNDARY(end);
516		    printf("Page (%#8lx) aligning region @%#8lx size from %#8lx to %#8lx\n",
517			   (long)pagesize, (long)r.range.address, (long)r.range.size, (long)(end - r.range.address));
518		    r.range.size = end - r.range.address;
519		    r.filesize = r.range.size;
520		    if (end == unexec_regions[i].range.address) {
521			    r.filesize += unexec_regions[i].filesize;
522			    r.range.size += unexec_regions[i].range.size;
523			    continue;
524		    }
525	    }
526	    /* Truncate zerod pages */
527	    zerodBytes = 0;
528	    while (r.filesize > 0) {
529		    vm_address_t p = r.range.address + r.filesize - pagesize;
530		    if (memcmp(p, zeropage, pagesize) == 0) {
531			    r.filesize -= pagesize;
532			    zerodBytes += pagesize;
533		    } else {
534			    break;
535		    }
536	    }
537	    if (zerodBytes) {
538		    printf("Removed %lx zerod bytes from filesize\n", zerodBytes);
539	    }
540	    unexec_regions[n++] = r;
541	    r = unexec_regions[i];
542	    if (r.range.address & (pagesize-1L)) { /* Align beginning of unmerged region */
543		    begin = r.range.address;
544		    r.range.address = r.range.address & ~(pagesize-1L);
545		    r.range.size += begin - r.range.address;
546		    r.filesize += begin - r.range.address;
547	    }
548    }
549  }
550  end = r.range.address + r.range.size;
551  if (end & (pagesize-1L)) {
552     end = ROUNDUP_TO_PAGE_BOUNDARY(end);
553     printf("Page (%#8lx) aligning region @%#8lx size from %#8lx to %#8lx\n",
554	    pagesize, (long)r.range.address, (long)r.range.size, (long)(end - r.range.address));
555     r.range.size = end - r.range.address;
556     r.filesize = r.range.size;
557  }
558  /* Truncate zerod pages */
559  zerodBytes = 0;
560  while (r.filesize > 0) {
561	  vm_address_t p = r.range.address + r.filesize - pagesize;
562	  if (memcmp(p, zeropage, pagesize) == 0) {
563		  r.filesize -= pagesize;
564		  zerodBytes += pagesize;
565	  } else {
566		  break;
567	  }
568  }
569  free(zeropage);
570  if (zerodBytes) {
571	  printf("Removed %lx zerod bytes from filesize\n", zerodBytes);
572  }
573  unexec_regions[n++] = r;
574  num_unexec_regions = n;
575}
576
577
578/* More informational messages routines.  */
579
580static void
581print_load_command_name (int lc)
582{
583  switch (lc)
584    {
585    case LC_SEGMENT:
586      printf("LC_SEGMENT             ");
587      break;
588    case LC_SYMTAB:
589      printf("LC_SYMTAB              ");
590      break;
591    case LC_SYMSEG:
592      printf("LC_SYMSEG              ");
593      break;
594    case LC_UNIXTHREAD:
595      printf("LC_UNIXTHREAD          ");
596      break;
597    case LC_DYSYMTAB:
598      printf("LC_DYSYMTAB            ");
599      break;
600    case LC_LOAD_DYLIB:
601      printf("LC_LOAD_DYLIB          ");
602      break;
603    case LC_ID_DYLIB:
604      printf("LC_ID_DYLIB            ");
605      break;
606    case LC_LOAD_DYLINKER:
607      printf("LC_LOAD_DYLINKER       ");
608      break;
609    case LC_PREBOUND_DYLIB:
610      printf("LC_PREBOUND_DYLIB      ");
611      break;
612    case LC_ROUTINES:
613      printf("LC_ROUTINES            ");
614      break;
615    case LC_SUB_FRAMEWORK:
616      printf("LC_SUBFRAMEWORK        ");
617      break;
618    case LC_SUB_UMBRELLA:
619      printf("LC_SUB_UMBRELLA        ");
620      break;
621    case LC_SUB_CLIENT:
622      printf("LC_SUB_CLIENT          ");
623      break;
624    case LC_SUB_LIBRARY:
625      printf("LC_SUB_LIBRARY         ");
626      break;
627    case LC_TWOLEVEL_HINTS:
628      printf("LC_TWOLEVEL_HINTS      ");
629      break;
630    case LC_PREBIND_CKSUM:
631      printf("LC_PREBIND_CKSUM       ");
632      break;
633    case LC_LOAD_WEAK_DYLIB:
634      printf("LC_LOAD_WEAK_DYLIB     ");
635      break;
636    case LC_SEGMENT_64:
637      printf("LC_SEGMENT_64          ");
638      break;
639    case LC_ROUTINES_64:
640      printf("LC_ROUTINES_64         ");
641      break;
642    case LC_UUID:
643      printf("LC_UUID                ");
644      break;
645    case LC_RPATH:
646      printf("LC_RPATH               ");
647      break;
648    case LC_CODE_SIGNATURE:
649      printf("LC_CODE_SIGNATURE      ");
650      break;
651    case LC_SEGMENT_SPLIT_INFO:
652      printf("LC_SEGMENT_SPLIT_INFO  ");
653      break;
654    case LC_REEXPORT_DYLIB:
655      printf("LC_REEXPORT_DYLIB      ");
656      break;
657    case LC_LAZY_LOAD_DYLIB:
658      printf("LC_LAZY_LOAD_DYLIB     ");
659      break;
660    case LC_ENCRYPTION_INFO:
661      printf("LC_ENCRYPTION_INFO     ");
662      break;
663    case LC_DYLD_INFO:
664      printf("LC_DYLD_INFO           ");
665      break;
666    case LC_DYLD_INFO_ONLY:
667      printf("LC_DYLD_INFO_ONLY      ");
668      break;
669    case LC_LOAD_UPWARD_DYLIB:
670      printf("LC_LOAD_UPWARD_DYLIB   ");
671      break;
672    case LC_VERSION_MIN_MACOSX:
673      printf("LC_VERSION_MIN_MACOSX  ");
674      break;
675    case LC_VERSION_MIN_IPHONEOS:
676      printf("LC_VERSION_MIN_IPHONEOS");
677      break;
678    case LC_FUNCTION_STARTS:
679      printf("LC_FUNCTION_STARTS     ");
680      break;
681    case LC_DYLD_ENVIRONMENT:
682      printf("LC_DYLD_ENVIRONMENT    ");
683      break;
684    case LC_SOURCE_VERSION:
685      printf("LC_SOURCE_VERSION      ");
686      break;
687    case LC_DYLIB_CODE_SIGN_DRS:
688      printf("LC_DYLIB_CODE_SIGN_DRS ");
689      break;
690    case LC_MAIN:
691      printf("LC_MAIN                ");
692      break;
693    case LC_DATA_IN_CODE:
694      printf("LC_DATA_IN_CODE        ");
695      break;
696    default:
697      printf("unknown(%08x)", lc);
698      break;
699    }
700}
701
702static void
703print_load_command (struct load_command *lc)
704{
705  print_load_command_name (lc->cmd);
706  printf ("%8d", lc->cmdsize);
707
708  if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64)
709    {
710      struct segment_command *scp;
711      struct section *sectp;
712      int j;
713
714      scp = (struct segment_command *) lc;
715      printf (" %-16.16s %#10lx %#8lx\n",
716	      scp->segname, (long) (scp->vmaddr), (long) (scp->vmsize));
717
718      sectp = (struct section *) (scp + 1);
719      for (j = 0; j < scp->nsects; j++)
720	{
721	  printf ("                           %-16.16s %#10lx %#8lx (flags: %#8lx)\n",
722		  sectp->sectname, (long) (sectp->addr), (long) (sectp->size), (long) (sectp->flags));
723	  sectp++;
724	}
725    }
726  else
727    printf ("\n");
728}
729
730/* Read header and load commands from input file.  Store the latter in
731   the global array lca.  Store the total number of load commands in
732   global variable nlc.  */
733static void
734read_load_commands ()
735{
736  int i;
737
738  if (!unexec_read (&mh, sizeof (struct mach_header)))
739    unexec_error ("cannot read mach-o header");
740
741  if (mh.magic != target_MH_MAGIC)
742    unexec_error ("input file not in correct Mach-O format");
743
744  if (mh.filetype != MH_EXECUTE)
745    unexec_error ("input Mach-O file is not an executable object file");
746
747#if VERBOSE
748  printf ("--- Header Information ---\n");
749  printf ("Magic = 0x%08x\n", mh.magic);
750  printf ("CPUType = %d\n", mh.cputype);
751  printf ("CPUSubType = %d\n", mh.cpusubtype);
752  printf ("FileType = 0x%x\n", mh.filetype);
753  printf ("NCmds = %d\n", mh.ncmds);
754  printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
755  printf ("Flags = 0x%08x\n", mh.flags);
756#endif
757
758  nlc = mh.ncmds;
759  lca = (struct load_command **) malloc (nlc * sizeof (struct load_command *));
760
761  for (i = 0; i < nlc; i++)
762    {
763      struct load_command lc;
764      /* Load commands are variable-size: so read the command type and
765	 size first and then read the rest.  */
766      if (!unexec_read (&lc, sizeof (struct load_command)))
767        unexec_error ("cannot read load command");
768      lca[i] = (struct load_command *) malloc (lc.cmdsize);
769      memcpy (lca[i], &lc, sizeof (struct load_command));
770      if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
771        unexec_error ("cannot read content of load command");
772      if (lc.cmd == LC_SEGMENT || lc.cmd == LC_SEGMENT_64)
773	{
774	  struct segment_command *scp = (struct segment_command *) lca[i];
775
776	  if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
777	    infile_lc_highest_addr = scp->vmaddr + scp->vmsize;
778
779	  if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
780	    {
781	      struct section *sectp = (struct section *) (scp + 1);
782	      int j;
783
784	      for (j = 0; j < scp->nsects; j++)
785		if (sectp->offset < text_seg_lowest_offset)
786		  text_seg_lowest_offset = sectp->offset;
787	    }
788	}
789    }
790
791  printf ("Highest address of load commands in input file: %#8lx\n",
792	  (long)infile_lc_highest_addr);
793
794  printf ("Lowest offset of all sections in __TEXT segment: %#8lx\n",
795	  text_seg_lowest_offset);
796
797  printf ("--- List of Load Commands in Input File ---\n");
798  printf ("# cmd              cmdsize name                address     size\n");
799
800  for (i = 0; i < nlc; i++)
801    {
802      printf ("%1d ", i);
803      print_load_command (lca[i]);
804    }
805}
806
807/* Copy a LC_SEGMENT load command other than the __DATA segment from
808   the input file to the output file, adjusting the file offset of the
809   segment and the file offsets of sections contained in it.  */
810static void
811copy_segment (struct load_command *lc)
812{
813  struct segment_command *scp = (struct segment_command *) lc;
814  unsigned long old_fileoff = scp->fileoff;
815  struct section *sectp;
816  int j;
817
818  scp->fileoff = curr_file_offset;
819
820  sectp = (struct section *) (scp + 1);
821  for (j = 0; j < scp->nsects; j++)
822    {
823      sectp->offset += curr_file_offset - old_fileoff;
824      sectp++;
825    }
826
827  printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
828	  scp->segname, (long) (scp->fileoff), (long) (scp->filesize),
829	  (long) (scp->vmsize), (long) (scp->vmaddr));
830
831  if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
832    unexec_error ("cannot copy segment from input to output file");
833  curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
834
835  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
836    unexec_error ("cannot write load command to header");
837
838  curr_header_offset += lc->cmdsize;
839}
840
841/* Copy a LC_SEGMENT load command for the __DATA segment in the input
842   file to the output file.  We assume that only one such segment load
843   command exists in the input file and it contains the sections
844   __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and
845   __dyld.  The first three of these should be dumped from memory and
846   the rest should be copied from the input file.  Note that the
847   sections __bss and __common contain no data in the input file
848   because their flag fields have the value S_ZEROFILL.  Dumping these
849   from memory makes it necessary to adjust file offset fields in
850   subsequently dumped load commands.  Then, create new __DATA segment
851   load commands for regions on the region list other than the one
852   corresponding to the __DATA segment in the input file.  */
853static void
854copy_data_segment (struct load_command *lc)
855{
856  struct segment_command *scp = (struct segment_command *) lc;
857  struct section *sectp;
858  int j;
859  unsigned long header_offset, old_file_offset;
860
861  /* The new filesize of the segment is set to its vmsize because data
862     blocks for segments must start at region boundaries.  Note that
863     this may leave unused locations at the end of the segment data
864     block because the total of the sizes of all sections in the
865     segment is generally smaller than vmsize.  */
866  scp->filesize = scp->vmsize;
867
868  printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
869	  scp->segname, curr_file_offset, (long)(scp->filesize),
870	  (long)(scp->vmsize), (long) (scp->vmaddr));
871
872  /* Offsets in the output file for writing the next section structure
873     and segment data block, respectively.  */
874  header_offset = curr_header_offset + sizeof (struct segment_command);
875
876  sectp = (struct section *) (scp + 1);
877  for (j = 0; j < scp->nsects; j++)
878    {
879      old_file_offset = sectp->offset;
880      sectp->offset = sectp->addr - scp->vmaddr + curr_file_offset;
881      /* The __data section is dumped from memory.  The __bss and
882	 __common sections are also dumped from memory but their flag
883	 fields require changing (from S_ZEROFILL to S_REGULAR).  The
884	 other three kinds of sections are just copied from the input
885	 file.  */
886
887      unsigned char sect_type = sectp->flags & SECTION_TYPE;
888
889      switch (sect_type) {
890      case S_LAZY_SYMBOL_POINTERS:
891      case S_NON_LAZY_SYMBOL_POINTERS:
892      case S_CSTRING_LITERALS:
893	  if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
894	    unexec_error ("cannot copy section %s", sectp->sectname);
895	  if (!unexec_write (header_offset, sectp, sizeof (struct section)))
896	    unexec_error ("cannot write section %s's header", sectp->sectname);
897	  break;
898
899      case S_REGULAR:
900	if (strncmp (sectp->sectname, "__const", 16) == 0
901	    || strncmp(sectp->sectname, "__program_vars", 16) == 0) {
902	  if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
903	    unexec_error ("cannot copy section %s", sectp->sectname);
904	} else {
905	  if (!unexec_write (sectp->offset, (void *)sectp->addr, sectp->size))
906	    unexec_error ("cannot write section %s", sectp->sectname);
907	}
908	if (!unexec_write (header_offset, sectp, sizeof (struct section)))
909	  unexec_error ("cannot write section %s's header", sectp->sectname);
910	break;
911
912      case S_ZEROFILL:
913	  sectp->flags = S_REGULAR;
914
915	  if (strncmp (sectp->sectname, SECT_BSS, 16) == 0) {
916	    extern char *my_endbss_static;
917	    unsigned long my_size;
918
919	    /* Clear uninitialized local variables in statically linked
920	       libraries.  In particular, function pointers stored by
921	       libSystemStub.a, which is introduced in Mac OS X 10.4 for
922	       binary compatibility with respect to long double, are
923	       cleared so that they will be reinitialized when the
924	       dumped binary is executed on other versions of OS.  */
925	    my_size = (unsigned long)my_endbss_static - sectp->addr;
926	    if (!(sectp->addr <= (unsigned long)my_endbss_static
927		  && my_size <= sectp->size))
928	      unexec_error ("my_endbss_static is not in section %s",
929			    sectp->sectname);
930	    if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size))
931	      unexec_error ("cannot write section %s", sectp->sectname);
932	    if (!unexec_write_zero (sectp->offset + my_size,
933				    sectp->size - my_size))
934	      unexec_error ("cannot write section %s", sectp->sectname);
935	    if (!unexec_write (header_offset, sectp, sizeof (struct section)))
936	      unexec_error ("cannot write section %s's header", sectp->sectname);
937	    printf("copy SECT_BSS\n");
938	  } else {
939	    if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
940	      unexec_error ("cannot write section %s", sectp->sectname);
941	    if (!unexec_write (header_offset, sectp, sizeof (struct section)))
942	      unexec_error ("cannot write section %s's header", sectp->sectname);
943	    printf("copy %s\n", sectp->sectname);
944	  }
945	  break;
946
947      default:
948	unexec_error("unrecognized section type '0x%x' '%s' in __DATA segment", sect_type, sectp->sectname);
949      }
950
951      printf ("        section %-16.16s at %#8lx - %#8lx (sz: %#8lx)\n",
952	      sectp->sectname, (long) (sectp->offset),
953	      (long) (sectp->offset + sectp->size), (long) (sectp->size));
954
955      header_offset += sizeof (struct section);
956      sectp++;
957    }
958
959  curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
960
961  if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
962    unexec_error ("cannot write header of __DATA segment");
963  curr_header_offset += lc->cmdsize;
964
965  /* Create new __DATA segment load commands for regions on the region
966     list that do not corresponding to any segment load commands in
967     the input file.
968  */
969  long total = 0;
970  for (j = 0; j < num_unexec_regions; j++)
971    {
972      struct segment_command sc;
973
974      sc.cmd = target_LC_SEGMENT;
975      sc.cmdsize = sizeof (struct segment_command);
976      strncpy (sc.segname, SEG_DATA, 16);
977      sc.vmaddr = unexec_regions[j].range.address;
978      sc.vmsize = unexec_regions[j].range.size;
979      sc.fileoff = curr_file_offset;
980      sc.filesize = unexec_regions[j].filesize;
981      sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
982      sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
983      sc.nsects = 0;
984      sc.flags = 0;
985      total += sc.filesize;
986      printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
987	      sc.segname, (long) (sc.fileoff), (long) (sc.filesize),
988	      (long) (sc.vmsize), (long) (sc.vmaddr));
989
990      if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.filesize))
991        unexec_error ("cannot write new __DATA segment %#8lx (sz: %#8lx)", sc.vmaddr, sc.filesize);
992      curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize);
993
994      if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
995	unexec_error ("cannot write new __DATA segment's header");
996      curr_header_offset += sc.cmdsize;
997      mh.ncmds++;
998    }
999  printf("Total written: %ld\n", total);
1000}
1001
1002/* Copy a LC_SYMTAB load command from the input file to the output
1003   file, adjusting the file offset fields.  */
1004static void
1005copy_symtab (struct load_command *lc, long delta)
1006{
1007  struct symtab_command *stp = (struct symtab_command *) lc;
1008
1009  stp->symoff += delta;
1010  stp->stroff += delta;
1011
1012  printf ("Writing ");
1013  print_load_command_name (lc->cmd);
1014  printf (" command\n");
1015
1016  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1017    unexec_error ("cannot write LC_SYMTAB command to header");
1018
1019  curr_header_offset += lc->cmdsize;
1020}
1021
1022/* Copy a LC_DYLD_INFO_ONLY load command from the input file to the output
1023   file, adjusting the file offset fields.  */
1024static void
1025copy_dyld_info_only (struct load_command *lc, long delta)
1026{
1027  struct dyld_info_command *dyld = (struct dyld_info_command *) lc;
1028
1029  if (dyld->rebase_size)
1030    dyld->rebase_off += delta;
1031  if (dyld->bind_size)
1032    dyld->bind_off += delta;
1033  if (dyld->weak_bind_size)
1034    dyld->weak_bind_off += delta;
1035  if (dyld->lazy_bind_size)
1036    dyld->lazy_bind_off += delta;
1037  if (dyld->export_size)
1038    dyld->export_off += delta;
1039
1040  printf ("Writing ");
1041  print_load_command_name (lc->cmd);
1042  printf (" command\n");
1043
1044  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1045    unexec_error ("cannot write LC_DYLD_INFO_ONLY command to header");
1046
1047  curr_header_offset += lc->cmdsize;
1048}
1049
1050/* Copy a LC_DYLIB_CODE_SIGN_DRS load command from the input file to the output
1051   file, adjusting the file offset fields.  */
1052static void
1053copy_linkedit_data (struct load_command *lc, long delta)
1054{
1055  struct linkedit_data_command *data = (struct linkedit_data_command *) lc;
1056
1057  if (data->dataoff)
1058    data->dataoff += delta;
1059
1060  printf ("Writing ");
1061  print_load_command_name (lc->cmd);
1062  printf (" command\n");
1063
1064  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1065	  unexec_error ("cannot write %d command to header", lc->cmd);
1066
1067  curr_header_offset += lc->cmdsize;
1068}
1069/* Fix up relocation entries. */
1070static void
1071unrelocate (const char *name, off_t reloff, int nrel)
1072{
1073  int i, unreloc_count;
1074  struct relocation_info reloc_info;
1075  struct scattered_relocation_info *sc_reloc_info
1076    = (struct scattered_relocation_info *) &reloc_info;
1077
1078  for (unreloc_count = 0, i = 0; i < nrel; i++)
1079    {
1080      if (lseek (infd, reloff, L_SET) != reloff)
1081	unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i);
1082      if (!unexec_read (&reloc_info, sizeof (reloc_info)))
1083	unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i);
1084      reloff += sizeof (reloc_info);
1085
1086      if (sc_reloc_info->r_scattered == 0)
1087	switch (reloc_info.r_type)
1088	  {
1089	  case GENERIC_RELOC_VANILLA:
1090	    if (reloc_info.r_address >= data_segment_scp->vmaddr
1091		&& reloc_info.r_address < (data_segment_scp->vmaddr
1092					   + data_segment_scp->vmsize))
1093	      {
1094		off_t src_off = data_segment_old_fileoff
1095		  + reloc_info.r_address - data_segment_scp->vmaddr;
1096		off_t dst_off = data_segment_scp->fileoff
1097		  + reloc_info.r_address - data_segment_scp->vmaddr;
1098
1099		if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length))
1100		  unexec_error ("unrelocate: %s:%d cannot copy original value",
1101				name, i);
1102		unreloc_count++;
1103	      }
1104	    break;
1105	  default:
1106	    unexec_error ("unrelocate: %s:%d cannot handle type = %d",
1107			  name, i, reloc_info.r_type);
1108	  }
1109      else
1110	switch (sc_reloc_info->r_type)
1111	  {
1112#if defined (__ppc__)
1113	  case PPC_RELOC_PB_LA_PTR:
1114	    /* nothing to do for prebound lazy pointer */
1115	    break;
1116#endif
1117	  default:
1118	    unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d",
1119			  name, i, sc_reloc_info->r_type);
1120	  }
1121    }
1122
1123  if (nrel > 0)
1124    printf ("Fixed up %d/%d %s relocation entries in data segment.\n",
1125	    unreloc_count, nrel, name);
1126}
1127
1128/* Copy a LC_DYSYMTAB load command from the input file to the output
1129   file, adjusting the file offset fields.  */
1130static void
1131copy_dysymtab (struct load_command *lc, long delta)
1132{
1133  struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
1134
1135  unrelocate ("local", dstp->locreloff, dstp->nlocrel);
1136  unrelocate ("external", dstp->extreloff, dstp->nextrel);
1137
1138  if (dstp->nextrel > 0) {
1139    dstp->extreloff += delta;
1140  }
1141
1142  if (dstp->nlocrel > 0) {
1143    dstp->locreloff += delta;
1144  }
1145
1146  if (dstp->nindirectsyms > 0)
1147    dstp->indirectsymoff += delta;
1148
1149  printf ("Writing ");
1150  print_load_command_name (lc->cmd);
1151  printf (" command\n");
1152
1153  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1154    unexec_error ("cannot write symtab command to header");
1155
1156  curr_header_offset += lc->cmdsize;
1157}
1158
1159/* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
1160   file, adjusting the file offset fields.  */
1161static void
1162copy_twolevelhints (struct load_command *lc, long delta)
1163{
1164  struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
1165
1166  if (tlhp->nhints > 0) {
1167    tlhp->offset += delta;
1168  }
1169
1170  printf ("Writing ");
1171  print_load_command_name (lc->cmd);
1172  printf (" command\n");
1173
1174  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1175    unexec_error ("cannot write two level hint command to header");
1176
1177  curr_header_offset += lc->cmdsize;
1178}
1179
1180/* Copy other kinds of load commands from the input file to the output
1181   file, ones that do not require adjustments of file offsets.  */
1182static void
1183copy_other (struct load_command *lc)
1184{
1185  printf ("Writing ");
1186  print_load_command_name (lc->cmd);
1187  printf (" command\n");
1188
1189  if (lc->cmd == LC_CODE_SIGNATURE)
1190    lc->cmd = 0x0;		/* Don't propagate signature */
1191  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1192    unexec_error ("cannot write load command to header");
1193
1194  curr_header_offset += lc->cmdsize;
1195}
1196
1197/* Loop through all load commands and dump them.  Then write the Mach
1198   header.  */
1199static void
1200dump_it ()
1201{
1202  int i;
1203  long linkedit_delta = 0;
1204
1205  printf ("--- Load Commands written to Output File ---\n");
1206
1207  for (i = 0; i < nlc; i++)
1208    switch (lca[i]->cmd)
1209      {
1210      case target_LC_SEGMENT:
1211	{
1212	  struct segment_command *scp = (struct segment_command *) lca[i];
1213	  if (strncmp (scp->segname, SEG_DATA, 16) == 0)
1214	    {
1215	      /* save data segment file offset and segment_command for
1216		 unrelocate */
1217	      if (data_segment_old_fileoff)
1218		unexec_error ("cannot handle multiple DATA segments"
1219			      " in input file");
1220	      data_segment_old_fileoff = scp->fileoff;
1221	      data_segment_scp = scp;
1222
1223	      copy_data_segment (lca[i]);
1224	    }
1225	  else
1226	    {
1227	      if (strncmp (scp->segname, SEG_LINKEDIT, 16) == 0)
1228		{
1229		  if (linkedit_delta)
1230		    unexec_error ("cannot handle multiple LINKEDIT segments"
1231				  " in input file");
1232		  linkedit_delta = curr_file_offset - scp->fileoff;
1233		}
1234
1235	      copy_segment (lca[i]);
1236	    }
1237	}
1238	break;
1239      case LC_SYMTAB:
1240	copy_symtab (lca[i], linkedit_delta);
1241	break;
1242      case LC_DYSYMTAB:
1243	copy_dysymtab (lca[i], linkedit_delta);
1244	break;
1245      case LC_TWOLEVEL_HINTS:
1246	copy_twolevelhints (lca[i], linkedit_delta);
1247	break;
1248      case LC_DYLD_INFO_ONLY:
1249	copy_dyld_info_only(lca[i], linkedit_delta);
1250	break;
1251      case LC_CODE_SIGNATURE:
1252      case LC_SEGMENT_SPLIT_INFO:
1253      case LC_FUNCTION_STARTS:
1254      case LC_DATA_IN_CODE:
1255      case LC_DYLIB_CODE_SIGN_DRS:
1256	copy_linkedit_data(lca[i], linkedit_delta);
1257	break;
1258
1259      default:
1260	copy_other (lca[i]);
1261	break;
1262      }
1263
1264  if (curr_header_offset > text_seg_lowest_offset)
1265    unexec_error ("not enough room for load commands for new __DATA segments");
1266
1267  printf ("%ld unused bytes follow Mach-O header\n",
1268	  text_seg_lowest_offset - curr_header_offset);
1269
1270  mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
1271  if (!unexec_write (0, &mh, sizeof (struct mach_header)))
1272    unexec_error ("cannot write final header contents");
1273}
1274
1275/* Take a snapshot of Emacs and make a Mach-O format executable file
1276   from it.  The file names of the output and input files are outfile
1277   and infile, respectively.  The three other parameters are
1278   ignored.  */
1279void
1280unexec (char *outfile, char *infile, void *start_data, void *start_bss,
1281        void *entry_address)
1282{
1283  if (in_dumped_exec)
1284    unexec_error ("Unexec from a dumped executable is not supported.");
1285
1286  pagesize = getpagesize ();
1287  infd = open (infile, O_RDONLY, 0);
1288  if (infd < 0)
1289    {
1290      unexec_error ("cannot open input file `%s'", infile);
1291    }
1292
1293  outfd = open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0755);
1294  if (outfd < 0)
1295    {
1296      close (infd);
1297      unexec_error ("cannot open output file `%s'", outfile);
1298    }
1299
1300  build_region_list ();
1301  read_load_commands ();
1302
1303  find_emacs_zone_regions ();
1304  unexec_regions_merge ();
1305
1306  in_dumped_exec = 1;
1307
1308  dump_it ();
1309
1310  close (outfd);
1311}
1312
1313
1314void
1315unexec_init_emacs_zone ()
1316{
1317  emacs_zone = malloc_create_zone (0, 0);
1318  malloc_set_zone_name (emacs_zone, "EmacsZone");
1319}
1320
1321#ifndef MACOSX_MALLOC_MULT16
1322#define MACOSX_MALLOC_MULT16 1
1323#endif
1324
1325typedef struct unexec_malloc_header {
1326  union {
1327    char c[8];
1328    size_t size;
1329  } u;
1330} unexec_malloc_header_t;
1331
1332#if MACOSX_MALLOC_MULT16
1333
1334#define ptr_in_unexec_regions(p) ((((vm_address_t) (p)) & 8) != 0)
1335
1336#else
1337
1338int
1339ptr_in_unexec_regions (void *ptr)
1340{
1341  int i;
1342
1343  for (i = 0; i < num_unexec_regions; i++)
1344    if ((vm_address_t) ptr - unexec_regions[i].range.address
1345	< unexec_regions[i].range.size)
1346      return 1;
1347
1348  return 0;
1349}
1350
1351#endif
1352
1353void *
1354unexec_malloc (size_t size)
1355{
1356  if (in_dumped_exec)
1357    {
1358      void *p;
1359
1360      p = malloc (size);
1361#if MACOSX_MALLOC_MULT16
1362      assert (((vm_address_t) p % 16) == 0);
1363#endif
1364      return p;
1365    }
1366  else
1367    {
1368      unexec_malloc_header_t *ptr;
1369
1370      ptr = (unexec_malloc_header_t *)
1371	malloc_zone_malloc (emacs_zone, size + sizeof (unexec_malloc_header_t));
1372      ptr->u.size = size;
1373      ptr++;
1374#if MACOSX_MALLOC_MULT16
1375      assert (((vm_address_t) ptr % 16) == 8);
1376#endif
1377      return (void *) ptr;
1378    }
1379}
1380
1381void *
1382unexec_realloc (void *old_ptr, size_t new_size)
1383{
1384  if (in_dumped_exec)
1385    {
1386      void *p;
1387
1388      if (ptr_in_unexec_regions (old_ptr))
1389	{
1390	  size_t old_size = ((unexec_malloc_header_t *) old_ptr)[-1].u.size;
1391	  size_t size = new_size > old_size ? old_size : new_size;
1392
1393	  p = (size_t *) malloc (new_size);
1394	  if (size)
1395	    memcpy (p, old_ptr, size);
1396	}
1397      else
1398	{
1399	  p = realloc (old_ptr, new_size);
1400	}
1401#if MACOSX_MALLOC_MULT16
1402      assert (((vm_address_t) p % 16) == 0);
1403#endif
1404      return p;
1405    }
1406  else
1407    {
1408      unexec_malloc_header_t *ptr;
1409
1410      ptr = (unexec_malloc_header_t *)
1411	malloc_zone_realloc (emacs_zone, (unexec_malloc_header_t *) old_ptr - 1,
1412			     new_size + sizeof (unexec_malloc_header_t));
1413      ptr->u.size = new_size;
1414      ptr++;
1415#if MACOSX_MALLOC_MULT16
1416      assert (((vm_address_t) ptr % 16) == 8);
1417#endif
1418      return (void *) ptr;
1419    }
1420}
1421
1422void
1423unexec_free (void *ptr)
1424{
1425  if (in_dumped_exec)
1426    {
1427      if (!ptr_in_unexec_regions (ptr))
1428	free (ptr);
1429    }
1430  else
1431    malloc_zone_free (emacs_zone, (unexec_malloc_header_t *) ptr - 1);
1432}
1433
1434/* arch-tag: 1a784f7b-a184-4c4f-9544-da8619593d72
1435   (do not change this comment) */
1436