Add arch taglines
[bpt/emacs.git] / src / unexmacosx.c
CommitLineData
e0f712ba
AC
1/* Dump Emacs in Mach-O format for use on Mac OS X.
2 Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, 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. */
111int malloc_cookie;
112
113/* Type of an element on the list of regions to be dumped. */
114struct 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. */
124struct region_t *region_list_head = 0;
125struct region_t *region_list_tail = 0;
126
127/* Pointer to array of load commands. */
128struct load_command **lca;
129
130/* Number of load commands. */
131int 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. */
136vm_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. */
143unsigned long text_seg_lowest_offset = 0x10000000;
144
145/* Mach header. */
146struct mach_header mh;
147
148/* Offset at which the next load command should be written. */
149unsigned 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. */
153unsigned long delta = 0;
154
155int infd, outfd;
156
157int in_dumped_exec = 0;
158
159malloc_zone_t *emacs_zone;
160
161/* Read n bytes from infd into memory starting at address dest.
162 Return true if successful, false otherwise. */
163static int
164unexec_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. */
171static int
172unexec_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. */
182static int
183unexec_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
210static void
211unexec_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
223static void
224print_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
237static void
238print_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
248static void
249print_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
259void
260print_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);
177c0ea7 279
e0f712ba
AC
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. */
289static void
290build_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));
177c0ea7 332
e0f712ba
AC
333 if (!r)
334 unexec_error ("cannot allocate region structure");
177c0ea7 335
e0f712ba
AC
336 r->address = address;
337 r->size = size;
338 r->protection = info.protection;
339 r->max_protection = info.max_protection;
177c0ea7 340
e0f712ba
AC
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 }
177c0ea7 352
e0f712ba
AC
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 }
177c0ea7 358
e0f712ba
AC
359 address += size;
360 }
361
362 printf ("--- List of Regions to be Dumped ---\n");
363 print_region_list ();
364}
365
366
1dd7ccf2 367#define MAX_UNEXEC_REGIONS 200
e0f712ba
AC
368
369int num_unexec_regions;
370vm_range_t unexec_regions[MAX_UNEXEC_REGIONS];
371
372static void
373unexec_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
386static kern_return_t
387unexec_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
393void
394find_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
1dd7ccf2
AC
406static int
407unexec_regions_sort_compare (const void *a, const void *b)
408{
409 vm_address_t aa = ((vm_range_t *) a)->address;
410 vm_address_t bb = ((vm_range_t *) b)->address;
411
412 if (aa < bb)
413 return -1;
414 else if (aa > bb)
415 return 1;
416 else
417 return 0;
418}
419
420static void
421unexec_regions_merge ()
422{
423 int i, n;
424 vm_range_t r;
425
426 qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]),
427 &unexec_regions_sort_compare);
428 n = 0;
429 r = unexec_regions[0];
430 for (i = 1; i < num_unexec_regions; i++)
431 {
432 if (r.address + r.size == unexec_regions[i].address)
433 {
434 r.size += unexec_regions[i].size;
435 }
436 else
437 {
438 unexec_regions[n++] = r;
439 r = unexec_regions[i];
440 }
441 }
442 unexec_regions[n++] = r;
443 num_unexec_regions = n;
444}
445
e0f712ba
AC
446
447/* More informational messages routines. */
448
449static void
450print_load_command_name (int lc)
451{
452 switch (lc)
453 {
454 case LC_SEGMENT:
455 printf ("LC_SEGMENT ");
456 break;
457 case LC_LOAD_DYLINKER:
458 printf ("LC_LOAD_DYLINKER ");
459 break;
460 case LC_LOAD_DYLIB:
461 printf ("LC_LOAD_DYLIB ");
462 break;
463 case LC_SYMTAB:
464 printf ("LC_SYMTAB ");
465 break;
466 case LC_DYSYMTAB:
467 printf ("LC_DYSYMTAB ");
468 break;
469 case LC_UNIXTHREAD:
470 printf ("LC_UNIXTHREAD ");
471 break;
472 case LC_PREBOUND_DYLIB:
473 printf ("LC_PREBOUND_DYLIB");
474 break;
475 case LC_TWOLEVEL_HINTS:
476 printf ("LC_TWOLEVEL_HINTS");
477 break;
478 default:
479 printf ("unknown ");
480 }
481}
482
483static void
484print_load_command (struct load_command *lc)
485{
486 print_load_command_name (lc->cmd);
487 printf ("%8d", lc->cmdsize);
488
489 if (lc->cmd == LC_SEGMENT)
490 {
491 struct segment_command *scp;
492 struct section *sectp;
493 int j;
494
495 scp = (struct segment_command *) lc;
496 printf (" %-16.16s %#10x %#8x\n",
497 scp->segname, scp->vmaddr, scp->vmsize);
498
499 sectp = (struct section *) (scp + 1);
500 for (j = 0; j < scp->nsects; j++)
501 {
502 printf (" %-16.16s %#10x %#8x\n",
503 sectp->sectname, sectp->addr, sectp->size);
504 sectp++;
505 }
506 }
507 else
508 printf ("\n");
509}
510
511/* Read header and load commands from input file. Store the latter in
512 the global array lca. Store the total number of load commands in
513 global variable nlc. */
514static void
515read_load_commands ()
516{
517 int n, i, j;
518
519 if (!unexec_read (&mh, sizeof (struct mach_header)))
520 unexec_error ("cannot read mach-o header");
521
522 if (mh.magic != MH_MAGIC)
523 unexec_error ("input file not in Mach-O format");
524
525 if (mh.filetype != MH_EXECUTE)
526 unexec_error ("input Mach-O file is not an executable object file");
527
528#if VERBOSE
529 printf ("--- Header Information ---\n");
530 printf ("Magic = 0x%08x\n", mh.magic);
531 printf ("CPUType = %d\n", mh.cputype);
532 printf ("CPUSubType = %d\n", mh.cpusubtype);
533 printf ("FileType = 0x%x\n", mh.filetype);
534 printf ("NCmds = %d\n", mh.ncmds);
535 printf ("SizeOfCmds = %d\n", mh.sizeofcmds);
536 printf ("Flags = 0x%08x\n", mh.flags);
537#endif
538
539 nlc = mh.ncmds;
540 lca = (struct load_command **) malloc (nlc * sizeof (struct load_command *));
177c0ea7 541
e0f712ba
AC
542 for (i = 0; i < nlc; i++)
543 {
544 struct load_command lc;
545 /* Load commands are variable-size: so read the command type and
546 size first and then read the rest. */
547 if (!unexec_read (&lc, sizeof (struct load_command)))
548 unexec_error ("cannot read load command");
549 lca[i] = (struct load_command *) malloc (lc.cmdsize);
550 memcpy (lca[i], &lc, sizeof (struct load_command));
551 if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command)))
552 unexec_error ("cannot read content of load command");
553 if (lc.cmd == LC_SEGMENT)
554 {
555 struct segment_command *scp = (struct segment_command *) lca[i];
177c0ea7 556
e0f712ba
AC
557 if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr)
558 infile_lc_highest_addr = scp->vmaddr + scp->vmsize;
559
560 if (strncmp (scp->segname, SEG_TEXT, 16) == 0)
561 {
562 struct section *sectp = (struct section *) (scp + 1);
563 int j;
564
565 for (j = 0; j < scp->nsects; j++)
566 if (sectp->offset < text_seg_lowest_offset)
567 text_seg_lowest_offset = sectp->offset;
568 }
569 }
570 }
571
572 printf ("Highest address of load commands in input file: %#8x\n",
573 infile_lc_highest_addr);
574
575 printf ("Lowest offset of all sections in __TEXT segment: %#8x\n",
576 text_seg_lowest_offset);
577
578 printf ("--- List of Load Commands in Input File ---\n");
579 printf ("# cmd cmdsize name address size\n");
580
581 for (i = 0; i < nlc; i++)
582 {
583 printf ("%1d ", i);
584 print_load_command (lca[i]);
585 }
586}
587
588/* Copy a LC_SEGMENT load command other than the __DATA segment from
589 the input file to the output file, adjusting the file offset of the
590 segment and the file offsets of sections contained in it. */
591static void
592copy_segment (struct load_command *lc)
593{
594 struct segment_command *scp = (struct segment_command *) lc;
595 unsigned long old_fileoff = scp->fileoff;
596 struct section *sectp;
597 int j;
598
599 scp->fileoff += delta;
600
601 sectp = (struct section *) (scp + 1);
602 for (j = 0; j < scp->nsects; j++)
603 {
604 sectp->offset += delta;
605 sectp++;
606 }
607
608 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
609 scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
610 scp->filesize);
611
612 if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
613 unexec_error ("cannot copy segment from input to output file");
614 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
615 unexec_error ("cannot write load command to header");
616
617 curr_header_offset += lc->cmdsize;
618}
619
620/* Copy a LC_SEGMENT load command for the __DATA segment in the input
621 file to the output file. We assume that only one such segment load
622 command exists in the input file and it contains the sections
623 __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and
624 __dyld. The first three of these should be dumped from memory and
625 the rest should be copied from the input file. Note that the
626 sections __bss and __common contain no data in the input file
627 because their flag fields have the value S_ZEROFILL. Dumping these
628 from memory makes it necessary to adjust file offset fields in
629 subsequently dumped load commands. Then, create new __DATA segment
630 load commands for regions on the region list other than the one
631 corresponding to the __DATA segment in the input file. */
632static void
633copy_data_segment (struct load_command *lc)
634{
635 struct segment_command *scp = (struct segment_command *) lc;
636 struct section *sectp;
637 int j;
638 unsigned long header_offset, file_offset, old_file_offset;
639 struct region_t *r;
640
641 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
642 scp->segname, scp->fileoff, scp->fileoff + scp->filesize,
643 scp->filesize);
644
645 if (delta != 0)
646 unexec_error ("cannot handle multiple DATA segments in input file");
647
648 /* Offsets in the output file for writing the next section structure
649 and segment data block, respectively. */
650 header_offset = curr_header_offset + sizeof (struct segment_command);
651
652 sectp = (struct section *) (scp + 1);
653 for (j = 0; j < scp->nsects; j++)
654 {
655 old_file_offset = sectp->offset;
656 sectp->offset = sectp->addr - scp->vmaddr + scp->fileoff;
657 /* The __data section is dumped from memory. The __bss and
658 __common sections are also dumped from memory but their flag
659 fields require changing (from S_ZEROFILL to S_REGULAR). The
660 other three kinds of sections are just copied from the input
661 file. */
662 if (strncmp (sectp->sectname, SECT_DATA, 16) == 0)
663 {
664 if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
665 unexec_error ("cannot write section %s", SECT_DATA);
666 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
667 unexec_error ("cannot write section %s's header", SECT_DATA);
668 }
669 else if (strncmp (sectp->sectname, SECT_BSS, 16) == 0
670 || strncmp (sectp->sectname, SECT_COMMON, 16) == 0)
671 {
672 sectp->flags = S_REGULAR;
673 if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size))
674 unexec_error ("cannot write section %s", SECT_DATA);
675 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
676 unexec_error ("cannot write section %s's header", SECT_DATA);
677 }
678 else if (strncmp (sectp->sectname, "__la_symbol_ptr", 16) == 0
679 || strncmp (sectp->sectname, "__nl_symbol_ptr", 16) == 0
680 || strncmp (sectp->sectname, "__dyld", 16) == 0
7290a344
AC
681 || strncmp (sectp->sectname, "__const", 16) == 0
682 || strncmp (sectp->sectname, "__cfstring", 16) == 0)
e0f712ba
AC
683 {
684 if (!unexec_copy (sectp->offset, old_file_offset, sectp->size))
685 unexec_error ("cannot copy section %s", sectp->sectname);
686 if (!unexec_write (header_offset, sectp, sizeof (struct section)))
687 unexec_error ("cannot write section %s's header", sectp->sectname);
688 }
689 else
690 unexec_error ("unrecognized section name in __DATA segment");
177c0ea7 691
e0f712ba
AC
692 printf (" section %-16.16s at %#8x - %#8x (sz: %#8x)\n",
693 sectp->sectname, sectp->offset, sectp->offset + sectp->size,
694 sectp->size);
695
696 header_offset += sizeof (struct section);
697 sectp++;
698 }
699
700 /* The new filesize of the segment is set to its vmsize because data
701 blocks for segments must start at region boundaries. Note that
702 this may leave unused locations at the end of the segment data
703 block because the total of the sizes of all sections in the
704 segment is generally smaller than vmsize. */
705 delta = scp->vmsize - scp->filesize;
706 scp->filesize = scp->vmsize;
707 if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
708 unexec_error ("cannot write header of __DATA segment");
709 curr_header_offset += lc->cmdsize;
710
711 /* Create new __DATA segment load commands for regions on the region
712 list that do not corresponding to any segment load commands in
713 the input file.
714 */
715 file_offset = scp->fileoff + scp->filesize;
716 for (j = 0; j < num_unexec_regions; j++)
717 {
718 struct segment_command sc;
177c0ea7 719
e0f712ba
AC
720 sc.cmd = LC_SEGMENT;
721 sc.cmdsize = sizeof (struct segment_command);
722 strncpy (sc.segname, SEG_DATA, 16);
723 sc.vmaddr = unexec_regions[j].address;
724 sc.vmsize = unexec_regions[j].size;
725 sc.fileoff = file_offset;
726 sc.filesize = unexec_regions[j].size;
727 sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
728 sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
729 sc.nsects = 0;
730 sc.flags = 0;
177c0ea7 731
e0f712ba
AC
732 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n",
733 sc.segname, sc.fileoff, sc.fileoff + sc.filesize,
734 sc.filesize);
735
736 if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize))
737 unexec_error ("cannot write new __DATA segment");
738 delta += sc.filesize;
739 file_offset += sc.filesize;
177c0ea7 740
e0f712ba
AC
741 if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
742 unexec_error ("cannot write new __DATA segment's header");
743 curr_header_offset += sc.cmdsize;
744 mh.ncmds++;
745 }
746}
747
748/* Copy a LC_SYMTAB load command from the input file to the output
749 file, adjusting the file offset fields. */
750static void
751copy_symtab (struct load_command *lc)
752{
753 struct symtab_command *stp = (struct symtab_command *) lc;
754
755 stp->symoff += delta;
756 stp->stroff += delta;
757
758 printf ("Writing LC_SYMTAB command\n");
759
760 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
761 unexec_error ("cannot write symtab command to header");
762
763 curr_header_offset += lc->cmdsize;
764}
765
766/* Copy a LC_DYSYMTAB load command from the input file to the output
767 file, adjusting the file offset fields. */
768static void
769copy_dysymtab (struct load_command *lc)
770{
771 struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
772
773 /* If Mach-O executable is not prebound, relocation entries need
774 fixing up. This is not supported currently. */
775 if (!(mh.flags & MH_PREBOUND) && (dstp->nextrel != 0 || dstp->nlocrel != 0))
776 unexec_error ("cannot handle LC_DYSYMTAB with relocation entries");
777
778 if (dstp->nextrel > 0) {
779 dstp->extreloff += delta;
780 }
781
782 if (dstp->nlocrel > 0) {
783 dstp->locreloff += delta;
784 }
785
786 if (dstp->nindirectsyms > 0)
787 dstp->indirectsymoff += delta;
788
789 printf ("Writing LC_DYSYMTAB command\n");
790
791 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
792 unexec_error ("cannot write symtab command to header");
793
794 curr_header_offset += lc->cmdsize;
795}
796
40e6ff95
ST
797/* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
798 file, adjusting the file offset fields. */
799static void
800copy_twolevelhints (struct load_command *lc)
801{
802 struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
803
804 if (tlhp->nhints > 0) {
805 tlhp->offset += delta;
806 }
807
808 printf ("Writing LC_TWOLEVEL_HINTS command\n");
809
810 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
811 unexec_error ("cannot write two level hint command to header");
812
813 curr_header_offset += lc->cmdsize;
814}
815
e0f712ba
AC
816/* Copy other kinds of load commands from the input file to the output
817 file, ones that do not require adjustments of file offsets. */
818static void
819copy_other (struct load_command *lc)
820{
821 printf ("Writing ");
822 print_load_command_name (lc->cmd);
823 printf (" command\n");
824
825 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
826 unexec_error ("cannot write symtab command to header");
827
828 curr_header_offset += lc->cmdsize;
829}
830
831/* Loop through all load commands and dump them. Then write the Mach
832 header. */
833static void
834dump_it ()
835{
836 int i;
837
838 printf ("--- Load Commands written to Output File ---\n");
839
840 for (i = 0; i < nlc; i++)
841 switch (lca[i]->cmd)
842 {
843 case LC_SEGMENT:
844 {
845 struct segment_command *scp = (struct segment_command *) lca[i];
846 if (strncmp (scp->segname, SEG_DATA, 16) == 0)
847 {
848 copy_data_segment (lca[i]);
849 }
850 else
851 {
852 copy_segment (lca[i]);
853 }
854 }
855 break;
856 case LC_SYMTAB:
857 copy_symtab (lca[i]);
858 break;
859 case LC_DYSYMTAB:
860 copy_dysymtab (lca[i]);
861 break;
40e6ff95
ST
862 case LC_TWOLEVEL_HINTS:
863 copy_twolevelhints (lca[i]);
864 break;
e0f712ba
AC
865 default:
866 copy_other (lca[i]);
867 break;
868 }
869
870 if (curr_header_offset > text_seg_lowest_offset)
871 unexec_error ("not enough room for load commands for new __DATA segments");
872
873 printf ("%d unused bytes follow Mach-O header\n",
874 text_seg_lowest_offset - curr_header_offset);
875
876 mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header);
877 if (!unexec_write (0, &mh, sizeof (struct mach_header)))
878 unexec_error ("cannot write final header contents");
879}
880
881/* Take a snapshot of Emacs and make a Mach-O format executable file
882 from it. The file names of the output and input files are outfile
883 and infile, respectively. The three other parameters are
884 ignored. */
885void
886unexec (char *outfile, char *infile, void *start_data, void *start_bss,
887 void *entry_address)
888{
889 infd = open (infile, O_RDONLY, 0);
890 if (infd < 0)
891 {
892 unexec_error ("cannot open input file `%s'", infile);
893 }
177c0ea7 894
e0f712ba
AC
895 outfd = open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0755);
896 if (outfd < 0)
897 {
898 close (infd);
899 unexec_error ("cannot open output file `%s'", outfile);
900 }
901
902 build_region_list ();
903 read_load_commands ();
904
905 find_emacs_zone_regions ();
1dd7ccf2 906 unexec_regions_merge ();
e0f712ba
AC
907
908 in_dumped_exec = 1;
909
910 dump_it ();
911
912 close (outfd);
913}
914
915
916void
917unexec_init_emacs_zone ()
918{
919 emacs_zone = malloc_create_zone (0, 0);
920 malloc_set_zone_name (emacs_zone, "EmacsZone");
921}
922
923int
924ptr_in_unexec_regions (void *ptr)
925{
926 int i;
927
928 for (i = 0; i < num_unexec_regions; i++)
929 if ((vm_address_t) ptr - unexec_regions[i].address
930 < unexec_regions[i].size)
931 return 1;
932
933 return 0;
934}
935
936void *
937unexec_malloc (size_t size)
938{
939 if (in_dumped_exec)
940 return malloc (size);
941 else
942 return malloc_zone_malloc (emacs_zone, size);
943}
944
945void *
946unexec_realloc (void *old_ptr, size_t new_size)
947{
948 if (in_dumped_exec)
949 if (ptr_in_unexec_regions (old_ptr))
950 {
951 char *p = malloc (new_size);
952 /* 2002-04-15 T. Ikegami <ikegami@adam.uprr.pr>. The original
953 code to get size failed to reallocate read_buffer
954 (lread.c). */
82122254 955 int old_size = malloc_default_zone()->size (emacs_zone, old_ptr);
e0f712ba
AC
956 int size = new_size > old_size ? old_size : new_size;
957
958 if (size)
959 memcpy (p, old_ptr, size);
960 return p;
961 }
962 else
963 return realloc (old_ptr, new_size);
964 else
965 return malloc_zone_realloc (emacs_zone, old_ptr, new_size);
966}
967
968void
969unexec_free (void *ptr)
970{
971 if (in_dumped_exec)
972 {
973 if (!ptr_in_unexec_regions (ptr))
974 free (ptr);
975 }
976 else
977 malloc_zone_free (emacs_zone, ptr);
978}
ab5796a9
MB
979
980/* arch-tag: 1a784f7b-a184-4c4f-9544-da8619593d72
981 (do not change this comment) */