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