Annotation of GNUtools/emacs/src/unexnext.c, revision 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.