Annotation of GNUtools/emacs/src/unexnext.c, revision 1.1.1.1

1.1       root        1: /* Dump Emacs in macho format.
                      2:    Copyright (C) 1990 Free Software Foundation, Inc.
                      3:    Written by Bradley Taylor ([email protected]).
                      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:                                &region.address, 
                    189:                                &region.size, 
                    190:                                &region.protection, 
                    191:                                &region.max_protection, 
                    192:                                &region.inheritance,
                    193:                                &region.shared, 
                    194:                                &region.object_name, 
                    195:                                &region.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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.