]> code.delx.au - gnu-emacs/blob - src/unexmacosx.c
*** empty log message ***
[gnu-emacs] / src / unexmacosx.c
1 /* Dump Emacs in Mach-O format for use on Mac OS X.
2 Copyright (C) 2001, 2002, 2003, 2004, 2005 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., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, 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 COUNT bytes from memory starting at address SRC to outfd
186 starting at offset DEST. Return true if successful, false
187 otherwise. */
188 static int
189 unexec_write (off_t dest, const void *src, size_t count)
190 {
191 if (lseek (outfd, dest, SEEK_SET) != dest)
192 return 0;
193
194 return write (outfd, src, count) == count;
195 }
196
197 /* Write COUNT bytes of zeros to outfd starting at offset DEST.
198 Return true if successful, false otherwise. */
199 static int
200 unexec_write_zero (off_t dest, size_t count)
201 {
202 char buf[UNEXEC_COPY_BUFSZ];
203 ssize_t bytes;
204
205 bzero (buf, UNEXEC_COPY_BUFSZ);
206 if (lseek (outfd, dest, SEEK_SET) != dest)
207 return 0;
208
209 while (count > 0)
210 {
211 bytes = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count;
212 if (write (outfd, buf, bytes) != bytes)
213 return 0;
214 count -= bytes;
215 }
216
217 return 1;
218 }
219
220 /* Copy COUNT bytes from starting offset SRC in infd to starting
221 offset DEST in outfd. Return true if successful, false
222 otherwise. */
223 static int
224 unexec_copy (off_t dest, off_t src, ssize_t count)
225 {
226 ssize_t bytes_read;
227 ssize_t bytes_to_read;
228
229 char buf[UNEXEC_COPY_BUFSZ];
230
231 if (lseek (infd, src, SEEK_SET) != src)
232 return 0;
233
234 if (lseek (outfd, dest, SEEK_SET) != dest)
235 return 0;
236
237 while (count > 0)
238 {
239 bytes_to_read = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count;
240 bytes_read = read (infd, buf, bytes_to_read);
241 if (bytes_read <= 0)
242 return 0;
243 if (write (outfd, buf, bytes_read) != bytes_read)
244 return 0;
245 count -= bytes_read;
246 }
247
248 return 1;
249 }
250
251 /* Debugging and informational messages routines. */
252
253 static void
254 unexec_error (char *format, ...)
255 {
256 va_list ap;
257
258 va_start (ap, format);
259 fprintf (stderr, "unexec: ");
260 vfprintf (stderr, format, ap);
261 fprintf (stderr, "\n");
262 va_end (ap);
263 exit (1);
264 }
265
266 static void
267 print_prot (vm_prot_t prot)
268 {
269 if (prot == VM_PROT_NONE)
270 printf ("none");
271 else
272 {
273 putchar (prot & VM_PROT_READ ? 'r' : ' ');
274 putchar (prot & VM_PROT_WRITE ? 'w' : ' ');
275 putchar (prot & VM_PROT_EXECUTE ? 'x' : ' ');
276 putchar (' ');
277 }
278 }
279
280 static void
281 print_region (vm_address_t address, vm_size_t size, vm_prot_t prot,
282 vm_prot_t max_prot)
283 {
284 printf ("%#10x %#8x ", address, size);
285 print_prot (prot);
286 putchar (' ');
287 print_prot (max_prot);
288 putchar ('\n');
289 }
290
291 static void
292 print_region_list ()
293 {
294 struct region_t *r;
295
296 printf (" address size prot maxp\n");
297
298 for (r = region_list_head; r; r = r->next)
299 print_region (r->address, r->size, r->protection, r->max_protection);
300 }
301
302 void
303 print_regions ()
304 {
305 task_t target_task = mach_task_self ();
306 vm_address_t address = (vm_address_t) 0;
307 vm_size_t size;
308 struct vm_region_basic_info info;
309 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
310 mach_port_t object_name;
311
312 printf (" address size prot maxp\n");
313
314 while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
315 (vm_region_info_t) &info, &info_count, &object_name)
316 == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
317 {
318 print_region (address, size, info.protection, info.max_protection);
319
320 if (object_name != MACH_PORT_NULL)
321 mach_port_deallocate (target_task, object_name);
322
323 address += size;
324 }
325 }
326
327 /* Build the list of regions that need to be dumped. Regions with
328 addresses above VM_DATA_TOP are omitted. Adjacent regions with
329 identical protection are merged. Note that non-writable regions
330 cannot be omitted because they some regions created at run time are
331 read-only. */
332 static void
333 build_region_list ()
334 {
335 task_t target_task = mach_task_self ();
336 vm_address_t address = (vm_address_t) 0;
337 vm_size_t size;
338 struct vm_region_basic_info info;
339 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
340 mach_port_t object_name;
341 struct region_t *r;
342
343 #if VERBOSE
344 printf ("--- List of All Regions ---\n");
345 printf (" address size prot maxp\n");
346 #endif
347
348 while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO,
349 (vm_region_info_t) &info, &info_count, &object_name)
350 == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT)
351 {
352 /* Done when we reach addresses of shared libraries, which are
353 loaded in high memory. */
354 if (address >= VM_DATA_TOP)
355 break;
356
357 #if VERBOSE
358 print_region (address, size, info.protection, info.max_protection);
359 #endif
360
361 /* If a region immediately follows the previous one (the one
362 most recently added to the list) and has identical
363 protection, merge it with the latter. Otherwise create a
364 new list element for it. */
365 if (region_list_tail
366 && info.protection == region_list_tail->protection
367 && info.max_protection == region_list_tail->max_protection
368 && region_list_tail->address + region_list_tail->size == address)
369 {
370 region_list_tail->size += size;
371 }
372 else
373 {
374 r = (struct region_t *) malloc (sizeof (struct region_t));
375
376 if (!r)
377 unexec_error ("cannot allocate region structure");
378
379 r->address = address;
380 r->size = size;
381 r->protection = info.protection;
382 r->max_protection = info.max_protection;
383
384 r->next = 0;
385 if (region_list_head == 0)
386 {
387 region_list_head = r;
388 region_list_tail = r;
389 }
390 else
391 {
392 region_list_tail->next = r;
393 region_list_tail = r;
394 }
395
396 /* Deallocate (unused) object name returned by
397 vm_region. */
398 if (object_name != MACH_PORT_NULL)
399 mach_port_deallocate (target_task, object_name);
400 }
401
402 address += size;
403 }
404
405 printf ("--- List of Regions to be Dumped ---\n");
406 print_region_list ();
407 }
408
409
410 #define MAX_UNEXEC_REGIONS 200
411
412 int num_unexec_regions;
413 vm_range_t unexec_regions[MAX_UNEXEC_REGIONS];
414
415 static void
416 unexec_regions_recorder (task_t task, void *rr, unsigned type,
417 vm_range_t *ranges, unsigned num)
418 {
419 while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
420 {
421 unexec_regions[num_unexec_regions++] = *ranges;
422 printf ("%#8x (sz: %#8x)\n", ranges->address, ranges->size);
423 ranges++; num--;
424 }
425 if (num_unexec_regions == MAX_UNEXEC_REGIONS)
426 fprintf (stderr, "malloc_freezedry_recorder: too many regions\n");
427 }
428
429 static kern_return_t
430 unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr)
431 {
432 *ptr = (void *) address;
433 return KERN_SUCCESS;
434 }
435
436 void
437 find_emacs_zone_regions ()
438 {
439 num_unexec_regions = 0;
440
441 emacs_zone->introspect->enumerator (mach_task_self(), 0,
442 MALLOC_PTR_REGION_RANGE_TYPE
443 | MALLOC_ADMIN_REGION_RANGE_TYPE,
444 (vm_address_t) emacs_zone,
445 unexec_reader,
446 unexec_regions_recorder);
447 }
448
449 static int
450 unexec_regions_sort_compare (const void *a, const void *b)
451 {
452 vm_address_t aa = ((vm_range_t *) a)->address;
453 vm_address_t bb = ((vm_range_t *) b)->address;
454
455 if (aa < bb)
456 return -1;
457 else if (aa > bb)
458 return 1;
459 else
460 return 0;
461 }
462
463 static void
464 unexec_regions_merge ()
465 {
466 int i, n;
467 vm_range_t r;
468
469 qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]),
470 &unexec_regions_sort_compare);
471 n = 0;
472 r = unexec_regions[0];
473 for (i = 1; i < num_unexec_regions; i++)
474 {
475 if (r.address + r.size == unexec_regions[i].address)
476 {
477 r.size += unexec_regions[i].size;
478 }
479 else
480 {
481 unexec_regions[n++] = r;
482 r = unexec_regions[i];
483 }
484 }
485 unexec_regions[n++] = r;
486 num_unexec_regions = n;
487 }
488
489
490 /* More informational messages routines. */
491
492 static void
493 print_load_command_name (int lc)
494 {
495 switch (lc)
496 {
497 case LC_SEGMENT:
498 printf ("LC_SEGMENT ");
499 break;
500 case LC_LOAD_DYLINKER:
501 printf ("LC_LOAD_DYLINKER ");
502 break;
503 case LC_LOAD_DYLIB:
504 printf ("LC_LOAD_DYLIB ");
505 break;
506 case LC_SYMTAB:
507 printf ("LC_SYMTAB ");
508 break;
509 case LC_DYSYMTAB:
510 printf ("LC_DYSYMTAB ");
511 break;
512 case LC_UNIXTHREAD:
513 printf ("LC_UNIXTHREAD ");
514 break;
515 case LC_PREBOUND_DYLIB:
516 printf ("LC_PREBOUND_DYLIB");
517 break;
518 case LC_TWOLEVEL_HINTS:
519 printf ("LC_TWOLEVEL_HINTS");
520 break;
521 default:
522 printf ("unknown ");
523 }
524 }
525
526 static void
527 print_load_command (struct load_command *lc)
528 {
529 print_load_command_name (lc->cmd);
530 printf ("%8d", lc->cmdsize);
531
532 if (lc->cmd == LC_SEGMENT)
533 {
534 struct segment_command *scp;
535 struct section *sectp;
536 int j;
537
538 scp = (struct segment_command *) lc;
539 printf (" %-16.16s %#10x %#8x\n",
540 scp->segname, scp->vmaddr, scp->vmsize);
541
542 sectp = (struct section *) (scp + 1);
543 for (j = 0; j < scp->nsects; j++)
544 {
545 printf (" %-16.16s %#10x %#8x\n",
546 sectp->sectname, sectp->addr, sectp->size);
547 sectp++;
548 }
549 }
550 else
551 printf ("\n");
552 }
553
554 /* Read header and load commands from input file. Store the latter in
555 the global array lca. Store the total number of load commands in
556 global variable nlc. */
557 static void
558 read_load_commands ()
559 {
560 int n, i, j;
561
562 if (!unexec_read (&mh, sizeof (struct mach_header)))
563 unexec_error ("cannot read mach-o header");
564
565 if (mh.magic != MH_MAGIC)
566 unexec_error ("input file not in Mach-O format");
567
568 if (mh.filetype != MH_EXECUTE)
569 unexec_error ("input Mach-O file is not an executable object file");
570
571 #if VERBOSE
572 printf ("--- Header Information ---\n");
573 printf ("Magic = 0x%08x\n", mh.magic);
574 printf ("CPUType = %d\n", mh.cputype);
575 printf ("CPUSubType = %d\n", mh.cpusubtype);
576 printf ("FileType = 0x%x\n", mh.filetype);
577 printf ("NCmds = %d\n", mh.ncmds);
578 printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
579 printf ("Flags = 0x%08x\n", mh.flags);
580 #endif
581
582 nlc = mh.ncmds;
583 lca = (struct load_command **) malloc (nlc * sizeof (struct load_command *));
584
585 for (i = 0; i < nlc; i++)
586 {
587 struct load_command lc;
588 /* Load commands are variable-size: so read the command type and
589 size first and then read the rest. */
590 if (!unexec_read (&lc, sizeof (struct load_command)))
591 unexec_error ("cannot read load command");
592 lca[i] = (struct load_command *) malloc (lc.cmdsize);
593 memcpy (lca[i], &lc, sizeof (struct load_command));
594 if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
595 unexec_error ("cannot read content of load command");
596 if (lc.cmd == LC_SEGMENT)
597 {
598 struct segment_command *scp = (struct segment_command *) lca[i];
599
600 if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
601 infile_lc_highest_addr = scp->vmaddr + scp->vmsize;
602
603 if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
604 {
605 struct section *sectp = (struct section *) (scp + 1);
606 int j;
607
608 for (j = 0; j < scp->nsects; j++)
609 if (sectp->offset < text_seg_lowest_offset)
610 text_seg_lowest_offset = sectp->offset;
611 }
612 }
613 }
614
615 printf ("Highest address of load commands in input file: %#8x\n",
616 infile_lc_highest_addr);
617
618 printf ("Lowest offset of all sections in __TEXT segment: %#8x\n",
619 text_seg_lowest_offset);
620
621 printf ("--- List of Load Commands in Input File ---\n");
622 printf ("# cmd cmdsize name address size\n");
623
624 for (i = 0; i < nlc; i++)
625 {
626 printf ("%1d ", i);
627 print_load_command (lca[i]);
628 }
629 }
630
631 /* Copy a LC_SEGMENT load command other than the __DATA segment from
632 the input file to the output file, adjusting the file offset of the
633 segment and the file offsets of sections contained in it. */
634 static void
635 copy_segment (struct load_command *lc)
636 {
637 struct segment_command *scp = (struct segment_command *) lc;
638 unsigned long old_fileoff = scp->fileoff;
639 struct section *sectp;
640 int j;
641
642 scp->fileoff += delta;
643
644 sectp = (struct section *) (scp + 1);
645 for (j = 0; j < scp->nsects; j++)
646 {
647 sectp->offset += delta;
648 sectp++;
649 }
650
651 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
652 scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
653 scp->filesize);
654
655 if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
656 unexec_error ("cannot copy segment from input to output file");
657 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
658 unexec_error ("cannot write load command to header");
659
660 curr_header_offset += lc->cmdsize;
661 }
662
663 /* Copy a LC_SEGMENT load command for the __DATA segment in the input
664 file to the output file. We assume that only one such segment load
665 command exists in the input file and it contains the sections
666 __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and
667 __dyld. The first three of these should be dumped from memory and
668 the rest should be copied from the input file. Note that the
669 sections __bss and __common contain no data in the input file
670 because their flag fields have the value S_ZEROFILL. Dumping these
671 from memory makes it necessary to adjust file offset fields in
672 subsequently dumped load commands. Then, create new __DATA segment
673 load commands for regions on the region list other than the one
674 corresponding to the __DATA segment in the input file. */
675 static void
676 copy_data_segment (struct load_command *lc)
677 {
678 struct segment_command *scp = (struct segment_command *) lc;
679 struct section *sectp;
680 int j;
681 unsigned long header_offset, file_offset, old_file_offset;
682 struct region_t *r;
683
684 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
685 scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
686 scp->filesize);
687
688 if (delta != 0)
689 unexec_error ("cannot handle multiple DATA segments in input file");
690
691 /* Offsets in the output file for writing the next section structure
692 and segment data block, respectively. */
693 header_offset = curr_header_offset + sizeof (struct segment_command);
694
695 sectp = (struct section *) (scp + 1);
696 for (j = 0; j < scp->nsects; j++)
697 {
698 old_file_offset = sectp->offset;
699 sectp->offset = sectp->addr - scp->vmaddr + scp->fileoff;
700 /* The __data section is dumped from memory. The __bss and
701 __common sections are also dumped from memory but their flag
702 fields require changing (from S_ZEROFILL to S_REGULAR). The
703 other three kinds of sections are just copied from the input
704 file. */
705 if (strncmp (sectp->sectname, SECT_DATA, 16) == 0)
706 {
707 if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
708 unexec_error ("cannot write section %s", SECT_DATA);
709 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
710 unexec_error ("cannot write section %s's header", SECT_DATA);
711 }
712 else if (strncmp (sectp->sectname, SECT_COMMON, 16) == 0)
713 {
714 sectp->flags = S_REGULAR;
715 if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
716 unexec_error ("cannot write section %s", sectp->sectname);
717 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
718 unexec_error ("cannot write section %s's header", sectp->sectname);
719 }
720 else if (strncmp (sectp->sectname, SECT_BSS, 16) == 0)
721 {
722 extern char *my_endbss_static;
723 unsigned long my_size;
724
725 sectp->flags = S_REGULAR;
726
727 /* Clear uninitialized local variables in statically linked
728 libraries. In particular, function pointers stored by
729 libSystemStub.a, which is introduced in Mac OS X 10.4 for
730 binary compatibility with respect to long double, are
731 cleared so that they will be reinitialized when the
732 dumped binary is executed on other versions of OS. */
733 my_size = (unsigned long)my_endbss_static - sectp->addr;
734 if (!(sectp->addr <= (unsigned long)my_endbss_static
735 && my_size <= sectp->size))
736 unexec_error ("my_endbss_static is not in section %s",
737 sectp->sectname);
738 if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size))
739 unexec_error ("cannot write section %s", sectp->sectname);
740 if (!unexec_write_zero (sectp->offset + my_size,
741 sectp->size - my_size))
742 unexec_error ("cannot write section %s", sectp->sectname);
743 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
744 unexec_error ("cannot write section %s's header", sectp->sectname);
745 }
746 else if (strncmp (sectp->sectname, "__la_symbol_ptr", 16) == 0
747 || strncmp (sectp->sectname, "__nl_symbol_ptr", 16) == 0
748 || strncmp (sectp->sectname, "__la_sym_ptr2", 16) == 0
749 || strncmp (sectp->sectname, "__dyld", 16) == 0
750 || strncmp (sectp->sectname, "__const", 16) == 0
751 || strncmp (sectp->sectname, "__cfstring", 16) == 0)
752 {
753 if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
754 unexec_error ("cannot copy section %s", sectp->sectname);
755 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
756 unexec_error ("cannot write section %s's header", sectp->sectname);
757 }
758 else
759 unexec_error ("unrecognized section name in __DATA segment");
760
761 printf (" section %-16.16s at %#8x - %#8x (sz: %#8x)\n",
762 sectp->sectname, sectp->offset, sectp->offset + sectp->size,
763 sectp->size);
764
765 header_offset += sizeof (struct section);
766 sectp++;
767 }
768
769 /* The new filesize of the segment is set to its vmsize because data
770 blocks for segments must start at region boundaries. Note that
771 this may leave unused locations at the end of the segment data
772 block because the total of the sizes of all sections in the
773 segment is generally smaller than vmsize. */
774 delta = scp->vmsize - scp->filesize;
775 scp->filesize = scp->vmsize;
776 if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
777 unexec_error ("cannot write header of __DATA segment");
778 curr_header_offset += lc->cmdsize;
779
780 /* Create new __DATA segment load commands for regions on the region
781 list that do not corresponding to any segment load commands in
782 the input file.
783 */
784 file_offset = scp->fileoff + scp->filesize;
785 for (j = 0; j < num_unexec_regions; j++)
786 {
787 struct segment_command sc;
788
789 sc.cmd = LC_SEGMENT;
790 sc.cmdsize = sizeof (struct segment_command);
791 strncpy (sc.segname, SEG_DATA, 16);
792 sc.vmaddr = unexec_regions[j].address;
793 sc.vmsize = unexec_regions[j].size;
794 sc.fileoff = file_offset;
795 sc.filesize = unexec_regions[j].size;
796 sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
797 sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
798 sc.nsects = 0;
799 sc.flags = 0;
800
801 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
802 sc.segname, sc.fileoff, sc.fileoff + sc.filesize,
803 sc.filesize);
804
805 if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize))
806 unexec_error ("cannot write new __DATA segment");
807 delta += sc.filesize;
808 file_offset += sc.filesize;
809
810 if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
811 unexec_error ("cannot write new __DATA segment's header");
812 curr_header_offset += sc.cmdsize;
813 mh.ncmds++;
814 }
815 }
816
817 /* Copy a LC_SYMTAB load command from the input file to the output
818 file, adjusting the file offset fields. */
819 static void
820 copy_symtab (struct load_command *lc)
821 {
822 struct symtab_command *stp = (struct symtab_command *) lc;
823
824 stp->symoff += delta;
825 stp->stroff += delta;
826
827 printf ("Writing LC_SYMTAB command\n");
828
829 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
830 unexec_error ("cannot write symtab command to header");
831
832 curr_header_offset += lc->cmdsize;
833 }
834
835 /* Fix up relocation entries. */
836 static void
837 unrelocate (const char *name, off_t reloff, int nrel)
838 {
839 int i, unreloc_count;
840 struct relocation_info reloc_info;
841 struct scattered_relocation_info *sc_reloc_info
842 = (struct scattered_relocation_info *) &reloc_info;
843
844 for (unreloc_count = 0, i = 0; i < nrel; i++)
845 {
846 if (lseek (infd, reloff, L_SET) != reloff)
847 unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i);
848 if (!unexec_read (&reloc_info, sizeof (reloc_info)))
849 unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i);
850 reloff += sizeof (reloc_info);
851
852 if (sc_reloc_info->r_scattered == 0)
853 switch (reloc_info.r_type)
854 {
855 case GENERIC_RELOC_VANILLA:
856 if (reloc_info.r_address >= data_segment_scp->vmaddr
857 && reloc_info.r_address < (data_segment_scp->vmaddr
858 + data_segment_scp->vmsize))
859 {
860 off_t src_off = data_segment_old_fileoff
861 + reloc_info.r_address - data_segment_scp->vmaddr;
862 off_t dst_off = data_segment_scp->fileoff
863 + reloc_info.r_address - data_segment_scp->vmaddr;
864
865 if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length))
866 unexec_error ("unrelocate: %s:%d cannot copy original value",
867 name, i);
868 unreloc_count++;
869 }
870 break;
871 default:
872 unexec_error ("unrelocate: %s:%d cannot handle type = %d",
873 name, i, reloc_info.r_type);
874 }
875 else
876 switch (sc_reloc_info->r_type)
877 {
878 #if defined (__ppc__)
879 case PPC_RELOC_PB_LA_PTR:
880 /* nothing to do for prebound lazy pointer */
881 break;
882 #endif
883 default:
884 unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d",
885 name, i, sc_reloc_info->r_type);
886 }
887 }
888
889 if (nrel > 0)
890 printf ("Fixed up %d/%d %s relocation entries in data segment.\n",
891 unreloc_count, nrel, name);
892 }
893
894 /* Copy a LC_DYSYMTAB load command from the input file to the output
895 file, adjusting the file offset fields. */
896 static void
897 copy_dysymtab (struct load_command *lc)
898 {
899 struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
900
901 unrelocate ("local", dstp->locreloff, dstp->nlocrel);
902 unrelocate ("external", dstp->extreloff, dstp->nextrel);
903
904 if (dstp->nextrel > 0) {
905 dstp->extreloff += delta;
906 }
907
908 if (dstp->nlocrel > 0) {
909 dstp->locreloff += delta;
910 }
911
912 if (dstp->nindirectsyms > 0)
913 dstp->indirectsymoff += delta;
914
915 printf ("Writing LC_DYSYMTAB command\n");
916
917 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
918 unexec_error ("cannot write symtab command to header");
919
920 curr_header_offset += lc->cmdsize;
921 }
922
923 /* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
924 file, adjusting the file offset fields. */
925 static void
926 copy_twolevelhints (struct load_command *lc)
927 {
928 struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
929
930 if (tlhp->nhints > 0) {
931 tlhp->offset += delta;
932 }
933
934 printf ("Writing LC_TWOLEVEL_HINTS command\n");
935
936 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
937 unexec_error ("cannot write two level hint command to header");
938
939 curr_header_offset += lc->cmdsize;
940 }
941
942 /* Copy other kinds of load commands from the input file to the output
943 file, ones that do not require adjustments of file offsets. */
944 static void
945 copy_other (struct load_command *lc)
946 {
947 printf ("Writing ");
948 print_load_command_name (lc->cmd);
949 printf (" command\n");
950
951 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
952 unexec_error ("cannot write symtab command to header");
953
954 curr_header_offset += lc->cmdsize;
955 }
956
957 /* Loop through all load commands and dump them. Then write the Mach
958 header. */
959 static void
960 dump_it ()
961 {
962 int i;
963
964 printf ("--- Load Commands written to Output File ---\n");
965
966 for (i = 0; i < nlc; i++)
967 switch (lca[i]->cmd)
968 {
969 case LC_SEGMENT:
970 {
971 struct segment_command *scp = (struct segment_command *) lca[i];
972 if (strncmp (scp->segname, SEG_DATA, 16) == 0)
973 {
974 /* save data segment file offset and segment_command for
975 unrelocate */
976 data_segment_old_fileoff = scp->fileoff;
977 data_segment_scp = scp;
978
979 copy_data_segment (lca[i]);
980 }
981 else
982 {
983 copy_segment (lca[i]);
984 }
985 }
986 break;
987 case LC_SYMTAB:
988 copy_symtab (lca[i]);
989 break;
990 case LC_DYSYMTAB:
991 copy_dysymtab (lca[i]);
992 break;
993 case LC_TWOLEVEL_HINTS:
994 copy_twolevelhints (lca[i]);
995 break;
996 default:
997 copy_other (lca[i]);
998 break;
999 }
1000
1001 if (curr_header_offset > text_seg_lowest_offset)
1002 unexec_error ("not enough room for load commands for new __DATA segments");
1003
1004 printf ("%d unused bytes follow Mach-O header\n",
1005 text_seg_lowest_offset - curr_header_offset);
1006
1007 mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
1008 if (!unexec_write (0, &mh, sizeof (struct mach_header)))
1009 unexec_error ("cannot write final header contents");
1010 }
1011
1012 /* Take a snapshot of Emacs and make a Mach-O format executable file
1013 from it. The file names of the output and input files are outfile
1014 and infile, respectively. The three other parameters are
1015 ignored. */
1016 void
1017 unexec (char *outfile, char *infile, void *start_data, void *start_bss,
1018 void *entry_address)
1019 {
1020 infd = open (infile, O_RDONLY, 0);
1021 if (infd < 0)
1022 {
1023 unexec_error ("cannot open input file `%s'", infile);
1024 }
1025
1026 outfd = open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0755);
1027 if (outfd < 0)
1028 {
1029 close (infd);
1030 unexec_error ("cannot open output file `%s'", outfile);
1031 }
1032
1033 build_region_list ();
1034 read_load_commands ();
1035
1036 find_emacs_zone_regions ();
1037 unexec_regions_merge ();
1038
1039 in_dumped_exec = 1;
1040
1041 dump_it ();
1042
1043 close (outfd);
1044 }
1045
1046
1047 void
1048 unexec_init_emacs_zone ()
1049 {
1050 emacs_zone = malloc_create_zone (0, 0);
1051 malloc_set_zone_name (emacs_zone, "EmacsZone");
1052 }
1053
1054 #ifndef MACOSX_MALLOC_MULT16
1055 #define MACOSX_MALLOC_MULT16 1
1056 #endif
1057
1058 typedef struct unexec_malloc_header {
1059 union {
1060 char c[8];
1061 size_t size;
1062 } u;
1063 } unexec_malloc_header_t;
1064
1065 #if MACOSX_MALLOC_MULT16
1066
1067 #define ptr_in_unexec_regions(p) ((((vm_address_t) (p)) & 8) != 0)
1068
1069 #else
1070
1071 int
1072 ptr_in_unexec_regions (void *ptr)
1073 {
1074 int i;
1075
1076 for (i = 0; i < num_unexec_regions; i++)
1077 if ((vm_address_t) ptr - unexec_regions[i].address
1078 < unexec_regions[i].size)
1079 return 1;
1080
1081 return 0;
1082 }
1083
1084 #endif
1085
1086 void *
1087 unexec_malloc (size_t size)
1088 {
1089 if (in_dumped_exec)
1090 {
1091 void *p;
1092
1093 p = malloc (size);
1094 #if MACOSX_MALLOC_MULT16
1095 assert (((vm_address_t) p % 16) == 0);
1096 #endif
1097 return p;
1098 }
1099 else
1100 {
1101 unexec_malloc_header_t *ptr;
1102
1103 ptr = (unexec_malloc_header_t *)
1104 malloc_zone_malloc (emacs_zone, size + sizeof (unexec_malloc_header_t));
1105 ptr->u.size = size;
1106 ptr++;
1107 #if MACOSX_MALLOC_MULT16
1108 assert (((vm_address_t) ptr % 16) == 8);
1109 #endif
1110 return (void *) ptr;
1111 }
1112 }
1113
1114 void *
1115 unexec_realloc (void *old_ptr, size_t new_size)
1116 {
1117 if (in_dumped_exec)
1118 {
1119 void *p;
1120
1121 if (ptr_in_unexec_regions (old_ptr))
1122 {
1123 size_t old_size = ((unexec_malloc_header_t *) old_ptr)[-1].u.size;
1124 size_t size = new_size > old_size ? old_size : new_size;
1125
1126 p = (size_t *) malloc (new_size);
1127 if (size)
1128 memcpy (p, old_ptr, size);
1129 }
1130 else
1131 {
1132 p = realloc (old_ptr, new_size);
1133 }
1134 #if MACOSX_MALLOC_MULT16
1135 assert (((vm_address_t) p % 16) == 0);
1136 #endif
1137 return p;
1138 }
1139 else
1140 {
1141 unexec_malloc_header_t *ptr;
1142
1143 ptr = (unexec_malloc_header_t *)
1144 malloc_zone_realloc (emacs_zone, (unexec_malloc_header_t *) old_ptr - 1,
1145 new_size + sizeof (unexec_malloc_header_t));
1146 ptr->u.size = new_size;
1147 ptr++;
1148 #if MACOSX_MALLOC_MULT16
1149 assert (((vm_address_t) ptr % 16) == 8);
1150 #endif
1151 return (void *) ptr;
1152 }
1153 }
1154
1155 void
1156 unexec_free (void *ptr)
1157 {
1158 if (in_dumped_exec)
1159 {
1160 if (!ptr_in_unexec_regions (ptr))
1161 free (ptr);
1162 }
1163 else
1164 malloc_zone_free (emacs_zone, (unexec_malloc_header_t *) ptr - 1);
1165 }
1166
1167 /* arch-tag: 1a784f7b-a184-4c4f-9544-da8619593d72
1168 (do not change this comment) */