Merged from miles@gnu.org--gnu-2005 (patch 296-306)
[bpt/emacs.git] / src / unexmacosx.c
1 /* Dump Emacs in Mach-O format for use on Mac OS X.
2 Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Contributed by Andrew Choi (akochoi@mac.com). */
22
23 /* Documentation note.
24
25 Consult the following documents/files for a description of the
26 Mach-O format: the file loader.h, man pages for Mach-O and ld, old
27 NEXTSTEP documents of the Mach-O format. The tool otool dumps the
28 mach header (-h option) and the load commands (-l option) in a
29 Mach-O file. The tool nm on Mac OS X displays the symbol table in
30 a Mach-O file. For examples of unexec for the Mach-O format, see
31 the file unexnext.c in the GNU Emacs distribution, the file
32 unexdyld.c in the Darwin port of GNU Emacs 20.7, and unexdyld.c in
33 the Darwin port of XEmacs 21.1. Also the Darwin Libc source
34 contains the source code for malloc_freezedry and malloc_jumpstart.
35 Read that to see what they do. This file was written completely
36 from scratch, making use of information from the above sources. */
37
38 /* The Mac OS X implementation of unexec makes use of Darwin's `zone'
39 memory allocator. All calls to malloc, realloc, and free in Emacs
40 are redirected to unexec_malloc, unexec_realloc, and unexec_free in
41 this file. When temacs is run, all memory requests are handled in
42 the zone EmacsZone. The Darwin memory allocator library calls
43 maintain the data structures to manage this zone. Dumping writes
44 its contents to data segments of the executable file. When emacs
45 is run, the loader recreates the contents of the zone in memory.
46 However since the initialization routine of the zone memory
47 allocator is run again, this `zone' can no longer be used as a
48 heap. That is why emacs uses the ordinary malloc system call to
49 allocate memory. Also, when a block of memory needs to be
50 reallocated and the new size is larger than the old one, a new
51 block must be obtained by malloc and the old contents copied to
52 it. */
53
54 /* Peculiarity of the Mach-O files generated by ld in Mac OS X
55 (possible causes of future bugs if changed).
56
57 The file offset of the start of the __TEXT segment is zero. Since
58 the Mach header and load commands are located at the beginning of a
59 Mach-O file, copying the contents of the __TEXT segment from the
60 input file overwrites them in the output file. Despite this,
61 unexec works fine as written below because the segment load command
62 for __TEXT appears, and is therefore processed, before all other
63 load commands except the segment load command for __PAGEZERO, which
64 remains unchanged.
65
66 Although the file offset of the start of the __TEXT segment is
67 zero, none of the sections it contains actually start there. In
68 fact, the earliest one starts a few hundred bytes beyond the end of
69 the last load command. The linker option -headerpad controls the
70 minimum size of this padding. Its setting can be changed in
71 s/darwin.h. A value of 0x300, e.g., leaves room for about 15
72 additional load commands for the newly created __DATA segments (at
73 56 bytes each). Unexec fails if there is not enough room for these
74 new segments.
75
76 The __TEXT segment contains the sections __text, __cstring,
77 __picsymbol_stub, and __const and the __DATA segment contains the
78 sections __data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __bss,
79 and __common. The other segments do not contain any sections.
80 These sections are copied from the input file to the output file,
81 except for __data, __bss, and __common, which are dumped from
82 memory. The types of the sections __bss and __common are changed
83 from S_ZEROFILL to S_REGULAR. Note that the number of sections and
84 their relative order in the input and output files remain
85 unchanged. Otherwise all n_sect fields in the nlist records in the
86 symbol table (specified by the LC_SYMTAB load command) will have to
87 be changed accordingly.
88 */
89
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <fcntl.h>
93 #include <stdarg.h>
94 #include <sys/types.h>
95 #include <unistd.h>
96 #include <mach/mach.h>
97 #include <mach-o/loader.h>
98 #include <mach-o/reloc.h>
99 #if defined (__ppc__)
100 #include <mach-o/ppc/reloc.h>
101 #endif
102 #if defined (HAVE_MALLOC_MALLOC_H)
103 #include <malloc/malloc.h>
104 #else
105 #include <objc/malloc.h>
106 #endif
107
108 #include <assert.h>
109
110
111 #define VERBOSE 1
112
113 /* Size of buffer used to copy data from the input file to the output
114 file in function unexec_copy. */
115 #define UNEXEC_COPY_BUFSZ 1024
116
117 /* Regions with memory addresses above this value are assumed to be
118 mapped to dynamically loaded libraries and will not be dumped. */
119 #define VM_DATA_TOP (20 * 1024 * 1024)
120
121 /* Used by malloc_freezedry and malloc_jumpstart. */
122 int malloc_cookie;
123
124 /* Type of an element on the list of regions to be dumped. */
125 struct region_t {
126 vm_address_t address;
127 vm_size_t size;
128 vm_prot_t protection;
129 vm_prot_t max_protection;
130
131 struct region_t *next;
132 };
133
134 /* Head and tail of the list of regions to be dumped. */
135 struct region_t *region_list_head = 0;
136 struct region_t *region_list_tail = 0;
137
138 /* Pointer to array of load commands. */
139 struct load_command **lca;
140
141 /* Number of load commands. */
142 int nlc;
143
144 /* The highest VM address of segments loaded by the input file.
145 Regions with addresses beyond this are assumed to be allocated
146 dynamically and thus require dumping. */
147 vm_address_t infile_lc_highest_addr = 0;
148
149 /* The lowest file offset used by the all sections in the __TEXT
150 segments. This leaves room at the beginning of the file to store
151 the Mach-O header. Check this value against header size to ensure
152 the added load commands for the new __DATA segments did not
153 overwrite any of the sections in the __TEXT segment. */
154 unsigned long text_seg_lowest_offset = 0x10000000;
155
156 /* Mach header. */
157 struct mach_header mh;
158
159 /* Offset at which the next load command should be written. */
160 unsigned long curr_header_offset = sizeof (struct mach_header);
161
162 /* Current adjustment that needs to be made to offset values because
163 of additional data segments. */
164 unsigned long delta = 0;
165
166 int infd, outfd;
167
168 int in_dumped_exec = 0;
169
170 malloc_zone_t *emacs_zone;
171
172 /* file offset of input file's data segment */
173 off_t data_segment_old_fileoff;
174
175 struct segment_command *data_segment_scp;
176
177 /* Read n bytes from infd into memory starting at address dest.
178 Return true if successful, false otherwise. */
179 static int
180 unexec_read (void *dest, size_t n)
181 {
182 return n == read (infd, dest, n);
183 }
184
185 /* Write n bytes from memory starting at address src to outfd starting
186 at offset dest. Return true if successful, false otherwise. */
187 static int
188 unexec_write (off_t dest, const void *src, size_t count)
189 {
190 if (lseek (outfd, dest, SEEK_SET) != dest)
191 return 0;
192
193 return write (outfd, src, count) == count;
194 }
195
196 /* Copy n bytes from starting offset src in infd to starting offset
197 dest in outfd. Return true if successful, false otherwise. */
198 static int
199 unexec_copy (off_t dest, off_t src, ssize_t count)
200 {
201 ssize_t bytes_read;
202 ssize_t bytes_to_read;
203
204 char buf[UNEXEC_COPY_BUFSZ];
205
206 if (lseek (infd, src, SEEK_SET) != src)
207 return 0;
208
209 if (lseek (outfd, dest, SEEK_SET) != dest)
210 return 0;
211
212 while (count > 0)
213 {
214 bytes_to_read = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count;
215 bytes_read = read (infd, buf, bytes_to_read);
216 if (bytes_read <= 0)
217 return 0;
218 if (write (outfd, buf, bytes_read) != bytes_read)
219 return 0;
220 count -= bytes_read;
221 }
222
223 return 1;
224 }
225
226 /* Debugging and informational messages routines. */
227
228 static void
229 unexec_error (char *format, ...)
230 {
231 va_list ap;
232
233 va_start (ap, format);
234 fprintf (stderr, "unexec: ");
235 vfprintf (stderr, format, ap);
236 fprintf (stderr, "\n");
237 va_end (ap);
238 exit (1);
239 }
240
241 static void
242 print_prot (vm_prot_t prot)
243 {
244 if (prot == VM_PROT_NONE)
245 printf ("none");
246 else
247 {
248 putchar (prot & VM_PROT_READ ? 'r' : ' ');
249 putchar (prot & VM_PROT_WRITE ? 'w' : ' ');
250 putchar (prot & VM_PROT_EXECUTE ? 'x' : ' ');
251 putchar (' ');
252 }
253 }
254
255 static void
256 print_region (vm_address_t address, vm_size_t size, vm_prot_t prot,
257 vm_prot_t max_prot)
258 {
259 printf ("%#10x %#8x ", address, size);
260 print_prot (prot);
261 putchar (' ');
262 print_prot (max_prot);
263 putchar ('\n');
264 }
265
266 static void
267 print_region_list ()
268 {
269 struct region_t *r;
270
271 printf (" address size prot maxp\n");
272
273 for (r = region_list_head; r; r = r->next)
274 print_region (r->address, r->size, r->protection, r->max_protection);
275 }
276
277 void
278 print_regions ()
279 {
280 task_t target_task = mach_task_self ();
281 vm_address_t address = (vm_address_t) 0;
282 vm_size_t size;
283 struct vm_region_basic_info info;
284 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
285 mach_port_t object_name;
286
287 printf (" address size prot maxp\n");
288
289 while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
290 (vm_region_info_t) &info, &info_count, &object_name)
291 == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
292 {
293 print_region (address, size, info.protection, info.max_protection);
294
295 if (object_name != MACH_PORT_NULL)
296 mach_port_deallocate (target_task, object_name);
297
298 address += size;
299 }
300 }
301
302 /* Build the list of regions that need to be dumped. Regions with
303 addresses above VM_DATA_TOP are omitted. Adjacent regions with
304 identical protection are merged. Note that non-writable regions
305 cannot be omitted because they some regions created at run time are
306 read-only. */
307 static void
308 build_region_list ()
309 {
310 task_t target_task = mach_task_self ();
311 vm_address_t address = (vm_address_t) 0;
312 vm_size_t size;
313 struct vm_region_basic_info info;
314 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
315 mach_port_t object_name;
316 struct region_t *r;
317
318 #if VERBOSE
319 printf ("--- List of All Regions ---\n");
320 printf (" address size prot maxp\n");
321 #endif
322
323 while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
324 (vm_region_info_t) &info, &info_count, &object_name)
325 == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
326 {
327 /* Done when we reach addresses of shared libraries, which are
328 loaded in high memory. */
329 if (address >= VM_DATA_TOP)
330 break;
331
332 #if VERBOSE
333 print_region (address, size, info.protection, info.max_protection);
334 #endif
335
336 /* If a region immediately follows the previous one (the one
337 most recently added to the list) and has identical
338 protection, merge it with the latter. Otherwise create a
339 new list element for it. */
340 if (region_list_tail
341 && info.protection == region_list_tail->protection
342 && info.max_protection == region_list_tail->max_protection
343 && region_list_tail->address + region_list_tail->size == address)
344 {
345 region_list_tail->size += size;
346 }
347 else
348 {
349 r = (struct region_t *) malloc (sizeof (struct region_t));
350
351 if (!r)
352 unexec_error ("cannot allocate region structure");
353
354 r->address = address;
355 r->size = size;
356 r->protection = info.protection;
357 r->max_protection = info.max_protection;
358
359 r->next = 0;
360 if (region_list_head == 0)
361 {
362 region_list_head = r;
363 region_list_tail = r;
364 }
365 else
366 {
367 region_list_tail->next = r;
368 region_list_tail = r;
369 }
370
371 /* Deallocate (unused) object name returned by
372 vm_region. */
373 if (object_name != MACH_PORT_NULL)
374 mach_port_deallocate (target_task, object_name);
375 }
376
377 address += size;
378 }
379
380 printf ("--- List of Regions to be Dumped ---\n");
381 print_region_list ();
382 }
383
384
385 #define MAX_UNEXEC_REGIONS 200
386
387 int num_unexec_regions;
388 vm_range_t unexec_regions[MAX_UNEXEC_REGIONS];
389
390 static void
391 unexec_regions_recorder (task_t task, void *rr, unsigned type,
392 vm_range_t *ranges, unsigned num)
393 {
394 while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
395 {
396 unexec_regions[num_unexec_regions++] = *ranges;
397 printf ("%#8x (sz: %#8x)\n", ranges->address, ranges->size);
398 ranges++; num--;
399 }
400 if (num_unexec_regions == MAX_UNEXEC_REGIONS)
401 fprintf (stderr, "malloc_freezedry_recorder: too many regions\n");
402 }
403
404 static kern_return_t
405 unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr)
406 {
407 *ptr = (void *) address;
408 return KERN_SUCCESS;
409 }
410
411 void
412 find_emacs_zone_regions ()
413 {
414 num_unexec_regions = 0;
415
416 emacs_zone->introspect->enumerator (mach_task_self(), 0,
417 MALLOC_PTR_REGION_RANGE_TYPE
418 | MALLOC_ADMIN_REGION_RANGE_TYPE,
419 (vm_address_t) emacs_zone,
420 unexec_reader,
421 unexec_regions_recorder);
422 }
423
424 static int
425 unexec_regions_sort_compare (const void *a, const void *b)
426 {
427 vm_address_t aa = ((vm_range_t *) a)->address;
428 vm_address_t bb = ((vm_range_t *) b)->address;
429
430 if (aa < bb)
431 return -1;
432 else if (aa > bb)
433 return 1;
434 else
435 return 0;
436 }
437
438 static void
439 unexec_regions_merge ()
440 {
441 int i, n;
442 vm_range_t r;
443
444 qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]),
445 &unexec_regions_sort_compare);
446 n = 0;
447 r = unexec_regions[0];
448 for (i = 1; i < num_unexec_regions; i++)
449 {
450 if (r.address + r.size == unexec_regions[i].address)
451 {
452 r.size += unexec_regions[i].size;
453 }
454 else
455 {
456 unexec_regions[n++] = r;
457 r = unexec_regions[i];
458 }
459 }
460 unexec_regions[n++] = r;
461 num_unexec_regions = n;
462 }
463
464
465 /* More informational messages routines. */
466
467 static void
468 print_load_command_name (int lc)
469 {
470 switch (lc)
471 {
472 case LC_SEGMENT:
473 printf ("LC_SEGMENT ");
474 break;
475 case LC_LOAD_DYLINKER:
476 printf ("LC_LOAD_DYLINKER ");
477 break;
478 case LC_LOAD_DYLIB:
479 printf ("LC_LOAD_DYLIB ");
480 break;
481 case LC_SYMTAB:
482 printf ("LC_SYMTAB ");
483 break;
484 case LC_DYSYMTAB:
485 printf ("LC_DYSYMTAB ");
486 break;
487 case LC_UNIXTHREAD:
488 printf ("LC_UNIXTHREAD ");
489 break;
490 case LC_PREBOUND_DYLIB:
491 printf ("LC_PREBOUND_DYLIB");
492 break;
493 case LC_TWOLEVEL_HINTS:
494 printf ("LC_TWOLEVEL_HINTS");
495 break;
496 default:
497 printf ("unknown ");
498 }
499 }
500
501 static void
502 print_load_command (struct load_command *lc)
503 {
504 print_load_command_name (lc->cmd);
505 printf ("%8d", lc->cmdsize);
506
507 if (lc->cmd == LC_SEGMENT)
508 {
509 struct segment_command *scp;
510 struct section *sectp;
511 int j;
512
513 scp = (struct segment_command *) lc;
514 printf (" %-16.16s %#10x %#8x\n",
515 scp->segname, scp->vmaddr, scp->vmsize);
516
517 sectp = (struct section *) (scp + 1);
518 for (j = 0; j < scp->nsects; j++)
519 {
520 printf (" %-16.16s %#10x %#8x\n",
521 sectp->sectname, sectp->addr, sectp->size);
522 sectp++;
523 }
524 }
525 else
526 printf ("\n");
527 }
528
529 /* Read header and load commands from input file. Store the latter in
530 the global array lca. Store the total number of load commands in
531 global variable nlc. */
532 static void
533 read_load_commands ()
534 {
535 int n, i, j;
536
537 if (!unexec_read (&mh, sizeof (struct mach_header)))
538 unexec_error ("cannot read mach-o header");
539
540 if (mh.magic != MH_MAGIC)
541 unexec_error ("input file not in Mach-O format");
542
543 if (mh.filetype != MH_EXECUTE)
544 unexec_error ("input Mach-O file is not an executable object file");
545
546 #if VERBOSE
547 printf ("--- Header Information ---\n");
548 printf ("Magic = 0x%08x\n", mh.magic);
549 printf ("CPUType = %d\n", mh.cputype);
550 printf ("CPUSubType = %d\n", mh.cpusubtype);
551 printf ("FileType = 0x%x\n", mh.filetype);
552 printf ("NCmds = %d\n", mh.ncmds);
553 printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
554 printf ("Flags = 0x%08x\n", mh.flags);
555 #endif
556
557 nlc = mh.ncmds;
558 lca = (struct load_command **) malloc (nlc * sizeof (struct load_command *));
559
560 for (i = 0; i < nlc; i++)
561 {
562 struct load_command lc;
563 /* Load commands are variable-size: so read the command type and
564 size first and then read the rest. */
565 if (!unexec_read (&lc, sizeof (struct load_command)))
566 unexec_error ("cannot read load command");
567 lca[i] = (struct load_command *) malloc (lc.cmdsize);
568 memcpy (lca[i], &lc, sizeof (struct load_command));
569 if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
570 unexec_error ("cannot read content of load command");
571 if (lc.cmd == LC_SEGMENT)
572 {
573 struct segment_command *scp = (struct segment_command *) lca[i];
574
575 if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
576 infile_lc_highest_addr = scp->vmaddr + scp->vmsize;
577
578 if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
579 {
580 struct section *sectp = (struct section *) (scp + 1);
581 int j;
582
583 for (j = 0; j < scp->nsects; j++)
584 if (sectp->offset < text_seg_lowest_offset)
585 text_seg_lowest_offset = sectp->offset;
586 }
587 }
588 }
589
590 printf ("Highest address of load commands in input file: %#8x\n",
591 infile_lc_highest_addr);
592
593 printf ("Lowest offset of all sections in __TEXT segment: %#8x\n",
594 text_seg_lowest_offset);
595
596 printf ("--- List of Load Commands in Input File ---\n");
597 printf ("# cmd cmdsize name address size\n");
598
599 for (i = 0; i < nlc; i++)
600 {
601 printf ("%1d ", i);
602 print_load_command (lca[i]);
603 }
604 }
605
606 /* Copy a LC_SEGMENT load command other than the __DATA segment from
607 the input file to the output file, adjusting the file offset of the
608 segment and the file offsets of sections contained in it. */
609 static void
610 copy_segment (struct load_command *lc)
611 {
612 struct segment_command *scp = (struct segment_command *) lc;
613 unsigned long old_fileoff = scp->fileoff;
614 struct section *sectp;
615 int j;
616
617 scp->fileoff += delta;
618
619 sectp = (struct section *) (scp + 1);
620 for (j = 0; j < scp->nsects; j++)
621 {
622 sectp->offset += delta;
623 sectp++;
624 }
625
626 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
627 scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
628 scp->filesize);
629
630 if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
631 unexec_error ("cannot copy segment from input to output file");
632 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
633 unexec_error ("cannot write load command to header");
634
635 curr_header_offset += lc->cmdsize;
636 }
637
638 /* Copy a LC_SEGMENT load command for the __DATA segment in the input
639 file to the output file. We assume that only one such segment load
640 command exists in the input file and it contains the sections
641 __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and
642 __dyld. The first three of these should be dumped from memory and
643 the rest should be copied from the input file. Note that the
644 sections __bss and __common contain no data in the input file
645 because their flag fields have the value S_ZEROFILL. Dumping these
646 from memory makes it necessary to adjust file offset fields in
647 subsequently dumped load commands. Then, create new __DATA segment
648 load commands for regions on the region list other than the one
649 corresponding to the __DATA segment in the input file. */
650 static void
651 copy_data_segment (struct load_command *lc)
652 {
653 struct segment_command *scp = (struct segment_command *) lc;
654 struct section *sectp;
655 int j;
656 unsigned long header_offset, file_offset, old_file_offset;
657 struct region_t *r;
658
659 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
660 scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
661 scp->filesize);
662
663 if (delta != 0)
664 unexec_error ("cannot handle multiple DATA segments in input file");
665
666 /* Offsets in the output file for writing the next section structure
667 and segment data block, respectively. */
668 header_offset = curr_header_offset + sizeof (struct segment_command);
669
670 sectp = (struct section *) (scp + 1);
671 for (j = 0; j < scp->nsects; j++)
672 {
673 old_file_offset = sectp->offset;
674 sectp->offset = sectp->addr - scp->vmaddr + scp->fileoff;
675 /* The __data section is dumped from memory. The __bss and
676 __common sections are also dumped from memory but their flag
677 fields require changing (from S_ZEROFILL to S_REGULAR). The
678 other three kinds of sections are just copied from the input
679 file. */
680 if (strncmp (sectp->sectname, SECT_DATA, 16) == 0)
681 {
682 if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
683 unexec_error ("cannot write section %s", SECT_DATA);
684 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
685 unexec_error ("cannot write section %s's header", SECT_DATA);
686 }
687 else if (strncmp (sectp->sectname, SECT_BSS, 16) == 0
688 || strncmp (sectp->sectname, SECT_COMMON, 16) == 0)
689 {
690 sectp->flags = S_REGULAR;
691 if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
692 unexec_error ("cannot write section %s", SECT_DATA);
693 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
694 unexec_error ("cannot write section %s's header", SECT_DATA);
695 }
696 else if (strncmp (sectp->sectname, "__la_symbol_ptr", 16) == 0
697 || strncmp (sectp->sectname, "__nl_symbol_ptr", 16) == 0
698 || strncmp (sectp->sectname, "__dyld", 16) == 0
699 || strncmp (sectp->sectname, "__const", 16) == 0
700 || strncmp (sectp->sectname, "__cfstring", 16) == 0)
701 {
702 if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
703 unexec_error ("cannot copy section %s", sectp->sectname);
704 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
705 unexec_error ("cannot write section %s's header", sectp->sectname);
706 }
707 else
708 unexec_error ("unrecognized section name in __DATA segment");
709
710 printf (" section %-16.16s at %#8x - %#8x (sz: %#8x)\n",
711 sectp->sectname, sectp->offset, sectp->offset + sectp->size,
712 sectp->size);
713
714 header_offset += sizeof (struct section);
715 sectp++;
716 }
717
718 /* The new filesize of the segment is set to its vmsize because data
719 blocks for segments must start at region boundaries. Note that
720 this may leave unused locations at the end of the segment data
721 block because the total of the sizes of all sections in the
722 segment is generally smaller than vmsize. */
723 delta = scp->vmsize - scp->filesize;
724 scp->filesize = scp->vmsize;
725 if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
726 unexec_error ("cannot write header of __DATA segment");
727 curr_header_offset += lc->cmdsize;
728
729 /* Create new __DATA segment load commands for regions on the region
730 list that do not corresponding to any segment load commands in
731 the input file.
732 */
733 file_offset = scp->fileoff + scp->filesize;
734 for (j = 0; j < num_unexec_regions; j++)
735 {
736 struct segment_command sc;
737
738 sc.cmd = LC_SEGMENT;
739 sc.cmdsize = sizeof (struct segment_command);
740 strncpy (sc.segname, SEG_DATA, 16);
741 sc.vmaddr = unexec_regions[j].address;
742 sc.vmsize = unexec_regions[j].size;
743 sc.fileoff = file_offset;
744 sc.filesize = unexec_regions[j].size;
745 sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
746 sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
747 sc.nsects = 0;
748 sc.flags = 0;
749
750 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
751 sc.segname, sc.fileoff, sc.fileoff + sc.filesize,
752 sc.filesize);
753
754 if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize))
755 unexec_error ("cannot write new __DATA segment");
756 delta += sc.filesize;
757 file_offset += sc.filesize;
758
759 if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
760 unexec_error ("cannot write new __DATA segment's header");
761 curr_header_offset += sc.cmdsize;
762 mh.ncmds++;
763 }
764 }
765
766 /* Copy a LC_SYMTAB load command from the input file to the output
767 file, adjusting the file offset fields. */
768 static void
769 copy_symtab (struct load_command *lc)
770 {
771 struct symtab_command *stp = (struct symtab_command *) lc;
772
773 stp->symoff += delta;
774 stp->stroff += delta;
775
776 printf ("Writing LC_SYMTAB command\n");
777
778 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
779 unexec_error ("cannot write symtab command to header");
780
781 curr_header_offset += lc->cmdsize;
782 }
783
784 /* Fix up relocation entries. */
785 static void
786 unrelocate (const char *name, off_t reloff, int nrel)
787 {
788 int i, unreloc_count;
789 struct relocation_info reloc_info;
790 struct scattered_relocation_info *sc_reloc_info
791 = (struct scattered_relocation_info *) &reloc_info;
792
793 for (unreloc_count = 0, i = 0; i < nrel; i++)
794 {
795 if (lseek (infd, reloff, L_SET) != reloff)
796 unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i);
797 if (!unexec_read (&reloc_info, sizeof (reloc_info)))
798 unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i);
799 reloff += sizeof (reloc_info);
800
801 if (sc_reloc_info->r_scattered == 0)
802 switch (reloc_info.r_type)
803 {
804 case GENERIC_RELOC_VANILLA:
805 if (reloc_info.r_address >= data_segment_scp->vmaddr
806 && reloc_info.r_address < (data_segment_scp->vmaddr
807 + data_segment_scp->vmsize))
808 {
809 off_t src_off = data_segment_old_fileoff
810 + reloc_info.r_address - data_segment_scp->vmaddr;
811 off_t dst_off = data_segment_scp->fileoff
812 + reloc_info.r_address - data_segment_scp->vmaddr;
813
814 if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length))
815 unexec_error ("unrelocate: %s:%d cannot copy original value",
816 name, i);
817 unreloc_count++;
818 }
819 break;
820 default:
821 unexec_error ("unrelocate: %s:%d cannot handle type = %d",
822 name, i, reloc_info.r_type);
823 }
824 else
825 switch (sc_reloc_info->r_type)
826 {
827 #if defined (__ppc__)
828 case PPC_RELOC_PB_LA_PTR:
829 /* nothing to do for prebound lazy pointer */
830 break;
831 #endif
832 default:
833 unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d",
834 name, i, sc_reloc_info->r_type);
835 }
836 }
837
838 if (nrel > 0)
839 printf ("Fixed up %d/%d %s relocation entries in data segment.\n",
840 unreloc_count, nrel, name);
841 }
842
843 /* Copy a LC_DYSYMTAB load command from the input file to the output
844 file, adjusting the file offset fields. */
845 static void
846 copy_dysymtab (struct load_command *lc)
847 {
848 struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
849
850 unrelocate ("local", dstp->locreloff, dstp->nlocrel);
851 unrelocate ("external", dstp->extreloff, dstp->nextrel);
852
853 if (dstp->nextrel > 0) {
854 dstp->extreloff += delta;
855 }
856
857 if (dstp->nlocrel > 0) {
858 dstp->locreloff += delta;
859 }
860
861 if (dstp->nindirectsyms > 0)
862 dstp->indirectsymoff += delta;
863
864 printf ("Writing LC_DYSYMTAB command\n");
865
866 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
867 unexec_error ("cannot write symtab command to header");
868
869 curr_header_offset += lc->cmdsize;
870 }
871
872 /* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
873 file, adjusting the file offset fields. */
874 static void
875 copy_twolevelhints (struct load_command *lc)
876 {
877 struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
878
879 if (tlhp->nhints > 0) {
880 tlhp->offset += delta;
881 }
882
883 printf ("Writing LC_TWOLEVEL_HINTS command\n");
884
885 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
886 unexec_error ("cannot write two level hint command to header");
887
888 curr_header_offset += lc->cmdsize;
889 }
890
891 /* Copy other kinds of load commands from the input file to the output
892 file, ones that do not require adjustments of file offsets. */
893 static void
894 copy_other (struct load_command *lc)
895 {
896 printf ("Writing ");
897 print_load_command_name (lc->cmd);
898 printf (" command\n");
899
900 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
901 unexec_error ("cannot write symtab command to header");
902
903 curr_header_offset += lc->cmdsize;
904 }
905
906 /* Loop through all load commands and dump them. Then write the Mach
907 header. */
908 static void
909 dump_it ()
910 {
911 int i;
912
913 printf ("--- Load Commands written to Output File ---\n");
914
915 for (i = 0; i < nlc; i++)
916 switch (lca[i]->cmd)
917 {
918 case LC_SEGMENT:
919 {
920 struct segment_command *scp = (struct segment_command *) lca[i];
921 if (strncmp (scp->segname, SEG_DATA, 16) == 0)
922 {
923 /* save data segment file offset and segment_command for
924 unrelocate */
925 data_segment_old_fileoff = scp->fileoff;
926 data_segment_scp = scp;
927
928 copy_data_segment (lca[i]);
929 }
930 else
931 {
932 copy_segment (lca[i]);
933 }
934 }
935 break;
936 case LC_SYMTAB:
937 copy_symtab (lca[i]);
938 break;
939 case LC_DYSYMTAB:
940 copy_dysymtab (lca[i]);
941 break;
942 case LC_TWOLEVEL_HINTS:
943 copy_twolevelhints (lca[i]);
944 break;
945 default:
946 copy_other (lca[i]);
947 break;
948 }
949
950 if (curr_header_offset > text_seg_lowest_offset)
951 unexec_error ("not enough room for load commands for new __DATA segments");
952
953 printf ("%d unused bytes follow Mach-O header\n",
954 text_seg_lowest_offset - curr_header_offset);
955
956 mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
957 if (!unexec_write (0, &mh, sizeof (struct mach_header)))
958 unexec_error ("cannot write final header contents");
959 }
960
961 /* Take a snapshot of Emacs and make a Mach-O format executable file
962 from it. The file names of the output and input files are outfile
963 and infile, respectively. The three other parameters are
964 ignored. */
965 void
966 unexec (char *outfile, char *infile, void *start_data, void *start_bss,
967 void *entry_address)
968 {
969 infd = open (infile, O_RDONLY, 0);
970 if (infd < 0)
971 {
972 unexec_error ("cannot open input file `%s'", infile);
973 }
974
975 outfd = open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0755);
976 if (outfd < 0)
977 {
978 close (infd);
979 unexec_error ("cannot open output file `%s'", outfile);
980 }
981
982 build_region_list ();
983 read_load_commands ();
984
985 find_emacs_zone_regions ();
986 unexec_regions_merge ();
987
988 in_dumped_exec = 1;
989
990 dump_it ();
991
992 close (outfd);
993 }
994
995
996 void
997 unexec_init_emacs_zone ()
998 {
999 emacs_zone = malloc_create_zone (0, 0);
1000 malloc_set_zone_name (emacs_zone, "EmacsZone");
1001 }
1002
1003 #ifndef MACOSX_MALLOC_MULT16
1004 #define MACOSX_MALLOC_MULT16 1
1005 #endif
1006
1007 typedef struct unexec_malloc_header {
1008 union {
1009 char c[8];
1010 size_t size;
1011 } u;
1012 } unexec_malloc_header_t;
1013
1014 #if MACOSX_MALLOC_MULT16
1015
1016 #define ptr_in_unexec_regions(p) ((((vm_address_t) (p)) & 8) != 0)
1017
1018 #else
1019
1020 int
1021 ptr_in_unexec_regions (void *ptr)
1022 {
1023 int i;
1024
1025 for (i = 0; i < num_unexec_regions; i++)
1026 if ((vm_address_t) ptr - unexec_regions[i].address
1027 < unexec_regions[i].size)
1028 return 1;
1029
1030 return 0;
1031 }
1032
1033 #endif
1034
1035 void *
1036 unexec_malloc (size_t size)
1037 {
1038 if (in_dumped_exec)
1039 {
1040 void *p;
1041
1042 p = malloc (size);
1043 #if MACOSX_MALLOC_MULT16
1044 assert (((vm_address_t) p % 16) == 0);
1045 #endif
1046 return p;
1047 }
1048 else
1049 {
1050 unexec_malloc_header_t *ptr;
1051
1052 ptr = (unexec_malloc_header_t *)
1053 malloc_zone_malloc (emacs_zone, size + sizeof (unexec_malloc_header_t));
1054 ptr->u.size = size;
1055 ptr++;
1056 #if MACOSX_MALLOC_MULT16
1057 assert (((vm_address_t) ptr % 16) == 8);
1058 #endif
1059 return (void *) ptr;
1060 }
1061 }
1062
1063 void *
1064 unexec_realloc (void *old_ptr, size_t new_size)
1065 {
1066 if (in_dumped_exec)
1067 {
1068 void *p;
1069
1070 if (ptr_in_unexec_regions (old_ptr))
1071 {
1072 p = (size_t *) malloc (new_size);
1073 size_t old_size = ((unexec_malloc_header_t *) old_ptr)[-1].u.size;
1074 size_t size = new_size > old_size ? old_size : new_size;
1075
1076 if (size)
1077 memcpy (p, old_ptr, size);
1078 }
1079 else
1080 {
1081 p = realloc (old_ptr, new_size);
1082 }
1083 #if MACOSX_MALLOC_MULT16
1084 assert (((vm_address_t) p % 16) == 0);
1085 #endif
1086 return p;
1087 }
1088 else
1089 {
1090 unexec_malloc_header_t *ptr;
1091
1092 ptr = (unexec_malloc_header_t *)
1093 malloc_zone_realloc (emacs_zone, (unexec_malloc_header_t *) old_ptr - 1,
1094 new_size + sizeof (unexec_malloc_header_t));
1095 ptr->u.size = new_size;
1096 ptr++;
1097 #if MACOSX_MALLOC_MULT16
1098 assert (((vm_address_t) ptr % 16) == 8);
1099 #endif
1100 return (void *) ptr;
1101 }
1102 }
1103
1104 void
1105 unexec_free (void *ptr)
1106 {
1107 if (in_dumped_exec)
1108 {
1109 if (!ptr_in_unexec_regions (ptr))
1110 free (ptr);
1111 }
1112 else
1113 malloc_zone_free (emacs_zone, (unexec_malloc_header_t *) ptr - 1);
1114 }
1115
1116 /* arch-tag: 1a784f7b-a184-4c4f-9544-da8619593d72
1117 (do not change this comment) */