comparison src/unexmacosx.c @ 73613:fd7f97a75198

2006-11-02 Nozomu Ando <nand@mac.com> * unexmacosx.c (mach_header, segment_command, vm_region, section) [_LP64]: New defines. (VM_REGION_BASIC_INFO_COUNT, VM_REGION_BASIC_INFO, LC_SEGMENT) (MH_MAGIC) [_LP64]: Redefine. (delta): Remove variable. (curr_file_offset, pagesize): New variables. (ROUNDUP_TO_PAGE_BOUNDARY): New macro. (data_segment_old_fileoff): Initialize explicitly. (print_region, unexec_regions_recorder, print_load_command_name) (copy_segment, copy_data_segment): Use long format in printf. (MAX_UNEXEC_REGIONS): Increase to 400. (unexec_regions_recorder): Don't warn too many regions here. (find_emacs_zone_regions): Warn too many regions here. (print_load_command_name) [_LP64]: Show correct load command name. (copy_segment, copy_data_segment): Use variable `curr_file_offset'. Show starting virtual memory address. Don't show ending file offset. (copy_symtab, copy_dysymtab, copy_twolevelhints): New argument DELTA. (dump_it): Use new local variable `linkedit_delta' and pass to them. Error if trying to handle multiple DATA segments. (unexec): Initialize variable `pagesize'.
author YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
date Thu, 02 Nov 2006 04:37:26 +0000
parents 470ac698d6f7
children 04b7851d50f8
comparison
equal deleted inserted replaced
73612:0dc9329d69be 73613:fd7f97a75198
110 #include <objc/malloc.h> 110 #include <objc/malloc.h>
111 #endif 111 #endif
112 112
113 #include <assert.h> 113 #include <assert.h>
114 114
115 #ifdef _LP64
116 #define mach_header mach_header_64
117 #define segment_command segment_command_64
118 #undef VM_REGION_BASIC_INFO_COUNT
119 #define VM_REGION_BASIC_INFO_COUNT VM_REGION_BASIC_INFO_COUNT_64
120 #undef VM_REGION_BASIC_INFO
121 #define VM_REGION_BASIC_INFO VM_REGION_BASIC_INFO_64
122 #undef LC_SEGMENT
123 #define LC_SEGMENT LC_SEGMENT_64
124 #define vm_region vm_region_64
125 #define section section_64
126 #undef MH_MAGIC
127 #define MH_MAGIC MH_MAGIC_64
128 #endif
115 129
116 #define VERBOSE 1 130 #define VERBOSE 1
117 131
118 /* Size of buffer used to copy data from the input file to the output 132 /* Size of buffer used to copy data from the input file to the output
119 file in function unexec_copy. */ 133 file in function unexec_copy. */
162 struct mach_header mh; 176 struct mach_header mh;
163 177
164 /* Offset at which the next load command should be written. */ 178 /* Offset at which the next load command should be written. */
165 unsigned long curr_header_offset = sizeof (struct mach_header); 179 unsigned long curr_header_offset = sizeof (struct mach_header);
166 180
167 /* Current adjustment that needs to be made to offset values because 181 /* Offset at which the next segment should be written. */
168 of additional data segments. */ 182 static unsigned long curr_file_offset = 0;
169 unsigned long delta = 0; 183
184 static unsigned long pagesize;
185 #define ROUNDUP_TO_PAGE_BOUNDARY(x) (((x) + pagesize - 1) & ~(pagesize - 1))
170 186
171 int infd, outfd; 187 int infd, outfd;
172 188
173 int in_dumped_exec = 0; 189 int in_dumped_exec = 0;
174 190
175 malloc_zone_t *emacs_zone; 191 malloc_zone_t *emacs_zone;
176 192
177 /* file offset of input file's data segment */ 193 /* file offset of input file's data segment */
178 off_t data_segment_old_fileoff; 194 off_t data_segment_old_fileoff = 0;
179 195
180 struct segment_command *data_segment_scp; 196 struct segment_command *data_segment_scp;
181 197
182 /* Read N bytes from infd into memory starting at address DEST. 198 /* Read N bytes from infd into memory starting at address DEST.
183 Return true if successful, false otherwise. */ 199 Return true if successful, false otherwise. */
284 300
285 static void 301 static void
286 print_region (vm_address_t address, vm_size_t size, vm_prot_t prot, 302 print_region (vm_address_t address, vm_size_t size, vm_prot_t prot,
287 vm_prot_t max_prot) 303 vm_prot_t max_prot)
288 { 304 {
289 printf ("%#10x %#8x ", address, size); 305 printf ("%#10lx %#8lx ", (long) address, (long) size);
290 print_prot (prot); 306 print_prot (prot);
291 putchar (' '); 307 putchar (' ');
292 print_prot (max_prot); 308 print_prot (max_prot);
293 putchar ('\n'); 309 putchar ('\n');
294 } 310 }
410 printf ("--- List of Regions to be Dumped ---\n"); 426 printf ("--- List of Regions to be Dumped ---\n");
411 print_region_list (); 427 print_region_list ();
412 } 428 }
413 429
414 430
415 #define MAX_UNEXEC_REGIONS 200 431 #define MAX_UNEXEC_REGIONS 400
416 432
417 int num_unexec_regions; 433 int num_unexec_regions;
418 vm_range_t unexec_regions[MAX_UNEXEC_REGIONS]; 434 vm_range_t unexec_regions[MAX_UNEXEC_REGIONS];
419 435
420 static void 436 static void
422 vm_range_t *ranges, unsigned num) 438 vm_range_t *ranges, unsigned num)
423 { 439 {
424 while (num && num_unexec_regions < MAX_UNEXEC_REGIONS) 440 while (num && num_unexec_regions < MAX_UNEXEC_REGIONS)
425 { 441 {
426 unexec_regions[num_unexec_regions++] = *ranges; 442 unexec_regions[num_unexec_regions++] = *ranges;
427 printf ("%#8x (sz: %#8x)\n", ranges->address, ranges->size); 443 printf ("%#8lx (sz: %#8lx)\n",
444 (long) (ranges->address), (long) (ranges->size));
428 ranges++; num--; 445 ranges++; num--;
429 } 446 }
430 if (num_unexec_regions == MAX_UNEXEC_REGIONS)
431 fprintf (stderr, "malloc_freezedry_recorder: too many regions\n");
432 } 447 }
433 448
434 static kern_return_t 449 static kern_return_t
435 unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr) 450 unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr)
436 { 451 {
447 MALLOC_PTR_REGION_RANGE_TYPE 462 MALLOC_PTR_REGION_RANGE_TYPE
448 | MALLOC_ADMIN_REGION_RANGE_TYPE, 463 | MALLOC_ADMIN_REGION_RANGE_TYPE,
449 (vm_address_t) emacs_zone, 464 (vm_address_t) emacs_zone,
450 unexec_reader, 465 unexec_reader,
451 unexec_regions_recorder); 466 unexec_regions_recorder);
467
468 if (num_unexec_regions == MAX_UNEXEC_REGIONS)
469 unexec_error ("find_emacs_zone_regions: too many regions");
452 } 470 }
453 471
454 static int 472 static int
455 unexec_regions_sort_compare (const void *a, const void *b) 473 unexec_regions_sort_compare (const void *a, const void *b)
456 { 474 {
498 print_load_command_name (int lc) 516 print_load_command_name (int lc)
499 { 517 {
500 switch (lc) 518 switch (lc)
501 { 519 {
502 case LC_SEGMENT: 520 case LC_SEGMENT:
521 #ifndef _LP64
503 printf ("LC_SEGMENT "); 522 printf ("LC_SEGMENT ");
523 #else
524 printf ("LC_SEGMENT_64 ");
525 #endif
504 break; 526 break;
505 case LC_LOAD_DYLINKER: 527 case LC_LOAD_DYLINKER:
506 printf ("LC_LOAD_DYLINKER "); 528 printf ("LC_LOAD_DYLINKER ");
507 break; 529 break;
508 case LC_LOAD_DYLIB: 530 case LC_LOAD_DYLIB:
539 struct segment_command *scp; 561 struct segment_command *scp;
540 struct section *sectp; 562 struct section *sectp;
541 int j; 563 int j;
542 564
543 scp = (struct segment_command *) lc; 565 scp = (struct segment_command *) lc;
544 printf (" %-16.16s %#10x %#8x\n", 566 printf (" %-16.16s %#10lx %#8lx\n",
545 scp->segname, scp->vmaddr, scp->vmsize); 567 scp->segname, (long) (scp->vmaddr), (long) (scp->vmsize));
546 568
547 sectp = (struct section *) (scp + 1); 569 sectp = (struct section *) (scp + 1);
548 for (j = 0; j < scp->nsects; j++) 570 for (j = 0; j < scp->nsects; j++)
549 { 571 {
550 printf (" %-16.16s %#10x %#8x\n", 572 printf (" %-16.16s %#10lx %#8lx\n",
551 sectp->sectname, sectp->addr, sectp->size); 573 sectp->sectname, (long) (sectp->addr), (long) (sectp->size));
552 sectp++; 574 sectp++;
553 } 575 }
554 } 576 }
555 else 577 else
556 printf ("\n"); 578 printf ("\n");
642 struct segment_command *scp = (struct segment_command *) lc; 664 struct segment_command *scp = (struct segment_command *) lc;
643 unsigned long old_fileoff = scp->fileoff; 665 unsigned long old_fileoff = scp->fileoff;
644 struct section *sectp; 666 struct section *sectp;
645 int j; 667 int j;
646 668
647 scp->fileoff += delta; 669 scp->fileoff = curr_file_offset;
648 670
649 sectp = (struct section *) (scp + 1); 671 sectp = (struct section *) (scp + 1);
650 for (j = 0; j < scp->nsects; j++) 672 for (j = 0; j < scp->nsects; j++)
651 { 673 {
652 sectp->offset += delta; 674 sectp->offset += curr_file_offset - old_fileoff;
653 sectp++; 675 sectp++;
654 } 676 }
655 677
656 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n", 678 printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
657 scp->segname, scp->fileoff, scp->fileoff + scp->filesize, 679 scp->segname, (long) (scp->fileoff), (long) (scp->vmsize),
658 scp->filesize); 680 (long) (scp->vmaddr));
659 681
660 if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize)) 682 if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize))
661 unexec_error ("cannot copy segment from input to output file"); 683 unexec_error ("cannot copy segment from input to output file");
684 curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
685
662 if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) 686 if (!unexec_write (curr_header_offset, lc, lc->cmdsize))
663 unexec_error ("cannot write load command to header"); 687 unexec_error ("cannot write load command to header");
664 688
665 curr_header_offset += lc->cmdsize; 689 curr_header_offset += lc->cmdsize;
666 } 690 }
683 struct segment_command *scp = (struct segment_command *) lc; 707 struct segment_command *scp = (struct segment_command *) lc;
684 struct section *sectp; 708 struct section *sectp;
685 int j; 709 int j;
686 unsigned long header_offset, file_offset, old_file_offset; 710 unsigned long header_offset, file_offset, old_file_offset;
687 711
688 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n", 712 printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
689 scp->segname, scp->fileoff, scp->fileoff + scp->filesize, 713 scp->segname, curr_file_offset, (long)(scp->vmsize),
690 scp->filesize); 714 (long) (scp->vmaddr));
691
692 if (delta != 0)
693 unexec_error ("cannot handle multiple DATA segments in input file");
694 715
695 /* Offsets in the output file for writing the next section structure 716 /* Offsets in the output file for writing the next section structure
696 and segment data block, respectively. */ 717 and segment data block, respectively. */
697 header_offset = curr_header_offset + sizeof (struct segment_command); 718 header_offset = curr_header_offset + sizeof (struct segment_command);
698 719
699 sectp = (struct section *) (scp + 1); 720 sectp = (struct section *) (scp + 1);
700 for (j = 0; j < scp->nsects; j++) 721 for (j = 0; j < scp->nsects; j++)
701 { 722 {
702 old_file_offset = sectp->offset; 723 old_file_offset = sectp->offset;
703 sectp->offset = sectp->addr - scp->vmaddr + scp->fileoff; 724 sectp->offset = sectp->addr - scp->vmaddr + curr_file_offset;
704 /* The __data section is dumped from memory. The __bss and 725 /* The __data section is dumped from memory. The __bss and
705 __common sections are also dumped from memory but their flag 726 __common sections are also dumped from memory but their flag
706 fields require changing (from S_ZEROFILL to S_REGULAR). The 727 fields require changing (from S_ZEROFILL to S_REGULAR). The
707 other three kinds of sections are just copied from the input 728 other three kinds of sections are just copied from the input
708 file. */ 729 file. */
760 unexec_error ("cannot write section %s's header", sectp->sectname); 781 unexec_error ("cannot write section %s's header", sectp->sectname);
761 } 782 }
762 else 783 else
763 unexec_error ("unrecognized section name in __DATA segment"); 784 unexec_error ("unrecognized section name in __DATA segment");
764 785
765 printf (" section %-16.16s at %#8x - %#8x (sz: %#8x)\n", 786 printf (" section %-16.16s at %#8lx - %#8lx (sz: %#8lx)\n",
766 sectp->sectname, sectp->offset, sectp->offset + sectp->size, 787 sectp->sectname, (long) (sectp->offset),
767 sectp->size); 788 (long) (sectp->offset + sectp->size), (long) (sectp->size));
768 789
769 header_offset += sizeof (struct section); 790 header_offset += sizeof (struct section);
770 sectp++; 791 sectp++;
771 } 792 }
772 793
773 /* The new filesize of the segment is set to its vmsize because data 794 /* The new filesize of the segment is set to its vmsize because data
774 blocks for segments must start at region boundaries. Note that 795 blocks for segments must start at region boundaries. Note that
775 this may leave unused locations at the end of the segment data 796 this may leave unused locations at the end of the segment data
776 block because the total of the sizes of all sections in the 797 block because the total of the sizes of all sections in the
777 segment is generally smaller than vmsize. */ 798 segment is generally smaller than vmsize. */
778 delta = scp->vmsize - scp->filesize;
779 scp->filesize = scp->vmsize; 799 scp->filesize = scp->vmsize;
780 if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command))) 800 if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command)))
781 unexec_error ("cannot write header of __DATA segment"); 801 unexec_error ("cannot write header of __DATA segment");
782 curr_header_offset += lc->cmdsize; 802 curr_header_offset += lc->cmdsize;
803 curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize);
783 804
784 /* Create new __DATA segment load commands for regions on the region 805 /* Create new __DATA segment load commands for regions on the region
785 list that do not corresponding to any segment load commands in 806 list that do not corresponding to any segment load commands in
786 the input file. 807 the input file.
787 */ 808 */
788 file_offset = scp->fileoff + scp->filesize;
789 for (j = 0; j < num_unexec_regions; j++) 809 for (j = 0; j < num_unexec_regions; j++)
790 { 810 {
791 struct segment_command sc; 811 struct segment_command sc;
792 812
793 sc.cmd = LC_SEGMENT; 813 sc.cmd = LC_SEGMENT;
794 sc.cmdsize = sizeof (struct segment_command); 814 sc.cmdsize = sizeof (struct segment_command);
795 strncpy (sc.segname, SEG_DATA, 16); 815 strncpy (sc.segname, SEG_DATA, 16);
796 sc.vmaddr = unexec_regions[j].address; 816 sc.vmaddr = unexec_regions[j].address;
797 sc.vmsize = unexec_regions[j].size; 817 sc.vmsize = unexec_regions[j].size;
798 sc.fileoff = file_offset; 818 sc.fileoff = curr_file_offset;
799 sc.filesize = unexec_regions[j].size; 819 sc.filesize = unexec_regions[j].size;
800 sc.maxprot = VM_PROT_READ | VM_PROT_WRITE; 820 sc.maxprot = VM_PROT_READ | VM_PROT_WRITE;
801 sc.initprot = VM_PROT_READ | VM_PROT_WRITE; 821 sc.initprot = VM_PROT_READ | VM_PROT_WRITE;
802 sc.nsects = 0; 822 sc.nsects = 0;
803 sc.flags = 0; 823 sc.flags = 0;
804 824
805 printf ("Writing segment %-16.16s at %#8x - %#8x (sz: %#8x)\n", 825 printf ("Writing segment %-16.16s @ %#8lx (%#8lx @ %#8lx)\n",
806 sc.segname, sc.fileoff, sc.fileoff + sc.filesize, 826 sc.segname, (long) (sc.fileoff), (long) (sc.vmsize),
807 sc.filesize); 827 (long) (sc.vmaddr));
808 828
809 if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize)) 829 if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.vmsize))
810 unexec_error ("cannot write new __DATA segment"); 830 unexec_error ("cannot write new __DATA segment");
811 delta += sc.filesize; 831 curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize);
812 file_offset += sc.filesize;
813 832
814 if (!unexec_write (curr_header_offset, &sc, sc.cmdsize)) 833 if (!unexec_write (curr_header_offset, &sc, sc.cmdsize))
815 unexec_error ("cannot write new __DATA segment's header"); 834 unexec_error ("cannot write new __DATA segment's header");
816 curr_header_offset += sc.cmdsize; 835 curr_header_offset += sc.cmdsize;
817 mh.ncmds++; 836 mh.ncmds++;
819 } 838 }
820 839
821 /* Copy a LC_SYMTAB load command from the input file to the output 840 /* Copy a LC_SYMTAB load command from the input file to the output
822 file, adjusting the file offset fields. */ 841 file, adjusting the file offset fields. */
823 static void 842 static void
824 copy_symtab (struct load_command *lc) 843 copy_symtab (struct load_command *lc, long delta)
825 { 844 {
826 struct symtab_command *stp = (struct symtab_command *) lc; 845 struct symtab_command *stp = (struct symtab_command *) lc;
827 846
828 stp->symoff += delta; 847 stp->symoff += delta;
829 stp->stroff += delta; 848 stp->stroff += delta;
896 } 915 }
897 916
898 /* Copy a LC_DYSYMTAB load command from the input file to the output 917 /* Copy a LC_DYSYMTAB load command from the input file to the output
899 file, adjusting the file offset fields. */ 918 file, adjusting the file offset fields. */
900 static void 919 static void
901 copy_dysymtab (struct load_command *lc) 920 copy_dysymtab (struct load_command *lc, long delta)
902 { 921 {
903 struct dysymtab_command *dstp = (struct dysymtab_command *) lc; 922 struct dysymtab_command *dstp = (struct dysymtab_command *) lc;
904 923
905 unrelocate ("local", dstp->locreloff, dstp->nlocrel); 924 unrelocate ("local", dstp->locreloff, dstp->nlocrel);
906 unrelocate ("external", dstp->extreloff, dstp->nextrel); 925 unrelocate ("external", dstp->extreloff, dstp->nextrel);
925 } 944 }
926 945
927 /* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output 946 /* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output
928 file, adjusting the file offset fields. */ 947 file, adjusting the file offset fields. */
929 static void 948 static void
930 copy_twolevelhints (struct load_command *lc) 949 copy_twolevelhints (struct load_command *lc, long delta)
931 { 950 {
932 struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc; 951 struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc;
933 952
934 if (tlhp->nhints > 0) { 953 if (tlhp->nhints > 0) {
935 tlhp->offset += delta; 954 tlhp->offset += delta;
962 header. */ 981 header. */
963 static void 982 static void
964 dump_it () 983 dump_it ()
965 { 984 {
966 int i; 985 int i;
986 long linkedit_delta = 0;
967 987
968 printf ("--- Load Commands written to Output File ---\n"); 988 printf ("--- Load Commands written to Output File ---\n");
969 989
970 for (i = 0; i < nlc; i++) 990 for (i = 0; i < nlc; i++)
971 switch (lca[i]->cmd) 991 switch (lca[i]->cmd)
975 struct segment_command *scp = (struct segment_command *) lca[i]; 995 struct segment_command *scp = (struct segment_command *) lca[i];
976 if (strncmp (scp->segname, SEG_DATA, 16) == 0) 996 if (strncmp (scp->segname, SEG_DATA, 16) == 0)
977 { 997 {
978 /* save data segment file offset and segment_command for 998 /* save data segment file offset and segment_command for
979 unrelocate */ 999 unrelocate */
1000 if (data_segment_old_fileoff)
1001 unexec_error ("cannot handle multiple DATA segments"
1002 " in input file");
980 data_segment_old_fileoff = scp->fileoff; 1003 data_segment_old_fileoff = scp->fileoff;
981 data_segment_scp = scp; 1004 data_segment_scp = scp;
982 1005
983 copy_data_segment (lca[i]); 1006 copy_data_segment (lca[i]);
984 } 1007 }
985 else 1008 else
986 { 1009 {
1010 if (strncmp (scp->segname, SEG_LINKEDIT, 16) == 0)
1011 {
1012 if (linkedit_delta)
1013 unexec_error ("cannot handle multiple LINKEDIT segments"
1014 " in input file");
1015 linkedit_delta = curr_file_offset - scp->fileoff;
1016 }
1017
987 copy_segment (lca[i]); 1018 copy_segment (lca[i]);
988 } 1019 }
989 } 1020 }
990 break; 1021 break;
991 case LC_SYMTAB: 1022 case LC_SYMTAB:
992 copy_symtab (lca[i]); 1023 copy_symtab (lca[i], linkedit_delta);
993 break; 1024 break;
994 case LC_DYSYMTAB: 1025 case LC_DYSYMTAB:
995 copy_dysymtab (lca[i]); 1026 copy_dysymtab (lca[i], linkedit_delta);
996 break; 1027 break;
997 case LC_TWOLEVEL_HINTS: 1028 case LC_TWOLEVEL_HINTS:
998 copy_twolevelhints (lca[i]); 1029 copy_twolevelhints (lca[i], linkedit_delta);
999 break; 1030 break;
1000 default: 1031 default:
1001 copy_other (lca[i]); 1032 copy_other (lca[i]);
1002 break; 1033 break;
1003 } 1034 }
1022 void *entry_address) 1053 void *entry_address)
1023 { 1054 {
1024 if (in_dumped_exec) 1055 if (in_dumped_exec)
1025 unexec_error ("Unexec from a dumped executable is not supported."); 1056 unexec_error ("Unexec from a dumped executable is not supported.");
1026 1057
1058 pagesize = getpagesize ();
1027 infd = open (infile, O_RDONLY, 0); 1059 infd = open (infile, O_RDONLY, 0);
1028 if (infd < 0) 1060 if (infd < 0)
1029 { 1061 {
1030 unexec_error ("cannot open input file `%s'", infile); 1062 unexec_error ("cannot open input file `%s'", infile);
1031 } 1063 }