1/* Dump Emacs in Mach-O format for use on Mac OS X. 2 Copyright (C) 2001, 2002, 2003, 2004, 2005, 3 2006, 2007 Free Software Foundation, Inc. 4 5This file is part of GNU Emacs. 6 7GNU Emacs is free software; you can redistribute it and/or modify 8it under the terms of the GNU General Public License as published by 9the Free Software Foundation; either version 2, or (at your option) 10any later version. 11 12GNU Emacs is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU General Public License 18along with GNU Emacs; see the file COPYING. If not, write to 19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20Boston, MA 02110-1301, USA. */ 21 22/* Contributed by Andrew Choi (akochoi@mac.com). */ 23 24/* Documentation note. 25 26 Consult the following documents/files for a description of the 27 Mach-O format: the file loader.h, man pages for Mach-O and ld, old 28 NEXTSTEP documents of the Mach-O format. The tool otool dumps the 29 mach header (-h option) and the load commands (-l option) in a 30 Mach-O file. The tool nm on Mac OS X displays the symbol table in 31 a Mach-O file. For examples of unexec for the Mach-O format, see 32 the file unexnext.c in the GNU Emacs distribution, the file 33 unexdyld.c in the Darwin port of GNU Emacs 20.7, and unexdyld.c in 34 the Darwin port of XEmacs 21.1. Also the Darwin Libc source 35 contains the source code for malloc_freezedry and malloc_jumpstart. 36 Read that to see what they do. This file was written completely 37 from scratch, making use of information from the above sources. */ 38 39/* The Mac OS X implementation of unexec makes use of Darwin's `zone' 40 memory allocator. All calls to malloc, realloc, and free in Emacs 41 are redirected to unexec_malloc, unexec_realloc, and unexec_free in 42 this file. When temacs is run, all memory requests are handled in 43 the zone EmacsZone. The Darwin memory allocator library calls 44 maintain the data structures to manage this zone. Dumping writes 45 its contents to data segments of the executable file. When emacs 46 is run, the loader recreates the contents of the zone in memory. 47 However since the initialization routine of the zone memory 48 allocator is run again, this `zone' can no longer be used as a 49 heap. That is why emacs uses the ordinary malloc system call to 50 allocate memory. Also, when a block of memory needs to be 51 reallocated and the new size is larger than the old one, a new 52 block must be obtained by malloc and the old contents copied to 53 it. */ 54 55/* Peculiarity of the Mach-O files generated by ld in Mac OS X 56 (possible causes of future bugs if changed). 57 58 The file offset of the start of the __TEXT segment is zero. Since 59 the Mach header and load commands are located at the beginning of a 60 Mach-O file, copying the contents of the __TEXT segment from the 61 input file overwrites them in the output file. Despite this, 62 unexec works fine as written below because the segment load command 63 for __TEXT appears, and is therefore processed, before all other 64 load commands except the segment load command for __PAGEZERO, which 65 remains unchanged. 66 67 Although the file offset of the start of the __TEXT segment is 68 zero, none of the sections it contains actually start there. In 69 fact, the earliest one starts a few hundred bytes beyond the end of 70 the last load command. The linker option -headerpad controls the 71 minimum size of this padding. Its setting can be changed in 72 s/darwin.h. A value of 0x690, e.g., leaves room for 30 additional 73 load commands for the newly created __DATA segments (at 56 bytes 74 each). Unexec fails if there is not enough room for these new 75 segments. 76 77 The __TEXT segment contains the sections __text, __cstring, 78 __picsymbol_stub, and __const and the __DATA segment contains the 79 sections __data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __bss, 80 and __common. The other segments do not contain any sections. 81 These sections are copied from the input file to the output file, 82 except for __data, __bss, and __common, which are dumped from 83 memory. The types of the sections __bss and __common are changed 84 from S_ZEROFILL to S_REGULAR. Note that the number of sections and 85 their relative order in the input and output files remain 86 unchanged. Otherwise all n_sect fields in the nlist records in the 87 symbol table (specified by the LC_SYMTAB load command) will have to 88 be changed accordingly. 89*/ 90 91#include <stdio.h> 92#include <stdlib.h> 93#include <fcntl.h> 94#include <stdarg.h> 95#include <sys/types.h> 96#include <unistd.h> 97#include <mach/mach.h> 98#include <mach-o/loader.h> 99#include <mach-o/reloc.h> 100#if defined (__ppc__) 101#include <mach-o/ppc/reloc.h> 102#endif 103#include <config.h> 104#undef malloc 105#undef realloc 106#undef free 107#ifdef HAVE_MALLOC_MALLOC_H 108#include <malloc/malloc.h> 109#else 110#include <objc/malloc.h> 111#endif 112 113#include <assert.h> 114#include "version.h" 115 116#if _LP64 117#define mach_header mach_header_64 118#define segment_command segment_command_64 119#define vm_region vm_region_64 120#define section section_64 121#define target_VM_REGION_BASIC_INFO_COUNT VM_REGION_BASIC_INFO_COUNT_64 122#define target_VM_REGION_BASIC_INFO VM_REGION_BASIC_INFO_64 123#define target_LC_SEGMENT LC_SEGMENT_64 124#define target_MH_MAGIC MH_MAGIC_64 125#else 126#define target_VM_REGION_BASIC_INFO_COUNT VM_REGION_BASIC_INFO_COUNT 127#define target_VM_REGION_BASIC_INFO VM_REGION_BASIC_INFO 128#define target_LC_SEGMENT LC_SEGMENT 129#define target_MH_MAGIC MH_MAGIC 130#endif 131 132#define VERBOSE 1 133 134/* Size of buffer used to copy data from the input file to the output 135 file in function unexec_copy. */ 136#define UNEXEC_COPY_BUFSZ 1024 137 138/* Regions with memory addresses above this value are assumed to be 139 mapped to dynamically loaded libraries and will not be dumped. */ 140#define VM_DATA_TOP (20 * 1024 * 1024) 141 142/* Type of an element on the list of regions to be dumped. */ 143struct region_t { 144 vm_address_t address; 145 vm_size_t size; 146 vm_prot_t protection; 147 vm_prot_t max_protection; 148 149 struct region_t *next; 150}; 151 152/* Head and tail of the list of regions to be dumped. */ 153static struct region_t *region_list_head = 0; 154static struct region_t *region_list_tail = 0; 155 156/* Pointer to array of load commands. */ 157static struct load_command **lca; 158 159/* Number of load commands. */ 160static int nlc; 161 162/* The highest VM address of segments loaded by the input file. 163 Regions with addresses beyond this are assumed to be allocated 164 dynamically and thus require dumping. */ 165static vm_address_t infile_lc_highest_addr = 0; 166 167/* The lowest file offset used by the all sections in the __TEXT 168 segments. This leaves room at the beginning of the file to store 169 the Mach-O header. Check this value against header size to ensure 170 the added load commands for the new __DATA segments did not 171 overwrite any of the sections in the __TEXT segment. */ 172static unsigned long text_seg_lowest_offset = 0x10000000; 173 174/* Mach header. */ 175static struct mach_header mh; 176 177/* Offset at which the next load command should be written. */ 178static unsigned long curr_header_offset = sizeof (struct mach_header); 179 180/* Offset at which the next segment should be written. */ 181static unsigned long curr_file_offset = 0; 182 183static unsigned long pagesize; 184#define ROUNDUP_TO_PAGE_BOUNDARY(x) (((x) + pagesize - 1) & ~(pagesize - 1)) 185 186static int infd, outfd; 187 188static int in_dumped_exec = 0; 189 190static malloc_zone_t *emacs_zone; 191 192/* file offset of input file's data segment */ 193static off_t data_segment_old_fileoff = 0; 194 195static struct segment_command *data_segment_scp; 196 197/* Read N bytes from infd into memory starting at address DEST. 198 Return true if successful, false otherwise. */ 199static int 200unexec_read (void *dest, size_t n) 201{ 202 return n == read (infd, dest, n); 203} 204 205/* Write COUNT bytes from memory starting at address SRC to outfd 206 starting at offset DEST. Return true if successful, false 207 otherwise. */ 208static int 209unexec_write (off_t dest, const void *src, size_t count) 210{ 211 if (lseek (outfd, dest, SEEK_SET) != dest) 212 return 0; 213 214 return (count == write(outfd, src, count)); 215} 216 217/* Write COUNT bytes of zeros to outfd starting at offset DEST. 218 Return true if successful, false otherwise. */ 219static int 220unexec_write_zero (off_t dest, size_t count) 221{ 222 char buf[UNEXEC_COPY_BUFSZ]; 223 ssize_t bytes; 224 225 bzero (buf, UNEXEC_COPY_BUFSZ); 226 if (lseek (outfd, dest, SEEK_SET) != dest) 227 return 0; 228 229 while (count > 0) 230 { 231 bytes = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count; 232 if (write (outfd, buf, bytes) != bytes) 233 return 0; 234 count -= bytes; 235 } 236 237 return 1; 238} 239 240/* Copy COUNT bytes from starting offset SRC in infd to starting 241 offset DEST in outfd. Return true if successful, false 242 otherwise. */ 243static int 244unexec_copy (off_t dest, off_t src, ssize_t count) 245{ 246 ssize_t bytes_read; 247 ssize_t bytes_to_read; 248 249 char buf[UNEXEC_COPY_BUFSZ]; 250 251 if (lseek (infd, src, SEEK_SET) != src) 252 return 0; 253 254 if (lseek (outfd, dest, SEEK_SET) != dest) 255 return 0; 256 257 while (count > 0) 258 { 259 bytes_to_read = count > UNEXEC_COPY_BUFSZ ? UNEXEC_COPY_BUFSZ : count; 260 bytes_read = read (infd, buf, bytes_to_read); 261 if (bytes_read <= 0) 262 return 0; 263 if (write (outfd, buf, bytes_read) != bytes_read) 264 return 0; 265 count -= bytes_read; 266 } 267 268 return 1; 269} 270 271/* Debugging and informational messages routines. */ 272 273static void 274unexec_error (char *format, ...) 275{ 276 va_list ap; 277 278 va_start (ap, format); 279 fprintf (stderr, "unexec: "); 280 vfprintf (stderr, format, ap); 281 fprintf (stderr, "\n"); 282 va_end (ap); 283 exit (1); 284} 285 286static void 287print_prot (vm_prot_t prot) 288{ 289 if (prot == VM_PROT_NONE) 290 printf ("none"); 291 else 292 { 293 putchar (prot & VM_PROT_READ ? 'r' : ' '); 294 putchar (prot & VM_PROT_WRITE ? 'w' : ' '); 295 putchar (prot & VM_PROT_EXECUTE ? 'x' : ' '); 296 putchar (' '); 297 } 298} 299 300static void 301print_region (vm_address_t address, vm_size_t size, vm_prot_t prot, 302 vm_prot_t max_prot) 303{ 304 printf ("%#10lx %#8lx ", (long) address, (long) size); 305 print_prot (prot); 306 putchar (' '); 307 print_prot (max_prot); 308 putchar ('\n'); 309} 310 311static void 312print_region_list () 313{ 314 struct region_t *r; 315 316 printf (" address size prot maxp\n"); 317 318 for (r = region_list_head; r; r = r->next) 319 print_region (r->address, r->size, r->protection, r->max_protection); 320} 321 322static void 323print_regions () 324{ 325 task_t target_task = mach_task_self (); 326 vm_address_t address = (vm_address_t) 0; 327 vm_size_t size; 328 struct vm_region_basic_info info; 329 mach_msg_type_number_t info_count = target_VM_REGION_BASIC_INFO_COUNT; 330 mach_port_t object_name; 331 332 printf (" address size prot maxp\n"); 333 334 while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO, 335 (vm_region_info_t) &info, &info_count, &object_name) 336 == KERN_SUCCESS && info_count == target_VM_REGION_BASIC_INFO_COUNT) 337 { 338 print_region (address, size, info.protection, info.max_protection); 339 340 if (object_name != MACH_PORT_NULL) 341 mach_port_deallocate (target_task, object_name); 342 343 address += size; 344 } 345} 346 347/* Build the list of regions that need to be dumped. Regions with 348 addresses above VM_DATA_TOP are omitted. Adjacent regions with 349 identical protection are merged. Note that non-writable regions 350 cannot be omitted because they some regions created at run time are 351 read-only. */ 352static void 353build_region_list () 354{ 355 task_t target_task = mach_task_self (); 356 vm_address_t address = (vm_address_t) 0; 357 vm_size_t size; 358 struct vm_region_basic_info info; 359 mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT; 360 mach_port_t object_name; 361 struct region_t *r; 362 363#if VERBOSE 364 printf ("--- List of All Regions ---\n"); 365 printf (" address size prot maxp\n"); 366#endif 367 368 while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO, 369 (vm_region_info_t) &info, &info_count, &object_name) 370 == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT) 371 { 372 /* Done when we reach addresses of shared libraries, which are 373 loaded in high memory. */ 374 if (address >= VM_DATA_TOP) 375 break; 376 377#if VERBOSE 378 print_region (address, size, info.protection, info.max_protection); 379#endif 380 381 /* If a region immediately follows the previous one (the one 382 most recently added to the list) and has identical 383 protection, merge it with the latter. Otherwise create a 384 new list element for it. */ 385 if (region_list_tail 386 && info.protection == region_list_tail->protection 387 && info.max_protection == region_list_tail->max_protection 388 && region_list_tail->address + region_list_tail->size == address) 389 { 390 region_list_tail->size += size; 391 } 392 else 393 { 394 r = (struct region_t *) malloc (sizeof (struct region_t)); 395 396 if (!r) 397 unexec_error ("cannot allocate region structure"); 398 399 r->address = address; 400 r->size = size; 401 r->protection = info.protection; 402 r->max_protection = info.max_protection; 403 404 r->next = 0; 405 if (region_list_head == 0) 406 { 407 region_list_head = r; 408 region_list_tail = r; 409 } 410 else 411 { 412 region_list_tail->next = r; 413 region_list_tail = r; 414 } 415 416 /* Deallocate (unused) object name returned by 417 vm_region. */ 418 if (object_name != MACH_PORT_NULL) 419 mach_port_deallocate (target_task, object_name); 420 } 421 422 address += size; 423 } 424 425 printf ("--- List of Regions to be Dumped ---\n"); 426 print_region_list (); 427} 428 429 430#define MAX_UNEXEC_REGIONS 400 431 432static int num_unexec_regions; 433typedef struct { 434 vm_range_t range; 435 vm_size_t filesize; 436} unexec_region_info; 437static unexec_region_info unexec_regions[MAX_UNEXEC_REGIONS]; 438 439static void 440unexec_regions_recorder (task_t task, void *rr, unsigned type, 441 vm_range_t *ranges, unsigned num) 442{ 443 while (num && num_unexec_regions < MAX_UNEXEC_REGIONS) 444 { 445 unexec_regions[num_unexec_regions].filesize = ranges->size; 446 unexec_regions[num_unexec_regions++].range = *ranges; 447 printf ("%#10lx (sz: %#8lx)\n", (long) (ranges->address), 448 (long) (ranges->size)); 449 ranges++; num--; 450 } 451} 452 453static kern_return_t 454unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr) 455{ 456 *ptr = (void *) address; 457 return KERN_SUCCESS; 458} 459 460static void 461find_emacs_zone_regions () 462{ 463 num_unexec_regions = 0; 464 465 emacs_zone->introspect->enumerator (mach_task_self(), 0, 466 MALLOC_PTR_REGION_RANGE_TYPE, 467 (vm_address_t) emacs_zone, 468 unexec_reader, 469 unexec_regions_recorder); 470 471 if (num_unexec_regions == MAX_UNEXEC_REGIONS) 472 unexec_error ("find_emacs_zone_regions: too many regions"); 473} 474 475static int 476unexec_regions_sort_compare (const void *a, const void *b) 477{ 478 vm_address_t aa = ((unexec_region_info *) a)->range.address; 479 vm_address_t bb = ((unexec_region_info *) b)->range.address; 480 481 if (aa < bb) 482 return -1; 483 else if (aa > bb) 484 return 1; 485 else 486 return 0; 487} 488 489static void 490unexec_regions_merge () 491{ 492 int i, n; 493 vm_address_t begin, end; 494 unexec_region_info r; 495 long total = 0; 496 void *zeropage = calloc(1, pagesize); 497 498 qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]), 499 &unexec_regions_sort_compare); 500 n = 0; 501 r = unexec_regions[0]; 502 if (r.range.address & (pagesize-1L)) { 503 begin = r.range.address; 504 r.range.address = r.range.address & ~(pagesize-1L); 505 r.range.size += begin - r.range.address; 506 r.filesize += begin - r.range.address; 507 } 508 for (i = 1; i < num_unexec_regions; i++) { 509 if ((r.range.address + r.range.size) == unexec_regions[i].range.address) { 510 r.filesize += unexec_regions[i].filesize; 511 r.range.size += unexec_regions[i].range.size; 512 } else { /* All segments must be a multiple of pagesize */ 513 end = r.range.address + r.range.size; 514 if (end & (pagesize-1L)) { 515 end = ROUNDUP_TO_PAGE_BOUNDARY(end); 516 printf("Page (%#8lx) aligning region @%#8lx size from %#8lx to %#8lx\n", 517 (long)pagesize, (long)r.range.address, (long)r.range.size, (long)(end - r.range.address)); 518 r.range.size = end - r.range.address; 519 r.filesize = r.range.size; 520 if (end == unexec_regions[i].range.address) { 521 r.filesize += unexec_regions[i].filesize; 522 r.range.size += unexec_regions[i].range.size; 523 continue; 524 } 525 } 526 /* Truncate zerod pages */ 527 while (r.filesize > 0) { 528 vm_address_t p = r.range.address + r.filesize - pagesize; 529 if (memcmp(p, zeropage, pagesize) == 0) { 530 r.filesize -= pagesize; 531 } else { 532 break; 533 } 534 } 535 if (r.filesize != r.range.size) { 536 printf("Removed %lx zerod bytes from filesize\n", r.range.size - r.filesize); 537 } 538 unexec_regions[n++] = r; 539 r = unexec_regions[i]; 540 if (r.range.address & (pagesize-1L)) { /* Align beginning of unmerged region */ 541 begin = r.range.address; 542 r.range.address = r.range.address & ~(pagesize-1L); 543 r.range.size += begin - r.range.address; 544 r.filesize += begin - r.range.address; 545 } 546 } 547 } 548 end = r.range.address + r.range.size; 549 if (end & (pagesize-1L)) { 550 end = ROUNDUP_TO_PAGE_BOUNDARY(end); 551 printf("Page (%#8lx) aligning region @%#8lx size from %#8lx to %#8lx\n", 552 pagesize, (long)r.range.address, (long)r.range.size, (long)(end - r.range.address)); 553 r.range.size = end - r.range.address; 554 r.filesize = r.range.size; 555 } 556 /* Truncate zerod pages */ 557 while (r.filesize > 0) { 558 vm_address_t p = r.range.address + r.filesize - pagesize; 559 if (memcmp(p, zeropage, pagesize) == 0) { 560 r.filesize -= pagesize; 561 } else { 562 break; 563 } 564 } 565 free(zeropage); 566 if (r.filesize != r.range.size) { 567 printf("Removed %lx zerod bytes from filesize\n", r.range.size - r.filesize); 568 } 569 unexec_regions[n++] = r; 570 num_unexec_regions = n; 571} 572 573 574/* More informational messages routines. */ 575 576static void 577print_load_command_name (int lc) 578{ 579 switch (lc) 580 { 581 case LC_SEGMENT: 582 printf("LC_SEGMENT "); 583 break; 584 case LC_SYMTAB: 585 printf("LC_SYMTAB "); 586 break; 587 case LC_SYMSEG: 588 printf("LC_SYMSEG "); 589 break; 590 case LC_UNIXTHREAD: 591 printf("LC_UNIXTHREAD "); 592 break; 593 case LC_DYSYMTAB: 594 printf("LC_DYSYMTAB "); 595 break; 596 case LC_LOAD_DYLIB: 597 printf("LC_LOAD_DYLIB "); 598 break; 599 case LC_ID_DYLIB: 600 printf("LC_ID_DYLIB "); 601 break; 602 case LC_LOAD_DYLINKER: 603 printf("LC_LOAD_DYLINKER "); 604 break; 605 case LC_PREBOUND_DYLIB: 606 printf("LC_PREBOUND_DYLIB "); 607 break; 608 case LC_ROUTINES: 609 printf("LC_ROUTINES "); 610 break; 611 case LC_SUB_FRAMEWORK: 612 printf("LC_SUBFRAMEWORK "); 613 break; 614 case LC_SUB_UMBRELLA: 615 printf("LC_SUB_UMBRELLA "); 616 break; 617 case LC_SUB_CLIENT: 618 printf("LC_SUB_CLIENT "); 619 break; 620 case LC_SUB_LIBRARY: 621 printf("LC_SUB_LIBRARY "); 622 break; 623 case LC_TWOLEVEL_HINTS: 624 printf("LC_TWOLEVEL_HINTS "); 625 break; 626 case LC_PREBIND_CKSUM: 627 printf("LC_PREBIND_CKSUM "); 628 break; 629 case LC_LOAD_WEAK_DYLIB: 630 printf("LC_LOAD_WEAK_DYLIB "); 631 break; 632 case LC_SEGMENT_64: 633 printf("LC_SEGMENT_64 "); 634 break; 635 case LC_ROUTINES_64: 636 printf("LC_ROUTINES_64 "); 637 break; 638 case LC_UUID: 639 printf("LC_UUID "); 640 break; 641 case LC_RPATH: 642 printf("LC_RPATH "); 643 break; 644 case LC_CODE_SIGNATURE: 645 printf("LC_CODE_SIGNATURE "); 646 break; 647 case LC_SEGMENT_SPLIT_INFO: 648 printf("LC_SEGMENT_SPLIT_INFO "); 649 break; 650 case LC_REEXPORT_DYLIB: 651 printf("LC_REEXPORT_DYLIB "); 652 break; 653 case LC_LAZY_LOAD_DYLIB: 654 printf("LC_LAZY_LOAD_DYLIB "); 655 break; 656 case LC_ENCRYPTION_INFO: 657 printf("LC_ENCRYPTION_INFO "); 658 break; 659 case LC_DYLD_INFO: 660 printf("LC_DYLD_INFO "); 661 break; 662 case LC_DYLD_INFO_ONLY: 663 printf("LC_DYLD_INFO_ONLY "); 664 break; 665 case LC_LOAD_UPWARD_DYLIB: 666 printf("LC_LOAD_UPWARD_DYLIB "); 667 break; 668 case LC_VERSION_MIN_MACOSX: 669 printf("LC_VERSION_MIN_MACOSX "); 670 break; 671 case LC_VERSION_MIN_IPHONEOS: 672 printf("LC_VERSION_MIN_IPHONEOS"); 673 break; 674 case LC_FUNCTION_STARTS: 675 printf("LC_FUNCTION_STARTS "); 676 break; 677 case LC_DYLD_ENVIRONMENT: 678 printf("LC_DYLD_ENVIRONMENT "); 679 break; 680 case LC_SOURCE_VERSION: 681 printf("LC_SOURCE_VERSION "); 682 break; 683 case LC_DYLIB_CODE_SIGN_DRS: 684 printf("LC_DYLIB_CODE_SIGN_DRS "); 685 break; 686 case LC_MAIN: 687 printf("LC_MAIN "); 688 break; 689 case LC_DATA_IN_CODE: 690 printf("LC_DATA_IN_CODE "); 691 break; 692 default: 693 printf("unknown(%08x)", lc); 694 break; 695 } 696} 697 698static void 699print_load_command (struct load_command *lc) 700{ 701 print_load_command_name (lc->cmd); 702 printf ("%8d", lc->cmdsize); 703 704 if (lc->cmd == LC_SEGMENT || lc->cmd == LC_SEGMENT_64) 705 { 706 struct segment_command *scp; 707 struct section *sectp; 708 int j; 709 710 scp = (struct segment_command *) lc; 711 printf (" %-16.16s %#10lx %#8lx\n", 712 scp->segname, (long) (scp->vmaddr), (long) (scp->vmsize)); 713 714 sectp = (struct section *) (scp + 1); 715 for (j = 0; j < scp->nsects; j++) 716 { 717 printf (" %-16.16s %#10lx %#8lx (flags: %#8lx)\n", 718 sectp->sectname, (long) (sectp->addr), (long) (sectp->size), (long) (sectp->flags)); 719 sectp++; 720 } 721 } 722 else 723 printf ("\n"); 724} 725 726/* Read header and load commands from input file. Store the latter in 727 the global array lca. Store the total number of load commands in 728 global variable nlc. */ 729static void 730read_load_commands () 731{ 732 int i; 733 734 if (!unexec_read (&mh, sizeof (struct mach_header))) 735 unexec_error ("cannot read mach-o header"); 736 737 if (mh.magic != target_MH_MAGIC) 738 unexec_error ("input file not in correct Mach-O format"); 739 740 if (mh.filetype != MH_EXECUTE) 741 unexec_error ("input Mach-O file is not an executable object file"); 742 743#if VERBOSE 744 printf ("--- Header Information ---\n"); 745 printf ("Magic = 0x%08x\n", mh.magic); 746 printf ("CPUType = %d\n", mh.cputype); 747 printf ("CPUSubType = %d\n", mh.cpusubtype); 748 printf ("FileType = 0x%x\n", mh.filetype); 749 printf ("NCmds = %d\n", mh.ncmds); 750 printf ("SizeOfCmds = %d\n", mh.sizeofcmds); 751 printf ("Flags = 0x%08x\n", mh.flags); 752#endif 753 754 nlc = mh.ncmds; 755 lca = (struct load_command **) malloc (nlc * sizeof (struct load_command *)); 756 757 for (i = 0; i < nlc; i++) 758 { 759 struct load_command lc; 760 /* Load commands are variable-size: so read the command type and 761 size first and then read the rest. */ 762 if (!unexec_read (&lc, sizeof (struct load_command))) 763 unexec_error ("cannot read load command"); 764 lca[i] = (struct load_command *) malloc (lc.cmdsize); 765 memcpy (lca[i], &lc, sizeof (struct load_command)); 766 if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command))) 767 unexec_error ("cannot read content of load command"); 768 if (lc.cmd == LC_SEGMENT || lc.cmd == LC_SEGMENT_64) 769 { 770 struct segment_command *scp = (struct segment_command *) lca[i]; 771 772 if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr) 773 infile_lc_highest_addr = scp->vmaddr + scp->vmsize; 774 775 if (strncmp (scp->segname, SEG_TEXT, 16) == 0) 776 { 777 struct section *sectp = (struct section *) (scp + 1); 778 int j; 779 780 for (j = 0; j < scp->nsects; j++) 781 if (sectp->offset < text_seg_lowest_offset) 782 text_seg_lowest_offset = sectp->offset; 783 } 784 } 785 } 786 787 printf ("Highest address of load commands in input file: %#8lx\n", 788 (long)infile_lc_highest_addr); 789 790 printf ("Lowest offset of all sections in __TEXT segment: %#8lx\n", 791 text_seg_lowest_offset); 792 793 printf ("--- List of Load Commands in Input File ---\n"); 794 printf ("# cmd cmdsize name address size\n"); 795 796 for (i = 0; i < nlc; i++) 797 { 798 printf ("%1d ", i); 799 print_load_command (lca[i]); 800 } 801} 802 803/* Copy a LC_SEGMENT load command other than the __DATA segment from 804 the input file to the output file, adjusting the file offset of the 805 segment and the file offsets of sections contained in it. */ 806static void 807copy_segment (struct load_command *lc) 808{ 809 struct segment_command *scp = (struct segment_command *) lc; 810 unsigned long old_fileoff = scp->fileoff; 811 struct section *sectp; 812 int j; 813 814 scp->fileoff = curr_file_offset; 815 816 sectp = (struct section *) (scp + 1); 817 for (j = 0; j < scp->nsects; j++) 818 { 819 sectp->offset += curr_file_offset - old_fileoff; 820 sectp++; 821 } 822 823 printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n", 824 scp->segname, (long) (scp->fileoff), (long) (scp->filesize), 825 (long) (scp->vmsize), (long) (scp->vmaddr)); 826 827 if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize)) 828 unexec_error ("cannot copy segment from input to output file"); 829 curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize); 830 831 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 832 unexec_error ("cannot write load command to header"); 833 834 curr_header_offset += lc->cmdsize; 835} 836 837/* Copy a LC_SEGMENT load command for the __DATA segment in the input 838 file to the output file. We assume that only one such segment load 839 command exists in the input file and it contains the sections 840 __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and 841 __dyld. The first three of these should be dumped from memory and 842 the rest should be copied from the input file. Note that the 843 sections __bss and __common contain no data in the input file 844 because their flag fields have the value S_ZEROFILL. Dumping these 845 from memory makes it necessary to adjust file offset fields in 846 subsequently dumped load commands. Then, create new __DATA segment 847 load commands for regions on the region list other than the one 848 corresponding to the __DATA segment in the input file. */ 849static void 850copy_data_segment (struct load_command *lc) 851{ 852 struct segment_command *scp = (struct segment_command *) lc; 853 struct section *sectp; 854 int j; 855 unsigned long header_offset, old_file_offset; 856 857 /* The new filesize of the segment is set to its vmsize because data 858 blocks for segments must start at region boundaries. Note that 859 this may leave unused locations at the end of the segment data 860 block because the total of the sizes of all sections in the 861 segment is generally smaller than vmsize. */ 862 scp->filesize = scp->vmsize; 863 864 printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n", 865 scp->segname, curr_file_offset, (long)(scp->filesize), 866 (long)(scp->vmsize), (long) (scp->vmaddr)); 867 868 /* Offsets in the output file for writing the next section structure 869 and segment data block, respectively. */ 870 header_offset = curr_header_offset + sizeof (struct segment_command); 871 872 sectp = (struct section *) (scp + 1); 873 for (j = 0; j < scp->nsects; j++) 874 { 875 old_file_offset = sectp->offset; 876 sectp->offset = sectp->addr - scp->vmaddr + curr_file_offset; 877 /* The __data section is dumped from memory. The __bss and 878 __common sections are also dumped from memory but their flag 879 fields require changing (from S_ZEROFILL to S_REGULAR). The 880 other three kinds of sections are just copied from the input 881 file. */ 882 883 unsigned char sect_type = sectp->flags & SECTION_TYPE; 884 885 switch (sect_type) { 886 case S_LAZY_SYMBOL_POINTERS: 887 case S_NON_LAZY_SYMBOL_POINTERS: 888 case S_CSTRING_LITERALS: 889 if (!unexec_copy (sectp->offset, old_file_offset, sectp->size)) 890 unexec_error ("cannot copy section %s", sectp->sectname); 891 if (!unexec_write (header_offset, sectp, sizeof (struct section))) 892 unexec_error ("cannot write section %s's header", sectp->sectname); 893 break; 894 895 case S_REGULAR: 896 if (strncmp (sectp->sectname, "__const", 16) == 0 897 || strncmp(sectp->sectname, "__program_vars", 16) == 0) { 898 if (!unexec_copy (sectp->offset, old_file_offset, sectp->size)) 899 unexec_error ("cannot copy section %s", sectp->sectname); 900 } else { 901 if (!unexec_write (sectp->offset, (void *)sectp->addr, sectp->size)) 902 unexec_error ("cannot write section %s", sectp->sectname); 903 } 904 if (!unexec_write (header_offset, sectp, sizeof (struct section))) 905 unexec_error ("cannot write section %s's header", sectp->sectname); 906 break; 907 908 case S_ZEROFILL: 909 sectp->flags = S_REGULAR; 910 911 if (strncmp (sectp->sectname, SECT_BSS, 16) == 0) { 912 extern char *my_endbss_static; 913 unsigned long my_size; 914 915 /* Clear uninitialized local variables in statically linked 916 libraries. In particular, function pointers stored by 917 libSystemStub.a, which is introduced in Mac OS X 10.4 for 918 binary compatibility with respect to long double, are 919 cleared so that they will be reinitialized when the 920 dumped binary is executed on other versions of OS. */ 921 my_size = (unsigned long)my_endbss_static - sectp->addr; 922 if (!(sectp->addr <= (unsigned long)my_endbss_static 923 && my_size <= sectp->size)) 924 unexec_error ("my_endbss_static is not in section %s", 925 sectp->sectname); 926 if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size)) 927 unexec_error ("cannot write section %s", sectp->sectname); 928 if (!unexec_write_zero (sectp->offset + my_size, 929 sectp->size - my_size)) 930 unexec_error ("cannot write section %s", sectp->sectname); 931 if (!unexec_write (header_offset, sectp, sizeof (struct section))) 932 unexec_error ("cannot write section %s's header", sectp->sectname); 933 printf("copy SECT_BSS\n"); 934 } else { 935 if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size)) 936 unexec_error ("cannot write section %s", sectp->sectname); 937 if (!unexec_write (header_offset, sectp, sizeof (struct section))) 938 unexec_error ("cannot write section %s's header", sectp->sectname); 939 printf("copy %s\n", sectp->sectname); 940 } 941 break; 942 943 default: 944 unexec_error("unrecognized section type '0x%x' '%s' in __DATA segment", sect_type, sectp->sectname); 945 } 946 947 printf (" section %-16.16s at %#8lx - %#8lx (sz: %#8lx)\n", 948 sectp->sectname, (long) (sectp->offset), 949 (long) (sectp->offset + sectp->size), (long) (sectp->size)); 950 951 header_offset += sizeof (struct section); 952 sectp++; 953 } 954 955 curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize); 956 957 if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command))) 958 unexec_error ("cannot write header of __DATA segment"); 959 curr_header_offset += lc->cmdsize; 960 961 /* Create new __DATA segment load commands for regions on the region 962 list that do not corresponding to any segment load commands in 963 the input file. 964 */ 965 long total = 0; 966 for (j = 0; j < num_unexec_regions; j++) 967 { 968 struct segment_command sc; 969 970 sc.cmd = target_LC_SEGMENT; 971 sc.cmdsize = sizeof (struct segment_command); 972 strncpy (sc.segname, SEG_DATA, 16); 973 sc.vmaddr = unexec_regions[j].range.address; 974 sc.vmsize = unexec_regions[j].range.size; 975 sc.fileoff = curr_file_offset; 976 sc.filesize = unexec_regions[j].filesize; 977 sc.maxprot = VM_PROT_READ | VM_PROT_WRITE; 978 sc.initprot = VM_PROT_READ | VM_PROT_WRITE; 979 sc.nsects = 0; 980 sc.flags = 0; 981 total += sc.filesize; 982 printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n", 983 sc.segname, (long) (sc.fileoff), (long) (sc.filesize), 984 (long) (sc.vmsize), (long) (sc.vmaddr)); 985 986 if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.filesize)) 987 unexec_error ("cannot write new __DATA segment %#8lx (sz: %#8lx)", sc.vmaddr, sc.filesize); 988 curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize); 989 990 if (!unexec_write (curr_header_offset, &sc, sc.cmdsize)) 991 unexec_error ("cannot write new __DATA segment's header"); 992 curr_header_offset += sc.cmdsize; 993 mh.ncmds++; 994 } 995 printf("Total written: %ld\n", total); 996} 997 998/* Copy a LC_SYMTAB load command from the input file to the output 999 file, adjusting the file offset fields. */ 1000static void 1001copy_symtab (struct load_command *lc, long delta) 1002{ 1003 struct symtab_command *stp = (struct symtab_command *) lc; 1004 1005 stp->symoff += delta; 1006 stp->stroff += delta; 1007 1008 printf ("Writing "); 1009 print_load_command_name (lc->cmd); 1010 printf (" command\n"); 1011 1012 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 1013 unexec_error ("cannot write LC_SYMTAB command to header"); 1014 1015 curr_header_offset += lc->cmdsize; 1016} 1017 1018/* Copy a LC_DYLD_INFO_ONLY load command from the input file to the output 1019 file, adjusting the file offset fields. */ 1020static void 1021copy_dyld_info_only (struct load_command *lc, long delta) 1022{ 1023 struct dyld_info_command *dyld = (struct dyld_info_command *) lc; 1024 1025 if (dyld->rebase_size) 1026 dyld->rebase_off += delta; 1027 if (dyld->bind_size) 1028 dyld->bind_off += delta; 1029 if (dyld->weak_bind_size) 1030 dyld->weak_bind_off += delta; 1031 if (dyld->lazy_bind_size) 1032 dyld->lazy_bind_off += delta; 1033 if (dyld->export_size) 1034 dyld->export_off += delta; 1035 1036 printf ("Writing "); 1037 print_load_command_name (lc->cmd); 1038 printf (" command\n"); 1039 1040 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 1041 unexec_error ("cannot write LC_DYLD_INFO_ONLY command to header"); 1042 1043 curr_header_offset += lc->cmdsize; 1044} 1045 1046/* Copy a LC_DYLIB_CODE_SIGN_DRS load command from the input file to the output 1047 file, adjusting the file offset fields. */ 1048static void 1049copy_linkedit_data (struct load_command *lc, long delta) 1050{ 1051 struct linkedit_data_command *data = (struct linkedit_data_command *) lc; 1052 1053 if (data->dataoff) 1054 data->dataoff += delta; 1055 1056 printf ("Writing "); 1057 print_load_command_name (lc->cmd); 1058 printf (" command\n"); 1059 1060 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 1061 unexec_error ("cannot write %d command to header", lc->cmd); 1062 1063 curr_header_offset += lc->cmdsize; 1064} 1065/* Fix up relocation entries. */ 1066static void 1067unrelocate (const char *name, off_t reloff, int nrel) 1068{ 1069 int i, unreloc_count; 1070 struct relocation_info reloc_info; 1071 struct scattered_relocation_info *sc_reloc_info 1072 = (struct scattered_relocation_info *) &reloc_info; 1073 1074 for (unreloc_count = 0, i = 0; i < nrel; i++) 1075 { 1076 if (lseek (infd, reloff, L_SET) != reloff) 1077 unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i); 1078 if (!unexec_read (&reloc_info, sizeof (reloc_info))) 1079 unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i); 1080 reloff += sizeof (reloc_info); 1081 1082 if (sc_reloc_info->r_scattered == 0) 1083 switch (reloc_info.r_type) 1084 { 1085 case GENERIC_RELOC_VANILLA: 1086 if (reloc_info.r_address >= data_segment_scp->vmaddr 1087 && reloc_info.r_address < (data_segment_scp->vmaddr 1088 + data_segment_scp->vmsize)) 1089 { 1090 off_t src_off = data_segment_old_fileoff 1091 + reloc_info.r_address - data_segment_scp->vmaddr; 1092 off_t dst_off = data_segment_scp->fileoff 1093 + reloc_info.r_address - data_segment_scp->vmaddr; 1094 1095 if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length)) 1096 unexec_error ("unrelocate: %s:%d cannot copy original value", 1097 name, i); 1098 unreloc_count++; 1099 } 1100 break; 1101 default: 1102 unexec_error ("unrelocate: %s:%d cannot handle type = %d", 1103 name, i, reloc_info.r_type); 1104 } 1105 else 1106 switch (sc_reloc_info->r_type) 1107 { 1108#if defined (__ppc__) 1109 case PPC_RELOC_PB_LA_PTR: 1110 /* nothing to do for prebound lazy pointer */ 1111 break; 1112#endif 1113 default: 1114 unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d", 1115 name, i, sc_reloc_info->r_type); 1116 } 1117 } 1118 1119 if (nrel > 0) 1120 printf ("Fixed up %d/%d %s relocation entries in data segment.\n", 1121 unreloc_count, nrel, name); 1122} 1123 1124/* Copy a LC_DYSYMTAB load command from the input file to the output 1125 file, adjusting the file offset fields. */ 1126static void 1127copy_dysymtab (struct load_command *lc, long delta) 1128{ 1129 struct dysymtab_command *dstp = (struct dysymtab_command *) lc; 1130 1131 unrelocate ("local", dstp->locreloff, dstp->nlocrel); 1132 unrelocate ("external", dstp->extreloff, dstp->nextrel); 1133 1134 if (dstp->nextrel > 0) { 1135 dstp->extreloff += delta; 1136 } 1137 1138 if (dstp->nlocrel > 0) { 1139 dstp->locreloff += delta; 1140 } 1141 1142 if (dstp->nindirectsyms > 0) 1143 dstp->indirectsymoff += delta; 1144 1145 printf ("Writing "); 1146 print_load_command_name (lc->cmd); 1147 printf (" command\n"); 1148 1149 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 1150 unexec_error ("cannot write symtab command to header"); 1151 1152 curr_header_offset += lc->cmdsize; 1153} 1154 1155/* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output 1156 file, adjusting the file offset fields. */ 1157static void 1158copy_twolevelhints (struct load_command *lc, long delta) 1159{ 1160 struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc; 1161 1162 if (tlhp->nhints > 0) { 1163 tlhp->offset += delta; 1164 } 1165 1166 printf ("Writing "); 1167 print_load_command_name (lc->cmd); 1168 printf (" command\n"); 1169 1170 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 1171 unexec_error ("cannot write two level hint command to header"); 1172 1173 curr_header_offset += lc->cmdsize; 1174} 1175 1176/* Copy other kinds of load commands from the input file to the output 1177 file, ones that do not require adjustments of file offsets. */ 1178static void 1179copy_other (struct load_command *lc) 1180{ 1181 printf ("Writing "); 1182 print_load_command_name (lc->cmd); 1183 printf (" command\n"); 1184 1185 if (lc->cmd == LC_CODE_SIGNATURE) 1186 lc->cmd = 0x0; /* Don't propagate signature */ 1187 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 1188 unexec_error ("cannot write load command to header"); 1189 1190 curr_header_offset += lc->cmdsize; 1191} 1192 1193/* Loop through all load commands and dump them. Then write the Mach 1194 header. */ 1195static void 1196dump_it () 1197{ 1198 int i; 1199 long linkedit_delta = 0; 1200 1201 printf ("--- Load Commands written to Output File ---\n"); 1202 1203 for (i = 0; i < nlc; i++) 1204 switch (lca[i]->cmd) 1205 { 1206 case target_LC_SEGMENT: 1207 { 1208 struct segment_command *scp = (struct segment_command *) lca[i]; 1209 if (strncmp (scp->segname, SEG_DATA, 16) == 0) 1210 { 1211 /* save data segment file offset and segment_command for 1212 unrelocate */ 1213 if (data_segment_old_fileoff) 1214 unexec_error ("cannot handle multiple DATA segments" 1215 " in input file"); 1216 data_segment_old_fileoff = scp->fileoff; 1217 data_segment_scp = scp; 1218 1219 copy_data_segment (lca[i]); 1220 } 1221 else 1222 { 1223 if (strncmp (scp->segname, SEG_LINKEDIT, 16) == 0) 1224 { 1225 if (linkedit_delta) 1226 unexec_error ("cannot handle multiple LINKEDIT segments" 1227 " in input file"); 1228 linkedit_delta = curr_file_offset - scp->fileoff; 1229 } 1230 1231 copy_segment (lca[i]); 1232 } 1233 } 1234 break; 1235 case LC_SYMTAB: 1236 copy_symtab (lca[i], linkedit_delta); 1237 break; 1238 case LC_DYSYMTAB: 1239 copy_dysymtab (lca[i], linkedit_delta); 1240 break; 1241 case LC_TWOLEVEL_HINTS: 1242 copy_twolevelhints (lca[i], linkedit_delta); 1243 break; 1244 case LC_DYLD_INFO_ONLY: 1245 copy_dyld_info_only(lca[i], linkedit_delta); 1246 break; 1247 case LC_CODE_SIGNATURE: 1248 case LC_SEGMENT_SPLIT_INFO: 1249 case LC_FUNCTION_STARTS: 1250 case LC_DATA_IN_CODE: 1251 case LC_DYLIB_CODE_SIGN_DRS: 1252 copy_linkedit_data(lca[i], linkedit_delta); 1253 break; 1254 1255 default: 1256 copy_other (lca[i]); 1257 break; 1258 } 1259 1260 if (curr_header_offset > text_seg_lowest_offset) 1261 unexec_error ("not enough room for load commands for new __DATA segments"); 1262 1263 printf ("%ld unused bytes follow Mach-O header\n", 1264 text_seg_lowest_offset - curr_header_offset); 1265 1266 mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header); 1267 if (!unexec_write (0, &mh, sizeof (struct mach_header))) 1268 unexec_error ("cannot write final header contents"); 1269} 1270 1271/* Take a snapshot of Emacs and make a Mach-O format executable file 1272 from it. The file names of the output and input files are outfile 1273 and infile, respectively. The three other parameters are 1274 ignored. */ 1275void 1276unexec (char *outfile, char *infile, void *start_data, void *start_bss, 1277 void *entry_address) 1278{ 1279 if (in_dumped_exec) 1280 unexec_error ("Unexec from a dumped executable is not supported."); 1281 1282 pagesize = getpagesize (); 1283 infd = open (infile, O_RDONLY, 0); 1284 if (infd < 0) 1285 { 1286 unexec_error ("cannot open input file `%s'", infile); 1287 } 1288 1289 outfd = open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0755); 1290 if (outfd < 0) 1291 { 1292 close (infd); 1293 unexec_error ("cannot open output file `%s'", outfile); 1294 } 1295 1296 build_region_list (); 1297 read_load_commands (); 1298 1299 find_emacs_zone_regions (); 1300 unexec_regions_merge (); 1301 1302 in_dumped_exec = 1; 1303 1304 dump_it (); 1305 1306 close (outfd); 1307} 1308 1309 1310void 1311unexec_init_emacs_zone () 1312{ 1313 emacs_zone = malloc_create_zone (0, 0); 1314 malloc_set_zone_name (emacs_zone, "EmacsZone"); 1315} 1316 1317#ifndef MACOSX_MALLOC_MULT16 1318#define MACOSX_MALLOC_MULT16 1 1319#endif 1320 1321typedef struct unexec_malloc_header { 1322 union { 1323 char c[8]; 1324 size_t size; 1325 } u; 1326} unexec_malloc_header_t; 1327 1328#if MACOSX_MALLOC_MULT16 1329 1330#define ptr_in_unexec_regions(p) ((((vm_address_t) (p)) & 8) != 0) 1331 1332#else 1333 1334int 1335ptr_in_unexec_regions (void *ptr) 1336{ 1337 int i; 1338 1339 for (i = 0; i < num_unexec_regions; i++) 1340 if ((vm_address_t) ptr - unexec_regions[i].range.address 1341 < unexec_regions[i].range.size) 1342 return 1; 1343 1344 return 0; 1345} 1346 1347#endif 1348 1349void * 1350unexec_malloc (size_t size) 1351{ 1352 if (in_dumped_exec) 1353 { 1354 void *p; 1355 1356 p = malloc (size); 1357#if MACOSX_MALLOC_MULT16 1358 assert (((vm_address_t) p % 16) == 0); 1359#endif 1360 return p; 1361 } 1362 else 1363 { 1364 unexec_malloc_header_t *ptr; 1365 1366 ptr = (unexec_malloc_header_t *) 1367 malloc_zone_malloc (emacs_zone, size + sizeof (unexec_malloc_header_t)); 1368 ptr->u.size = size; 1369 ptr++; 1370#if MACOSX_MALLOC_MULT16 1371 assert (((vm_address_t) ptr % 16) == 8); 1372#endif 1373 return (void *) ptr; 1374 } 1375} 1376 1377void * 1378unexec_realloc (void *old_ptr, size_t new_size) 1379{ 1380 if (in_dumped_exec) 1381 { 1382 void *p; 1383 1384 if (ptr_in_unexec_regions (old_ptr)) 1385 { 1386 size_t old_size = ((unexec_malloc_header_t *) old_ptr)[-1].u.size; 1387 size_t size = new_size > old_size ? old_size : new_size; 1388 1389 p = (size_t *) malloc (new_size); 1390 if (size) 1391 memcpy (p, old_ptr, size); 1392 } 1393 else 1394 { 1395 p = realloc (old_ptr, new_size); 1396 } 1397#if MACOSX_MALLOC_MULT16 1398 assert (((vm_address_t) p % 16) == 0); 1399#endif 1400 return p; 1401 } 1402 else 1403 { 1404 unexec_malloc_header_t *ptr; 1405 1406 ptr = (unexec_malloc_header_t *) 1407 malloc_zone_realloc (emacs_zone, (unexec_malloc_header_t *) old_ptr - 1, 1408 new_size + sizeof (unexec_malloc_header_t)); 1409 ptr->u.size = new_size; 1410 ptr++; 1411#if MACOSX_MALLOC_MULT16 1412 assert (((vm_address_t) ptr % 16) == 8); 1413#endif 1414 return (void *) ptr; 1415 } 1416} 1417 1418void 1419unexec_free (void *ptr) 1420{ 1421 if (in_dumped_exec) 1422 { 1423 if (!ptr_in_unexec_regions (ptr)) 1424 free (ptr); 1425 } 1426 else 1427 malloc_zone_free (emacs_zone, (unexec_malloc_header_t *) ptr - 1); 1428} 1429 1430/* arch-tag: 1a784f7b-a184-4c4f-9544-da8619593d72 1431 (do not change this comment) */ 1432