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