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
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	    while (r.filesize > 0) {
528		    vm_address_t p = r.range.address + r.filesize - pagesize;
529		    if (memcmp(p, zeropage, pagesize) == 0) {
530			    r.filesize -= pagesize;
531		    } else {
532			    break;
533		    }
534	    }
535	    if (r.filesize != r.range.size) {
536		    printf("Removed %lx zerod bytes from filesize\n", r.range.size - r.filesize);
537	    }
538	    unexec_regions[n++] = r;
539	    r = unexec_regions[i];
540	    if (r.range.address & (pagesize-1L)) { /* Align beginning of unmerged region */
541		    begin = r.range.address;
542		    r.range.address = r.range.address & ~(pagesize-1L);
543		    r.range.size += begin - r.range.address;
544		    r.filesize += begin - r.range.address;
545	    }
546    }
547  }
548  end = r.range.address + r.range.size;
549  if (end & (pagesize-1L)) {
550     end = ROUNDUP_TO_PAGE_BOUNDARY(end);
551     printf("Page (%#8lx) aligning region @%#8lx size from %#8lx to %#8lx\n",
552	    pagesize, (long)r.range.address, (long)r.range.size, (long)(end - r.range.address));
553     r.range.size = end - r.range.address;
554     r.filesize = r.range.size;
555  }
556  /* Truncate zerod pages */
557  while (r.filesize > 0) {
558	  vm_address_t p = r.range.address + r.filesize - pagesize;
559	  if (memcmp(p, zeropage, pagesize) == 0) {
560		  r.filesize -= pagesize;
561	  } else {
562		  break;
563	  }
564  }
565  free(zeropage);
566  if (r.filesize != r.range.size) {
567	  printf("Removed %lx zerod bytes from filesize\n", r.range.size - r.filesize);
568  }
569  unexec_regions[n++] = r;
570  num_unexec_regions = n;
571}
572
573
574/* More informational messages routines.  */
575
576static void
577print_load_command_name (int lc)
578{
579  switch (lc)
580    {
581    case LC_SEGMENT:
582      printf("LC_SEGMENT             ");
583      break;
584    case LC_SYMTAB:
585      printf("LC_SYMTAB              ");
586      break;
587    case LC_SYMSEG:
588      printf("LC_SYMSEG              ");
589      break;
590    case LC_UNIXTHREAD:
591      printf("LC_UNIXTHREAD          ");
592      break;
593    case LC_DYSYMTAB:
594      printf("LC_DYSYMTAB            ");
595      break;
596    case LC_LOAD_DYLIB:
597      printf("LC_LOAD_DYLIB          ");
598      break;
599    case LC_ID_DYLIB:
600      printf("LC_ID_DYLIB            ");
601      break;
602    case LC_LOAD_DYLINKER:
603      printf("LC_LOAD_DYLINKER       ");
604      break;
605    case LC_PREBOUND_DYLIB:
606      printf("LC_PREBOUND_DYLIB      ");
607      break;
608    case LC_ROUTINES:
609      printf("LC_ROUTINES            ");
610      break;
611    case LC_SUB_FRAMEWORK:
612      printf("LC_SUBFRAMEWORK        ");
613      break;
614    case LC_SUB_UMBRELLA:
615      printf("LC_SUB_UMBRELLA        ");
616      break;
617    case LC_SUB_CLIENT:
618      printf("LC_SUB_CLIENT          ");
619      break;
620    case LC_SUB_LIBRARY:
621      printf("LC_SUB_LIBRARY         ");
622      break;
623    case LC_TWOLEVEL_HINTS:
624      printf("LC_TWOLEVEL_HINTS      ");
625      break;
626    case LC_PREBIND_CKSUM:
627      printf("LC_PREBIND_CKSUM       ");
628      break;
629    case LC_LOAD_WEAK_DYLIB:
630      printf("LC_LOAD_WEAK_DYLIB     ");
631      break;
632    case LC_SEGMENT_64:
633      printf("LC_SEGMENT_64          ");
634      break;
635    case LC_ROUTINES_64:
636      printf("LC_ROUTINES_64         ");
637      break;
638    case LC_UUID:
639      printf("LC_UUID                ");
640      break;
641    case LC_RPATH:
642      printf("LC_RPATH               ");
643      break;
644    case LC_CODE_SIGNATURE:
645      printf("LC_CODE_SIGNATURE      ");
646      break;
647    case LC_SEGMENT_SPLIT_INFO:
648      printf("LC_SEGMENT_SPLIT_INFO  ");
649      break;
650    case LC_REEXPORT_DYLIB:
651      printf("LC_REEXPORT_DYLIB      ");
652      break;
653    case LC_LAZY_LOAD_DYLIB:
654      printf("LC_LAZY_LOAD_DYLIB     ");
655      break;
656    case LC_ENCRYPTION_INFO:
657      printf("LC_ENCRYPTION_INFO     ");
658      break;
659    case LC_DYLD_INFO:
660      printf("LC_DYLD_INFO           ");
661      break;
662    case LC_DYLD_INFO_ONLY:
663      printf("LC_DYLD_INFO_ONLY      ");
664      break;
665    case LC_LOAD_UPWARD_DYLIB:
666      printf("LC_LOAD_UPWARD_DYLIB   ");
667      break;
668    case LC_VERSION_MIN_MACOSX:
669      printf("LC_VERSION_MIN_MACOSX  ");
670      break;
671    case LC_VERSION_MIN_IPHONEOS:
672      printf("LC_VERSION_MIN_IPHONEOS");
673      break;
674    case LC_FUNCTION_STARTS:
675      printf("LC_FUNCTION_STARTS     ");
676      break;
677    case LC_DYLD_ENVIRONMENT:
678      printf("LC_DYLD_ENVIRONMENT    ");
679      break;
680    case LC_SOURCE_VERSION:
681      printf("LC_SOURCE_VERSION      ");
682      break;
683    case LC_DYLIB_CODE_SIGN_DRS:
684      printf("LC_DYLIB_CODE_SIGN_DRS ");
685      break;
686    case LC_MAIN:
687      printf("LC_MAIN                ");
688      break;
689    case LC_DATA_IN_CODE:
690      printf("LC_DATA_IN_CODE        ");
691      break;
692    default:
693      printf("unknown(%08x)", lc);
694      break;
695    }
696}
697
698static void
699print_load_command (struct load_command *lc)
700{
701  print_load_command_name (lc->cmd);
702  printf ("%8d", lc->cmdsize);
703
704  if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64)
705    {
706      struct segment_command *scp;
707      struct section *sectp;
708      int j;
709
710      scp = (struct segment_command *) lc;
711      printf (" %-16.16s %#10lx %#8lx\n",
712	      scp->segname, (long) (scp->vmaddr), (long) (scp->vmsize));
713
714      sectp = (struct section *) (scp + 1);
715      for (j = 0; j < scp->nsects; j++)
716	{
717	  printf ("                           %-16.16s %#10lx %#8lx (flags: %#8lx)\n",
718		  sectp->sectname, (long) (sectp->addr), (long) (sectp->size), (long) (sectp->flags));
719	  sectp++;
720	}
721    }
722  else
723    printf ("\n");
724}
725
726/* Read header and load commands from input file.  Store the latter in
727   the global array lca.  Store the total number of load commands in
728   global variable nlc.  */
729static void
730read_load_commands ()
731{
732  int i;
733
734  if (!unexec_read (&mh, sizeof (struct mach_header)))
735    unexec_error ("cannot read mach-o header");
736
737  if (mh.magic != target_MH_MAGIC)
738    unexec_error ("input file not in correct Mach-O format");
739
740  if (mh.filetype != MH_EXECUTE)
741    unexec_error ("input Mach-O file is not an executable object file");
742
743#if VERBOSE
744  printf ("--- Header Information ---\n");
745  printf ("Magic = 0x%08x\n", mh.magic);
746  printf ("CPUType = %d\n", mh.cputype);
747  printf ("CPUSubType = %d\n", mh.cpusubtype);
748  printf ("FileType = 0x%x\n", mh.filetype);
749  printf ("NCmds = %d\n", mh.ncmds);
750  printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
751  printf ("Flags = 0x%08x\n", mh.flags);
752#endif
753
754  nlc = mh.ncmds;
755  lca = (struct load_command **) malloc (nlc * sizeof (struct load_command *));
756
757  for (i = 0; i < nlc; i++)
758    {
759      struct load_command lc;
760      /* Load commands are variable-size: so read the command type and
761	 size first and then read the rest.  */
762      if (!unexec_read (&lc, sizeof (struct load_command)))
763        unexec_error ("cannot read load command");
764      lca[i] = (struct load_command *) malloc (lc.cmdsize);
765      memcpy (lca[i], &lc, sizeof (struct load_command));
766      if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
767        unexec_error ("cannot read content of load command");
768      if (lc.cmd == LC_SEGMENT || lc.cmd == LC_SEGMENT_64)
769	{
770	  struct segment_command *scp = (struct segment_command *) lca[i];
771
772	  if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
773	    infile_lc_highest_addr = scp->vmaddr + scp->vmsize;
774
775	  if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
776	    {
777	      struct section *sectp = (struct section *) (scp + 1);
778	      int j;
779
780	      for (j = 0; j < scp->nsects; j++)
781		if (sectp->offset < text_seg_lowest_offset)
782		  text_seg_lowest_offset = sectp->offset;
783	    }
784	}
785    }
786
787  printf ("Highest address of load commands in input file: %#8lx\n",
788	  (long)infile_lc_highest_addr);
789
790  printf ("Lowest offset of all sections in __TEXT segment: %#8lx\n",
791	  text_seg_lowest_offset);
792
793  printf ("--- List of Load Commands in Input File ---\n");
794  printf ("# cmd              cmdsize name                address     size\n");
795
796  for (i = 0; i < nlc; i++)
797    {
798      printf ("%1d ", i);
799      print_load_command (lca[i]);
800    }
801}
802
803/* Copy a LC_SEGMENT load command other than the __DATA segment from
804   the input file to the output file, adjusting the file offset of the
805   segment and the file offsets of sections contained in it.  */
806static void
807copy_segment (struct load_command *lc)
808{
809  struct segment_command *scp = (struct segment_command *) lc;
810  unsigned long old_fileoff = scp->fileoff;
811  struct section *sectp;
812  int j;
813
814  scp->fileoff = curr_file_offset;
815
816  sectp = (struct section *) (scp + 1);
817  for (j = 0; j < scp->nsects; j++)
818    {
819      sectp->offset += curr_file_offset - old_fileoff;
820      sectp++;
821    }
822
823  printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
824	  scp->segname, (long) (scp->fileoff), (long) (scp->filesize),
825	  (long) (scp->vmsize), (long) (scp->vmaddr));
826
827  if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
828    unexec_error ("cannot copy segment from input to output file");
829  curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
830
831  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
832    unexec_error ("cannot write load command to header");
833
834  curr_header_offset += lc->cmdsize;
835}
836
837/* Copy a LC_SEGMENT load command for the __DATA segment in the input
838   file to the output file.  We assume that only one such segment load
839   command exists in the input file and it contains the sections
840   __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and
841   __dyld.  The first three of these should be dumped from memory and
842   the rest should be copied from the input file.  Note that the
843   sections __bss and __common contain no data in the input file
844   because their flag fields have the value S_ZEROFILL.  Dumping these
845   from memory makes it necessary to adjust file offset fields in
846   subsequently dumped load commands.  Then, create new __DATA segment
847   load commands for regions on the region list other than the one
848   corresponding to the __DATA segment in the input file.  */
849static void
850copy_data_segment (struct load_command *lc)
851{
852  struct segment_command *scp = (struct segment_command *) lc;
853  struct section *sectp;
854  int j;
855  unsigned long header_offset, old_file_offset;
856
857  /* The new filesize of the segment is set to its vmsize because data
858     blocks for segments must start at region boundaries.  Note that
859     this may leave unused locations at the end of the segment data
860     block because the total of the sizes of all sections in the
861     segment is generally smaller than vmsize.  */
862  scp->filesize = scp->vmsize;
863
864  printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
865	  scp->segname, curr_file_offset, (long)(scp->filesize),
866	  (long)(scp->vmsize), (long) (scp->vmaddr));
867
868  /* Offsets in the output file for writing the next section structure
869     and segment data block, respectively.  */
870  header_offset = curr_header_offset + sizeof (struct segment_command);
871
872  sectp = (struct section *) (scp + 1);
873  for (j = 0; j < scp->nsects; j++)
874    {
875      old_file_offset = sectp->offset;
876      sectp->offset = sectp->addr - scp->vmaddr + curr_file_offset;
877      /* The __data section is dumped from memory.  The __bss and
878	 __common sections are also dumped from memory but their flag
879	 fields require changing (from S_ZEROFILL to S_REGULAR).  The
880	 other three kinds of sections are just copied from the input
881	 file.  */
882
883      unsigned char sect_type = sectp->flags & SECTION_TYPE;
884
885      switch (sect_type) {
886      case S_LAZY_SYMBOL_POINTERS:
887      case S_NON_LAZY_SYMBOL_POINTERS:
888      case S_CSTRING_LITERALS:
889	  if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
890	    unexec_error ("cannot copy section %s", sectp->sectname);
891	  if (!unexec_write (header_offset, sectp, sizeof (struct section)))
892	    unexec_error ("cannot write section %s's header", sectp->sectname);
893	  break;
894
895      case S_REGULAR:
896	if (strncmp (sectp->sectname, "__const", 16) == 0
897	    || strncmp(sectp->sectname, "__program_vars", 16) == 0) {
898	  if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
899	    unexec_error ("cannot copy section %s", sectp->sectname);
900	} else {
901	  if (!unexec_write (sectp->offset, (void *)sectp->addr, sectp->size))
902	    unexec_error ("cannot write section %s", sectp->sectname);
903	}
904	if (!unexec_write (header_offset, sectp, sizeof (struct section)))
905	  unexec_error ("cannot write section %s's header", sectp->sectname);
906	break;
907
908      case S_ZEROFILL:
909	  sectp->flags = S_REGULAR;
910
911	  if (strncmp (sectp->sectname, SECT_BSS, 16) == 0) {
912	    extern char *my_endbss_static;
913	    unsigned long my_size;
914
915	    /* Clear uninitialized local variables in statically linked
916	       libraries.  In particular, function pointers stored by
917	       libSystemStub.a, which is introduced in Mac OS X 10.4 for
918	       binary compatibility with respect to long double, are
919	       cleared so that they will be reinitialized when the
920	       dumped binary is executed on other versions of OS.  */
921	    my_size = (unsigned long)my_endbss_static - sectp->addr;
922	    if (!(sectp->addr <= (unsigned long)my_endbss_static
923		  && my_size <= sectp->size))
924	      unexec_error ("my_endbss_static is not in section %s",
925			    sectp->sectname);
926	    if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size))
927	      unexec_error ("cannot write section %s", sectp->sectname);
928	    if (!unexec_write_zero (sectp->offset + my_size,
929				    sectp->size - my_size))
930	      unexec_error ("cannot write section %s", sectp->sectname);
931	    if (!unexec_write (header_offset, sectp, sizeof (struct section)))
932	      unexec_error ("cannot write section %s's header", sectp->sectname);
933	    printf("copy SECT_BSS\n");
934	  } else {
935	    if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
936	      unexec_error ("cannot write section %s", sectp->sectname);
937	    if (!unexec_write (header_offset, sectp, sizeof (struct section)))
938	      unexec_error ("cannot write section %s's header", sectp->sectname);
939	    printf("copy %s\n", sectp->sectname);
940	  }
941	  break;
942
943      default:
944	unexec_error("unrecognized section type '0x%x' '%s' in __DATA segment", sect_type, sectp->sectname);
945      }
946
947      printf ("        section %-16.16s at %#8lx - %#8lx (sz: %#8lx)\n",
948	      sectp->sectname, (long) (sectp->offset),
949	      (long) (sectp->offset + sectp->size), (long) (sectp->size));
950
951      header_offset += sizeof (struct section);
952      sectp++;
953    }
954
955  curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
956
957  if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
958    unexec_error ("cannot write header of __DATA segment");
959  curr_header_offset += lc->cmdsize;
960
961  /* Create new __DATA segment load commands for regions on the region
962     list that do not corresponding to any segment load commands in
963     the input file.
964  */
965  long total = 0;
966  for (j = 0; j < num_unexec_regions; j++)
967    {
968      struct segment_command sc;
969
970      sc.cmd = target_LC_SEGMENT;
971      sc.cmdsize = sizeof (struct segment_command);
972      strncpy (sc.segname, SEG_DATA, 16);
973      sc.vmaddr = unexec_regions[j].range.address;
974      sc.vmsize = unexec_regions[j].range.size;
975      sc.fileoff = curr_file_offset;
976      sc.filesize = unexec_regions[j].filesize;
977      sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
978      sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
979      sc.nsects = 0;
980      sc.flags = 0;
981      total += sc.filesize;
982      printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n",
983	      sc.segname, (long) (sc.fileoff), (long) (sc.filesize),
984	      (long) (sc.vmsize), (long) (sc.vmaddr));
985
986      if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.filesize))
987        unexec_error ("cannot write new __DATA segment %#8lx (sz: %#8lx)", sc.vmaddr, sc.filesize);
988      curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize);
989
990      if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
991	unexec_error ("cannot write new __DATA segment's header");
992      curr_header_offset += sc.cmdsize;
993      mh.ncmds++;
994    }
995  printf("Total written: %ld\n", total);
996}
997
998/* Copy a LC_SYMTAB load command from the input file to the output
999   file, adjusting the file offset fields.  */
1000static void
1001copy_symtab (struct load_command *lc, long delta)
1002{
1003  struct symtab_command *stp = (struct symtab_command *) lc;
1004
1005  stp->symoff += delta;
1006  stp->stroff += delta;
1007
1008  printf ("Writing ");
1009  print_load_command_name (lc->cmd);
1010  printf (" command\n");
1011
1012  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1013    unexec_error ("cannot write LC_SYMTAB command to header");
1014
1015  curr_header_offset += lc->cmdsize;
1016}
1017
1018/* Copy a LC_DYLD_INFO_ONLY load command from the input file to the output
1019   file, adjusting the file offset fields.  */
1020static void
1021copy_dyld_info_only (struct load_command *lc, long delta)
1022{
1023  struct dyld_info_command *dyld = (struct dyld_info_command *) lc;
1024
1025  if (dyld->rebase_size)
1026    dyld->rebase_off += delta;
1027  if (dyld->bind_size)
1028    dyld->bind_off += delta;
1029  if (dyld->weak_bind_size)
1030    dyld->weak_bind_off += delta;
1031  if (dyld->lazy_bind_size)
1032    dyld->lazy_bind_off += delta;
1033  if (dyld->export_size)
1034    dyld->export_off += delta;
1035
1036  printf ("Writing ");
1037  print_load_command_name (lc->cmd);
1038  printf (" command\n");
1039
1040  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1041    unexec_error ("cannot write LC_DYLD_INFO_ONLY command to header");
1042
1043  curr_header_offset += lc->cmdsize;
1044}
1045
1046/* Copy a LC_DYLIB_CODE_SIGN_DRS load command from the input file to the output
1047   file, adjusting the file offset fields.  */
1048static void
1049copy_linkedit_data (struct load_command *lc, long delta)
1050{
1051  struct linkedit_data_command *data = (struct linkedit_data_command *) lc;
1052
1053  if (data->dataoff)
1054    data->dataoff += delta;
1055
1056  printf ("Writing ");
1057  print_load_command_name (lc->cmd);
1058  printf (" command\n");
1059
1060  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1061	  unexec_error ("cannot write %d command to header", lc->cmd);
1062
1063  curr_header_offset += lc->cmdsize;
1064}
1065/* Fix up relocation entries. */
1066static void
1067unrelocate (const char *name, off_t reloff, int nrel)
1068{
1069  int i, unreloc_count;
1070  struct relocation_info reloc_info;
1071  struct scattered_relocation_info *sc_reloc_info
1072    = (struct scattered_relocation_info *) &reloc_info;
1073
1074  for (unreloc_count = 0, i = 0; i < nrel; i++)
1075    {
1076      if (lseek (infd, reloff, L_SET) != reloff)
1077	unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i);
1078      if (!unexec_read (&reloc_info, sizeof (reloc_info)))
1079	unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i);
1080      reloff += sizeof (reloc_info);
1081
1082      if (sc_reloc_info->r_scattered == 0)
1083	switch (reloc_info.r_type)
1084	  {
1085	  case GENERIC_RELOC_VANILLA:
1086	    if (reloc_info.r_address >= data_segment_scp->vmaddr
1087		&& reloc_info.r_address < (data_segment_scp->vmaddr
1088					   + data_segment_scp->vmsize))
1089	      {
1090		off_t src_off = data_segment_old_fileoff
1091		  + reloc_info.r_address - data_segment_scp->vmaddr;
1092		off_t dst_off = data_segment_scp->fileoff
1093		  + reloc_info.r_address - data_segment_scp->vmaddr;
1094
1095		if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length))
1096		  unexec_error ("unrelocate: %s:%d cannot copy original value",
1097				name, i);
1098		unreloc_count++;
1099	      }
1100	    break;
1101	  default:
1102	    unexec_error ("unrelocate: %s:%d cannot handle type = %d",
1103			  name, i, reloc_info.r_type);
1104	  }
1105      else
1106	switch (sc_reloc_info->r_type)
1107	  {
1108#if defined (__ppc__)
1109	  case PPC_RELOC_PB_LA_PTR:
1110	    /* nothing to do for prebound lazy pointer */
1111	    break;
1112#endif
1113	  default:
1114	    unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d",
1115			  name, i, sc_reloc_info->r_type);
1116	  }
1117    }
1118
1119  if (nrel > 0)
1120    printf ("Fixed up %d/%d %s relocation entries in data segment.\n",
1121	    unreloc_count, nrel, name);
1122}
1123
1124/* Copy a LC_DYSYMTAB load command from the input file to the output
1125   file, adjusting the file offset fields.  */
1126static void
1127copy_dysymtab (struct load_command *lc, long delta)
1128{
1129  struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
1130
1131  unrelocate ("local", dstp->locreloff, dstp->nlocrel);
1132  unrelocate ("external", dstp->extreloff, dstp->nextrel);
1133
1134  if (dstp->nextrel > 0) {
1135    dstp->extreloff += delta;
1136  }
1137
1138  if (dstp->nlocrel > 0) {
1139    dstp->locreloff += delta;
1140  }
1141
1142  if (dstp->nindirectsyms > 0)
1143    dstp->indirectsymoff += delta;
1144
1145  printf ("Writing ");
1146  print_load_command_name (lc->cmd);
1147  printf (" command\n");
1148
1149  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1150    unexec_error ("cannot write symtab command to header");
1151
1152  curr_header_offset += lc->cmdsize;
1153}
1154
1155/* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
1156   file, adjusting the file offset fields.  */
1157static void
1158copy_twolevelhints (struct load_command *lc, long delta)
1159{
1160  struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
1161
1162  if (tlhp->nhints > 0) {
1163    tlhp->offset += delta;
1164  }
1165
1166  printf ("Writing ");
1167  print_load_command_name (lc->cmd);
1168  printf (" command\n");
1169
1170  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1171    unexec_error ("cannot write two level hint command to header");
1172
1173  curr_header_offset += lc->cmdsize;
1174}
1175
1176/* Copy other kinds of load commands from the input file to the output
1177   file, ones that do not require adjustments of file offsets.  */
1178static void
1179copy_other (struct load_command *lc)
1180{
1181  printf ("Writing ");
1182  print_load_command_name (lc->cmd);
1183  printf (" command\n");
1184
1185  if (lc->cmd == LC_CODE_SIGNATURE)
1186    lc->cmd = 0x0;		/* Don't propagate signature */
1187  if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
1188    unexec_error ("cannot write load command to header");
1189
1190  curr_header_offset += lc->cmdsize;
1191}
1192
1193/* Loop through all load commands and dump them.  Then write the Mach
1194   header.  */
1195static void
1196dump_it ()
1197{
1198  int i;
1199  long linkedit_delta = 0;
1200
1201  printf ("--- Load Commands written to Output File ---\n");
1202
1203  for (i = 0; i < nlc; i++)
1204    switch (lca[i]->cmd)
1205      {
1206      case target_LC_SEGMENT:
1207	{
1208	  struct segment_command *scp = (struct segment_command *) lca[i];
1209	  if (strncmp (scp->segname, SEG_DATA, 16) == 0)
1210	    {
1211	      /* save data segment file offset and segment_command for
1212		 unrelocate */
1213	      if (data_segment_old_fileoff)
1214		unexec_error ("cannot handle multiple DATA segments"
1215			      " in input file");
1216	      data_segment_old_fileoff = scp->fileoff;
1217	      data_segment_scp = scp;
1218
1219	      copy_data_segment (lca[i]);
1220	    }
1221	  else
1222	    {
1223	      if (strncmp (scp->segname, SEG_LINKEDIT, 16) == 0)
1224		{
1225		  if (linkedit_delta)
1226		    unexec_error ("cannot handle multiple LINKEDIT segments"
1227				  " in input file");
1228		  linkedit_delta = curr_file_offset - scp->fileoff;
1229		}
1230
1231	      copy_segment (lca[i]);
1232	    }
1233	}
1234	break;
1235      case LC_SYMTAB:
1236	copy_symtab (lca[i], linkedit_delta);
1237	break;
1238      case LC_DYSYMTAB:
1239	copy_dysymtab (lca[i], linkedit_delta);
1240	break;
1241      case LC_TWOLEVEL_HINTS:
1242	copy_twolevelhints (lca[i], linkedit_delta);
1243	break;
1244      case LC_DYLD_INFO_ONLY:
1245	copy_dyld_info_only(lca[i], linkedit_delta);
1246	break;
1247      case LC_CODE_SIGNATURE:
1248      case LC_SEGMENT_SPLIT_INFO:
1249      case LC_FUNCTION_STARTS:
1250      case LC_DATA_IN_CODE:
1251      case LC_DYLIB_CODE_SIGN_DRS:
1252	copy_linkedit_data(lca[i], linkedit_delta);
1253	break;
1254
1255      default:
1256	copy_other (lca[i]);
1257	break;
1258      }
1259
1260  if (curr_header_offset > text_seg_lowest_offset)
1261    unexec_error ("not enough room for load commands for new __DATA segments");
1262
1263  printf ("%ld unused bytes follow Mach-O header\n",
1264	  text_seg_lowest_offset - curr_header_offset);
1265
1266  mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
1267  if (!unexec_write (0, &mh, sizeof (struct mach_header)))
1268    unexec_error ("cannot write final header contents");
1269}
1270
1271/* Take a snapshot of Emacs and make a Mach-O format executable file
1272   from it.  The file names of the output and input files are outfile
1273   and infile, respectively.  The three other parameters are
1274   ignored.  */
1275void
1276unexec (char *outfile, char *infile, void *start_data, void *start_bss,
1277        void *entry_address)
1278{
1279  if (in_dumped_exec)
1280    unexec_error ("Unexec from a dumped executable is not supported.");
1281
1282  pagesize = getpagesize ();
1283  infd = open (infile, O_RDONLY, 0);
1284  if (infd < 0)
1285    {
1286      unexec_error ("cannot open input file `%s'", infile);
1287    }
1288
1289  outfd = open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0755);
1290  if (outfd < 0)
1291    {
1292      close (infd);
1293      unexec_error ("cannot open output file `%s'", outfile);
1294    }
1295
1296  build_region_list ();
1297  read_load_commands ();
1298
1299  find_emacs_zone_regions ();
1300  unexec_regions_merge ();
1301
1302  in_dumped_exec = 1;
1303
1304  dump_it ();
1305
1306  close (outfd);
1307}
1308
1309
1310void
1311unexec_init_emacs_zone ()
1312{
1313  emacs_zone = malloc_create_zone (0, 0);
1314  malloc_set_zone_name (emacs_zone, "EmacsZone");
1315}
1316
1317#ifndef MACOSX_MALLOC_MULT16
1318#define MACOSX_MALLOC_MULT16 1
1319#endif
1320
1321typedef struct unexec_malloc_header {
1322  union {
1323    char c[8];
1324    size_t size;
1325  } u;
1326} unexec_malloc_header_t;
1327
1328#if MACOSX_MALLOC_MULT16
1329
1330#define ptr_in_unexec_regions(p) ((((vm_address_t) (p)) & 8) != 0)
1331
1332#else
1333
1334int
1335ptr_in_unexec_regions (void *ptr)
1336{
1337  int i;
1338
1339  for (i = 0; i < num_unexec_regions; i++)
1340    if ((vm_address_t) ptr - unexec_regions[i].range.address
1341	< unexec_regions[i].range.size)
1342      return 1;
1343
1344  return 0;
1345}
1346
1347#endif
1348
1349void *
1350unexec_malloc (size_t size)
1351{
1352  if (in_dumped_exec)
1353    {
1354      void *p;
1355
1356      p = malloc (size);
1357#if MACOSX_MALLOC_MULT16
1358      assert (((vm_address_t) p % 16) == 0);
1359#endif
1360      return p;
1361    }
1362  else
1363    {
1364      unexec_malloc_header_t *ptr;
1365
1366      ptr = (unexec_malloc_header_t *)
1367	malloc_zone_malloc (emacs_zone, size + sizeof (unexec_malloc_header_t));
1368      ptr->u.size = size;
1369      ptr++;
1370#if MACOSX_MALLOC_MULT16
1371      assert (((vm_address_t) ptr % 16) == 8);
1372#endif
1373      return (void *) ptr;
1374    }
1375}
1376
1377void *
1378unexec_realloc (void *old_ptr, size_t new_size)
1379{
1380  if (in_dumped_exec)
1381    {
1382      void *p;
1383
1384      if (ptr_in_unexec_regions (old_ptr))
1385	{
1386	  size_t old_size = ((unexec_malloc_header_t *) old_ptr)[-1].u.size;
1387	  size_t size = new_size > old_size ? old_size : new_size;
1388
1389	  p = (size_t *) malloc (new_size);
1390	  if (size)
1391	    memcpy (p, old_ptr, size);
1392	}
1393      else
1394	{
1395	  p = realloc (old_ptr, new_size);
1396	}
1397#if MACOSX_MALLOC_MULT16
1398      assert (((vm_address_t) p % 16) == 0);
1399#endif
1400      return p;
1401    }
1402  else
1403    {
1404      unexec_malloc_header_t *ptr;
1405
1406      ptr = (unexec_malloc_header_t *)
1407	malloc_zone_realloc (emacs_zone, (unexec_malloc_header_t *) old_ptr - 1,
1408			     new_size + sizeof (unexec_malloc_header_t));
1409      ptr->u.size = new_size;
1410      ptr++;
1411#if MACOSX_MALLOC_MULT16
1412      assert (((vm_address_t) ptr % 16) == 8);
1413#endif
1414      return (void *) ptr;
1415    }
1416}
1417
1418void
1419unexec_free (void *ptr)
1420{
1421  if (in_dumped_exec)
1422    {
1423      if (!ptr_in_unexec_regions (ptr))
1424	free (ptr);
1425    }
1426  else
1427    malloc_zone_free (emacs_zone, (unexec_malloc_header_t *) ptr - 1);
1428}
1429
1430/* arch-tag: 1a784f7b-a184-4c4f-9544-da8619593d72
1431   (do not change this comment) */
1432