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