home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / unexnext.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  12KB  |  513 lines

  1. /* Dump Emacs in macho format.
  2.    Copyright (C) 1990, 1993 Free Software Foundation, Inc.
  3.    Written by Bradley Taylor (btaylor@next.com).
  4.  
  5. This file is part of GNU Emacs.
  6.  
  7. GNU Emacs is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2, or (at your option)
  10. any later version.
  11.  
  12. GNU Emacs is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU Emacs; see the file COPYING.  If not, write to
  19. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20. Boston, MA 02111-1307, USA.  */
  21.  
  22.  
  23. #undef __STRICT_BSD__
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <stdarg.h>
  28. #include <mach/mach.h>
  29. #include <mach-o/loader.h>
  30. #include <mach-o/reloc.h>
  31. #include <sys/file.h>
  32. #include <sys/stat.h>
  33. #include <unistd.h>
  34. /* Instead of unistd.h, this used to include libc.h.
  35.    "Nelson H. F. Beebe" <beebe@math.utah.edu> says that doesn't work
  36.    in system version 3.3.  */
  37.  
  38.  
  39. int malloc_cookie;
  40.  
  41. /*
  42.  * Kludge: we don't expect any program data beyond VM_HIGHDATA
  43.  * What is really needed is a way to find out from malloc() which
  44.  * pages it vm_allocated and write only those out into the data segment.
  45.  *
  46.  * This kludge may break when we stop using fixed virtual address
  47.  * shared libraries. Actually, emacs will probably continue working, but be 
  48.  * much larger on disk than it needs to be (because non-malloced data will
  49.  * be in the file).
  50.  */
  51. static const unsigned VM_HIGHDATA = 0x2000000;
  52.  
  53. typedef struct region_t {
  54.     vm_address_t address;
  55.     vm_size_t size;
  56.     vm_prot_t protection;
  57.     vm_prot_t max_protection;
  58.     vm_inherit_t inheritance;
  59.     boolean_t shared;
  60.     port_t object_name;
  61.     vm_offset_t offset;
  62. } region_t;
  63.  
  64.  
  65. static void
  66. grow(
  67.      struct load_command ***the_commands,
  68.      unsigned *the_commands_len
  69.      )
  70. {
  71.     if (*the_commands == NULL) {
  72.         *the_commands_len = 1;
  73.         *the_commands = malloc(sizeof(*the_commands));
  74.     } else {
  75.         (*the_commands_len)++;
  76.         *the_commands = realloc(*the_commands, 
  77.                     (*the_commands_len *
  78.                      sizeof(**the_commands)));
  79.     }
  80. }
  81.  
  82.  
  83. static void
  84. save_command(
  85.          struct load_command *command,
  86.          struct load_command ***the_commands,
  87.          unsigned *the_commands_len
  88.          )
  89. {
  90.     struct load_command **tmp;
  91.  
  92.     grow(the_commands, the_commands_len);
  93.     tmp = &(*the_commands)[*the_commands_len - 1];
  94.     *tmp = malloc(command->cmdsize);
  95.     bcopy(command, *tmp, command->cmdsize);
  96. }
  97.  
  98. static void
  99. fatal_unexec(char *format, ...)
  100. {
  101.     va_list ap;
  102.  
  103.     va_start(ap, format);
  104.     fprintf(stderr, "unexec: ");
  105.     vfprintf(stderr, format, ap);
  106.     fprintf(stderr, "\n");
  107.     va_end(ap);
  108. }
  109.  
  110. static int
  111. read_macho(
  112.        int fd,
  113.        struct mach_header *the_header,
  114.        struct load_command ***the_commands,
  115.        unsigned *the_commands_len
  116.        )
  117. {
  118.     struct load_command command;
  119.     struct load_command *buf;
  120.     int i;
  121.     int size;
  122.  
  123.     if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) {
  124.         fatal_unexec("cannot read macho header");
  125.         return (0);
  126.     }
  127.     for (i = 0; i < the_header->ncmds; i++) {
  128.         if (read(fd, &command, sizeof(struct load_command)) != 
  129.             sizeof(struct load_command)) {
  130.               fatal_unexec("cannot read macho load command header");
  131.             return (0);
  132.         }
  133.         size = command.cmdsize - sizeof(struct load_command);
  134.         if (size < 0) {
  135.               fatal_unexec("bogus load command size");
  136.             return (0);
  137.         }
  138.         buf = malloc(command.cmdsize);
  139.         buf->cmd = command.cmd;
  140.         buf->cmdsize = command.cmdsize;
  141.         if (read(fd, ((char *)buf + 
  142.                   sizeof(struct load_command)), 
  143.              size) != size) {
  144.               fatal_unexec("cannot read load command data");
  145.             return (0);
  146.         }
  147.         save_command(buf, the_commands, the_commands_len);
  148.     }
  149.     return (1);
  150. }
  151.  
  152. static int
  153. filldatagap(
  154.         vm_address_t start_address,
  155.         vm_size_t *size,
  156.         vm_address_t end_address
  157.         )
  158. {
  159.     vm_address_t address;
  160.     vm_size_t gapsize;
  161.  
  162.     address = (start_address + *size);
  163.     gapsize = end_address - address;
  164.     *size += gapsize;
  165.     if (vm_allocate(task_self(), &address, gapsize,
  166.             FALSE) != KERN_SUCCESS) {
  167.         fatal_unexec("cannot vm_allocate");
  168.             return (0);
  169.     }
  170.     return (1);
  171. }
  172.  
  173. static int
  174. get_data_region(
  175.         vm_address_t *address,
  176.         vm_size_t *size
  177.         )
  178. {
  179.     region_t region;
  180.     kern_return_t ret;
  181.     struct section *sect;
  182.  
  183.     sect = (struct section *) getsectbyname(SEG_DATA, SECT_DATA);
  184.     region.address = 0;
  185.     *address = 0;
  186.     for (;;) {
  187.         ret = vm_region(task_self(), 
  188.                 ®ion.address, 
  189.                 ®ion.size, 
  190.                 ®ion.protection, 
  191.                 ®ion.max_protection, 
  192.                 ®ion.inheritance,
  193.                 ®ion.shared, 
  194.                 ®ion.object_name, 
  195.                 ®ion.offset);
  196.         if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) {
  197.             break;
  198.         }
  199.         if (*address != 0) {
  200.             if (region.address > *address + *size) {
  201.                 if (!filldatagap(*address, size, 
  202.                          region.address)) {
  203.                     return (0);
  204.                 }
  205.             } 
  206.             *size += region.size;
  207.         } else {
  208.             if (region.address == sect->addr) {
  209.                 *address = region.address;
  210.                 *size = region.size;
  211.             } 
  212.         }
  213.         region.address += region.size;
  214.     }
  215.     return (1);
  216. }
  217.  
  218. static char *
  219. my_malloc(
  220.       vm_size_t size
  221.       )
  222. {
  223.     vm_address_t address;
  224.  
  225.     if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) {
  226.         return (NULL);
  227.     }
  228.     return ((char *)address);
  229. }
  230.  
  231. static void
  232. my_free(
  233.     char *buf,
  234.     vm_size_t size
  235.     )
  236. {
  237.     vm_deallocate(task_self(), (vm_address_t)buf, size);
  238. }
  239.  
  240. static int
  241. unexec_doit(
  242.         int infd,
  243.         int outfd
  244.         )
  245. {
  246.     int i;
  247.     struct load_command **the_commands = NULL;
  248.     unsigned the_commands_len;
  249.     struct mach_header the_header;
  250.     int fgrowth = 0;
  251.     int fdatastart;
  252.     int fdatasize;
  253.     int size;
  254.     struct stat st;
  255.     char *buf;
  256.     vm_address_t data_address;
  257.     vm_size_t data_size;
  258.     vm_size_t vmaddr_growth = 0;
  259.     vm_size_t dataseg_vmaddr, dataseg_vmend;
  260.  
  261.     struct segment_command *segment;
  262.  
  263. #ifdef NS_TARGET
  264.     unsigned long extreloff = 0;
  265.     unsigned long nextrel = 0;
  266.     struct dysymtab_command *dysymtab;
  267.     struct relocation_info reloc_info;
  268. #endif
  269.  
  270.     if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) {
  271.         return (0);
  272.     }
  273.  
  274.  
  275.     malloc_cookie = malloc_freezedry ();
  276.     if (!get_data_region(&data_address, &data_size)) {
  277.         return (0);
  278.     }
  279.  
  280.  
  281.     /*
  282.      * DO NOT USE MALLOC IN THIS SECTION
  283.      */
  284.     {
  285.         /*
  286.          * Fix offsets
  287.          */
  288.         for (i = 0; i < the_commands_len; i++) {
  289.             switch (the_commands[i]->cmd) {
  290.             case LC_SEGMENT:
  291.                 segment = ((struct segment_command *)
  292.                        the_commands[i]);
  293.                 if (strcmp(segment->segname, SEG_DATA) == 0) {
  294.                     fdatastart = segment->fileoff;
  295.                     fdatasize = segment->filesize;
  296.                     fgrowth = (data_size - 
  297.                            segment->filesize);
  298.                     segment->vmsize = data_size;
  299.                     segment->filesize = data_size;
  300.                     dataseg_vmaddr = segment->vmaddr;
  301.                     dataseg_vmend = segment->vmaddr + segment->vmsize;
  302.                     vmaddr_growth = segment->vmaddr + segment->vmsize;
  303.                 } else {
  304.                     ((struct segment_command *)the_commands[i])->fileoff += fgrowth;
  305.                 }
  306.  
  307.                 if( strcmp( segment->segname, SEG_LINKEDIT ) == 0 ) {
  308.                     segment->vmaddr = vmaddr_growth;
  309.                 }
  310.  
  311.                 break;
  312.             case LC_SYMTAB:
  313.                 ((struct symtab_command *)
  314.                  the_commands[i])->symoff += fgrowth;
  315.                 ((struct symtab_command *)
  316.                  the_commands[i])->stroff += fgrowth;
  317.                 break;
  318.             case LC_SYMSEG:
  319.                 ((struct symseg_command *)
  320.                  the_commands[i])->offset += fgrowth;
  321.                 break;
  322. #ifdef NS_TARGET
  323.             case LC_DYSYMTAB:
  324.                 dysymtab = ((struct dysymtab_command *)the_commands[i]);
  325.                 extreloff = dysymtab->extreloff;
  326.                 nextrel = dysymtab->nextrel;
  327.                 dysymtab->indirectsymoff += fgrowth;
  328.                 dysymtab->extreloff += fgrowth;
  329.                 break;
  330. #endif
  331.             default:
  332.                 break;
  333.             }
  334.         }
  335.         
  336.         /*
  337.          * Write header
  338.          */
  339.         if (write(outfd, &the_header, 
  340.               sizeof(the_header)) != sizeof(the_header)) {
  341.             fatal_unexec("cannot write output file");
  342.             return (0);
  343.         }
  344.         
  345.         /*
  346.          * Write commands
  347.          */
  348.         for (i = 0; i < the_commands_len; i++) {
  349.             if (write(outfd, the_commands[i], 
  350.                   the_commands[i]->cmdsize) != 
  351.                 the_commands[i]->cmdsize) {
  352.                   fatal_unexec("cannot write output file");
  353.                 return (0);
  354.             }
  355.         }
  356.         
  357.         /*
  358.          * Write original text
  359.          */
  360.         if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), 
  361.               L_SET) < 0) {
  362.               fatal_unexec("cannot seek input file");
  363.             return (0);
  364.         }
  365.         size = fdatastart - (sizeof(the_header) + 
  366.                      the_header.sizeofcmds);
  367.         buf = my_malloc(size);
  368.         if (read(infd, buf, size) != size) {
  369.             my_free(buf, size);
  370.               fatal_unexec("cannot read input file");
  371.         }
  372.         if (write(outfd, buf, size) != size) {
  373.             my_free(buf, size);
  374.             fatal_unexec("cannot write output file");
  375.             return (0);
  376.         }
  377.         my_free(buf, size);
  378.         
  379.         
  380.         /*
  381.          * Write new data
  382.          */
  383.         if (write(outfd, (char *)data_address, 
  384.               data_size) != data_size) {
  385.             fatal_unexec("cannot write output file");
  386.             return (0);
  387.         }
  388.         
  389.     }
  390.  
  391.     /*
  392.      * OKAY TO USE MALLOC NOW
  393.      */
  394.  
  395.     /*
  396.      * Write rest of file
  397.      */
  398.     fstat(infd, &st);
  399.     if (lseek(infd, fdatasize, L_INCR) < 0) {
  400.         fatal_unexec("cannot seek input file");
  401.         return (0);
  402.     }
  403.     size = st.st_size - lseek(infd, 0, L_INCR);
  404.  
  405.     buf = malloc(size);
  406.     if (read(infd, buf, size) != size) {
  407.         free(buf);
  408.         fatal_unexec("cannot read input file");
  409.         return (0);
  410.     }
  411.     if (write(outfd, buf, size) != size) {
  412.         free(buf);
  413.         fatal_unexec("cannot write output file");
  414.         return (0);
  415.     }
  416.     free(buf);
  417.  
  418. #ifdef NS_TARGET
  419.         /*
  420.          * Fix up relocation entries in the data segment.
  421.          */
  422.  
  423.     if (lseek(infd, extreloff, L_SET) < 0) {
  424.         fatal_unexec("cannot seek input file");
  425.         return (0);
  426.     }
  427.         
  428.         for (i = 0; i < nextrel; i++)
  429.         {
  430.           long zeroval = 0;
  431.  
  432.           if (read(infd, &reloc_info, sizeof (reloc_info)) != sizeof (reloc_info)) {
  433.             fatal_unexec("cannot read input file");
  434.             return (0);
  435.           }
  436.           if (reloc_info.r_address >= dataseg_vmaddr && reloc_info.r_address < dataseg_vmend)
  437.           {
  438.             if (lseek (outfd, fdatastart + reloc_info.r_address - dataseg_vmaddr, L_SET) < 0 ) {
  439.               fatal_unexec("cannot seek input file");
  440.               return (0);
  441.             }
  442.             switch (reloc_info.r_length) {
  443.               case 0:
  444.         if (write(outfd, &zeroval, 1) != 1) {
  445.             fatal_unexec("cannot write output file");
  446.             return (0);
  447.         }
  448.                 break;
  449.               case 1:
  450.         if (write(outfd, &zeroval, 2) != 2) {
  451.             fatal_unexec("cannot write output file");
  452.             return (0);
  453.         }
  454.                 break;
  455.               case 2:
  456.         if (write(outfd, &zeroval, 4) != 4) {
  457.             fatal_unexec("cannot write output file");
  458.             return (0);
  459.         }
  460.                 break;
  461.             }
  462.           }
  463.         }
  464. #endif
  465.  
  466.     return (1);
  467. }
  468.  
  469. void
  470. unexec(
  471.        char *outfile,
  472.        char *infile
  473.        )
  474. {
  475.     int infd;
  476.     int outfd;
  477.     char tmpbuf[L_tmpnam];
  478.     char *tmpfile;
  479.  
  480.     infd = open(infile, O_RDONLY, 0);
  481.     if (infd < 0) {
  482.           fatal_unexec("cannot open input file `%s'", infile);
  483.         exit(1);
  484.     }
  485.     
  486.     tmpnam(tmpbuf);
  487.     tmpfile = rindex(tmpbuf, '/');
  488.     if (tmpfile == NULL) {
  489.         tmpfile = tmpbuf;
  490.     } else {
  491.         tmpfile++;
  492.     }
  493.     outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755);
  494.     if (outfd < 0) {
  495.         close(infd);
  496.         fatal_unexec("cannot open tmp file `%s'", tmpfile);
  497.         exit(1);
  498.     }
  499.     if (!unexec_doit(infd, outfd)) {
  500.         close(infd);
  501.         close(outfd);
  502.         unlink(tmpfile);
  503.         exit(1);
  504.     }
  505.     close(infd);
  506.     close(outfd);
  507.     if (rename(tmpfile, outfile) < 0) {
  508.         unlink(tmpfile);
  509.         fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
  510.         exit(1);
  511.     }
  512. }
  513.