Mercurial > emacs
view src/unexnext.c @ 20279:69a6030e443a
(kill-region): Detect read-only text
by getting an error trying to delete it.
Handle the cases where we can, and can't, get the killed text
from the undo list with much the same code.
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Wed, 19 Nov 1997 21:36:56 +0000 |
parents | 4383d4a532de |
children | 23a1cea22d13 |
line wrap: on
line source
/* Dump Emacs in macho format. Copyright (C) 1990, 1993 Free Software Foundation, Inc. Written by Bradley Taylor (btaylor@next.com). This file is part of GNU Emacs. GNU Emacs is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #undef __STRICT_BSD__ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <mach/mach.h> #include <mach-o/loader.h> #include <mach-o/reloc.h> #include <sys/file.h> #include <sys/stat.h> #include <unistd.h> /* Instead of unistd.h, this used to include libc.h. "Nelson H. F. Beebe" <beebe@math.utah.edu> says that doesn't work in system version 3.3. */ int malloc_cookie; /* * Kludge: we don't expect any program data beyond VM_HIGHDATA * What is really needed is a way to find out from malloc() which * pages it vm_allocated and write only those out into the data segment. * * This kludge may break when we stop using fixed virtual address * shared libraries. Actually, emacs will probably continue working, but be * much larger on disk than it needs to be (because non-malloced data will * be in the file). */ static const unsigned VM_HIGHDATA = 0x2000000; typedef struct region_t { vm_address_t address; vm_size_t size; vm_prot_t protection; vm_prot_t max_protection; vm_inherit_t inheritance; boolean_t shared; port_t object_name; vm_offset_t offset; } region_t; static void grow( struct load_command ***the_commands, unsigned *the_commands_len ) { if (*the_commands == NULL) { *the_commands_len = 1; *the_commands = malloc(sizeof(*the_commands)); } else { (*the_commands_len)++; *the_commands = realloc(*the_commands, (*the_commands_len * sizeof(**the_commands))); } } static void save_command( struct load_command *command, struct load_command ***the_commands, unsigned *the_commands_len ) { struct load_command **tmp; grow(the_commands, the_commands_len); tmp = &(*the_commands)[*the_commands_len - 1]; *tmp = malloc(command->cmdsize); bcopy(command, *tmp, command->cmdsize); } static void fatal_unexec(char *format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "unexec: "); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); } static int read_macho( int fd, struct mach_header *the_header, struct load_command ***the_commands, unsigned *the_commands_len ) { struct load_command command; struct load_command *buf; int i; int size; if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) { fatal_unexec("cannot read macho header"); return (0); } for (i = 0; i < the_header->ncmds; i++) { if (read(fd, &command, sizeof(struct load_command)) != sizeof(struct load_command)) { fatal_unexec("cannot read macho load command header"); return (0); } size = command.cmdsize - sizeof(struct load_command); if (size < 0) { fatal_unexec("bogus load command size"); return (0); } buf = malloc(command.cmdsize); buf->cmd = command.cmd; buf->cmdsize = command.cmdsize; if (read(fd, ((char *)buf + sizeof(struct load_command)), size) != size) { fatal_unexec("cannot read load command data"); return (0); } save_command(buf, the_commands, the_commands_len); } return (1); } static int filldatagap( vm_address_t start_address, vm_size_t *size, vm_address_t end_address ) { vm_address_t address; vm_size_t gapsize; address = (start_address + *size); gapsize = end_address - address; *size += gapsize; if (vm_allocate(task_self(), &address, gapsize, FALSE) != KERN_SUCCESS) { fatal_unexec("cannot vm_allocate"); return (0); } return (1); } static int get_data_region( vm_address_t *address, vm_size_t *size ) { region_t region; kern_return_t ret; struct section *sect; sect = (struct section *) getsectbyname(SEG_DATA, SECT_DATA); region.address = 0; *address = 0; for (;;) { ret = vm_region(task_self(), ®ion.address, ®ion.size, ®ion.protection, ®ion.max_protection, ®ion.inheritance, ®ion.shared, ®ion.object_name, ®ion.offset); if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) { break; } if (*address != 0) { if (region.address > *address + *size) { if (!filldatagap(*address, size, region.address)) { return (0); } } *size += region.size; } else { if (region.address == sect->addr) { *address = region.address; *size = region.size; } } region.address += region.size; } return (1); } static char * my_malloc( vm_size_t size ) { vm_address_t address; if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) { return (NULL); } return ((char *)address); } static void my_free( char *buf, vm_size_t size ) { vm_deallocate(task_self(), (vm_address_t)buf, size); } static int unexec_doit( int infd, int outfd ) { int i; struct load_command **the_commands = NULL; unsigned the_commands_len; struct mach_header the_header; int fgrowth = 0; int fdatastart; int fdatasize; int size; struct stat st; char *buf; vm_address_t data_address; vm_size_t data_size; vm_size_t vmaddr_growth = 0; vm_size_t dataseg_vmaddr, dataseg_vmend; struct segment_command *segment; #ifdef NS_TARGET unsigned long extreloff = 0; unsigned long nextrel = 0; struct dysymtab_command *dysymtab; struct relocation_info reloc_info; #endif if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) { return (0); } malloc_cookie = malloc_freezedry (); if (!get_data_region(&data_address, &data_size)) { return (0); } /* * DO NOT USE MALLOC IN THIS SECTION */ { /* * Fix offsets */ for (i = 0; i < the_commands_len; i++) { switch (the_commands[i]->cmd) { case LC_SEGMENT: segment = ((struct segment_command *) the_commands[i]); if (strcmp(segment->segname, SEG_DATA) == 0) { fdatastart = segment->fileoff; fdatasize = segment->filesize; fgrowth = (data_size - segment->filesize); segment->vmsize = data_size; segment->filesize = data_size; dataseg_vmaddr = segment->vmaddr; dataseg_vmend = segment->vmaddr + segment->vmsize; vmaddr_growth = segment->vmaddr + segment->vmsize; } else { ((struct segment_command *)the_commands[i])->fileoff += fgrowth; } if( strcmp( segment->segname, SEG_LINKEDIT ) == 0 ) { segment->vmaddr = vmaddr_growth; } break; case LC_SYMTAB: ((struct symtab_command *) the_commands[i])->symoff += fgrowth; ((struct symtab_command *) the_commands[i])->stroff += fgrowth; break; case LC_SYMSEG: ((struct symseg_command *) the_commands[i])->offset += fgrowth; break; #ifdef NS_TARGET case LC_DYSYMTAB: dysymtab = ((struct dysymtab_command *)the_commands[i]); extreloff = dysymtab->extreloff; nextrel = dysymtab->nextrel; dysymtab->indirectsymoff += fgrowth; dysymtab->extreloff += fgrowth; break; #endif default: break; } } /* * Write header */ if (write(outfd, &the_header, sizeof(the_header)) != sizeof(the_header)) { fatal_unexec("cannot write output file"); return (0); } /* * Write commands */ for (i = 0; i < the_commands_len; i++) { if (write(outfd, the_commands[i], the_commands[i]->cmdsize) != the_commands[i]->cmdsize) { fatal_unexec("cannot write output file"); return (0); } } /* * Write original text */ if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), L_SET) < 0) { fatal_unexec("cannot seek input file"); return (0); } size = fdatastart - (sizeof(the_header) + the_header.sizeofcmds); buf = my_malloc(size); if (read(infd, buf, size) != size) { my_free(buf, size); fatal_unexec("cannot read input file"); } if (write(outfd, buf, size) != size) { my_free(buf, size); fatal_unexec("cannot write output file"); return (0); } my_free(buf, size); /* * Write new data */ if (write(outfd, (char *)data_address, data_size) != data_size) { fatal_unexec("cannot write output file"); return (0); } } /* * OKAY TO USE MALLOC NOW */ /* * Write rest of file */ fstat(infd, &st); if (lseek(infd, fdatasize, L_INCR) < 0) { fatal_unexec("cannot seek input file"); return (0); } size = st.st_size - lseek(infd, 0, L_INCR); buf = malloc(size); if (read(infd, buf, size) != size) { free(buf); fatal_unexec("cannot read input file"); return (0); } if (write(outfd, buf, size) != size) { free(buf); fatal_unexec("cannot write output file"); return (0); } free(buf); #ifdef NS_TARGET /* * Fix up relocation entries in the data segment. */ if (lseek(infd, extreloff, L_SET) < 0) { fatal_unexec("cannot seek input file"); return (0); } for (i = 0; i < nextrel; i++) { long zeroval = 0; if (read(infd, &reloc_info, sizeof (reloc_info)) != sizeof (reloc_info)) { fatal_unexec("cannot read input file"); return (0); } if (reloc_info.r_address >= dataseg_vmaddr && reloc_info.r_address < dataseg_vmend) { if (lseek (outfd, fdatastart + reloc_info.r_address - dataseg_vmaddr, L_SET) < 0 ) { fatal_unexec("cannot seek input file"); return (0); } switch (reloc_info.r_length) { case 0: if (write(outfd, &zeroval, 1) != 1) { fatal_unexec("cannot write output file"); return (0); } break; case 1: if (write(outfd, &zeroval, 2) != 2) { fatal_unexec("cannot write output file"); return (0); } break; case 2: if (write(outfd, &zeroval, 4) != 4) { fatal_unexec("cannot write output file"); return (0); } break; } } } #endif return (1); } void unexec( char *outfile, char *infile ) { int infd; int outfd; char tmpbuf[L_tmpnam]; char *tmpfile; infd = open(infile, O_RDONLY, 0); if (infd < 0) { fatal_unexec("cannot open input file `%s'", infile); exit(1); } tmpnam(tmpbuf); tmpfile = rindex(tmpbuf, '/'); if (tmpfile == NULL) { tmpfile = tmpbuf; } else { tmpfile++; } outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755); if (outfd < 0) { close(infd); fatal_unexec("cannot open tmp file `%s'", tmpfile); exit(1); } if (!unexec_doit(infd, outfd)) { close(infd); close(outfd); unlink(tmpfile); exit(1); } close(infd); close(outfd); if (rename(tmpfile, outfile) < 0) { unlink(tmpfile); fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile); exit(1); } }