From 89b89fd77844ae903202bdbe64e1e3628a69b462 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Tue, 20 Aug 2024 18:29:53 +0000 Subject: [PATCH] Unexec removal: Remove obsolete files * src/sheap.c, src/sheap.h, src/unexec.h, src/unexaix.c, unexcoff.c: * src/unexcw.c, src/unexelf.c, src/unexhp9k800.c, src/unexmacosx.c: * src/unexsol.c, src/unexw32.c: Remove files. (cherry picked from commit 7ce34a3bcf5ed277ef37aa75e1ccbd858543b6cf) --- src/sheap.c | 79 --- src/sheap.h | 30 - src/unexaix.c | 611 -------------------- src/unexcoff.c | 540 ----------------- src/unexcw.c | 302 ---------- src/unexec.h | 4 - src/unexelf.c | 658 --------------------- src/unexhp9k800.c | 324 ----------- src/unexmacosx.c | 1401 --------------------------------------------- src/unexsol.c | 28 - src/unexw32.c | 684 ---------------------- 11 files changed, 4661 deletions(-) delete mode 100644 src/sheap.c delete mode 100644 src/sheap.h delete mode 100644 src/unexaix.c delete mode 100644 src/unexcoff.c delete mode 100644 src/unexcw.c delete mode 100644 src/unexec.h delete mode 100644 src/unexelf.c delete mode 100644 src/unexhp9k800.c delete mode 100644 src/unexmacosx.c delete mode 100644 src/unexsol.c delete mode 100644 src/unexw32.c diff --git a/src/sheap.c b/src/sheap.c deleted file mode 100644 index ff23c702c2b..00000000000 --- a/src/sheap.c +++ /dev/null @@ -1,79 +0,0 @@ -/* simulate `sbrk' with an array in .bss, for `unexec' support for Cygwin; - complete rewrite of xemacs Cygwin `unexec' code - - Copyright (C) 2004-2025 Free Software Foundation, Inc. - -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 of the License, 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. If not, see . */ - -#include - -#include "sheap.h" - -#include -#include "lisp.h" -#include -#include /* for exit */ - -static int debug_sheap; - -char bss_sbrk_buffer[STATIC_HEAP_SIZE]; -char *max_bss_sbrk_ptr; - -void * -bss_sbrk (ptrdiff_t request_size) -{ - static char *bss_sbrk_ptr; - - if (!bss_sbrk_ptr) - { - max_bss_sbrk_ptr = bss_sbrk_ptr = bss_sbrk_buffer; -#ifdef CYGWIN - /* Force space for fork to work. */ - sbrk (4096); -#endif - } - - int used = bss_sbrk_ptr - bss_sbrk_buffer; - - if (request_size < -used) - { - printf (("attempt to free too much: " - "avail %d used %d failed request %"pD"d\n"), - STATIC_HEAP_SIZE, used, request_size); - exit (-1); - return 0; - } - else if (STATIC_HEAP_SIZE - used < request_size) - { - printf ("static heap exhausted: avail %d used %d failed request %"pD"d\n", - STATIC_HEAP_SIZE, used, request_size); - exit (-1); - return 0; - } - - void *ret = bss_sbrk_ptr; - bss_sbrk_ptr += request_size; - if (max_bss_sbrk_ptr < bss_sbrk_ptr) - max_bss_sbrk_ptr = bss_sbrk_ptr; - if (debug_sheap) - { - if (request_size < 0) - printf ("freed size %"pD"d\n", request_size); - else - printf ("allocated %p size %"pD"d\n", ret, request_size); - } - return ret; -} diff --git a/src/sheap.h b/src/sheap.h deleted file mode 100644 index 331494e8774..00000000000 --- a/src/sheap.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Static heap allocation for GNU Emacs. - -Copyright 2016-2025 Free Software Foundation, Inc. - -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 of the License, 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. If not, see . */ - -#include -#include "lisp.h" - -/* Size of the static heap. Guess a value that is probably too large, - by up to a factor of four or so. Typically the unused part is not - paged in and so does not cost much. */ -enum { STATIC_HEAP_SIZE = sizeof (Lisp_Object) << 24 }; - -extern char bss_sbrk_buffer[STATIC_HEAP_SIZE]; -extern char *max_bss_sbrk_ptr; -extern void *bss_sbrk (ptrdiff_t); diff --git a/src/unexaix.c b/src/unexaix.c deleted file mode 100644 index 90c6cb7470c..00000000000 --- a/src/unexaix.c +++ /dev/null @@ -1,611 +0,0 @@ -/* Dump an executable file. - Copyright (C) 1985-1988, 1999, 2001-2025 Free Software Foundation, - Inc. - -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 of the License, 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. If not, see . */ - -/* -In other words, you are welcome to use, share and improve this program. -You are forbidden to forbid anyone else to use, share and improve -what you give them. Help stamp out software-hoarding! */ - - -/* Originally based on the COFF unexec.c by Spencer W. Thomas. - * - * Subsequently hacked on by - * Bill Mann - * Andrew Vignaux - * Mike Sperber - * - * Synopsis: - * unexec (const char *new_name, const *old_name); - * - * Takes a snapshot of the program and makes an a.out format file in the - * file named by the string argument new_name. - * If a_name is non-NULL, the symbol table will be taken from the given file. - * On some machines, an existing a_name file is required. - * - */ - -#include -#include "unexec.h" -#include "lisp.h" - -#define PERROR(file) report_error (file, new) -#include -/* Define getpagesize () if the system does not. - Note that this may depend on symbols defined in a.out.h - */ -#include "getpagesize.h" - -#include -#include -#include -#include -#include -#include -#include - -extern char _data[]; -extern char _text[]; - -#include -#include -#include -#include - -static struct filehdr f_hdr; /* File header */ -static struct aouthdr f_ohdr; /* Optional file header (a.out) */ -static off_t bias; /* Bias to add for growth */ -static off_t lnnoptr; /* Pointer to line-number info within file */ - -static off_t text_scnptr; -static off_t data_scnptr; -#define ALIGN(val, pwr) (((val) + ((1L<<(pwr))-1)) & ~((1L<<(pwr))-1)) -static off_t load_scnptr; -static off_t orig_load_scnptr; -static off_t orig_data_scnptr; -static int unrelocate_symbols (int, int, const char *, const char *); - -#ifndef MAX_SECTIONS -#define MAX_SECTIONS 10 -#endif - -static int adjust_lnnoptrs (int, int, const char *); - -static int pagemask; - -#include "lisp.h" - -static _Noreturn void -report_error (const char *file, int fd) -{ - int err = errno; - if (fd) - emacs_close (fd); - report_file_errno ("Cannot unexec", build_string (file), err); -} - -#define ERROR0(msg) report_error_1 (new, msg) -#define ERROR1(msg,x) report_error_1 (new, msg, x) -#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y) - -static _Noreturn void ATTRIBUTE_FORMAT_PRINTF (2, 3) -report_error_1 (int fd, const char *msg, ...) -{ - va_list ap; - emacs_close (fd); - va_start (ap, msg); - verror (msg, ap); - va_end (ap); -} - -static int make_hdr (int, int, const char *, const char *); -static void mark_x (const char *); -static int copy_text_and_data (int); -static int copy_sym (int, int, const char *, const char *); -static void write_segment (int, char *, char *); - -/* **************************************************************** - * unexec - * - * driving logic. - */ -void -unexec (const char *new_name, const char *a_name) -{ - int new = -1, a_out = -1; - - if (a_name && (a_out = emacs_open (a_name, O_RDONLY, 0)) < 0) - { - PERROR (a_name); - } - if ((new = emacs_open (new_name, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0) - { - PERROR (new_name); - } - if (make_hdr (new, a_out, - a_name, new_name) < 0 - || copy_text_and_data (new) < 0 - || copy_sym (new, a_out, a_name, new_name) < 0 - || adjust_lnnoptrs (new, a_out, new_name) < 0 - || unrelocate_symbols (new, a_out, a_name, new_name) < 0) - { - emacs_close (new); - return; - } - - emacs_close (new); - if (a_out >= 0) - emacs_close (a_out); -} - -/* **************************************************************** - * make_hdr - * - * Make the header in the new a.out from the header in core. - * Modify the text and data sizes. - */ -static int -make_hdr (int new, int a_out, - const char *a_name, const char *new_name) -{ - int scns; - uintptr_t bss_start; - uintptr_t data_start; - - struct scnhdr section[MAX_SECTIONS]; - struct scnhdr * f_thdr; /* Text section header */ - struct scnhdr * f_dhdr; /* Data section header */ - struct scnhdr * f_bhdr; /* Bss section header */ - struct scnhdr * f_lhdr; /* Loader section header */ - struct scnhdr * f_tchdr; /* Typechk section header */ - struct scnhdr * f_dbhdr; /* Debug section header */ - struct scnhdr * f_xhdr; /* Except section header */ - - load_scnptr = orig_load_scnptr = lnnoptr = 0; - pagemask = getpagesize () - 1; - - /* Adjust text/data boundary. */ - data_start = (uintptr_t) _data; - - data_start = data_start & ~pagemask; /* (Down) to page boundary. */ - - bss_start = (uintptr_t) sbrk (0) + pagemask; - bss_start &= ~ pagemask; - - if (data_start > bss_start) /* Can't have negative data size. */ - { - ERROR2 (("unexec: data_start (0x%"PRIxPTR - ") can't be greater than bss_start (0x%"PRIxPTR")"), - data_start, bss_start); - } - - /* Salvage as much info from the existing file as possible */ - f_thdr = NULL; f_dhdr = NULL; f_bhdr = NULL; - f_lhdr = NULL; f_tchdr = NULL; f_dbhdr = NULL; f_xhdr = NULL; - if (a_out >= 0) - { - if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) - { - PERROR (a_name); - } - if (f_hdr.f_opthdr > 0) - { - if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) - { - PERROR (a_name); - } - } - if (f_hdr.f_nscns > MAX_SECTIONS) - { - ERROR0 ("unexec: too many section headers -- increase MAX_SECTIONS"); - } - /* Loop through section headers */ - for (scns = 0; scns < f_hdr.f_nscns; scns++) { - struct scnhdr *s = §ion[scns]; - if (read (a_out, s, sizeof (*s)) != sizeof (*s)) - { - PERROR (a_name); - } - -#define CHECK_SCNHDR(ptr, name, flags) \ - if (strcmp (s->s_name, name) == 0) { \ - if (s->s_flags != flags) { \ - fprintf (stderr, "unexec: %lx flags where %x expected in %s section.\n", \ - (unsigned long)s->s_flags, flags, name); \ - } \ - if (ptr) { \ - fprintf (stderr, "unexec: duplicate section header for section %s.\n", \ - name); \ - } \ - ptr = s; \ - } - CHECK_SCNHDR (f_thdr, _TEXT, STYP_TEXT); - CHECK_SCNHDR (f_dhdr, _DATA, STYP_DATA); - CHECK_SCNHDR (f_bhdr, _BSS, STYP_BSS); - CHECK_SCNHDR (f_lhdr, _LOADER, STYP_LOADER); - CHECK_SCNHDR (f_dbhdr, _DEBUG, STYP_DEBUG); - CHECK_SCNHDR (f_tchdr, _TYPCHK, STYP_TYPCHK); - CHECK_SCNHDR (f_xhdr, _EXCEPT, STYP_EXCEPT); - } - - if (f_thdr == 0) - { - ERROR1 ("unexec: couldn't find \"%s\" section", _TEXT); - } - if (f_dhdr == 0) - { - ERROR1 ("unexec: couldn't find \"%s\" section", _DATA); - } - if (f_bhdr == 0) - { - ERROR1 ("unexec: couldn't find \"%s\" section", _BSS); - } - } - else - { - ERROR0 ("can't build a COFF file from scratch yet"); - } - orig_data_scnptr = f_dhdr->s_scnptr; - orig_load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; - - /* Now we alter the contents of all the f_*hdr variables - to correspond to what we want to dump. */ - - /* Indicate that the reloc information is no longer valid for ld (bind); - we only update it enough to fake out the exec-time loader. */ - f_hdr.f_flags |= (F_RELFLG | F_EXEC); - - f_ohdr.dsize = bss_start - f_ohdr.data_start; - f_ohdr.bsize = 0; - - f_dhdr->s_size = f_ohdr.dsize; - f_bhdr->s_size = f_ohdr.bsize; - f_bhdr->s_paddr = f_ohdr.data_start + f_ohdr.dsize; - f_bhdr->s_vaddr = f_ohdr.data_start + f_ohdr.dsize; - - /* fix scnptr's */ - { - off_t ptr = section[0].s_scnptr; - - bias = -1; - for (scns = 0; scns < f_hdr.f_nscns; scns++) - { - struct scnhdr *s = §ion[scns]; - - if (s->s_flags & STYP_PAD) /* .pad sections omitted in AIX 4.1 */ - { - /* - * the text_start should probably be o_algntext but that doesn't - * seem to change - */ - if (f_ohdr.text_start != 0) /* && scns != 0 */ - { - s->s_size = 512 - (ptr % 512); - if (s->s_size == 512) - s->s_size = 0; - } - s->s_scnptr = ptr; - } - else if (s->s_flags & STYP_DATA) - s->s_scnptr = ptr; - else if (!(s->s_flags & (STYP_TEXT | STYP_BSS))) - { - if (bias == -1) /* if first section after bss */ - bias = ptr - s->s_scnptr; - - s->s_scnptr += bias; - ptr = s->s_scnptr; - } - - ptr = ptr + s->s_size; - } - } - - /* fix other pointers */ - for (scns = 0; scns < f_hdr.f_nscns; scns++) - { - struct scnhdr *s = §ion[scns]; - - if (s->s_relptr != 0) - { - s->s_relptr += bias; - } - if (s->s_lnnoptr != 0) - { - if (lnnoptr == 0) lnnoptr = s->s_lnnoptr; - s->s_lnnoptr += bias; - } - } - - if (f_hdr.f_symptr > 0L) - { - f_hdr.f_symptr += bias; - } - - text_scnptr = f_thdr->s_scnptr; - data_scnptr = f_dhdr->s_scnptr; - load_scnptr = f_lhdr ? f_lhdr->s_scnptr : 0; - - if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) - { - PERROR (new_name); - } - - if (f_hdr.f_opthdr > 0) - { - if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) - { - PERROR (new_name); - } - } - - for (scns = 0; scns < f_hdr.f_nscns; scns++) { - struct scnhdr *s = §ion[scns]; - if (write (new, s, sizeof (*s)) != sizeof (*s)) - { - PERROR (new_name); - } - } - - return (0); -} - -/* **************************************************************** - - * - * Copy the text and data segments from memory to the new a.out - */ -static int -copy_text_and_data (int new) -{ - char *end; - char *ptr; - - lseek (new, text_scnptr, SEEK_SET); - ptr = _text; - end = ptr + f_ohdr.tsize; - write_segment (new, ptr, end); - - lseek (new, data_scnptr, SEEK_SET); - ptr = (char *) (ptrdiff_t) f_ohdr.data_start; - end = ptr + f_ohdr.dsize; - write_segment (new, ptr, end); - - return 0; -} - -#define UnexBlockSz (1<<12) /* read/write block size */ -static void -write_segment (int new, char *ptr, char *end) -{ - int i, nwrite, ret; - char zeros[UnexBlockSz]; - - for (i = 0; ptr < end;) - { - /* distance to next block. */ - nwrite = (((ptrdiff_t) ptr + UnexBlockSz) & -UnexBlockSz) - (ptrdiff_t) ptr; - /* But not beyond specified end. */ - if (nwrite > end - ptr) nwrite = end - ptr; - ret = write (new, ptr, nwrite); - /* If write gets a page fault, it means we reached - a gap between the old text segment and the old data segment. - This gap has probably been remapped into part of the text segment. - So write zeros for it. */ - if (ret == -1 && errno == EFAULT) - { - memset (zeros, 0, nwrite); - write (new, zeros, nwrite); - } - else if (nwrite != ret) - { - int write_errno = errno; - char buf[1000]; - void *addr = ptr; - sprintf (buf, - "unexec write failure: addr %p, fileno %d, size 0x%x, wrote 0x%x, errno %d", - addr, new, nwrite, ret, errno); - errno = write_errno; - PERROR (buf); - } - i += nwrite; - ptr += nwrite; - } -} - -/* **************************************************************** - * copy_sym - * - * Copy the relocation information and symbol table from the a.out to the new - */ -static int -copy_sym (int new, int a_out, const char *a_name, const char *new_name) -{ - char page[UnexBlockSz]; - int n; - - if (a_out < 0) - return 0; - - if (orig_load_scnptr == 0L) - return 0; - - if (lnnoptr && lnnoptr < orig_load_scnptr) /* if there is line number info */ - lseek (a_out, lnnoptr, SEEK_SET); /* start copying from there */ - else - lseek (a_out, orig_load_scnptr, SEEK_SET); /* Position a.out to symtab. */ - - while ((n = read (a_out, page, sizeof page)) > 0) - { - if (write (new, page, n) != n) - { - PERROR (new_name); - } - } - if (n < 0) - { - PERROR (a_name); - } - return 0; -} - -static int -adjust_lnnoptrs (int writedesc, int readdesc, const char *new_name) -{ - int nsyms; - int naux; - int new; - struct syment symentry; - union auxent auxentry; - - if (!lnnoptr || !f_hdr.f_symptr) - return 0; - - if ((new = emacs_open (new_name, O_RDWR, 0)) < 0) - { - PERROR (new_name); - return -1; - } - - lseek (new, f_hdr.f_symptr, SEEK_SET); - for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) - { - read (new, &symentry, SYMESZ); - if (symentry.n_sclass == C_BINCL || symentry.n_sclass == C_EINCL) - { - symentry.n_value += bias; - lseek (new, -SYMESZ, SEEK_CUR); - write (new, &symentry, SYMESZ); - } - - for (naux = symentry.n_numaux; naux-- != 0; ) - { - read (new, &auxentry, AUXESZ); - nsyms++; - if (naux != 0 /* skip csect auxentry (last entry) */ - && (symentry.n_sclass == C_EXT || symentry.n_sclass == C_HIDEXT)) - { - auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; - lseek (new, -AUXESZ, SEEK_CUR); - write (new, &auxentry, AUXESZ); - } - } - } - emacs_close (new); - - return 0; -} - -static int -unrelocate_symbols (int new, int a_out, - const char *a_name, const char *new_name) -{ - int i; - LDHDR ldhdr; - LDREL ldrel; - off_t t_reloc = (intptr_t) _text - f_ohdr.text_start; -#ifndef ALIGN_DATA_RELOC - off_t d_reloc = (intptr_t) _data - f_ohdr.data_start; -#else - /* This worked (and was needed) before AIX 4.2. - I have no idea why. -- Mike */ - off_t d_reloc = (intptr_t) _data - ALIGN (f_ohdr.data_start, 2); -#endif - int * p; - - if (load_scnptr == 0) - return 0; - - lseek (a_out, orig_load_scnptr, SEEK_SET); - if (read (a_out, &ldhdr, sizeof (ldhdr)) != sizeof (ldhdr)) - { - PERROR (new_name); - } - -#define SYMNDX_TEXT 0 -#define SYMNDX_DATA 1 -#define SYMNDX_BSS 2 - - for (i = 0; i < ldhdr.l_nreloc; i++) - { - lseek (a_out, - orig_load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, - SEEK_SET); - - if (read (a_out, &ldrel, LDRELSZ) != LDRELSZ) - { - PERROR (a_name); - } - - /* move the BSS loader symbols to the DATA segment */ - if (ldrel.l_symndx == SYMNDX_BSS) - { - ldrel.l_symndx = SYMNDX_DATA; - - lseek (new, - load_scnptr + LDHDRSZ + LDSYMSZ*ldhdr.l_nsyms + LDRELSZ*i, - SEEK_SET); - - if (write (new, &ldrel, LDRELSZ) != LDRELSZ) - { - PERROR (new_name); - } - } - - if (ldrel.l_rsecnm == f_ohdr.o_sndata) - { - int orig_int; - - lseek (a_out, - orig_data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start), - SEEK_SET); - - if (read (a_out, (void *) &orig_int, sizeof (orig_int)) - != sizeof (orig_int)) - { - PERROR (a_name); - } - - p = (int *) (intptr_t) (ldrel.l_vaddr + d_reloc); - - switch (ldrel.l_symndx) { - case SYMNDX_TEXT: - orig_int = * p - t_reloc; - break; - - case SYMNDX_DATA: - case SYMNDX_BSS: - orig_int = * p - d_reloc; - break; - } - - if (orig_int != * p) - { - lseek (new, - data_scnptr + (ldrel.l_vaddr - f_ohdr.data_start), - SEEK_SET); - if (write (new, (void *) &orig_int, sizeof (orig_int)) - != sizeof (orig_int)) - { - PERROR (new_name); - } - } - } - } - return 0; -} diff --git a/src/unexcoff.c b/src/unexcoff.c deleted file mode 100644 index 10930dff287..00000000000 --- a/src/unexcoff.c +++ /dev/null @@ -1,540 +0,0 @@ -/* Copyright (C) 1985-1988, 1992-1994, 2001-2025 Free Software - * Foundation, Inc. - -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 of the License, 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. If not, see . */ - - -/* - * unexcoff.c - Convert a running program into an a.out or COFF file. - * - * ================================================================== - * Note: This file is currently used only by the MSDOS (a.k.a. DJGPP) - * build of Emacs. If you are not interested in the MSDOS build, you - * are looking at the wrong version of unexec! - * ================================================================== - * - * Author: Spencer W. Thomas - * Computer Science Dept. - * University of Utah - * Date: Tue Mar 2 1982 - * Originally under the name unexec.c. - * Modified heavily since then. - * - * Synopsis: - * unexec (const char *new_name, const char *old_name); - * - * Takes a snapshot of the program and makes an a.out format file in the - * file named by the string argument new_name. - * If a_name is non-NULL, the symbol table will be taken from the given file. - * On some machines, an existing a_name file is required. - * - * If you make improvements I'd like to get them too. - * harpo!utah-cs!thomas, thomas@Utah-20 - * - */ - -/* Modified to support SysVr3 shared libraries by James Van Artsdalen - * of Dell Computer Corporation. james@bigtex.cactus.org. - */ - -#include -#include "unexec.h" -#include "lisp.h" - -#define PERROR(file) report_error (file, new) - -#ifdef HAVE_UNEXEC /* all rest of file! */ - -#ifdef HAVE_COFF_H -#include -#ifdef MSDOS -#include /* for O_RDONLY, O_RDWR */ -#include /* for _crt0_startup_flags and its bits */ -#include -static int save_djgpp_startup_flags; -#include -static struct __atexit *save_atexit_ptr; -#define filehdr external_filehdr -#define scnhdr external_scnhdr -#define syment external_syment -#define auxent external_auxent -#define n_numaux e_numaux -#define n_type e_type -struct aouthdr -{ - unsigned short magic; /* type of file */ - unsigned short vstamp; /* version stamp */ - unsigned long tsize; /* text size in bytes, padded to FW bdry*/ - unsigned long dsize; /* initialized data " " */ - unsigned long bsize; /* uninitialized data " " */ - unsigned long entry; /* entry pt. */ - unsigned long text_start;/* base of text used for this file */ - unsigned long data_start;/* base of data used for this file */ -}; -#endif /* MSDOS */ -#else /* not HAVE_COFF_H */ -#include -#endif /* not HAVE_COFF_H */ - -/* Define getpagesize if the system does not. - Note that this may depend on symbols defined in a.out.h. */ -#include "getpagesize.h" - -#ifndef makedev /* Try to detect types.h already loaded */ -#include -#endif /* makedev */ -#include - -#include - -extern int etext; - -static long block_copy_start; /* Old executable start point */ -static struct filehdr f_hdr; /* File header */ -static struct aouthdr f_ohdr; /* Optional file header (a.out) */ -long bias; /* Bias to add for growth */ -long lnnoptr; /* Pointer to line-number info within file */ -#define SYMS_START block_copy_start - -static long text_scnptr; -static long data_scnptr; - -static long coff_offset; - -static int pagemask; - -/* Correct an int which is the bit pattern of a pointer to a byte - into an int which is the number of a byte. - This is a no-op on ordinary machines, but not on all. */ - -#define ADDR_CORRECT(x) ((char *) (x) - (char *) 0) - -#include "lisp.h" - -static void -report_error (const char *file, int fd) -{ - int err = errno; - if (fd) - emacs_close (fd); - report_file_errno ("Cannot unexec", build_string (file), err); -} - -#define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1 -#define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1 -#define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1 - -static void -report_error_1 (int fd, const char *msg, int a1, int a2) -{ - emacs_close (fd); - error (msg, a1, a2); -} - -static int make_hdr (int, int, const char *, const char *); -static int copy_text_and_data (int, int); -static int copy_sym (int, int, const char *, const char *); -static void mark_x (const char *); - -/* **************************************************************** - * make_hdr - * - * Make the header in the new a.out from the header in core. - * Modify the text and data sizes. - */ -static int -make_hdr (int new, int a_out, - const char *a_name, const char *new_name) -{ - auto struct scnhdr f_thdr; /* Text section header */ - auto struct scnhdr f_dhdr; /* Data section header */ - auto struct scnhdr f_bhdr; /* Bss section header */ - auto struct scnhdr scntemp; /* Temporary section header */ - register int scns; - unsigned int bss_start; - unsigned int data_start; - - pagemask = getpagesize () - 1; - - /* Adjust text/data boundary. */ - data_start = (int) DATA_START; - data_start = ADDR_CORRECT (data_start); - data_start = data_start & ~pagemask; /* (Down) to page boundary. */ - - bss_start = ADDR_CORRECT (sbrk (0)) + pagemask; - bss_start &= ~ pagemask; - - if (data_start > bss_start) /* Can't have negative data size. */ - { - ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)", - data_start, bss_start); - } - - coff_offset = 0L; /* stays zero, except in DJGPP */ - - /* Salvage as much info from the existing file as possible */ - if (a_out >= 0) - { -#ifdef MSDOS - /* Support the coff-go32-exe format with a prepended stub, since - this is what GCC 2.8.0 and later generates by default in DJGPP. */ - unsigned short mz_header[3]; - - if (read (a_out, &mz_header, sizeof (mz_header)) != sizeof (mz_header)) - { - PERROR (a_name); - } - if (mz_header[0] == 0x5a4d || mz_header[0] == 0x4d5a) /* "MZ" or "ZM" */ - { - coff_offset = (long)mz_header[2] * 512L; - if (mz_header[1]) - coff_offset += (long)mz_header[1] - 512L; - lseek (a_out, coff_offset, 0); - } - else - lseek (a_out, 0L, 0); -#endif /* MSDOS */ - if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) - { - PERROR (a_name); - } - block_copy_start += sizeof (f_hdr); - if (f_hdr.f_opthdr > 0) - { - if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) - { - PERROR (a_name); - } - block_copy_start += sizeof (f_ohdr); - } - /* Loop through section headers, copying them in */ - lseek (a_out, coff_offset + sizeof (f_hdr) + f_hdr.f_opthdr, 0); - for (scns = f_hdr.f_nscns; scns > 0; scns--) { - if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp)) - { - PERROR (a_name); - } - if (scntemp.s_scnptr > 0L) - { - if (block_copy_start < scntemp.s_scnptr + scntemp.s_size) - block_copy_start = scntemp.s_scnptr + scntemp.s_size; - } - if (strcmp (scntemp.s_name, ".text") == 0) - { - f_thdr = scntemp; - } - else if (strcmp (scntemp.s_name, ".data") == 0) - { - f_dhdr = scntemp; - } - else if (strcmp (scntemp.s_name, ".bss") == 0) - { - f_bhdr = scntemp; - } - } - } - else - { - ERROR0 ("can't build a COFF file from scratch yet"); - } - - /* Now we alter the contents of all the f_*hdr variables - to correspond to what we want to dump. */ - - f_hdr.f_flags |= (F_RELFLG | F_EXEC); - f_ohdr.dsize = bss_start - f_ohdr.data_start; - f_ohdr.bsize = 0; - f_thdr.s_size = f_ohdr.tsize; - f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr); - f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr)); - lnnoptr = f_thdr.s_lnnoptr; - text_scnptr = f_thdr.s_scnptr; - f_dhdr.s_paddr = f_ohdr.data_start; - f_dhdr.s_vaddr = f_ohdr.data_start; - f_dhdr.s_size = f_ohdr.dsize; - f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size; - data_scnptr = f_dhdr.s_scnptr; - f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize; - f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize; - f_bhdr.s_size = f_ohdr.bsize; - f_bhdr.s_scnptr = 0L; - bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start; - - if (f_hdr.f_symptr > 0L) - { - f_hdr.f_symptr += bias; - } - - if (f_thdr.s_lnnoptr > 0L) - { - f_thdr.s_lnnoptr += bias; - } - - if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) - { - PERROR (new_name); - } - - if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) - { - PERROR (new_name); - } - - if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr)) - { - PERROR (new_name); - } - - if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr)) - { - PERROR (new_name); - } - - if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr)) - { - PERROR (new_name); - } - - return (0); - -} - -void -write_segment (int new, const char *ptr, const char *end) -{ - register int i, nwrite, ret; - /* This is the normal amount to write at once. - It is the size of block that NFS uses. */ - int writesize = 1 << 13; - int pagesize = getpagesize (); - char zeros[1 << 13]; - - memset (zeros, 0, sizeof (zeros)); - - for (i = 0; ptr < end;) - { - /* Distance to next multiple of writesize. */ - nwrite = (((int) ptr + writesize) & -writesize) - (int) ptr; - /* But not beyond specified end. */ - if (nwrite > end - ptr) nwrite = end - ptr; - ret = write (new, ptr, nwrite); - /* If write gets a page fault, it means we reached - a gap between the old text segment and the old data segment. - This gap has probably been remapped into part of the text segment. - So write zeros for it. */ - if (ret == -1 && errno == EFAULT) - { - /* Write only a page of zeros at once, - so that we don't overshoot the start - of the valid memory in the old data segment. */ - if (nwrite > pagesize) - nwrite = pagesize; - write (new, zeros, nwrite); - } - i += nwrite; - ptr += nwrite; - } -} -/* **************************************************************** - * copy_text_and_data - * - * Copy the text and data segments from memory to the new a.out - */ -static int -copy_text_and_data (int new, int a_out) -{ - register char *end; - register char *ptr; - -#ifdef MSDOS - /* Dump the original table of exception handlers, not the one - where our exception hooks are registered. */ - __djgpp_exception_toggle (); - - /* Switch off startup flags that might have been set at runtime - and which might change the way that dumped Emacs works. */ - save_djgpp_startup_flags = _crt0_startup_flags; - _crt0_startup_flags &= ~(_CRT0_FLAG_NO_LFN | _CRT0_FLAG_NEARPTR); - - /* Zero out the 'atexit' chain in the dumped executable, to avoid - calling the atexit functions twice. (emacs.c:main installs an - atexit function.) */ - save_atexit_ptr = __atexit_ptr; - __atexit_ptr = NULL; -#endif - - lseek (new, (long) text_scnptr, 0); - ptr = (char *) f_ohdr.text_start; - end = ptr + f_ohdr.tsize; - write_segment (new, ptr, end); - - lseek (new, (long) data_scnptr, 0); - ptr = (char *) f_ohdr.data_start; - end = ptr + f_ohdr.dsize; - write_segment (new, ptr, end); - -#ifdef MSDOS - /* Restore our exception hooks. */ - __djgpp_exception_toggle (); - - /* Restore the startup flags. */ - _crt0_startup_flags = save_djgpp_startup_flags; - - /* Restore the atexit chain. */ - __atexit_ptr = save_atexit_ptr; -#endif - - - return 0; -} - -/* **************************************************************** - * copy_sym - * - * Copy the relocation information and symbol table from the a.out to the new - */ -static int -copy_sym (int new, int a_out, const char *a_name, const char *new_name) -{ - char page[1024]; - int n; - - if (a_out < 0) - return 0; - - if (SYMS_START == 0L) - return 0; - - if (lnnoptr) /* if there is line number info */ - lseek (a_out, coff_offset + lnnoptr, 0); /* start copying from there */ - else - lseek (a_out, coff_offset + SYMS_START, 0); /* Position a.out to symtab. */ - - while ((n = read (a_out, page, sizeof page)) > 0) - { - if (write (new, page, n) != n) - { - PERROR (new_name); - } - } - if (n < 0) - { - PERROR (a_name); - } - return 0; -} - - -/* - * If the COFF file contains a symbol table and a line number section, - * then any auxiliary entries that have values for x_lnnoptr must - * be adjusted by the amount that the line number section has moved - * in the file (bias computed in make_hdr). The #@$%&* designers of - * the auxiliary entry structures used the absolute file offsets for - * the line number entry rather than an offset from the start of the - * line number section! - * - * When I figure out how to scan through the symbol table and pick out - * the auxiliary entries that need adjustment, this routine will - * be fixed. As it is now, all such entries are wrong and sdb - * will complain. Fred Fish, UniSoft Systems Inc. - */ - -/* This function is probably very slow. Instead of reopening the new - file for input and output it should copy from the old to the new - using the two descriptors already open (WRITEDESC and READDESC). - Instead of reading one small structure at a time it should use - a reasonable size buffer. But I don't have time to work on such - things, so I am installing it as submitted to me. -- RMS. */ - -int -adjust_lnnoptrs (int writedesc, int readdesc, const char *new_name) -{ - register int nsyms; - register int new; - struct syment symentry; - union auxent auxentry; - - if (!lnnoptr || !f_hdr.f_symptr) - return 0; - -#ifdef MSDOS - if ((new = writedesc) < 0) -#else - if ((new = emacs_open (new_name, O_RDWR, 0)) < 0) -#endif - { - PERROR (new_name); - return -1; - } - - lseek (new, f_hdr.f_symptr, 0); - for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++) - { - read (new, &symentry, SYMESZ); - if (symentry.n_numaux) - { - read (new, &auxentry, AUXESZ); - nsyms++; - if (ISFCN (symentry.n_type) || symentry.n_type == 0x2400) - { - auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias; - lseek (new, -AUXESZ, 1); - write (new, &auxentry, AUXESZ); - } - } - } -#ifndef MSDOS - emacs_close (new); -#endif - return 0; -} - -/* **************************************************************** - * unexec - * - * driving logic. - */ -void -unexec (const char *new_name, const char *a_name) -{ - int new = -1, a_out = -1; - - if (a_name && (a_out = emacs_open (a_name, O_RDONLY, 0)) < 0) - { - PERROR (a_name); - } - if ((new = emacs_open (new_name, O_WRONLY | O_CREAT | O_TRUNC, 0777)) < 0) - { - PERROR (new_name); - } - - if (make_hdr (new, a_out, a_name, new_name) < 0 - || copy_text_and_data (new, a_out) < 0 - || copy_sym (new, a_out, a_name, new_name) < 0 - || adjust_lnnoptrs (new, a_out, new_name) < 0 - ) - { - emacs_close (new); - return; - } - - emacs_close (new); - if (a_out >= 0) - emacs_close (a_out); -} - -#endif /* HAVE_UNEXEC */ diff --git a/src/unexcw.c b/src/unexcw.c deleted file mode 100644 index 33f148e84e9..00000000000 --- a/src/unexcw.c +++ /dev/null @@ -1,302 +0,0 @@ -/* unexec() support for Cygwin; - complete rewrite of xemacs Cygwin unexec() code - - Copyright (C) 2004-2025 Free Software Foundation, Inc. - -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 of the License, 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. If not, see . */ - -#include -#include "unexec.h" -#include "lisp.h" -#include -#include -#include -#include -#include - -#define DOTEXE ".exe" - -/* -** header for Windows executable files -*/ -typedef struct -{ - FILHDR file_header; - PEAOUTHDR file_optional_header; - SCNHDR section_header[32]; -} exe_header_t; - -int debug_unexcw = 0; - -/* -** Read the header from the executable into memory so we can more easily access it. -*/ -static exe_header_t * -read_exe_header (int fd, exe_header_t * exe_header_buffer) -{ - int i; - MAYBE_UNUSED int ret; - - assert (fd >= 0); - assert (exe_header_buffer != 0); - - ret = lseek (fd, 0L, SEEK_SET); - assert (ret != -1); - - ret = - read (fd, &exe_header_buffer->file_header, - sizeof (exe_header_buffer->file_header)); - assert (ret == sizeof (exe_header_buffer->file_header)); - - assert (exe_header_buffer->file_header.e_magic == 0x5a4d); - assert (exe_header_buffer->file_header.nt_signature == 0x4550); -#ifdef __x86_64__ - assert (exe_header_buffer->file_header.f_magic == 0x8664); -#else - assert (exe_header_buffer->file_header.f_magic == 0x014c); -#endif - assert (exe_header_buffer->file_header.f_nscns > 0); - assert (exe_header_buffer->file_header.f_nscns <= - ARRAYELTS (exe_header_buffer->section_header)); - assert (exe_header_buffer->file_header.f_opthdr > 0); - - ret = - read (fd, &exe_header_buffer->file_optional_header, - sizeof (exe_header_buffer->file_optional_header)); - assert (ret == sizeof (exe_header_buffer->file_optional_header)); - -#ifdef __x86_64__ - assert (exe_header_buffer->file_optional_header.magic == 0x020b); -#else - assert (exe_header_buffer->file_optional_header.magic == 0x010b); -#endif - - for (i = 0; i < exe_header_buffer->file_header.f_nscns; ++i) - { - ret = - read (fd, &exe_header_buffer->section_header[i], - sizeof (exe_header_buffer->section_header[i])); - assert (ret == sizeof (exe_header_buffer->section_header[i])); - } - - return (exe_header_buffer); -} - -/* -** Fix the dumped emacs executable: -** -** - copy .data section data of interest from running executable into -** output .exe file -** -** - convert .bss section into an initialized data section (like -** .data) and copy .bss section data of interest from running -** executable into output .exe file -*/ -static void -fixup_executable (int fd) -{ - exe_header_t exe_header_buffer; - exe_header_t *exe_header; - int i; - MAYBE_UNUSED int ret; - int found_data = 0; - int found_bss = 0; - - exe_header = read_exe_header (fd, &exe_header_buffer); - assert (exe_header != 0); - - assert (exe_header->file_header.f_nscns > 0); - for (i = 0; i < exe_header->file_header.f_nscns; ++i) - { - unsigned long start_address = - exe_header->section_header[i].s_vaddr + - exe_header->file_optional_header.ImageBase; - unsigned long end_address = - exe_header->section_header[i].s_vaddr + - exe_header->file_optional_header.ImageBase + - exe_header->section_header[i].s_paddr; - if (debug_unexcw) - printf ("%8s start %#lx end %#lx\n", - exe_header->section_header[i].s_name, - start_address, end_address); - if (my_edata >= (char *) start_address - && my_edata < (char *) end_address) - { - /* data section */ - ret = - lseek (fd, (long) (exe_header->section_header[i].s_scnptr), - SEEK_SET); - assert (ret != -1); - ret = - write (fd, (char *) start_address, - my_edata - (char *) start_address); - assert (ret == my_edata - (char *) start_address); - ++found_data; - if (debug_unexcw) - printf (" .data, mem start %#lx mem length %td\n", - start_address, my_edata - (char *) start_address); - if (debug_unexcw) - printf (" .data, file start %d file length %d\n", - (int) exe_header->section_header[i].s_scnptr, - (int) exe_header->section_header[i].s_paddr); - } - else if (my_endbss >= (char *) start_address - && my_endbss < (char *) end_address) - { - /* bss section */ - ++found_bss; - if (exe_header->section_header[i].s_flags & 0x00000080) - { - /* convert uninitialized data section to initialized data section */ - struct stat statbuf; - ret = fstat (fd, &statbuf); - assert (ret != -1); - - exe_header->section_header[i].s_flags &= ~0x00000080; - exe_header->section_header[i].s_flags |= 0x00000040; - - exe_header->section_header[i].s_scnptr = - (statbuf.st_size + - exe_header->file_optional_header.FileAlignment) / - exe_header->file_optional_header.FileAlignment * - exe_header->file_optional_header.FileAlignment; - - exe_header->section_header[i].s_size = - (exe_header->section_header[i].s_paddr + - exe_header->file_optional_header.FileAlignment) / - exe_header->file_optional_header.FileAlignment * - exe_header->file_optional_header.FileAlignment; - - /* Make sure the generated bootstrap binary isn't - * sparse. NT doesn't use a file cache for sparse - * executables, so if we bootstrap Emacs using a sparse - * bootstrap-emacs.exe, bootstrap takes about twenty - * times longer than it would otherwise. */ - - ret = posix_fallocate (fd, - ( exe_header->section_header[i].s_scnptr + - exe_header->section_header[i].s_size ), - 1); - - assert (ret != -1); - - ret = - lseek (fd, - (long) (exe_header->section_header[i].s_scnptr + - exe_header->section_header[i].s_size - 1), - SEEK_SET); - assert (ret != -1); - ret = write (fd, "", 1); - assert (ret == 1); - - ret = - lseek (fd, - (long) ((char *) &exe_header->section_header[i] - - (char *) exe_header), SEEK_SET); - assert (ret != -1); - ret = - write (fd, &exe_header->section_header[i], - sizeof (exe_header->section_header[i])); - assert (ret == sizeof (exe_header->section_header[i])); - if (debug_unexcw) - printf (" seek to %ld, write %zu\n", - (long) ((char *) &exe_header->section_header[i] - - (char *) exe_header), - sizeof (exe_header->section_header[i])); - } - /* write initialized data section */ - ret = - lseek (fd, (long) (exe_header->section_header[i].s_scnptr), - SEEK_SET); - assert (ret != -1); - ret = - write (fd, (char *) start_address, - my_endbss - (char *) start_address); - assert (ret == (my_endbss - (char *) start_address)); - if (debug_unexcw) - printf (" .bss, mem start %#lx mem length %td\n", - start_address, my_endbss - (char *) start_address); - if (debug_unexcw) - printf (" .bss, file start %d file length %d\n", - (int) exe_header->section_header[i].s_scnptr, - (int) exe_header->section_header[i].s_paddr); - } - } - assert (found_bss == 1); - assert (found_data == 1); -} - -/* -** Windows likes .exe suffixes on executables. -*/ -static char * -add_exe_suffix_if_necessary (const char *name, char *modified) -{ - int i = strlen (name); - if (i <= (sizeof (DOTEXE) - 1)) - { - sprintf (modified, "%s%s", name, DOTEXE); - } - else if (!strcasecmp (name + i - (sizeof (DOTEXE) - 1), DOTEXE)) - { - strcpy (modified, name); - } - else - { - sprintf (modified, "%s%s", name, DOTEXE); - } - return (modified); -} - -void -unexec (const char *outfile, const char *infile) -{ - char infile_buffer[FILENAME_MAX]; - char outfile_buffer[FILENAME_MAX]; - int fd_in; - int fd_out; - int ret; - MAYBE_UNUSED int ret2; - - infile = add_exe_suffix_if_necessary (infile, infile_buffer); - outfile = add_exe_suffix_if_necessary (outfile, outfile_buffer); - - fd_in = emacs_open (infile, O_RDONLY, 0); - assert (fd_in >= 0); - fd_out = emacs_open (outfile, O_RDWR | O_TRUNC | O_CREAT, 0755); - assert (fd_out >= 0); - for (;;) - { - char buffer[4096]; - ret = read (fd_in, buffer, sizeof (buffer)); - if (ret == 0) - { - /* eof */ - break; - } - assert (ret > 0); - /* data */ - ret2 = write (fd_out, buffer, ret); - assert (ret2 == ret); - } - ret = emacs_close (fd_in); - assert (ret == 0); - - fixup_executable (fd_out); - - ret = emacs_close (fd_out); - assert (ret == 0); -} diff --git a/src/unexec.h b/src/unexec.h deleted file mode 100644 index cdb2e8016ea..00000000000 --- a/src/unexec.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef EMACS_UNEXEC_H -#define EMACS_UNEXEC_H -void unexec (const char *, const char *); -#endif /* EMACS_UNEXEC_H */ diff --git a/src/unexelf.c b/src/unexelf.c deleted file mode 100644 index 1cb1476e267..00000000000 --- a/src/unexelf.c +++ /dev/null @@ -1,658 +0,0 @@ -/* Copyright (C) 1985-1988, 1990, 1992, 1999-2025 Free Software - Foundation, Inc. - -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 of the License, 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. If not, see . */ - -/* -In other words, you are welcome to use, share and improve this program. -You are forbidden to forbid anyone else to use, share and improve -what you give them. Help stamp out software-hoarding! */ - - -/* - * unexec.c - Convert a running program into an a.out file. - * - * Author: Spencer W. Thomas - * Computer Science Dept. - * University of Utah - * Date: Tue Mar 2 1982 - * Modified heavily since then. - * - * Synopsis: - * unexec (const char *new_name, const char *old_name); - * - * Takes a snapshot of the program and makes an a.out format file in the - * file named by the string argument new_name. - * If old_name is non-NULL, the symbol table will be taken from the given file. - * On some machines, an existing old_name file is required. - * - */ - -/* We do not use mmap because that fails with NFS. - Instead we read the whole file, modify it, and write it out. */ - -#include -#include "unexec.h" -#include "lisp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __QNX__ -# include -#elif !defined __NetBSD__ && !defined __OpenBSD__ -# include -#endif -#include -#if defined (_SYSTYPE_SYSV) -#include -#include -#endif /* _SYSTYPE_SYSV */ - -#ifndef MAP_ANON -#ifdef MAP_ANONYMOUS -#define MAP_ANON MAP_ANONYMOUS -#else -#define MAP_ANON 0 -#endif -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *) -1) -#endif - -#if defined (__alpha__) && !defined (__NetBSD__) && !defined (__OpenBSD__) -/* Declare COFF debugging symbol table. This used to be in - /usr/include/sym.h, but this file is no longer included in Red Hat - 5.0 and presumably in any other glibc 2.x based distribution. */ -typedef struct { - short magic; - short vstamp; - int ilineMax; - int idnMax; - int ipdMax; - int isymMax; - int ioptMax; - int iauxMax; - int issMax; - int issExtMax; - int ifdMax; - int crfd; - int iextMax; - long cbLine; - long cbLineOffset; - long cbDnOffset; - long cbPdOffset; - long cbSymOffset; - long cbOptOffset; - long cbAuxOffset; - long cbSsOffset; - long cbSsExtOffset; - long cbFdOffset; - long cbRfdOffset; - long cbExtOffset; -} HDRR, *pHDRR; -#define cbHDRR sizeof (HDRR) -#define hdrNil ((pHDRR)0) -#endif - -#ifdef __NetBSD__ -/* - * NetBSD does not have normal-looking user-land ELF support. - */ -# if defined __alpha__ || defined __sparc_v9__ || defined _LP64 -# define ELFSIZE 64 -# else -# define ELFSIZE 32 -# endif -# include - -# ifndef PT_LOAD -# define PT_LOAD Elf_pt_load -# if 0 /* was in pkgsrc patches for 20.7 */ -# define SHT_PROGBITS Elf_sht_progbits -# endif -# define SHT_SYMTAB Elf_sht_symtab -# define SHT_DYNSYM Elf_sht_dynsym -# define SHT_NULL Elf_sht_null -# define SHT_NOBITS Elf_sht_nobits -# define SHT_REL Elf_sht_rel -# define SHT_RELA Elf_sht_rela - -# define SHN_UNDEF Elf_eshn_undefined -# define SHN_ABS Elf_eshn_absolute -# define SHN_COMMON Elf_eshn_common -# endif /* !PT_LOAD */ - -# ifdef __alpha__ -# include -# define HDRR struct ecoff_symhdr -# define pHDRR HDRR * -# endif /* __alpha__ */ - -#ifdef __mips__ /* was in pkgsrc patches for 20.7 */ -# define SHT_MIPS_DEBUG DT_MIPS_FLAGS -# define HDRR struct Elf_Shdr -#endif /* __mips__ */ -#endif /* __NetBSD__ */ - -#ifdef __OpenBSD__ -# include -#endif - -#if __GNU_LIBRARY__ - 0 >= 6 -# include /* get ElfW etc */ -#endif - -#ifndef ElfW -# define ElfBitsW(bits, type) Elf##bits##_##type -# ifndef ELFSIZE -# ifdef _LP64 -# define ELFSIZE 64 -# else -# define ELFSIZE 32 -# endif -# endif - /* This macro expands `bits' before invoking ElfBitsW. */ -# define ElfExpandBitsW(bits, type) ElfBitsW (bits, type) -# define ElfW(type) ElfExpandBitsW (ELFSIZE, type) -#endif - -/* The code often converts ElfW (Half) values like e_shentsize to ptrdiff_t; - check that this doesn't lose information. */ -#include -static_assert ((! TYPE_SIGNED (ElfW (Half)) - || PTRDIFF_MIN <= TYPE_MINIMUM (ElfW (Half))) - && TYPE_MAXIMUM (ElfW (Half)) <= PTRDIFF_MAX); - -#ifdef UNEXELF_DEBUG -# define DEBUG_LOG(expr) fprintf (stderr, #expr " 0x%"PRIxMAX"\n", \ - (uintmax_t) (expr)) -#endif - -/* Get the address of a particular section or program header entry, - * accounting for the size of the entries. - */ - -static void * -entry_address (void *section_h, ptrdiff_t idx, ptrdiff_t entsize) -{ - char *h = section_h; - return h + idx * entsize; -} - -#define OLD_SECTION_H(n) \ - (*(ElfW (Shdr) *) entry_address (old_section_h, n, old_file_h->e_shentsize)) -#define NEW_SECTION_H(n) \ - (*(ElfW (Shdr) *) entry_address (new_section_h, n, new_file_h->e_shentsize)) -#define OLD_PROGRAM_H(n) \ - (*(ElfW (Phdr) *) entry_address (old_program_h, n, old_file_h->e_phentsize)) - -typedef unsigned char byte; - -/* **************************************************************** - * unexec - * - * driving logic. - * - * In ELF, this works by replacing the old bss SHT_NOBITS section with - * a new, larger, SHT_PROGBITS section. - * - */ -void -unexec (const char *new_name, const char *old_name) -{ - int new_file, old_file; - off_t new_file_size; - - /* Pointers to the base of the image of the two files. */ - caddr_t old_base, new_base; - -#if MAP_ANON == 0 - int mmap_fd; -#else -# define mmap_fd -1 -#endif - - /* Pointers to the file, program and section headers for the old and - new files. */ - ElfW (Ehdr) *old_file_h, *new_file_h; - ElfW (Phdr) *old_program_h, *new_program_h; - ElfW (Shdr) *old_section_h, *new_section_h; - - /* Point to the section name table. */ - char *old_section_names, *new_section_names; - - ElfW (Phdr) *old_bss_seg, *new_bss_seg; - ElfW (Addr) old_bss_addr, new_bss_addr; - ElfW (Word) old_bss_size, bss_size_growth, new_data2_size; - ElfW (Off) old_bss_offset, new_data2_offset; - - ptrdiff_t n; - ptrdiff_t old_bss_index; - struct stat stat_buf; - off_t old_file_size; - - /* Open the old file, allocate a buffer of the right size, and read - in the file contents. */ - - old_file = emacs_open (old_name, O_RDONLY, 0); - - if (old_file < 0) - fatal ("Can't open %s for reading: %s", old_name, strerror (errno)); - - if (fstat (old_file, &stat_buf) != 0) - fatal ("Can't fstat (%s): %s", old_name, strerror (errno)); - -#if MAP_ANON == 0 - mmap_fd = emacs_open ("/dev/zero", O_RDONLY, 0); - if (mmap_fd < 0) - fatal ("Can't open /dev/zero for reading: %s", strerror (errno)); -#endif - - /* We cannot use malloc here because that may use sbrk. If it does, - we'd dump our temporary buffers with Emacs, and we'd have to be - extra careful to use the correct value of sbrk(0) after - allocating all buffers in the code below, which we aren't. */ - old_file_size = stat_buf.st_size; - if (! (0 <= old_file_size && old_file_size <= SIZE_MAX)) - fatal ("File size out of range"); - old_base = mmap (NULL, old_file_size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, mmap_fd, 0); - if (old_base == MAP_FAILED) - fatal ("Can't allocate buffer for %s: %s", old_name, strerror (errno)); - - if (read (old_file, old_base, old_file_size) != old_file_size) - fatal ("Didn't read all of %s: %s", old_name, strerror (errno)); - - /* Get pointers to headers & section names */ - - old_file_h = (ElfW (Ehdr) *) old_base; - old_program_h = (ElfW (Phdr) *) ((byte *) old_base + old_file_h->e_phoff); - old_section_h = (ElfW (Shdr) *) ((byte *) old_base + old_file_h->e_shoff); - old_section_names = (char *) old_base - + OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset; - - /* Find the PT_LOAD header covering the highest address. This - segment will be where bss sections are located, past p_filesz. */ - old_bss_seg = 0; - for (n = old_file_h->e_phnum; --n >= 0; ) - { - ElfW (Phdr) *seg = &OLD_PROGRAM_H (n); - if (seg->p_type == PT_LOAD - && (old_bss_seg == 0 - || seg->p_vaddr > old_bss_seg->p_vaddr)) - old_bss_seg = seg; - } - eassume (old_bss_seg); - if (!old_bss_seg) - emacs_abort (); - - /* Note that old_bss_addr may be lower than the first bss section - address, since the section may need aligning. */ - old_bss_addr = old_bss_seg->p_vaddr + old_bss_seg->p_filesz; - old_bss_offset = old_bss_seg->p_offset + old_bss_seg->p_filesz; - old_bss_size = old_bss_seg->p_memsz - old_bss_seg->p_filesz; - - /* Find the last bss style section in the bss segment range. */ - old_bss_index = -1; - for (n = old_file_h->e_shnum; --n > 0; ) - { - ElfW (Shdr) *shdr = &OLD_SECTION_H (n); - if (shdr->sh_type == SHT_NOBITS - && shdr->sh_addr >= old_bss_addr - && shdr->sh_addr + shdr->sh_size <= old_bss_addr + old_bss_size - && (old_bss_index == -1 - || OLD_SECTION_H (old_bss_index).sh_addr < shdr->sh_addr)) - old_bss_index = n; - } - - if (old_bss_index == -1) - fatal ("no bss section found"); - - void *no_break = (void *) (intptr_t) -1; - void *new_break = no_break; -#ifdef HAVE_SBRK - new_break = sbrk (0); -#endif - if (new_break == no_break) - new_break = (byte *) old_bss_addr + old_bss_size; - new_bss_addr = (ElfW (Addr)) new_break; - bss_size_growth = new_bss_addr - old_bss_addr; - new_data2_size = bss_size_growth; - new_data2_size += alignof (ElfW (Shdr)) - 1; - new_data2_size -= new_data2_size % alignof (ElfW (Shdr)); - - new_data2_offset = old_bss_offset; - -#ifdef UNEXELF_DEBUG - fprintf (stderr, "old_bss_index %td\n", old_bss_index); - DEBUG_LOG (old_bss_addr); - DEBUG_LOG (old_bss_size); - DEBUG_LOG (old_bss_offset); - DEBUG_LOG (new_bss_addr); - DEBUG_LOG (new_data2_size); - DEBUG_LOG (new_data2_offset); -#endif - - if (new_bss_addr < old_bss_addr + old_bss_size) - fatal (".bss shrank when undumping"); - - /* Set the output file to the right size. Allocate a buffer to hold - the image of the new file. Set pointers to various interesting - objects. */ - - new_file = emacs_open (new_name, O_RDWR | O_CREAT, 0777); - if (new_file < 0) - fatal ("Can't creat (%s): %s", new_name, strerror (errno)); - - new_file_size = old_file_size + new_data2_size; - - if (ftruncate (new_file, new_file_size)) - fatal ("Can't ftruncate (%s): %s", new_name, strerror (errno)); - - new_base = mmap (NULL, new_file_size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, mmap_fd, 0); - if (new_base == MAP_FAILED) - fatal ("Can't allocate buffer for %s: %s", old_name, strerror (errno)); - - /* Make our new file, program and section headers as copies of the - originals. */ - - new_file_h = (ElfW (Ehdr) *) new_base; - memcpy (new_file_h, old_file_h, old_file_h->e_ehsize); - - /* Fix up file header. Section header is further away now. */ - - if (new_file_h->e_shoff >= old_bss_offset) - new_file_h->e_shoff += new_data2_size; - - new_program_h = (ElfW (Phdr) *) ((byte *) new_base + new_file_h->e_phoff); - new_section_h = (ElfW (Shdr) *) ((byte *) new_base + new_file_h->e_shoff); - - memcpy (new_program_h, old_program_h, - old_file_h->e_phnum * old_file_h->e_phentsize); - memcpy (new_section_h, old_section_h, - old_file_h->e_shnum * old_file_h->e_shentsize); - -#ifdef UNEXELF_DEBUG - DEBUG_LOG (old_file_h->e_shoff); - fprintf (stderr, "Old section count %td\n", (ptrdiff_t) old_file_h->e_shnum); - DEBUG_LOG (new_file_h->e_shoff); - fprintf (stderr, "New section count %td\n", (ptrdiff_t) new_file_h->e_shnum); -#endif - - /* Fix up program header. Extend the writable data segment so - that the bss area is covered too. */ - - new_bss_seg = new_program_h + (old_bss_seg - old_program_h); - new_bss_seg->p_filesz = new_bss_addr - new_bss_seg->p_vaddr; - new_bss_seg->p_memsz = new_bss_seg->p_filesz; - - /* Copy over what we have in memory now for the bss area. */ - memcpy (new_base + new_data2_offset, (caddr_t) old_bss_addr, - bss_size_growth); - - /* Walk through all section headers, copying data and updating. */ - for (n = 1; n < old_file_h->e_shnum; n++) - { - caddr_t src; - ElfW (Shdr) *old_shdr = &OLD_SECTION_H (n); - ElfW (Shdr) *new_shdr = &NEW_SECTION_H (n); - - if (new_shdr->sh_type == SHT_NOBITS - && new_shdr->sh_addr >= old_bss_addr - && (new_shdr->sh_addr + new_shdr->sh_size - <= old_bss_addr + old_bss_size)) - { - /* This section now has file backing. */ - new_shdr->sh_type = SHT_PROGBITS; - - /* SHT_NOBITS sections do not need a valid sh_offset, so it - might be incorrect. Write the correct value. */ - new_shdr->sh_offset = (new_shdr->sh_addr - new_bss_seg->p_vaddr - + new_bss_seg->p_offset); - - /* If this is was a SHT_NOBITS .plt section, then it is - probably a PowerPC PLT. If it is PowerPC64 ELFv1 then - glibc ld.so doesn't initialize the toc pointer word. A - non-zero toc pointer word can defeat Power7 thread safety - during lazy update of a PLT entry. This only matters if - emacs becomes multi-threaded. */ - if (strcmp (old_section_names + new_shdr->sh_name, ".plt") == 0) - memset (new_shdr->sh_offset + new_base, 0, new_shdr->sh_size); - - /* Extend the size of the last bss section to cover dumped - data. */ - if (n == old_bss_index) - new_shdr->sh_size = new_bss_addr - new_shdr->sh_addr; - - /* We have already copied this section from the current - process. */ - continue; - } - - /* Any section that was originally placed after the .bss - section should now be offset by NEW_DATA2_SIZE. */ - if (new_shdr->sh_offset >= old_bss_offset) - new_shdr->sh_offset += new_data2_size; - - /* Now, start to copy the content of sections. */ - if (new_shdr->sh_type == SHT_NULL - || new_shdr->sh_type == SHT_NOBITS) - continue; - - /* Some sections are copied from the current process instead of - the old file. */ - if (!strcmp (old_section_names + new_shdr->sh_name, ".data") - || !strcmp (old_section_names + new_shdr->sh_name, ".sdata") - || !strcmp (old_section_names + new_shdr->sh_name, ".lit4") - || !strcmp (old_section_names + new_shdr->sh_name, ".lit8") - || !strcmp (old_section_names + new_shdr->sh_name, ".sdata1") - || !strcmp (old_section_names + new_shdr->sh_name, ".data1")) - src = (caddr_t) old_shdr->sh_addr; - else - src = old_base + old_shdr->sh_offset; - - memcpy (new_shdr->sh_offset + new_base, src, new_shdr->sh_size); - -#if (defined __alpha__ && !defined __OpenBSD__) || defined _SYSTYPE_SYSV - /* Update Alpha and MIPS COFF debug symbol table. */ - if (strcmp (old_section_names + new_shdr->sh_name, ".mdebug") == 0 - && new_shdr->sh_offset - old_shdr->sh_offset != 0 -#if defined _SYSTYPE_SYSV - && new_shdr->sh_type == SHT_MIPS_DEBUG -#endif - ) - { - ptrdiff_t diff = new_shdr->sh_offset - old_shdr->sh_offset; - HDRR *phdr = (HDRR *) (new_shdr->sh_offset + new_base); - - phdr->cbLineOffset += diff; - phdr->cbDnOffset += diff; - phdr->cbPdOffset += diff; - phdr->cbSymOffset += diff; - phdr->cbOptOffset += diff; - phdr->cbAuxOffset += diff; - phdr->cbSsOffset += diff; - phdr->cbSsExtOffset += diff; - phdr->cbFdOffset += diff; - phdr->cbRfdOffset += diff; - phdr->cbExtOffset += diff; - } -#endif /* __alpha__ || _SYSTYPE_SYSV */ - } - - /* Update the symbol values of _edata and _end. */ - for (n = new_file_h->e_shnum; 0 < --n; ) - { - byte *symnames; - ElfW (Sym) *symp, *symendp; - ElfW (Shdr) *sym_shdr = &NEW_SECTION_H (n); - - if (sym_shdr->sh_type != SHT_DYNSYM - && sym_shdr->sh_type != SHT_SYMTAB) - continue; - - symnames = ((byte *) new_base - + NEW_SECTION_H (sym_shdr->sh_link).sh_offset); - symp = (ElfW (Sym) *) (sym_shdr->sh_offset + new_base); - symendp = (ElfW (Sym) *) ((byte *) symp + sym_shdr->sh_size); - - for (; symp < symendp; symp ++) - { - if (strcmp ((char *) (symnames + symp->st_name), "_end") == 0 - || strcmp ((char *) (symnames + symp->st_name), "end") == 0 - || strcmp ((char *) (symnames + symp->st_name), "_edata") == 0 - || strcmp ((char *) (symnames + symp->st_name), "edata") == 0) - memcpy (&symp->st_value, &new_bss_addr, sizeof (new_bss_addr)); - - /* Strictly speaking, #ifdef below is not necessary. But we - keep it to indicate that this kind of change may also be - necessary for other unexecs to support GNUstep. */ -#ifdef NS_IMPL_GNUSTEP - /* ObjC runtime modifies the values of some data structures - such as classes and selectors in the .data section after - loading. As the dump process copies the .data section - from the current process, that causes problems when the - modified classes are reinitialized in the dumped - executable. We copy such data from the old file, not - from the current process. */ - if (strncmp ((char *) (symnames + symp->st_name), - "_OBJC_", sizeof ("_OBJC_") - 1) == 0) - { - ElfW (Shdr) *new_shdr = &NEW_SECTION_H (symp->st_shndx); - if (new_shdr->sh_type != SHT_NOBITS) - { - ElfW (Shdr) *old_shdr = &OLD_SECTION_H (symp->st_shndx); - ptrdiff_t reladdr = symp->st_value - new_shdr->sh_addr; - ptrdiff_t newoff = reladdr + new_shdr->sh_offset; - - if (old_shdr->sh_type == SHT_NOBITS) - memset (new_base + newoff, 0, symp->st_size); - else - { - ptrdiff_t oldoff = reladdr + old_shdr->sh_offset; - memcpy (new_base + newoff, old_base + oldoff, - symp->st_size); - } - } - } -#endif - } - } - - /* Modify the names of sections we changed from SHT_NOBITS to - SHT_PROGBITS. This is really just cosmetic, but some tools that - (wrongly) operate on section names rather than types might be - confused by a SHT_PROGBITS .bss section. */ - new_section_names = ((char *) new_base - + NEW_SECTION_H (new_file_h->e_shstrndx).sh_offset); - for (n = new_file_h->e_shnum; 0 < --n; ) - { - ElfW (Shdr) *old_shdr = &OLD_SECTION_H (n); - ElfW (Shdr) *new_shdr = &NEW_SECTION_H (n); - - /* Replace the leading '.' with ','. When .shstrtab is string - merged this will rename both .bss and .rela.bss to ,bss and - .rela,bss. */ - if (old_shdr->sh_type == SHT_NOBITS - && new_shdr->sh_type == SHT_PROGBITS) - *(new_section_names + new_shdr->sh_name) = ','; - } - - /* This loop seeks out relocation sections for the data section, so - that it can undo relocations performed by the runtime loader. - - The following approach does not work on x86 platforms that use - the GNU Gold linker, which can generate .rel.dyn relocation - sections containing R_386_32 entries that the following code does - not grok. Emacs works around this problem by avoiding C - constructs that generate such entries, which is horrible hack. - - FIXME: Presumably more problems like this will crop up as linkers - get fancier. We really need to stop assuming that Emacs can grok - arbitrary linker output. See Bug#27248. */ - for (n = new_file_h->e_shnum; 0 < --n; ) - { - ElfW (Shdr) *rel_shdr = &NEW_SECTION_H (n); - ElfW (Shdr) *shdr; - - switch (rel_shdr->sh_type) - { - default: - break; - case SHT_REL: - case SHT_RELA: - /* This code handles two different size structs, but there should - be no harm in that provided that r_offset is always the first - member. */ - shdr = &NEW_SECTION_H (rel_shdr->sh_info); - if (!strcmp (old_section_names + shdr->sh_name, ".data") - || !strcmp (old_section_names + shdr->sh_name, ".sdata") - || !strcmp (old_section_names + shdr->sh_name, ".lit4") - || !strcmp (old_section_names + shdr->sh_name, ".lit8") - || !strcmp (old_section_names + shdr->sh_name, ".sdata1") - || !strcmp (old_section_names + shdr->sh_name, ".data1")) - { - ElfW (Addr) offset = shdr->sh_addr - shdr->sh_offset; - caddr_t reloc = old_base + rel_shdr->sh_offset, end; - for (end = reloc + rel_shdr->sh_size; - reloc < end; - reloc += rel_shdr->sh_entsize) - { - ElfW (Addr) addr = ((ElfW (Rel) *) reloc)->r_offset - offset; - /* Ignore R_*_NONE relocs. */ - if (((ElfW (Rel) *) reloc)->r_offset == 0) - continue; - /* Assume reloc applies to a word. - ??? This is not always true, eg. TLS module/index - pair in .got which occupies two words. */ - memcpy (new_base + addr, old_base + addr, - sizeof (ElfW (Addr))); - } - } - break; - } - } - - /* Write out new_file, and free the buffers. */ - - if (write (new_file, new_base, new_file_size) != new_file_size) - fatal ("Didn't write %lu bytes to %s: %s", - (unsigned long) new_file_size, new_name, strerror (errno)); - munmap (old_base, old_file_size); - munmap (new_base, new_file_size); - - /* Close the files and make the new file executable. */ - -#if MAP_ANON == 0 - emacs_close (mmap_fd); -#endif - - if (emacs_close (old_file) != 0) - fatal ("Can't close (%s): %s", old_name, strerror (errno)); - - if (emacs_close (new_file) != 0) - fatal ("Can't close (%s): %s", new_name, strerror (errno)); -} diff --git a/src/unexhp9k800.c b/src/unexhp9k800.c deleted file mode 100644 index d2943eb18c9..00000000000 --- a/src/unexhp9k800.c +++ /dev/null @@ -1,324 +0,0 @@ -/* Unexec for HP 9000 Series 800 machines. - - This file is in the public domain. - - Author: John V. Morris - - This file was written by John V. Morris at Hewlett Packard. - Both the author and Hewlett Packard Co. have disclaimed the - copyright on this file, and it is therefore in the public domain. - (Search for "hp9k800" in copyright.list.) -*/ - -/* - Bob Desinger - - Note that the GNU project considers support for HP operation a - peripheral activity which should not be allowed to divert effort - from development of the GNU system. Changes in this code will be - installed when users send them in, but aside from that we don't - plan to think about it, or about whether other Emacs maintenance - might break it. - - - Unexec creates a copy of the old a.out file, and replaces the old data - area with the current data area. When the new file is executed, the - process will see the same data structures and data values that the - original process had when unexec was called. - - Unlike other versions of unexec, this one copies symbol table and - debug information to the new a.out file. Thus, the new a.out file - may be debugged with symbolic debuggers. - - If you fix any bugs in this, I'd like to incorporate your fixes. - Send them to uunet!hpda!hpsemc!jmorris or jmorris%hpsemc@hplabs.HP.COM. - - CAVEATS: - This routine saves the current value of all static and external - variables. This means that any data structure that needs to be - initialized must be explicitly reset. Variables will not have their - expected default values. - - Unfortunately, the HP-UX signal handler has internal initialization - flags which are not explicitly reset. Thus, for signals to work in - conjunction with this routine, the following code must executed when - the new process starts up. - - void _sigreturn (); - ... - sigsetreturn (_sigreturn); -*/ - -#include -#include "unexec.h" -#include "lisp.h" -#include "sysstdio.h" - -#include -#include -#include -#include - -/* brk value to restore, stored as a global. - This is really used only if we used shared libraries. */ -static long brk_on_dump = 0; - -/* Called from main, if we use shared libraries. */ -int -run_time_remap (char *ignored) -{ - brk ((char *) brk_on_dump); -} - -#undef roundup -#define roundup(x,n) (((x) + ((n) - 1)) & ~((n) - 1)) /* n is power of 2 */ - -/* Report a fatal error and exit. */ -static _Noreturn void -unexec_error (char const *msg) -{ - perror (msg); - exit (1); -} - -/* Do an lseek and check the result. */ -static void -check_lseek (int fd, off_t offset, int whence) -{ - if (lseek (fd, offset, whence) < 0) - unexec_error ("Cannot lseek"); -} - -/* Save current data space in the file, update header. */ - -static void -save_data_space (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr, - int size) -{ - /* Write the entire data space out to the file */ - if (write (file, auxhdr->exec_dmem, size) != size) - unexec_error ("Can't save new data space"); - - /* Update the header to reflect the new data size */ - auxhdr->exec_dsize = size; - auxhdr->exec_bsize = 0; -} - -/* Update the values of file pointers when something is inserted. */ - -static void -update_file_ptrs (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr, - unsigned int location, int offset) -{ - struct subspace_dictionary_record subspace; - int i; - - /* Increase the overall size of the module */ - hdr->som_length += offset; - - /* Update the various file pointers in the header */ -#define update(ptr) if (ptr > location) ptr = ptr + offset - update (hdr->aux_header_location); - update (hdr->space_strings_location); - update (hdr->init_array_location); - update (hdr->compiler_location); - update (hdr->symbol_location); - update (hdr->fixup_request_location); - update (hdr->symbol_strings_location); - update (hdr->unloadable_sp_location); - update (auxhdr->exec_tfile); - update (auxhdr->exec_dfile); - - /* Do for each subspace dictionary entry */ - check_lseek (file, hdr->subspace_location, 0); - for (i = 0; i < hdr->subspace_total; i++) - { - ptrdiff_t subspace_size = sizeof subspace; - if (read (file, &subspace, subspace_size) != subspace_size) - unexec_error ("Can't read subspace record"); - - /* If subspace has a file location, update it */ - if (subspace.initialization_length > 0 - && subspace.file_loc_init_value > location) - { - subspace.file_loc_init_value += offset; - check_lseek (file, -subspace_size, 1); - if (write (file, &subspace, subspace_size) != subspace_size) - unexec_error ("Can't update subspace record"); - } - } - - /* Do for each initialization pointer record */ - /* (I don't think it applies to executable files, only relocatables) */ -#undef update -} - -/* Read in the header records from an a.out file. */ - -static void -read_header (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr) -{ - - /* Read the header in */ - check_lseek (file, 0, 0); - if (read (file, hdr, sizeof (*hdr)) != sizeof (*hdr)) - unexec_error ("Couldn't read header from a.out file"); - - if (hdr->a_magic != EXEC_MAGIC && hdr->a_magic != SHARE_MAGIC - && hdr->a_magic != DEMAND_MAGIC) - { - fputs ("a.out file doesn't have valid magic number\n", stderr); - exit (1); - } - - check_lseek (file, hdr->aux_header_location, 0); - if (read (file, auxhdr, sizeof (*auxhdr)) != sizeof (*auxhdr)) - unexec_error ("Couldn't read auxiliary header from a.out file"); -} - -/* Write out the header records into an a.out file. */ - -static void -write_header (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr) -{ - /* Update the checksum */ - hdr->checksum = calculate_checksum (hdr); - - /* Write the header back into the a.out file */ - check_lseek (file, 0, 0); - if (write (file, hdr, sizeof (*hdr)) != sizeof (*hdr)) - unexec_error ("Couldn't write header to a.out file"); - check_lseek (file, hdr->aux_header_location, 0); - if (write (file, auxhdr, sizeof (*auxhdr)) != sizeof (*auxhdr)) - unexec_error ("Couldn't write auxiliary header to a.out file"); -} - -/* Calculate the checksum of a SOM header record. */ - -static int -calculate_checksum (struct header *hdr) -{ - int checksum, i, *ptr; - - checksum = 0; ptr = (int *) hdr; - - for (i = 0; i < sizeof (*hdr) / sizeof (int) - 1; i++) - checksum ^= ptr[i]; - - return (checksum); -} - -/* Copy size bytes from the old file to the new one. */ - -static void -copy_file (int old, int new, int size) -{ - int len; - int buffer[8192]; /* word aligned will be faster */ - - for (; size > 0; size -= len) - { - len = min (size, sizeof (buffer)); - if (read (old, buffer, len) != len) - unexec_error ("Read failure on a.out file"); - if (write (new, buffer, len) != len) - unexec_error ("Write failure in a.out file"); - } -} - -/* Copy the rest of the file, up to EOF. */ - -static void -copy_rest (int old, int new) -{ - int buffer[4096]; - int len; - - /* Copy bytes until end of file or error */ - while ((len = read (old, buffer, sizeof (buffer))) > 0) - if (write (new, buffer, len) != len) break; - - if (len != 0) - unexec_error ("Unable to copy the rest of the file"); -} - -#ifdef DEBUG -static void -display_header (struct header *hdr, struct som_exec_auxhdr *auxhdr) -{ - /* Display the header information (debug) */ - printf ("\n\nFILE HEADER\n"); - printf ("magic number %d \n", hdr->a_magic); - printf ("text loc %.8x size %d \n", auxhdr->exec_tmem, auxhdr->exec_tsize); - printf ("data loc %.8x size %d \n", auxhdr->exec_dmem, auxhdr->exec_dsize); - printf ("entry %x \n", auxhdr->exec_entry); - printf ("Bss segment size %u\n", auxhdr->exec_bsize); - printf ("\n"); - printf ("data file loc %d size %d\n", - auxhdr->exec_dfile, auxhdr->exec_dsize); - printf ("som_length %d\n", hdr->som_length); - printf ("unloadable sploc %d size %d\n", - hdr->unloadable_sp_location, hdr->unloadable_sp_size); -} -#endif /* DEBUG */ - - -/* Create a new a.out file, same as old but with current data space */ -void -unexec (const char *new_name, /* name of the new a.out file to be created */ - const char *old_name) /* name of the old a.out file */ -{ - int old, new; - int old_size, new_size; - struct header hdr; - struct som_exec_auxhdr auxhdr; - long i; - - /* For the greatest flexibility, should create a temporary file in - the same directory as the new file. When everything is complete, - rename the temp file to the new name. - This way, a program could update its own a.out file even while - it is still executing. If problems occur, everything is still - intact. NOT implemented. */ - - /* Open the input and output a.out files. */ - old = emacs_open (old_name, O_RDONLY, 0); - if (old < 0) - unexec_error (old_name); - new = emacs_open (new_name, O_CREAT | O_RDWR | O_TRUNC, 0777); - if (new < 0) - unexec_error (new_name); - - /* Read the old headers. */ - read_header (old, &hdr, &auxhdr); - - brk_on_dump = (long) sbrk (0); - - /* Decide how large the new and old data areas are. */ - old_size = auxhdr.exec_dsize; - /* I suspect these two statements are separate - to avoid a compiler bug in hpux version 8. */ - i = (long) sbrk (0); - new_size = i - auxhdr.exec_dmem; - - /* Copy the old file to the new, up to the data space. */ - check_lseek (old, 0, 0); - copy_file (old, new, auxhdr.exec_dfile); - - /* Skip the old data segment and write a new one. */ - check_lseek (old, old_size, 1); - save_data_space (new, &hdr, &auxhdr, new_size); - - /* Copy the rest of the file. */ - copy_rest (old, new); - - /* Update file pointers since we probably changed size of data area. */ - update_file_ptrs (new, &hdr, &auxhdr, auxhdr.exec_dfile, new_size-old_size); - - /* Save the modified header. */ - write_header (new, &hdr, &auxhdr); - - /* Close the binary file. */ - emacs_close (old); - emacs_close (new); -} diff --git a/src/unexmacosx.c b/src/unexmacosx.c deleted file mode 100644 index 10524224711..00000000000 --- a/src/unexmacosx.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* Dump Emacs in Mach-O format for use on macOS. - Copyright (C) 2001-2025 Free Software Foundation, Inc. - -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 of the License, 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. If not, see . */ - -/* Contributed by Andrew Choi (akochoi@mac.com). */ - -/* Documentation note. - - Consult the following documents/files for a description of the - Mach-O format: the file loader.h, man pages for Mach-O and ld, old - NEXTSTEP documents of the Mach-O format. The tool otool dumps the - mach header (-h option) and the load commands (-l option) in a - Mach-O file. The tool nm on macOS displays the symbol table in - a Mach-O file. For examples of unexec for the Mach-O format, see - the file unexnext.c in the GNU Emacs distribution, the file - unexdyld.c in the Darwin port of GNU Emacs 20.7, and unexdyld.c in - the Darwin port of XEmacs 21.1. Also the Darwin Libc source - contains the source code for malloc_freezedry and malloc_jumpstart. - Read that to see what they do. This file was written completely - from scratch, making use of information from the above sources. */ - -/* The macOS implementation of unexec makes use of Darwin's `zone' - memory allocator. All calls to malloc, realloc, and free in Emacs - are redirected to unexec_malloc, unexec_realloc, and unexec_free in - this file. When temacs is run, all memory requests are handled in - the zone EmacsZone. The Darwin memory allocator library calls - maintain the data structures to manage this zone. Dumping writes - its contents to data segments of the executable file. When emacs - is run, the loader recreates the contents of the zone in memory. - However since the initialization routine of the zone memory - allocator is run again, this `zone' can no longer be used as a - heap. That is why emacs uses the ordinary malloc system call to - allocate memory. Also, when a block of memory needs to be - reallocated and the new size is larger than the old one, a new - block must be obtained by malloc and the old contents copied to - it. */ - -/* Peculiarity of the Mach-O files generated by ld in macOS - (possible causes of future bugs if changed). - - The file offset of the start of the __TEXT segment is zero. Since - the Mach header and load commands are located at the beginning of a - Mach-O file, copying the contents of the __TEXT segment from the - input file overwrites them in the output file. Despite this, - unexec works fine as written below because the segment load command - for __TEXT appears, and is therefore processed, before all other - load commands except the segment load command for __PAGEZERO, which - remains unchanged. - - Although the file offset of the start of the __TEXT segment is - zero, none of the sections it contains actually start there. In - fact, the earliest one starts a few hundred bytes beyond the end of - the last load command. The linker option -headerpad controls the - minimum size of this padding. Its setting can be changed in - s/darwin.h. A value of 0x690, e.g., leaves room for 30 additional - load commands for the newly created __DATA segments (at 56 bytes - each). Unexec fails if there is not enough room for these new - segments. - - The __TEXT segment contains the sections __text, __cstring, - __picsymbol_stub, and __const and the __DATA segment contains the - sections __data, __la_symbol_ptr, __nl_symbol_ptr, __dyld, __bss, - and __common. The other segments do not contain any sections. - These sections are copied from the input file to the output file, - except for __data, __bss, and __common, which are dumped from - memory. The types of the sections __bss and __common are changed - from S_ZEROFILL to S_REGULAR. Note that the number of sections and - their relative order in the input and output files remain - unchanged. Otherwise all n_sect fields in the nlist records in the - symbol table (specified by the LC_SYMTAB load command) will have to - be changed accordingly. -*/ - -#include - -#include - -#include "unexec.h" -#define UNEXMACOSX_C /* Tell lisp.h we want the system malloc, etc. */ -#include "lisp.h" -#include "sysstdio.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_MALLOC_MALLOC_H -#include -#else -#include -#endif - -#include - -/* LC_DATA_IN_CODE is not defined in mach-o/loader.h on Mac OS X 10.7. - But it is used if we build with "Command Line Tools for Xcode 4.5 - (Mac OS X Lion) - September 2012". */ -#ifndef LC_DATA_IN_CODE -#define LC_DATA_IN_CODE 0x29 /* table of non-instructions in __text */ -#endif - -#ifdef _LP64 -#define mach_header mach_header_64 -#define segment_command segment_command_64 -#undef VM_REGION_BASIC_INFO_COUNT -#define VM_REGION_BASIC_INFO_COUNT VM_REGION_BASIC_INFO_COUNT_64 -#undef VM_REGION_BASIC_INFO -#define VM_REGION_BASIC_INFO VM_REGION_BASIC_INFO_64 -#undef LC_SEGMENT -#define LC_SEGMENT LC_SEGMENT_64 -#define vm_region vm_region_64 -#define section section_64 -#undef MH_MAGIC -#define MH_MAGIC MH_MAGIC_64 -#endif - -#define VERBOSE 1 - -/* Size of buffer used to copy data from the input file to the output - file in function unexec_copy. */ -#define UNEXEC_COPY_BUFSZ 1024 - -/* Regions with memory addresses above this value are assumed to be - mapped to dynamically loaded libraries and will not be dumped. */ -#define VM_DATA_TOP (20 * 1024 * 1024) - -/* Type of an element on the list of regions to be dumped. */ -struct region_t { - vm_address_t address; - vm_size_t size; - vm_prot_t protection; - vm_prot_t max_protection; - - struct region_t *next; -}; - -/* Head and tail of the list of regions to be dumped. */ -static struct region_t *region_list_head = 0; -static struct region_t *region_list_tail = 0; - -/* Pointer to array of load commands. */ -static struct load_command **lca; - -/* Number of load commands. */ -static int nlc; - -/* The highest VM address of segments loaded by the input file. - Regions with addresses beyond this are assumed to be allocated - dynamically and thus require dumping. */ -static vm_address_t infile_lc_highest_addr = 0; - -/* The lowest file offset used by the all sections in the __TEXT - segments. This leaves room at the beginning of the file to store - the Mach-O header. Check this value against header size to ensure - the added load commands for the new __DATA segments did not - overwrite any of the sections in the __TEXT segment. */ -static unsigned long text_seg_lowest_offset = 0x10000000; - -/* Mach header. */ -static struct mach_header mh; - -/* Offset at which the next load command should be written. */ -static unsigned long curr_header_offset = sizeof (struct mach_header); - -/* Offset at which the next segment should be written. */ -static unsigned long curr_file_offset = 0; - -static unsigned long pagesize; -#define ROUNDUP_TO_PAGE_BOUNDARY(x) (((x) + pagesize - 1) & ~(pagesize - 1)) - -static int infd, outfd; - -static int in_dumped_exec = 0; - -static malloc_zone_t *emacs_zone; - -/* file offset of input file's data segment */ -static off_t data_segment_old_fileoff = 0; - -static struct segment_command *data_segment_scp; - -/* Read N bytes from infd into memory starting at address DEST. - Return true if successful, false otherwise. */ -static int -unexec_read (void *dest, size_t n) -{ - return n == read (infd, dest, n); -} - -/* Write COUNT bytes from memory starting at address SRC to outfd - starting at offset DEST. Return true if successful, false - otherwise. */ -static int -unexec_write (off_t dest, const void *src, size_t count) -{ - task_t task = mach_task_self(); - if (task == MACH_PORT_NULL || task == MACH_PORT_DEAD) - return false; - - if (lseek (outfd, dest, SEEK_SET) != dest) - return 0; - - /* We use the Mach virtual memory API to read our process memory - because using src directly would be undefined behavior and fails - under Address Sanitizer. */ - bool success = false; - vm_offset_t data; - mach_msg_type_number_t data_count; - if (vm_read (task, (uintptr_t) src, count, &data, &data_count) - == KERN_SUCCESS) - { - success = - write (outfd, (const void *) (uintptr_t) data, data_count) == count; - vm_deallocate (task, data, data_count); - } - return success; -} - -/* Write COUNT bytes of zeros to outfd starting at offset DEST. - Return true if successful, false otherwise. */ -static int -unexec_write_zero (off_t dest, size_t count) -{ - char buf[UNEXEC_COPY_BUFSZ]; - ssize_t bytes; - - memset (buf, 0, UNEXEC_COPY_BUFSZ); - if (lseek (outfd, dest, SEEK_SET) != dest) - return 0; - - while (count > 0) - { - bytes = min (count, UNEXEC_COPY_BUFSZ); - if (write (outfd, buf, bytes) != bytes) - return 0; - count -= bytes; - } - - return 1; -} - -/* Copy COUNT bytes from starting offset SRC in infd to starting - offset DEST in outfd. Return true if successful, false - otherwise. */ -static int -unexec_copy (off_t dest, off_t src, ssize_t count) -{ - ssize_t bytes_read; - ssize_t bytes_to_read; - - char buf[UNEXEC_COPY_BUFSZ]; - - if (lseek (infd, src, SEEK_SET) != src) - return 0; - - if (lseek (outfd, dest, SEEK_SET) != dest) - return 0; - - while (count > 0) - { - bytes_to_read = min (count, UNEXEC_COPY_BUFSZ); - bytes_read = read (infd, buf, bytes_to_read); - if (bytes_read <= 0) - return 0; - if (write (outfd, buf, bytes_read) != bytes_read) - return 0; - count -= bytes_read; - } - - return 1; -} - -/* Debugging and informational messages routines. */ - -static _Noreturn void -unexec_error (const char *format, ...) -{ - va_list ap; - - va_start (ap, format); - fputs ("unexec: ", stderr); - vfprintf (stderr, format, ap); - putc ('\n', stderr); - va_end (ap); - exit (1); -} - -static void -print_prot (vm_prot_t prot) -{ - if (prot == VM_PROT_NONE) - printf ("none"); - else - { - putchar (prot & VM_PROT_READ ? 'r' : ' '); - putchar (prot & VM_PROT_WRITE ? 'w' : ' '); - putchar (prot & VM_PROT_EXECUTE ? 'x' : ' '); - putchar (' '); - } -} - -static void -print_region (vm_address_t address, vm_size_t size, vm_prot_t prot, - vm_prot_t max_prot) -{ - printf ("%#10lx %#8lx ", (long) address, (long) size); - print_prot (prot); - putchar (' '); - print_prot (max_prot); - putchar ('\n'); -} - -static void -print_region_list (void) -{ - struct region_t *r; - - printf (" address size prot maxp\n"); - - for (r = region_list_head; r; r = r->next) - print_region (r->address, r->size, r->protection, r->max_protection); -} - -/* Build the list of regions that need to be dumped. Regions with - addresses above VM_DATA_TOP are omitted. Adjacent regions with - identical protection are merged. Note that non-writable regions - cannot be omitted because they some regions created at run time are - read-only. */ -static void -build_region_list (void) -{ - task_t target_task = mach_task_self (); - vm_address_t address = (vm_address_t) 0; - vm_size_t size; - struct vm_region_basic_info info; - mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT; - mach_port_t object_name; - struct region_t *r; - -#if VERBOSE - printf ("--- List of All Regions ---\n"); - printf (" address size prot maxp\n"); -#endif - - while (vm_region (target_task, &address, &size, VM_REGION_BASIC_INFO, - (vm_region_info_t) &info, &info_count, &object_name) - == KERN_SUCCESS && info_count == VM_REGION_BASIC_INFO_COUNT) - { - /* Done when we reach addresses of shared libraries, which are - loaded in high memory. */ - if (address >= VM_DATA_TOP) - break; - -#if VERBOSE - print_region (address, size, info.protection, info.max_protection); -#endif - - /* If a region immediately follows the previous one (the one - most recently added to the list) and has identical - protection, merge it with the latter. Otherwise create a - new list element for it. */ - if (region_list_tail - && info.protection == region_list_tail->protection - && info.max_protection == region_list_tail->max_protection - && region_list_tail->address + region_list_tail->size == address) - { - region_list_tail->size += size; - } - else - { - r = malloc (sizeof *r); - - if (!r) - unexec_error ("cannot allocate region structure"); - - r->address = address; - r->size = size; - r->protection = info.protection; - r->max_protection = info.max_protection; - - r->next = 0; - if (region_list_head == 0) - { - region_list_head = r; - region_list_tail = r; - } - else - { - region_list_tail->next = r; - region_list_tail = r; - } - - /* Deallocate (unused) object name returned by - vm_region. */ - if (object_name != MACH_PORT_NULL) - mach_port_deallocate (target_task, object_name); - } - - address += size; - } - - printf ("--- List of Regions to be Dumped ---\n"); - print_region_list (); -} - - -#define MAX_UNEXEC_REGIONS 400 - -static int num_unexec_regions; -typedef struct { - vm_range_t range; - vm_size_t filesize; -} unexec_region_info; -static unexec_region_info unexec_regions[MAX_UNEXEC_REGIONS]; - -static void -unexec_regions_recorder (task_t task, void *rr, unsigned type, - vm_range_t *ranges, unsigned num) -{ - vm_address_t p; - vm_size_t filesize; - - while (num && num_unexec_regions < MAX_UNEXEC_REGIONS) - { - /* Subtract the size of trailing null bytes from filesize. It - can be smaller than vmsize in segment commands. In such a - case, trailing bytes are initialized with zeros. */ - for (p = ranges->address + ranges->size; p > ranges->address; p--) - if (*(((char *) p)-1)) - break; - filesize = p - ranges->address; - - unexec_regions[num_unexec_regions].filesize = filesize; - unexec_regions[num_unexec_regions++].range = *ranges; - printf ("%#10lx (sz: %#8lx/%#8lx)\n", (long) (ranges->address), - (long) filesize, (long) (ranges->size)); - ranges++; num--; - } -} - -static kern_return_t -unexec_reader (task_t task, vm_address_t address, vm_size_t size, void **ptr) -{ - *ptr = (void *) address; - return KERN_SUCCESS; -} - -static void -find_emacs_zone_regions (void) -{ - num_unexec_regions = 0; - - emacs_zone->introspect->enumerator (mach_task_self (), 0, - MALLOC_PTR_REGION_RANGE_TYPE - | MALLOC_ADMIN_REGION_RANGE_TYPE, - (vm_address_t) emacs_zone, - unexec_reader, - unexec_regions_recorder); - - if (num_unexec_regions == MAX_UNEXEC_REGIONS) - unexec_error ("find_emacs_zone_regions: too many regions"); -} - -static int -unexec_regions_sort_compare (const void *a, const void *b) -{ - vm_address_t aa = ((unexec_region_info *) a)->range.address; - vm_address_t bb = ((unexec_region_info *) b)->range.address; - - if (aa < bb) - return -1; - else if (aa > bb) - return 1; - else - return 0; -} - -static void -unexec_regions_merge (void) -{ - qsort (unexec_regions, num_unexec_regions, sizeof (unexec_regions[0]), - &unexec_regions_sort_compare); - - /* Align each region start address to a page boundary. */ - for (unexec_region_info *cur = unexec_regions; - cur < unexec_regions + num_unexec_regions; cur++) - { - vm_size_t padsize = cur->range.address & (pagesize - 1); - if (padsize) - { - cur->range.address -= padsize; - cur->range.size += padsize; - cur->filesize += padsize; - - unexec_region_info *prev = cur == unexec_regions ? NULL : cur - 1; - if (prev - && prev->range.address + prev->range.size > cur->range.address) - { - prev->range.size = cur->range.address - prev->range.address; - if (prev->filesize > prev->range.size) - prev->filesize = prev->range.size; - } - } - } - - int n = 0; - unexec_region_info r = unexec_regions[0]; - for (int i = 1; i < num_unexec_regions; i++) - { - if (r.range.address + r.range.size == unexec_regions[i].range.address - && r.range.size - r.filesize < 2 * pagesize) - { - r.filesize = r.range.size + unexec_regions[i].filesize; - r.range.size += unexec_regions[i].range.size; - } - else - { - unexec_regions[n++] = r; - r = unexec_regions[i]; - } - } - unexec_regions[n++] = r; - num_unexec_regions = n; -} - - -/* More informational messages routines. */ - -static void -print_load_command_name (int lc) -{ - switch (lc) - { - case LC_SEGMENT: -#ifndef _LP64 - printf ("LC_SEGMENT "); -#else - printf ("LC_SEGMENT_64 "); -#endif - break; - case LC_LOAD_DYLINKER: - printf ("LC_LOAD_DYLINKER "); - break; - case LC_LOAD_DYLIB: - printf ("LC_LOAD_DYLIB "); - break; - case LC_SYMTAB: - printf ("LC_SYMTAB "); - break; - case LC_DYSYMTAB: - printf ("LC_DYSYMTAB "); - break; - case LC_UNIXTHREAD: - printf ("LC_UNIXTHREAD "); - break; - case LC_PREBOUND_DYLIB: - printf ("LC_PREBOUND_DYLIB"); - break; - case LC_TWOLEVEL_HINTS: - printf ("LC_TWOLEVEL_HINTS"); - break; -#ifdef LC_UUID - case LC_UUID: - printf ("LC_UUID "); - break; -#endif -#ifdef LC_DYLD_INFO - case LC_DYLD_INFO: - printf ("LC_DYLD_INFO "); - break; - case LC_DYLD_INFO_ONLY: - printf ("LC_DYLD_INFO_ONLY"); - break; -#endif -#ifdef LC_VERSION_MIN_MACOSX - case LC_VERSION_MIN_MACOSX: - printf ("LC_VERSION_MIN_MACOSX"); - break; -#endif -#ifdef LC_FUNCTION_STARTS - case LC_FUNCTION_STARTS: - printf ("LC_FUNCTION_STARTS"); - break; -#endif -#ifdef LC_MAIN - case LC_MAIN: - printf ("LC_MAIN "); - break; -#endif -#ifdef LC_DATA_IN_CODE - case LC_DATA_IN_CODE: - printf ("LC_DATA_IN_CODE "); - break; -#endif -#ifdef LC_SOURCE_VERSION - case LC_SOURCE_VERSION: - printf ("LC_SOURCE_VERSION"); - break; -#endif -#ifdef LC_DYLIB_CODE_SIGN_DRS - case LC_DYLIB_CODE_SIGN_DRS: - printf ("LC_DYLIB_CODE_SIGN_DRS"); - break; -#endif - default: - printf ("unknown "); - } -} - -static void -print_load_command (struct load_command *lc) -{ - print_load_command_name (lc->cmd); - printf ("%8d", lc->cmdsize); - - if (lc->cmd == LC_SEGMENT) - { - struct segment_command *scp; - struct section *sectp; - int j; - - scp = (struct segment_command *) lc; - printf (" %-16.16s %#10lx %#8lx\n", - scp->segname, (long) (scp->vmaddr), (long) (scp->vmsize)); - - sectp = (struct section *) (scp + 1); - for (j = 0; j < scp->nsects; j++) - { - printf (" %-16.16s %#10lx %#8lx\n", - sectp->sectname, (long) (sectp->addr), (long) (sectp->size)); - sectp++; - } - } - else - printf ("\n"); -} - -/* Read header and load commands from input file. Store the latter in - the global array lca. Store the total number of load commands in - global variable nlc. */ -static void -read_load_commands (void) -{ - int i; - - if (!unexec_read (&mh, sizeof (struct mach_header))) - unexec_error ("cannot read mach-o header"); - - if (mh.magic != MH_MAGIC) - unexec_error ("input file not in Mach-O format"); - - if (mh.filetype != MH_EXECUTE) - unexec_error ("input Mach-O file is not an executable object file"); - -#if VERBOSE - printf ("--- Header Information ---\n"); - printf ("Magic = 0x%08x\n", mh.magic); - printf ("CPUType = %d\n", mh.cputype); - printf ("CPUSubType = %d\n", mh.cpusubtype); - printf ("FileType = 0x%x\n", mh.filetype); - printf ("NCmds = %d\n", mh.ncmds); - printf ("SizeOfCmds = %d\n", mh.sizeofcmds); - printf ("Flags = 0x%08x\n", mh.flags); -#endif - - nlc = mh.ncmds; - lca = malloc (nlc * sizeof *lca); - - for (i = 0; i < nlc; i++) - { - struct load_command lc; - /* Load commands are variable-size: so read the command type and - size first and then read the rest. */ - if (!unexec_read (&lc, sizeof (struct load_command))) - unexec_error ("cannot read load command"); - lca[i] = malloc (lc.cmdsize); - memcpy (lca[i], &lc, sizeof (struct load_command)); - if (!unexec_read (lca[i] + 1, lc.cmdsize - sizeof (struct load_command))) - unexec_error ("cannot read content of load command"); - if (lc.cmd == LC_SEGMENT) - { - struct segment_command *scp = (struct segment_command *) lca[i]; - - if (scp->vmaddr + scp->vmsize > infile_lc_highest_addr) - infile_lc_highest_addr = scp->vmaddr + scp->vmsize; - - if (strncmp (scp->segname, SEG_TEXT, 16) == 0) - { - struct section *sectp = (struct section *) (scp + 1); - int j; - - for (j = 0; j < scp->nsects; j++) - if (sectp->offset < text_seg_lowest_offset) - text_seg_lowest_offset = sectp->offset; - } - } - } - - printf ("Highest address of load commands in input file: %#8lx\n", - (unsigned long)infile_lc_highest_addr); - - printf ("Lowest offset of all sections in __TEXT segment: %#8lx\n", - text_seg_lowest_offset); - - printf ("--- List of Load Commands in Input File ---\n"); - printf ("# cmd cmdsize name address size\n"); - - for (i = 0; i < nlc; i++) - { - printf ("%1d ", i); - print_load_command (lca[i]); - } -} - -/* Copy a LC_SEGMENT load command other than the __DATA segment from - the input file to the output file, adjusting the file offset of the - segment and the file offsets of sections contained in it. */ -static void -copy_segment (struct load_command *lc) -{ - struct segment_command *scp = (struct segment_command *) lc; - unsigned long old_fileoff = scp->fileoff; - struct section *sectp; - int j; - - scp->fileoff = curr_file_offset; - - sectp = (struct section *) (scp + 1); - for (j = 0; j < scp->nsects; j++) - { - sectp->offset += curr_file_offset - old_fileoff; - sectp++; - } - - printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n", - scp->segname, (long) (scp->fileoff), (long) (scp->filesize), - (long) (scp->vmsize), (long) (scp->vmaddr)); - - if (!unexec_copy (scp->fileoff, old_fileoff, scp->filesize)) - unexec_error ("cannot copy segment from input to output file"); - curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize); - - if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) - unexec_error ("cannot write load command to header"); - - curr_header_offset += lc->cmdsize; -} - -/* Copy a LC_SEGMENT load command for the __DATA segment in the input - file to the output file. We assume that only one such segment load - command exists in the input file and it contains the sections - __data, __bss, __common, __la_symbol_ptr, __nl_symbol_ptr, and - __dyld. The first three of these should be dumped from memory and - the rest should be copied from the input file. Note that the - sections __bss and __common contain no data in the input file - because their flag fields have the value S_ZEROFILL. Dumping these - from memory makes it necessary to adjust file offset fields in - subsequently dumped load commands. Then, create new __DATA segment - load commands for regions on the region list other than the one - corresponding to the __DATA segment in the input file. */ -static void -copy_data_segment (struct load_command *lc) -{ - struct segment_command *scp = (struct segment_command *) lc; - struct section *sectp; - int j; - unsigned long header_offset, old_file_offset; - - /* The new filesize of the segment is set to its vmsize because data - blocks for segments must start at region boundaries. Note that - this may leave unused locations at the end of the segment data - block because the total of the sizes of all sections in the - segment is generally smaller than vmsize. */ - scp->filesize = scp->vmsize; - - printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n", - scp->segname, curr_file_offset, (long)(scp->filesize), - (long)(scp->vmsize), (long) (scp->vmaddr)); - - /* Offsets in the output file for writing the next section structure - and segment data block, respectively. */ - header_offset = curr_header_offset + sizeof (struct segment_command); - - sectp = (struct section *) (scp + 1); - for (j = 0; j < scp->nsects; j++) - { - old_file_offset = sectp->offset; - sectp->offset = sectp->addr - scp->vmaddr + curr_file_offset; - /* The __data section is dumped from memory. The __bss and - __common sections are also dumped from memory but their flag - fields require changing (from S_ZEROFILL to S_REGULAR). The - other three kinds of sections are just copied from the input - file. */ - if (strncmp (sectp->sectname, SECT_DATA, 16) == 0) - { - unsigned long my_size; - - /* The __data section is basically dumped from memory. But - initialized data in statically linked libraries are - copied from the input file. In particular, - add_image_hook.names and add_image_hook.pointers stored - by libarclite_macosx.a, are restored so that they will be - reinitialized when the dumped binary is executed. */ - my_size = (unsigned long)my_edata - sectp->addr; - if (!(sectp->addr <= (unsigned long)my_edata - && my_size <= sectp->size)) - unexec_error ("my_edata is not in section %s", SECT_DATA); - if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size)) - unexec_error ("cannot write section %s", SECT_DATA); - if (!unexec_copy (sectp->offset + my_size, old_file_offset + my_size, - sectp->size - my_size)) - unexec_error ("cannot copy section %s", SECT_DATA); - if (!unexec_write (header_offset, sectp, sizeof (struct section))) - unexec_error ("cannot write section %s's header", SECT_DATA); - } - else if (strncmp (sectp->sectname, SECT_COMMON, 16) == 0) - { - sectp->flags = S_REGULAR; - if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size)) - unexec_error ("cannot write section %.16s", sectp->sectname); - if (!unexec_write (header_offset, sectp, sizeof (struct section))) - unexec_error ("cannot write section %.16s's header", sectp->sectname); - } - else if (strncmp (sectp->sectname, SECT_BSS, 16) == 0) - { - unsigned long my_size; - - sectp->flags = S_REGULAR; - - /* Clear uninitialized local variables in statically linked - libraries. In particular, function pointers stored by - libSystemStub.a, which is introduced in Mac OS X 10.4 for - binary compatibility with respect to long double, are - cleared so that they will be reinitialized when the - dumped binary is executed on other versions of OS. */ - my_size = (unsigned long)my_endbss_static - sectp->addr; - if (!(sectp->addr <= (unsigned long)my_endbss_static - && my_size <= sectp->size)) - unexec_error ("my_endbss_static is not in section %.16s", - sectp->sectname); - if (!unexec_write (sectp->offset, (void *) sectp->addr, my_size)) - unexec_error ("cannot write section %.16s", sectp->sectname); - if (!unexec_write_zero (sectp->offset + my_size, - sectp->size - my_size)) - unexec_error ("cannot write section %.16s", sectp->sectname); - if (!unexec_write (header_offset, sectp, sizeof (struct section))) - unexec_error ("cannot write section %.16s's header", sectp->sectname); - } - else if (strncmp (sectp->sectname, "__bss", 5) == 0 - || strncmp (sectp->sectname, "__pu_bss", 8) == 0) - { - sectp->flags = S_REGULAR; - - /* These sections are produced by GCC 4.6+. - - FIXME: We possibly ought to clear uninitialized local - variables in statically linked libraries like for - SECT_BSS (__bss) above, but setting up the markers we - need in lastfile.c would be rather messy. See - darwin_output_aligned_bss () in gcc/config/darwin.c for - the root of the problem, keeping in mind that the - sections are numbered by their alignment in GCC 4.6, but - by log2(alignment) in GCC 4.7. */ - - if (!unexec_write (sectp->offset, (void *) sectp->addr, sectp->size)) - unexec_error ("cannot copy section %.16s", sectp->sectname); - if (!unexec_write (header_offset, sectp, sizeof (struct section))) - unexec_error ("cannot write section %.16s's header", sectp->sectname); - } - else if (strncmp (sectp->sectname, "__la_symbol_ptr", 16) == 0 - || strncmp (sectp->sectname, "__nl_symbol_ptr", 16) == 0 - || strncmp (sectp->sectname, "__got", 16) == 0 - || strncmp (sectp->sectname, "__la_sym_ptr2", 16) == 0 - || strncmp (sectp->sectname, "__dyld", 16) == 0 - || strncmp (sectp->sectname, "__const", 16) == 0 - || strncmp (sectp->sectname, "__cfstring", 16) == 0 - || strncmp (sectp->sectname, "__gcc_except_tab", 16) == 0 - || strncmp (sectp->sectname, "__program_vars", 16) == 0 - || strncmp (sectp->sectname, "__mod_init_func", 16) == 0 - || strncmp (sectp->sectname, "__mod_term_func", 16) == 0 - || strncmp (sectp->sectname, "__static_data", 16) == 0 - || strncmp (sectp->sectname, "__objc_", 7) == 0) - { - if (!unexec_copy (sectp->offset, old_file_offset, sectp->size)) - unexec_error ("cannot copy section %.16s", sectp->sectname); - if (!unexec_write (header_offset, sectp, sizeof (struct section))) - unexec_error ("cannot write section %.16s's header", sectp->sectname); - } - else - unexec_error ("unrecognized section %.16s in __DATA segment", - sectp->sectname); - - printf (" section %-16.16s at %#8lx - %#8lx (sz: %#8lx)\n", - sectp->sectname, (long) (sectp->offset), - (long) (sectp->offset + sectp->size), (long) (sectp->size)); - - header_offset += sizeof (struct section); - sectp++; - } - - curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (scp->filesize); - - if (!unexec_write (curr_header_offset, scp, sizeof (struct segment_command))) - unexec_error ("cannot write header of __DATA segment"); - curr_header_offset += lc->cmdsize; - - /* Create new __DATA segment load commands for regions on the region - list that do not corresponding to any segment load commands in - the input file. - */ - for (j = 0; j < num_unexec_regions; j++) - { - struct segment_command sc; - - sc.cmd = LC_SEGMENT; - sc.cmdsize = sizeof (struct segment_command); - strncpy (sc.segname, SEG_DATA, 16); - sc.vmaddr = unexec_regions[j].range.address; - sc.vmsize = unexec_regions[j].range.size; - sc.fileoff = curr_file_offset; - sc.filesize = unexec_regions[j].filesize; - sc.maxprot = VM_PROT_READ | VM_PROT_WRITE; - sc.initprot = VM_PROT_READ | VM_PROT_WRITE; - sc.nsects = 0; - sc.flags = 0; - - printf ("Writing segment %-16.16s @ %#8lx (%#8lx/%#8lx @ %#10lx)\n", - sc.segname, (long) (sc.fileoff), (long) (sc.filesize), - (long) (sc.vmsize), (long) (sc.vmaddr)); - - if (!unexec_write (sc.fileoff, (void *) sc.vmaddr, sc.filesize)) - unexec_error ("cannot write new __DATA segment"); - curr_file_offset += ROUNDUP_TO_PAGE_BOUNDARY (sc.filesize); - - if (!unexec_write (curr_header_offset, &sc, sc.cmdsize)) - unexec_error ("cannot write new __DATA segment's header"); - curr_header_offset += sc.cmdsize; - mh.ncmds++; - } -} - -/* Copy a LC_SYMTAB load command from the input file to the output - file, adjusting the file offset fields. */ -static void -copy_symtab (struct load_command *lc, long delta) -{ - struct symtab_command *stp = (struct symtab_command *) lc; - - stp->symoff += delta; - stp->stroff += delta; - - printf ("Writing LC_SYMTAB command\n"); - - if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) - unexec_error ("cannot write symtab command to header"); - - curr_header_offset += lc->cmdsize; -} - -/* Fix up relocation entries. */ -static void -unrelocate (const char *name, off_t reloff, int nrel, vm_address_t base) -{ - int i, unreloc_count; - struct relocation_info reloc_info; - struct scattered_relocation_info *sc_reloc_info - = (struct scattered_relocation_info *) &reloc_info; - vm_address_t location; - - for (unreloc_count = 0, i = 0; i < nrel; i++) - { - if (lseek (infd, reloff, L_SET) != reloff) - unexec_error ("unrelocate: %s:%d cannot seek to reloc_info", name, i); - if (!unexec_read (&reloc_info, sizeof (reloc_info))) - unexec_error ("unrelocate: %s:%d cannot read reloc_info", name, i); - reloff += sizeof (reloc_info); - - if (sc_reloc_info->r_scattered == 0) - switch (reloc_info.r_type) - { - case GENERIC_RELOC_VANILLA: - location = base + reloc_info.r_address; - if (location >= data_segment_scp->vmaddr - && location < (data_segment_scp->vmaddr - + data_segment_scp->vmsize)) - { - off_t src_off = data_segment_old_fileoff - + (location - data_segment_scp->vmaddr); - off_t dst_off = data_segment_scp->fileoff - + (location - data_segment_scp->vmaddr); - - if (!unexec_copy (dst_off, src_off, 1 << reloc_info.r_length)) - unexec_error ("unrelocate: %s:%d cannot copy original value", - name, i); - unreloc_count++; - } - break; - default: - unexec_error ("unrelocate: %s:%d cannot handle type = %d", - name, i, reloc_info.r_type); - } - else - unexec_error ("unrelocate: %s:%d cannot handle scattered type = %d", - name, i, sc_reloc_info->r_type); - } - - if (nrel > 0) - printf ("Fixed up %d/%d %s relocation entries in data segment.\n", - unreloc_count, nrel, name); -} - -/* Copy a LC_DYSYMTAB load command from the input file to the output - file, adjusting the file offset fields. */ -static void -copy_dysymtab (struct load_command *lc, long delta) -{ - struct dysymtab_command *dstp = (struct dysymtab_command *) lc; - vm_address_t base; - -#ifdef _LP64 - /* First writable segment address. */ - base = data_segment_scp->vmaddr; -#else - /* First segment address in the file (unless MH_SPLIT_SEGS set). */ - base = 0; -#endif - - unrelocate ("local", dstp->locreloff, dstp->nlocrel, base); - unrelocate ("external", dstp->extreloff, dstp->nextrel, base); - - if (dstp->nextrel > 0) { - dstp->extreloff += delta; - } - - if (dstp->nlocrel > 0) { - dstp->locreloff += delta; - } - - if (dstp->nindirectsyms > 0) - dstp->indirectsymoff += delta; - - printf ("Writing LC_DYSYMTAB command\n"); - - if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) - unexec_error ("cannot write symtab command to header"); - - curr_header_offset += lc->cmdsize; -} - -/* Copy a LC_TWOLEVEL_HINTS load command from the input file to the output - file, adjusting the file offset fields. */ -static void -copy_twolevelhints (struct load_command *lc, long delta) -{ - struct twolevel_hints_command *tlhp = (struct twolevel_hints_command *) lc; - - if (tlhp->nhints > 0) { - tlhp->offset += delta; - } - - printf ("Writing LC_TWOLEVEL_HINTS command\n"); - - if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) - unexec_error ("cannot write two level hint command to header"); - - curr_header_offset += lc->cmdsize; -} - -#ifdef LC_DYLD_INFO -/* Copy a LC_DYLD_INFO(_ONLY) load command from the input file to the output - file, adjusting the file offset fields. */ -static void -copy_dyld_info (struct load_command *lc, long delta) -{ - struct dyld_info_command *dip = (struct dyld_info_command *) lc; - - if (dip->rebase_off > 0) - dip->rebase_off += delta; - if (dip->bind_off > 0) - dip->bind_off += delta; - if (dip->weak_bind_off > 0) - dip->weak_bind_off += delta; - if (dip->lazy_bind_off > 0) - dip->lazy_bind_off += delta; - if (dip->export_off > 0) - dip->export_off += delta; - - printf ("Writing "); - print_load_command_name (lc->cmd); - printf (" command\n"); - - if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) - unexec_error ("cannot write dyld info command to header"); - - curr_header_offset += lc->cmdsize; -} -#endif - -#ifdef LC_FUNCTION_STARTS -/* Copy a LC_FUNCTION_STARTS/LC_DATA_IN_CODE/LC_DYLIB_CODE_SIGN_DRS - load command from the input file to the output file, adjusting the - data offset field. */ -static void -copy_linkedit_data (struct load_command *lc, long delta) -{ - struct linkedit_data_command *ldp = (struct linkedit_data_command *) lc; - - if (ldp->dataoff > 0) - ldp->dataoff += delta; - - printf ("Writing "); - print_load_command_name (lc->cmd); - printf (" command\n"); - - if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) - unexec_error ("cannot write linkedit data command to header"); - - curr_header_offset += lc->cmdsize; -} -#endif - -/* Copy other kinds of load commands from the input file to the output - file, ones that do not require adjustments of file offsets. */ -static void -copy_other (struct load_command *lc) -{ - printf ("Writing "); - print_load_command_name (lc->cmd); - printf (" command\n"); - - if (!unexec_write (curr_header_offset, lc, lc->cmdsize)) - unexec_error ("cannot write symtab command to header"); - - curr_header_offset += lc->cmdsize; -} - -/* Loop through all load commands and dump them. Then write the Mach - header. */ -static void -dump_it (void) -{ - int i; - long linkedit_delta = 0; - - printf ("--- Load Commands written to Output File ---\n"); - - for (i = 0; i < nlc; i++) - switch (lca[i]->cmd) - { - case LC_SEGMENT: - { - struct segment_command *scp = (struct segment_command *) lca[i]; - if (strncmp (scp->segname, SEG_DATA, 16) == 0) - { - /* save data segment file offset and segment_command for - unrelocate */ - if (data_segment_old_fileoff) - unexec_error ("cannot handle multiple DATA segments" - " in input file"); - data_segment_old_fileoff = scp->fileoff; - data_segment_scp = scp; - - copy_data_segment (lca[i]); - } - else - { - if (strncmp (scp->segname, SEG_LINKEDIT, 16) == 0) - { - if (linkedit_delta) - unexec_error ("cannot handle multiple LINKEDIT segments" - " in input file"); - linkedit_delta = curr_file_offset - scp->fileoff; - } - - copy_segment (lca[i]); - } - } - break; - case LC_SYMTAB: - copy_symtab (lca[i], linkedit_delta); - break; - case LC_DYSYMTAB: - copy_dysymtab (lca[i], linkedit_delta); - break; - case LC_TWOLEVEL_HINTS: - copy_twolevelhints (lca[i], linkedit_delta); - break; -#ifdef LC_DYLD_INFO - case LC_DYLD_INFO: - case LC_DYLD_INFO_ONLY: - copy_dyld_info (lca[i], linkedit_delta); - break; -#endif -#ifdef LC_FUNCTION_STARTS - case LC_FUNCTION_STARTS: -#ifdef LC_DATA_IN_CODE - case LC_DATA_IN_CODE: -#endif -#ifdef LC_DYLIB_CODE_SIGN_DRS - case LC_DYLIB_CODE_SIGN_DRS: -#endif - copy_linkedit_data (lca[i], linkedit_delta); - break; -#endif - default: - copy_other (lca[i]); - break; - } - - if (curr_header_offset > text_seg_lowest_offset) - unexec_error ("not enough room for load commands for new __DATA segments" - " (increase headerpad_extra in configure.in to at least %lX)", - num_unexec_regions * sizeof (struct segment_command)); - - printf ("%ld unused bytes follow Mach-O header\n", - text_seg_lowest_offset - curr_header_offset); - - mh.sizeofcmds = curr_header_offset - sizeof (struct mach_header); - if (!unexec_write (0, &mh, sizeof (struct mach_header))) - unexec_error ("cannot write final header contents"); -} - -/* Take a snapshot of Emacs and make a Mach-O format executable file - from it. The file names of the output and input files are outfile - and infile, respectively. The three other parameters are - ignored. */ -void -unexec (const char *outfile, const char *infile) -{ - if (in_dumped_exec) - unexec_error ("Unexec from a dumped executable is not supported."); - - pagesize = getpagesize (); - infd = emacs_open (infile, O_RDONLY, 0); - if (infd < 0) - { - unexec_error ("%s: %s", infile, strerror (errno)); - } - - outfd = emacs_open (outfile, O_WRONLY | O_TRUNC | O_CREAT, 0777); - if (outfd < 0) - { - emacs_close (infd); - unexec_error ("%s: %s", outfile, strerror (errno)); - } - - build_region_list (); - read_load_commands (); - - find_emacs_zone_regions (); - unexec_regions_merge (); - - in_dumped_exec = 1; - - dump_it (); - - emacs_close (outfd); -} - - -void -unexec_init_emacs_zone (void) -{ - emacs_zone = malloc_create_zone (0, 0); - malloc_set_zone_name (emacs_zone, "EmacsZone"); -} - -#ifndef MACOSX_MALLOC_MULT16 -#define MACOSX_MALLOC_MULT16 1 -#endif - -typedef struct unexec_malloc_header { - union { - char c[8]; - size_t size; - } u; -} unexec_malloc_header_t; - -#if MACOSX_MALLOC_MULT16 - -#define ptr_in_unexec_regions(p) ((((vm_address_t) (p)) & 8) != 0) - -#else - -int -ptr_in_unexec_regions (void *ptr) -{ - int i; - - for (i = 0; i < num_unexec_regions; i++) - if ((vm_address_t) ptr - unexec_regions[i].range.address - < unexec_regions[i].range.size) - return 1; - - return 0; -} - -#endif - -void * -unexec_malloc (size_t size) -{ - if (in_dumped_exec) - { - void *p; - - p = malloc (size); -#if MACOSX_MALLOC_MULT16 - assert (((vm_address_t) p % 16) == 0); -#endif - return p; - } - else - { - unexec_malloc_header_t *ptr; - - ptr = (unexec_malloc_header_t *) - malloc_zone_malloc (emacs_zone, size + sizeof (unexec_malloc_header_t)); - ptr->u.size = size; - ptr++; -#if MACOSX_MALLOC_MULT16 - assert (((vm_address_t) ptr % 16) == 8); -#endif - return (void *) ptr; - } -} - -void * -unexec_realloc (void *old_ptr, size_t new_size) -{ - if (in_dumped_exec) - { - void *p; - - if (ptr_in_unexec_regions (old_ptr)) - { - size_t old_size = ((unexec_malloc_header_t *) old_ptr)[-1].u.size; - size_t size = min (new_size, old_size); - - p = malloc (new_size); - if (size) - memcpy (p, old_ptr, size); - } - else - { - p = realloc (old_ptr, new_size); - } -#if MACOSX_MALLOC_MULT16 - assert (((vm_address_t) p % 16) == 0); -#endif - return p; - } - else - { - unexec_malloc_header_t *ptr; - - ptr = (unexec_malloc_header_t *) - malloc_zone_realloc (emacs_zone, (unexec_malloc_header_t *) old_ptr - 1, - new_size + sizeof (unexec_malloc_header_t)); - ptr->u.size = new_size; - ptr++; -#if MACOSX_MALLOC_MULT16 - assert (((vm_address_t) ptr % 16) == 8); -#endif - return (void *) ptr; - } -} - -void -unexec_free (void *ptr) -{ - if (ptr == NULL) - return; - if (in_dumped_exec) - { - if (!ptr_in_unexec_regions (ptr)) - free (ptr); - } - else - malloc_zone_free (emacs_zone, (unexec_malloc_header_t *) ptr - 1); -} diff --git a/src/unexsol.c b/src/unexsol.c deleted file mode 100644 index 0f84099d39e..00000000000 --- a/src/unexsol.c +++ /dev/null @@ -1,28 +0,0 @@ -/* Trivial unexec for Solaris. */ - -#include -#include "unexec.h" - -#include - -#include "lisp.h" -#include "buffer.h" -#include "coding.h" - -void -unexec (const char *new_name, const char *old_name) -{ - Lisp_Object data; - Lisp_Object errstring; - - if (! dldump (0, new_name, RTLD_MEMORY)) - return; - - data = list1 (build_string (new_name)); - synchronize_system_messages_locale (); - errstring = code_convert_string_norecord (build_string (dlerror ()), - Vlocale_coding_system, 0); - - xsignal (Qfile_error, - Fcons (build_string ("Cannot unexec"), Fcons (errstring, data))); -} diff --git a/src/unexw32.c b/src/unexw32.c deleted file mode 100644 index fd01e04cf18..00000000000 --- a/src/unexw32.c +++ /dev/null @@ -1,684 +0,0 @@ -/* unexec for GNU Emacs on Windows NT. - Copyright (C) 1994, 2001-2025 Free Software Foundation, Inc. - -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 of the License, 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. If not, see . */ - -/* - Geoff Voelker (voelker@cs.washington.edu) 8-12-94 -*/ - -#include -#include "unexec.h" -#include "lisp.h" -#include "w32common.h" -#include "w32.h" - -#include -#include -#include -#include - -/* Include relevant definitions from IMAGEHLP.H, which can be found - in \\win32sdk\mstools\samples\image\include\imagehlp.h. */ - -PIMAGE_NT_HEADERS (__stdcall * pfnCheckSumMappedFile) (LPVOID BaseAddress, - DWORD FileLength, - LPDWORD HeaderSum, - LPDWORD CheckSum); - -extern char my_begdata[]; -extern char my_begbss[]; -extern char *my_begbss_static; - -#include "w32heap.h" - -void get_section_info (file_data *p_file); -void copy_executable_and_dump_data (file_data *, file_data *); -void dump_bss_and_heap (file_data *p_infile, file_data *p_outfile); - -/* Cached info about the .data section in the executable. */ -PIMAGE_SECTION_HEADER data_section; -PCHAR data_start = 0; -DWORD_PTR data_size = 0; - -/* Cached info about the .bss section in the executable. */ -PIMAGE_SECTION_HEADER bss_section; -PCHAR bss_start = 0; -DWORD_PTR bss_size = 0; -DWORD_PTR extra_bss_size = 0; -/* bss data that is static might be discontiguous from non-static. */ -PIMAGE_SECTION_HEADER bss_section_static; -PCHAR bss_start_static = 0; -DWORD_PTR bss_size_static = 0; -DWORD_PTR extra_bss_size_static = 0; - -/* File handling. */ - -/* Implementation note: this and the next functions work with ANSI - codepage encoded file names! */ - -int -open_output_file (file_data *p_file, char *filename, unsigned long size) -{ - HANDLE file; - HANDLE file_mapping; - void *file_base; - - /* We delete any existing FILENAME because loadup.el will create a - hard link to it under the name emacs-XX.YY.ZZ.nn.exe. Evidently, - overwriting a file on Unix breaks any hard links to it, but that - doesn't happen on Windows. If we don't delete the file before - creating it, all the emacs-XX.YY.ZZ.nn.exe end up being hard - links to the same file, which defeats the purpose of these hard - links: being able to run previous builds. */ - DeleteFileA (filename); - file = CreateFileA (filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, - CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); - if (file == INVALID_HANDLE_VALUE) - return FALSE; - - file_mapping = CreateFileMapping (file, NULL, PAGE_READWRITE, - 0, size, NULL); - if (!file_mapping) - return FALSE; - - file_base = MapViewOfFile (file_mapping, FILE_MAP_WRITE, 0, 0, size); - if (file_base == 0) - return FALSE; - - p_file->name = filename; - p_file->size = size; - p_file->file = file; - p_file->file_mapping = file_mapping; - p_file->file_base = file_base; - - return TRUE; -} - - -/* Routines to manipulate NT executable file sections. */ - -/* Return pointer to section header for named section. */ -IMAGE_SECTION_HEADER * -find_section (const char * name, IMAGE_NT_HEADERS * nt_header) -{ - PIMAGE_SECTION_HEADER section; - int i; - - section = IMAGE_FIRST_SECTION (nt_header); - - for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) - { - if (strcmp ((char *)section->Name, name) == 0) - return section; - section++; - } - return NULL; -} - -#if 0 /* unused */ -/* Return pointer to section header for section containing the given - offset in its raw data area. */ -static IMAGE_SECTION_HEADER * -offset_to_section (DWORD_PTR offset, IMAGE_NT_HEADERS * nt_header) -{ - PIMAGE_SECTION_HEADER section; - int i; - - section = IMAGE_FIRST_SECTION (nt_header); - - for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) - { - if (offset >= section->PointerToRawData - && offset < section->PointerToRawData + section->SizeOfRawData) - return section; - section++; - } - return NULL; -} -#endif - -/* Return offset to an object in dst, given offset in src. We assume - there is at least one section in both src and dst images, and that - the some sections may have been added to dst (after sections in src). */ -static DWORD_PTR -relocate_offset (DWORD_PTR offset, - IMAGE_NT_HEADERS * src_nt_header, - IMAGE_NT_HEADERS * dst_nt_header) -{ - PIMAGE_SECTION_HEADER src_section = IMAGE_FIRST_SECTION (src_nt_header); - PIMAGE_SECTION_HEADER dst_section = IMAGE_FIRST_SECTION (dst_nt_header); - int i = 0; - - while (offset >= src_section->PointerToRawData) - { - if (offset < src_section->PointerToRawData + src_section->SizeOfRawData) - break; - i++; - if (i == src_nt_header->FileHeader.NumberOfSections) - { - /* Handle offsets after the last section. */ - dst_section = IMAGE_FIRST_SECTION (dst_nt_header); - dst_section += dst_nt_header->FileHeader.NumberOfSections - 1; - while (dst_section->PointerToRawData == 0) - dst_section--; - while (src_section->PointerToRawData == 0) - src_section--; - return offset - + (dst_section->PointerToRawData + dst_section->SizeOfRawData) - - (src_section->PointerToRawData + src_section->SizeOfRawData); - } - src_section++; - dst_section++; - } - return offset + - (dst_section->PointerToRawData - src_section->PointerToRawData); -} - -#define RVA_TO_OFFSET(rva, section) \ - ((section)->PointerToRawData + ((DWORD_PTR)(rva) - (section)->VirtualAddress)) - -#define RVA_TO_SECTION_OFFSET(rva, section) \ - ((DWORD_PTR)(rva) - (section)->VirtualAddress) - -/* Convert address in executing image to RVA. */ -#define PTR_TO_RVA(ptr) ((DWORD_PTR)(ptr) - (DWORD_PTR) GetModuleHandle (NULL)) - -#define PTR_TO_OFFSET(ptr, pfile_data) \ - ((unsigned char *)(ptr) - (pfile_data)->file_base) - -#define OFFSET_TO_PTR(offset, pfile_data) \ - ((pfile_data)->file_base + (DWORD_PTR)(offset)) - -#if 0 /* unused */ -#define OFFSET_TO_RVA(offset, section) \ - ((section)->VirtualAddress + ((DWORD_PTR)(offset) - (section)->PointerToRawData)) - -#define RVA_TO_PTR(var,section,filedata) \ - ((unsigned char *)(RVA_TO_OFFSET (var,section) + (filedata).file_base)) -#endif - - -/* Flip through the executable and cache the info necessary for dumping. */ -void -get_section_info (file_data *p_infile) -{ - PIMAGE_DOS_HEADER dos_header; - PIMAGE_NT_HEADERS nt_header; - int overlap; - - dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; - if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) - { - printf ("Unknown EXE header in %s...bailing.\n", p_infile->name); - exit (1); - } - nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) + - dos_header->e_lfanew); - if (nt_header == NULL) - { - printf ("Failed to find IMAGE_NT_HEADER in %s...bailing.\n", - p_infile->name); - exit (1); - } - - /* Check the NT header signature ... */ - if (nt_header->Signature != IMAGE_NT_SIGNATURE) - { - printf ("Invalid IMAGE_NT_SIGNATURE 0x%lx in %s...bailing.\n", - nt_header->Signature, p_infile->name); - exit (1); - } - - /* Locate the ".data" and ".bss" sections for Emacs. (Note that the - actual section names are probably different from these, and might - actually be the same section.) - - We do this as follows: first we determine the virtual address - ranges in this process for the data and bss variables that we wish - to preserve. Then we map these VAs to the section entries in the - source image. Finally, we determine the new size of the raw data - area for the bss section, so we can make the new image the correct - size. */ - - /* We arrange for the Emacs initialized data to be in a separate - section if possible, because we cannot rely on my_begdata and - my_edata marking out the full extent of the initialized data, at - least on the Alpha where the linker freely reorders variables - across libraries. If we can arrange for this, all we need to do is - find the start and size of the EMDATA section. */ - data_section = find_section ("EMDATA", nt_header); - if (data_section) - { - data_start = (char *) nt_header->OptionalHeader.ImageBase + - data_section->VirtualAddress; - data_size = data_section->Misc.VirtualSize; - } - else - { - /* Fallback on the old method if compiler doesn't support the - data_set #pragma (or its equivalent). */ - data_start = my_begdata; - data_size = my_edata - my_begdata; - data_section = rva_to_section (PTR_TO_RVA (my_begdata), nt_header); - if (data_section != rva_to_section (PTR_TO_RVA (my_edata), nt_header)) - { - printf ("Initialized data is not in a single section...bailing\n"); - exit (1); - } - } - - /* As noted in lastfile.c, the Alpha (but not the Intel) MSVC linker - globally segregates all static and public bss data (ie. across all - linked modules, not just per module), so we must take both static - and public bss areas into account to determine the true extent of - the bss area used by Emacs. - - To be strictly correct, we dump the static and public bss areas - used by Emacs separately if non-overlapping (since otherwise we are - dumping bss data belonging to system libraries, eg. the static bss - system data on the Alpha). */ - - bss_start = my_begbss; - bss_size = my_endbss - my_begbss; - bss_section = rva_to_section (PTR_TO_RVA (my_begbss), nt_header); - if (bss_section != rva_to_section (PTR_TO_RVA (my_endbss), nt_header)) - { - printf ("Uninitialized data is not in a single section...bailing\n"); - exit (1); - } - /* Compute how much the .bss section's raw data will grow. */ - extra_bss_size = - ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss), bss_section), - nt_header->OptionalHeader.FileAlignment) - - bss_section->SizeOfRawData; - - bss_start_static = my_begbss_static; - bss_size_static = my_endbss_static - my_begbss_static; - bss_section_static = rva_to_section (PTR_TO_RVA (my_begbss_static), nt_header); - if (bss_section_static != rva_to_section (PTR_TO_RVA (my_endbss_static), nt_header)) - { - printf ("Uninitialized static data is not in a single section...bailing\n"); - exit (1); - } - /* Compute how much the static .bss section's raw data will grow. */ - extra_bss_size_static = - ROUND_UP (RVA_TO_SECTION_OFFSET (PTR_TO_RVA (my_endbss_static), bss_section_static), - nt_header->OptionalHeader.FileAlignment) - - bss_section_static->SizeOfRawData; - - /* Combine the bss sections into one if they overlap. */ -#ifdef _ALPHA_ - overlap = 1; /* force all bss data to be dumped */ -#else - overlap = 0; -#endif - if (bss_start < bss_start_static) - { - if (bss_start_static < bss_start + bss_size) - overlap = 1; - } - else - { - if (bss_start < bss_start_static + bss_size_static) - overlap = 1; - } - if (overlap) - { - if (bss_section != bss_section_static) - { - printf ("BSS data not in a single section...bailing\n"); - exit (1); - } - bss_start = min (bss_start, bss_start_static); - bss_size = max (my_endbss, my_endbss_static) - bss_start; - bss_section_static = 0; - extra_bss_size = max (extra_bss_size, extra_bss_size_static); - extra_bss_size_static = 0; - } -} - -/* Format to print a DWORD_PTR value. */ -#if defined MINGW_W64 && defined _WIN64 -# define pDWP "16llx" -#else -# define pDWP "08lx" -#endif - -/* The dump routines. */ - -void -copy_executable_and_dump_data (file_data *p_infile, - file_data *p_outfile) -{ - unsigned char *dst, *dst_save; - PIMAGE_DOS_HEADER dos_header; - PIMAGE_NT_HEADERS nt_header; - PIMAGE_NT_HEADERS dst_nt_header; - PIMAGE_SECTION_HEADER section; - PIMAGE_SECTION_HEADER dst_section; - DWORD_PTR offset; - int i; - int be_verbose = GetEnvironmentVariable ("DEBUG_DUMP", NULL, 0) > 0; - -#define COPY_CHUNK(message, src, size, verbose) \ - do { \ - unsigned char *s = (void *)(src); \ - DWORD_PTR count = (size); \ - if (verbose) \ - { \ - printf ("%s\n", (message)); \ - printf ("\t0x%"pDWP" Offset in input file.\n", (DWORD_PTR)(s - p_infile->file_base)); \ - printf ("\t0x%"pDWP" Offset in output file.\n", (DWORD_PTR)(dst - p_outfile->file_base)); \ - printf ("\t0x%"pDWP" Size in bytes.\n", count); \ - } \ - memcpy (dst, s, count); \ - dst += count; \ - } while (0) - -#define COPY_PROC_CHUNK(message, src, size, verbose) \ - do { \ - unsigned char *s = (void *)(src); \ - DWORD_PTR count = (size); \ - if (verbose) \ - { \ - printf ("%s\n", (message)); \ - printf ("\t0x%p Address in process.\n", s); \ - printf ("\t0x%p Base output file.\n", p_outfile->file_base); \ - printf ("\t0x%"pDWP" Offset in output file.\n", (DWORD_PTR)(dst - p_outfile->file_base)); \ - printf ("\t0x%p Address in output file.\n", dst); \ - printf ("\t0x%"pDWP" Size in bytes.\n", count); \ - } \ - memcpy (dst, s, count); \ - dst += count; \ - } while (0) - -#define DST_TO_OFFSET() PTR_TO_OFFSET (dst, p_outfile) -#define ROUND_UP_DST(align) \ - (dst = p_outfile->file_base + ROUND_UP (DST_TO_OFFSET (), (align))) -#define ROUND_UP_DST_AND_ZERO(align) \ - do { \ - unsigned char *newdst = p_outfile->file_base \ - + ROUND_UP (DST_TO_OFFSET (), (align)); \ - /* Zero the alignment slop; it may actually initialize real data. */ \ - memset (dst, 0, newdst - dst); \ - dst = newdst; \ - } while (0) - - /* Copy the source image sequentially, ie. section by section after - copying the headers and section table, to simplify the process of - dumping the raw data for the bss and heap sections. - - Note that dst is updated implicitly by each COPY_CHUNK. */ - - dos_header = (PIMAGE_DOS_HEADER) p_infile->file_base; - nt_header = (PIMAGE_NT_HEADERS) (((DWORD_PTR) dos_header) + - dos_header->e_lfanew); - section = IMAGE_FIRST_SECTION (nt_header); - - dst = (unsigned char *) p_outfile->file_base; - - COPY_CHUNK ("Copying DOS header...", dos_header, - (DWORD_PTR) nt_header - (DWORD_PTR) dos_header, be_verbose); - dst_nt_header = (PIMAGE_NT_HEADERS) dst; - COPY_CHUNK ("Copying NT header...", nt_header, - (DWORD_PTR) section - (DWORD_PTR) nt_header, be_verbose); - dst_section = (PIMAGE_SECTION_HEADER) dst; - COPY_CHUNK ("Copying section table...", section, - nt_header->FileHeader.NumberOfSections * sizeof (*section), - be_verbose); - - /* Align the first section's raw data area, and set the header size - field accordingly. */ - ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment); - dst_nt_header->OptionalHeader.SizeOfHeaders = DST_TO_OFFSET (); - - for (i = 0; i < nt_header->FileHeader.NumberOfSections; i++) - { - char msg[100]; - /* Windows section names are fixed 8-char strings, only - zero-terminated if the name is shorter than 8 characters. */ - sprintf (msg, "Copying raw data for %.8s...", section->Name); - - dst_save = dst; - - /* Update the file-relative offset for this section's raw data (if - it has any) in case things have been relocated; we will update - the other offsets below once we know where everything is. */ - if (dst_section->PointerToRawData) - dst_section->PointerToRawData = DST_TO_OFFSET (); - - /* Can always copy the original raw data. */ - COPY_CHUNK - (msg, OFFSET_TO_PTR (section->PointerToRawData, p_infile), - section->SizeOfRawData, be_verbose); - /* Ensure alignment slop is zeroed. */ - ROUND_UP_DST_AND_ZERO (dst_nt_header->OptionalHeader.FileAlignment); - - /* Note that various sections below may be aliases. */ - if (section == data_section) - { - dst = dst_save - + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (data_start), dst_section); - COPY_PROC_CHUNK ("Dumping initialized data...", - data_start, data_size, be_verbose); - dst = dst_save + dst_section->SizeOfRawData; - } - if (section == bss_section) - { - /* Dump contents of bss variables, adjusting the section's raw - data size as necessary. */ - dst = dst_save - + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start), dst_section); - COPY_PROC_CHUNK ("Dumping bss data...", bss_start, - bss_size, be_verbose); - ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); - dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile); - /* Determine new size of raw data area. */ - dst = max (dst, dst_save + dst_section->SizeOfRawData); - dst_section->SizeOfRawData = dst - dst_save; - dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA; - dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; - } - if (section == bss_section_static) - { - /* Dump contents of static bss variables, adjusting the - section's raw data size as necessary. */ - dst = dst_save - + RVA_TO_SECTION_OFFSET (PTR_TO_RVA (bss_start_static), dst_section); - COPY_PROC_CHUNK ("Dumping static bss data...", bss_start_static, - bss_size_static, be_verbose); - ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); - dst_section->PointerToRawData = PTR_TO_OFFSET (dst_save, p_outfile); - /* Determine new size of raw data area. */ - dst = max (dst, dst_save + dst_section->SizeOfRawData); - dst_section->SizeOfRawData = dst - dst_save; - dst_section->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA; - dst_section->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA; - } - - /* Align the section's raw data area. */ - ROUND_UP_DST (dst_nt_header->OptionalHeader.FileAlignment); - - section++; - dst_section++; - } - - /* Copy remainder of source image. */ - do - section--; - while (section->PointerToRawData == 0); - offset = ROUND_UP (section->PointerToRawData + section->SizeOfRawData, - nt_header->OptionalHeader.FileAlignment); - COPY_CHUNK - ("Copying remainder of executable...", - OFFSET_TO_PTR (offset, p_infile), - p_infile->size - offset, be_verbose); - - /* Final size for new image. */ - p_outfile->size = DST_TO_OFFSET (); - - /* Now patch up remaining file-relative offsets. */ - section = IMAGE_FIRST_SECTION (nt_header); - dst_section = IMAGE_FIRST_SECTION (dst_nt_header); - -#define ADJUST_OFFSET(var) \ - do { \ - if ((var) != 0) \ - (var) = relocate_offset ((var), nt_header, dst_nt_header); \ - } while (0) - - dst_nt_header->OptionalHeader.SizeOfInitializedData = 0; - dst_nt_header->OptionalHeader.SizeOfUninitializedData = 0; - for (i = 0; i < dst_nt_header->FileHeader.NumberOfSections; i++) - { - /* Recompute data sizes for completeness. */ - if (dst_section[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) - dst_nt_header->OptionalHeader.SizeOfInitializedData += - ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment); - else if (dst_section[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) - dst_nt_header->OptionalHeader.SizeOfUninitializedData += - ROUND_UP (dst_section[i].Misc.VirtualSize, dst_nt_header->OptionalHeader.FileAlignment); - - ADJUST_OFFSET (dst_section[i].PointerToLinenumbers); - } - - ADJUST_OFFSET (dst_nt_header->FileHeader.PointerToSymbolTable); - - /* Update offsets in debug directory entries. */ - { - IMAGE_DATA_DIRECTORY debug_dir = - dst_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]; - PIMAGE_DEBUG_DIRECTORY debug_entry; - - section = rva_to_section (debug_dir.VirtualAddress, dst_nt_header); - if (section) - { - debug_entry = (PIMAGE_DEBUG_DIRECTORY) - (RVA_TO_OFFSET (debug_dir.VirtualAddress, section) + p_outfile->file_base); - debug_dir.Size /= sizeof (IMAGE_DEBUG_DIRECTORY); - - for (i = 0; i < debug_dir.Size; i++, debug_entry++) - ADJUST_OFFSET (debug_entry->PointerToRawData); - } - } -} - - -/* Dump out .data and .bss sections into a new executable. */ -void -unexec (const char *new_name, const char *old_name) -{ - file_data in_file, out_file; - char out_filename[MAX_PATH], in_filename[MAX_PATH], new_name_a[MAX_PATH]; - unsigned long size; - char *p; - char *q; - - /* Ignore old_name, and get our actual location from the OS. */ - if (!GetModuleFileNameA (NULL, in_filename, MAX_PATH)) - abort (); - - /* Can't use dostounix_filename here, since that needs its file name - argument encoded in UTF-8. */ - for (p = in_filename; *p; p = CharNextA (p)) - if (*p == '\\') - *p = '/'; - - strcpy (out_filename, in_filename); - filename_to_ansi (new_name, new_name_a); - - /* Change the base of the output filename to match the requested name. */ - if ((p = strrchr (out_filename, '/')) == NULL) - abort (); - /* The filenames have already been expanded, and will be in Unix - format, so it is safe to expect an absolute name. */ - if ((q = strrchr (new_name_a, '/')) == NULL) - abort (); - strcpy (p, q); - -#ifdef ENABLE_CHECKING - report_temacs_memory_usage (); -#endif - - /* Make sure that the output filename has the ".exe" extension...patch - it up if not. */ - p = out_filename + strlen (out_filename) - 4; - if (strcmp (p, ".exe")) - strcat (out_filename, ".exe"); - - printf ("Dumping from %s\n", in_filename); - printf (" to %s\n", out_filename); - - /* Open the undumped executable file. */ - if (!open_input_file (&in_file, in_filename)) - { - printf ("Failed to open %s (%lu)...bailing.\n", - in_filename, GetLastError ()); - exit (1); - } - - /* Get the interesting section info, like start and size of .bss... */ - get_section_info (&in_file); - - /* The size of the dumped executable is the size of the original - executable plus the size of the heap and the size of the .bss section. */ - size = in_file.size + - extra_bss_size + - extra_bss_size_static; - if (!open_output_file (&out_file, out_filename, size)) - { - printf ("Failed to open %s (%lu)...bailing.\n", - out_filename, GetLastError ()); - exit (1); - } - - copy_executable_and_dump_data (&in_file, &out_file); - - /* Patch up header fields; profiler is picky about this. */ - { - PIMAGE_DOS_HEADER dos_header; - PIMAGE_NT_HEADERS nt_header; - HANDLE hImagehelp = LoadLibrary ("imagehlp.dll"); - DWORD headersum; - DWORD checksum; - - dos_header = (PIMAGE_DOS_HEADER) out_file.file_base; - nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew); - - nt_header->OptionalHeader.CheckSum = 0; - /* nt_header->FileHeader.TimeDateStamp = time (NULL); */ - /* dos_header->e_cp = size / 512; */ - /* nt_header->OptionalHeader.SizeOfImage = size; */ - - pfnCheckSumMappedFile = (void *) GetProcAddress (hImagehelp, "CheckSumMappedFile"); - if (pfnCheckSumMappedFile) - { - /* nt_header->FileHeader.TimeDateStamp = time (NULL); */ - pfnCheckSumMappedFile (out_file.file_base, - out_file.size, - &headersum, - &checksum); - nt_header->OptionalHeader.CheckSum = checksum; - } - FreeLibrary (hImagehelp); - } - - close_file_data (&in_file); - close_file_data (&out_file); -} - -/* eof */ -- 2.39.5