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