view src/unexnext.c @ 79799:57956dd69d3f

(top-level): Fix spacing. (verilog-mode-version, verilog-mode-release-date): Update version number. (verilog-mode-release-emacs): New variable. (compile-command, reporter-prompt-for-summary-p): Define for byte compiler. (verilog-startup-message-lines) (verilog-startup-message-displayed) (verilog-display-startup-message): Remove. (verilog-highlight-p1800-keywords): Improve docstring. (sigs-in, sigs-out, got-sig, got-rvalue, uses-delayed) (vector-skip-list): Only defvar at compile time. (verilog-highlight-translate-off, verilog-indent-level) (verilog-indent-level-module, verilog-indent-level-declaration) (verilog-indent-declaration-macros, verilog-indent-lists) (verilog-indent-level-behavioral) (verilog-indent-level-directive, verilog-cexp-indent) (verilog-case-indent, verilog-auto-newline) (verilog-auto-indent-on-newline, verilog-tab-always-indent) (verilog-tab-to-comment, verilog-indent-begin-after-if) (verilog-align-ifelse, verilog-minimum-comment-distance) (verilog-auto-lineup, verilog-highlight-p1800-keywords) (verilog-auto-endcomments, verilog-auto-read-includes) (verilog-auto-star-expand, verilog-auto-star-save) (verilog-library-flags, verilog-library-directories) (verilog-library-files, verilog-library-extensions) (verilog-active-low-regexp, verilog-auto-sense-include-inputs) (verilog-auto-sense-defines-constant, verilog-auto-reset-widths) (verilog-assignment-delay, verilog-auto-inst-vector) (verilog-auto-inst-template-numbers) (verilog-auto-input-ignore-regexp) (verilog-auto-inout-ignore-regexp) (verilog-auto-output-ignore-regexp) (verilog-auto-unused-ignore-regexp, verilog-typedef-regexp): Add safe-local-variable properties. (verilog-statement-menu, verilog-company) (verilog-re-search-forward, verilog-re-search-backward) (verilog-error-regexp-add, verilog-end-block-re) (verilog-emacs-features, verilog-populate-syntax-table) (verilog-setup-dual-comments, verilog-type-font-keywords) (verilog-inside-comment-p, electric-verilog-backward-sexp) (verilog-backward-sexp, verilog-forward-sexp) (verilog-font-lock-init, verilog-mode) (electric-verilog-terminate-line, electric-verilog-semi) (electric-verilog-tab, verilog-insert-1, ) (verilog-insert-indices, verilog-generate-numbers) (verilog-comment-region, verilog-label-be) (verilog-beg-of-statement, verilog-in-case-region-p) (verilog-in-struct-region-p, verilog-in-generate-region-p) (verilog-in-fork-region-p, verilog-backward-case-item) (verilog-set-auto-endcomments, verilog-get-expr) (verilog-expand-vector-internal, verilog-surelint-off) (verilog-batch-execute-func, verilog-calculate-indent) (verilog-calc-1, verilog-calculate-indent-directive) (verilog-leap-to-head, verilog-continued-line) (verilog-backward-token, verilog-backward-syntactic-ws) (verilog-forward-syntactic-ws, verilog-backward-ws&directives) (verilog-forward-ws&directives, verilog-at-constraint-p) (verilog-skip-backward-comments, verilog-indent-line-relative) (verilog-do-indent, verilog-indent-comment) (verilog-more-comment, verilog-pretty-declarations) (verilog-pretty-expr, verilog-just-one-space) (verilog-indent-declaration, verilog-get-completion-decl) (verilog-goto-defun, verilog-showscopes, verilog-header) (verilog-signals-combine-bus, verilog-read-decls) (verilog-read-always-signals-recurse, verilog-read-instants) (verilog-read-auto-template, verilog-set-define) (verilog-read-defines, verilog-read-signals, verilog-getopt) (verilog-is-number, verilog-expand-dirnames) (verilog-modi-lookup, verilog-modi-cache-results) (verilog-insert-one-definition, verilog-make-width-expression) (verilog-delete-autos-lined, verilog-auto-save-check) (verilog-auto-arg, verilog-auto-inst-port, verilog-auto-inst) (verilog-auto-inst-param, verilog-auto-reg) (verilog-auto-reg-input, verilog-auto-wire, ) (verilog-auto-output, verilog-auto-output-every) (verilog-auto-input, verilog-auto-inout) (verilog-auto-inout-module, verilog-auto-sense) (verilog-auto-reset, verilog-auto-tieoff, verilog-auto-unused) (verilog-auto-ascii-enum, verilog-auto) (verilog-sk-define-signal, verilog-mode-mouse-map) (verilog-load-file-at-mouse, verilog-load-file-at-point) (verilog-library-files): Cleanup spacing of )'s they should not be on unique lines. Fix checkdoc warnings.
author Dan Nicolaescu <dann@ics.uci.edu>
date Wed, 09 Jan 2008 06:30:58 +0000
parents fc2bcd2a8aad
children 606f2d163a64 8971ddf55736
line wrap: on
line source

/* Dump Emacs in macho format.
   Copyright (C) 1990, 1993, 2001, 2002, 2003, 2004,
                 2005, 2006, 2007, 2008  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 3, 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., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, 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(),
				&region.address,
				&region.size,
				&region.protection,
				&region.max_protection,
				&region.inheritance,
				&region.shared,
				&region.object_name,
				&region.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);
	}
}

/* arch-tag: 9796bdc3-c050-417a-b2f5-4cfd31032634
   (do not change this comment) */