home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / emacs / src / unexnext.c < prev    next >
C/C++ Source or Header  |  1992-10-16  |  9KB  |  433 lines

  1. /* Dump Emacs in macho format.
  2.    Copyright (C) 1990 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21.  
  22. #undef __STRICT_BSD__
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <stdarg.h>
  27. #include <mach/mach.h>
  28. #include <mach-o/loader.h>
  29. #include <mach-o/fat.h>
  30. #include <sys/file.h>
  31. #include <sys/stat.h>
  32. #include <libc.h>
  33.  
  34. int malloc_cookie;
  35.     
  36. /*
  37.  * Kludge: we don't expect any program data beyond VM_HIGHDATA
  38.  * What is really needed is a way to find out from malloc() which
  39.  * pages it vm_allocated and write only those out into the data segment.
  40.  *
  41.  * This kludge may break when we stop using fixed virtual address
  42.  * shared libraries. Actually, emacs will probably continue working, but be 
  43.  * much larger on disk than it needs to be (because non-malloced data will
  44.  * be in the file).
  45.  */
  46. static const unsigned VM_HIGHDATA = 0x2000000;
  47.  
  48. typedef struct region_t {
  49.     vm_address_t address;
  50.     vm_size_t size;
  51.     vm_prot_t protection;
  52.     vm_prot_t max_protection;
  53.     vm_inherit_t inheritance;
  54.     boolean_t shared;
  55.     port_t object_name;
  56.     vm_offset_t offset;
  57. } region_t;
  58.  
  59.  
  60. static void
  61. grow(
  62.      struct load_command ***the_commands,
  63.      unsigned *the_commands_len
  64.      )
  65. {
  66.     if (*the_commands == NULL) {
  67.         *the_commands_len = 1;
  68.         *the_commands = malloc(sizeof(*the_commands));
  69.     } else {
  70.         (*the_commands_len)++;
  71.         *the_commands = realloc(*the_commands, 
  72.                     (*the_commands_len *
  73.                      sizeof(**the_commands)));
  74.     }
  75. }
  76.  
  77.  
  78. static void
  79. save_command(
  80.          struct load_command *command,
  81.          struct load_command ***the_commands,
  82.          unsigned *the_commands_len
  83.          )
  84. {
  85.     struct load_command **tmp;
  86.  
  87.     grow(the_commands, the_commands_len);
  88.     tmp = &(*the_commands)[*the_commands_len - 1];
  89.     *tmp = malloc(command->cmdsize);
  90.     bcopy(command, *tmp, command->cmdsize);
  91. }
  92.  
  93. static void
  94. fatal_unexec(char *format, ...)
  95. {
  96.     va_list ap;
  97.  
  98.     va_start(ap, format);
  99.     fprintf(stderr, "unexec: ");
  100.     vfprintf(stderr, format, ap);
  101.     fprintf(stderr, "\n");
  102.     va_end(ap);
  103. }
  104.  
  105. static int
  106. read_macho(
  107.        int fd,
  108.        struct mach_header *the_header,
  109.        struct load_command ***the_commands,
  110.        unsigned *the_commands_len
  111.        )
  112. {
  113.     struct load_command command;
  114.     struct load_command *buf;
  115.     int i;
  116.     int size;
  117.  
  118.     if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) {
  119.         fatal_unexec("cannot read macho header");
  120.         return (0);
  121.     }
  122.     /* the mach header should already be in native form */
  123.     if (the_header->magic != MH_MAGIC) {
  124.         fatal_unexec("wrong magic in macho header");
  125.     }
  126.     for (i = 0; i < the_header->ncmds; i++) {
  127.         if (read(fd, &command, sizeof(struct load_command)) != 
  128.             sizeof(struct load_command)) {
  129.               fatal_unexec("cannot read macho load command header");
  130.             return (0);
  131.         }
  132.         size = command.cmdsize - sizeof(struct load_command);
  133.         if (size < 0) {
  134.               fatal_unexec("bogus load command size");
  135.             return (0);
  136.         }
  137.         buf = malloc(command.cmdsize);
  138.         buf->cmd = command.cmd;
  139.         buf->cmdsize = command.cmdsize;
  140.         if (read(fd, ((char *)buf + 
  141.                   sizeof(struct load_command)), 
  142.              size) != size) {
  143.               fatal_unexec("cannot read load command data");
  144.             return (0);
  145.         }
  146.         save_command(buf, the_commands, the_commands_len);
  147.     }
  148.     /* Leave the file pointer at the beginning of the text segment */
  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.     const struct section *sect;
  182.  
  183.     sect = 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;
  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.  
  259.     struct segment_command *segment;
  260.  
  261.     if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) {
  262.         return (0);
  263.     }
  264.  
  265.     malloc_cookie = malloc_freezedry();
  266.  
  267.     if (!get_data_region(&data_address, &data_size)) {
  268.         return (0);
  269.     }
  270.  
  271.  
  272.     /*
  273.      * DO NOT USE MALLOC IN THIS SECTION
  274.      */
  275.     {
  276.         /*
  277.          * Fix offsets
  278.          */
  279.         for (i = 0; i < the_commands_len; i++) {
  280.             switch (the_commands[i]->cmd) {
  281.             case LC_SEGMENT:
  282.                 segment = ((struct segment_command *)
  283.                        the_commands[i]);
  284.                 if (strcmp(segment->segname, SEG_DATA) == 0) {
  285.                     fdatastart = segment->fileoff;
  286.                     fdatasize = segment->filesize;
  287.                     fgrowth = (data_size - 
  288.                            segment->filesize);
  289.                     segment->vmsize = data_size;
  290.                     segment->filesize = data_size;
  291.                 }
  292.                 break;
  293.             case LC_SYMTAB:
  294.                 ((struct symtab_command *)
  295.                  the_commands[i])->symoff += fgrowth;
  296.                 ((struct symtab_command *)
  297.                  the_commands[i])->stroff += fgrowth;
  298.                 break;
  299.             case LC_SYMSEG:
  300.                 ((struct symseg_command *)
  301.                  the_commands[i])->offset += fgrowth;
  302.                 break;
  303.             default:
  304.                 break;
  305.             }
  306.         }
  307.         
  308.         /*
  309.          * Write header
  310.          */
  311.         if (write(outfd, &the_header, 
  312.               sizeof(the_header)) != sizeof(the_header)) {
  313.             fatal_unexec("cannot write output file");
  314.             return (0);
  315.         }
  316.         
  317.         /*
  318.          * Write commands
  319.          */
  320.         for (i = 0; i < the_commands_len; i++) {
  321.             if (write(outfd, the_commands[i], 
  322.                   the_commands[i]->cmdsize) != 
  323.                 the_commands[i]->cmdsize) {
  324.                   fatal_unexec("cannot write output file");
  325.                 return (0);
  326.             }
  327.         }
  328.         
  329.         /*
  330.          * Write original text
  331.          * We're already positioned at the beginning of the text
  332.          * segment, so all we need to do is to copy the bytes.
  333.          */
  334.         size = fdatastart - (sizeof(the_header) + 
  335.                      the_header.sizeofcmds);
  336.         buf = my_malloc(size);
  337.         if (read(infd, buf, size) != size) {
  338.             my_free(buf, size);
  339.               fatal_unexec("cannot read input file");
  340.         }
  341.         if (write(outfd, buf, size) != size) {
  342.             my_free(buf, size);
  343.             fatal_unexec("cannot write output file");
  344.             return (0);
  345.         }
  346.         my_free(buf, size);
  347.         
  348.         
  349.         /*
  350.          * Write new data
  351.          */
  352.         if (write(outfd, (char *)data_address, 
  353.               data_size) != data_size) {
  354.             fatal_unexec("cannot write output file");
  355.             return (0);
  356.         }
  357.         
  358.     }
  359.  
  360.     /*
  361.      * OKAY TO USE MALLOC NOW
  362.      */
  363.  
  364.     /*
  365.      * Write rest of file
  366.      */
  367.     fstat(infd, &st);
  368.     if (lseek(infd, fdatasize, L_INCR) < 0) {
  369.         fatal_unexec("cannot seek input file");
  370.         return (0);
  371.     }
  372.     size = st.st_size - lseek(infd, 0, L_INCR);
  373.  
  374.     buf = malloc(size);
  375.     if (read(infd, buf, size) != size) {
  376.         free(buf);
  377.         fatal_unexec("cannot read input file");
  378.         return (0);
  379.     }
  380.     if (write(outfd, buf, size) != size) {
  381.         free(buf);
  382.         fatal_unexec("cannot write output file");
  383.         return (0);
  384.     }
  385.     free(buf);
  386.     return (1);
  387. }
  388.  
  389. void
  390. unexec(
  391.        char *outfile,
  392.        char *infile
  393.        )
  394. {
  395.     int infd;
  396.     int outfd;
  397.     char tmpbuf[L_tmpnam];
  398.     char *tmpfile;
  399.  
  400.     infd = open(infile, O_RDONLY, 0);
  401.     if (infd < 0) {
  402.           fatal_unexec("cannot open input file `%s'", infile);
  403.         exit(1);
  404.     }
  405.     
  406.     tmpnam(tmpbuf);
  407.     tmpfile = rindex(tmpbuf, '/');
  408.     if (tmpfile == NULL) {
  409.         tmpfile = tmpbuf;
  410.     } else {
  411.         tmpfile++;
  412.     }
  413.     outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755);
  414.     if (outfd < 0) {
  415.         close(infd);
  416.         fatal_unexec("cannot open tmp file `%s'", tmpfile);
  417.         exit(1);
  418.     }
  419.     if (!unexec_doit(infd, outfd)) {
  420.         close(infd);
  421.         close(outfd);
  422.         unlink(tmpfile);
  423.         exit(1);
  424.     }
  425.     close(infd);
  426.     close(outfd);
  427.     if (rename(tmpfile, outfile) < 0) {
  428.         unlink(tmpfile);
  429.         fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
  430.         exit(1);
  431.     }
  432. }
  433.