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