-/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999
+/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999, 2000, 2001
Free Software Foundation, Inc.
This file is part of GNU Emacs.
* The value you specify may be rounded down to a suitable boundary
* as required by the machine you are using.
*
- * Specifying zero for data_start means the boundary between text and data
- * should not be the same as when the program was loaded.
- * If NO_REMAP is defined, the argument data_start is ignored and the
- * segment boundaries are never changed.
- *
* Bss_start indicates how much of the data segment is to be saved in the
* a.out file and restored when the program is executed. It gives the lowest
* unsaved address, and is rounded up to a page boundary. The default when 0
*
* The new file is set up to start at entry_address.
*
- * If you make improvements I'd like to get them too.
- * harpo!utah-cs!thomas, thomas@Utah-20
- *
*/
/* Even more heavily modified by james@bigtex.cactus.org of Dell Computer Co.
*/
\f
+/* We do not use mmap because that fails with NFS.
+ Instead we read the whole file, modify it, and write it out. */
+
#ifndef emacs
#define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1)
+#include <string.h>
#else
#include <config.h>
extern void fatal (char *, ...);
#include <stdio.h>
#include <sys/stat.h>
#include <memory.h>
-#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sym.h>
#endif /* __sony_news && _SYSTYPE_SYSV */
#if __sgi
-#include <sym.h> /* for HDRR declaration */
+#include <syms.h> /* for HDRR declaration */
#endif /* __sgi */
+#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
/*
* NetBSD does not have normal-looking user-land ELF support.
*/
-# ifdef __alpha__
+# if defined __alpha__ || defined __sparc_v9__
# define ELFSIZE 64
# else
# define ELFSIZE 32
# endif
# include <sys/exec_elf.h>
-# define PT_LOAD Elf_pt_load
-# 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
-
-/*
- * The magic of picking the right size types is handled by the ELFSIZE
- * definition above.
- */
-# ifdef __STDC__
-# define ElfW(type) Elf_##type
-# else
-# define ElfW(type) Elf_/**/type
-# endif
+# 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 <sys/exec_ecoff.h>
# define HDRR struct ecoff_symhdr
# define pHDRR HDRR *
-# endif
+# 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__
return x - rem + y;
}
+/* Return the index of the section named NAME.
+ SECTION_NAMES, FILE_NAME and FILE_H give information
+ about the file we are looking in.
+
+ If we don't find the section NAME, that is a fatal error
+ if NOERROR is 0; we return -1 if NOERROR is nonzero. */
+
+static int
+find_section (name, section_names, file_name, old_file_h, old_section_h, noerror)
+ char *name;
+ char *section_names;
+ char *file_name;
+ ElfW(Ehdr) *old_file_h;
+ ElfW(Shdr) *old_section_h;
+ int noerror;
+{
+ int idx;
+
+ for (idx = 1; idx < old_file_h->e_shnum; idx++)
+ {
+#ifdef DEBUG
+ fprintf (stderr, "Looking for %s - found %s\n", name,
+ section_names + OLD_SECTION_H (idx).sh_name);
+#endif
+ if (!strcmp (section_names + OLD_SECTION_H (idx).sh_name,
+ name))
+ break;
+ }
+ if (idx == old_file_h->e_shnum)
+ {
+ if (noerror)
+ return -1;
+ else
+ fatal ("Can't find %s in %s.\n", name, file_name);
+ }
+
+ return idx;
+}
+
/* ****************************************************************
* unexec
*
{
int new_file, old_file, new_file_size;
- /* Pointers to the base of the image of the two files. */
+ /* Pointers to the base of the image of the two files. */
caddr_t old_base, new_base;
- /* Pointers to the file, program and section headers for the old and new
- * files.
- */
+#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 in the old file */
+ /* Point to the section name table in the old file. */
char *old_section_names;
ElfW(Addr) old_bss_addr, new_bss_addr;
ElfW(Off) new_data2_offset;
ElfW(Addr) new_data2_addr;
- int n, nn, old_bss_index, old_data_index, new_data2_index;
- int old_sbss_index, old_mdebug_index;
+ int n, nn;
+ int old_bss_index, old_sbss_index;
+ int old_data_index, new_data2_index;
+ int old_mdebug_index;
struct stat stat_buf;
+ int old_file_size;
- /* Open the old file & map it into the address space. */
+ /* Open the old file, allocate a buffer of the right size, and read
+ in the file contents. */
old_file = open (old_name, O_RDONLY);
if (fstat (old_file, &stat_buf) == -1)
fatal ("Can't fstat (%s): errno %d\n", old_name, errno);
- old_base = mmap ((caddr_t) 0, stat_buf.st_size, PROT_READ, MAP_SHARED,
- old_file, 0);
+#if MAP_ANON == 0
+ mmap_fd = open ("/dev/zero", O_RDONLY);
+ if (mmap_fd < 0)
+ fatal ("Can't open /dev/zero for reading: errno %d\n", errno);
+#endif
- if (old_base == (caddr_t) -1)
- fatal ("Can't mmap (%s): errno %d\n", old_name, errno);
+ /* 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;
+ 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\n", old_name);
-#ifdef DEBUG
- fprintf (stderr, "mmap (%s, %x) -> %x\n", old_name, stat_buf.st_size,
- old_base);
-#endif
+ if (read (old_file, old_base, stat_buf.st_size) != stat_buf.st_size)
+ fatal ("Didn't read all of %s: errno %d\n", old_name, errno);
/* Get pointers to headers & section names */
old_section_names = (char *) old_base
+ OLD_SECTION_H (old_file_h->e_shstrndx).sh_offset;
+ /* Find the mdebug section, if any. */
+
+ old_mdebug_index = find_section (".mdebug", old_section_names,
+ old_name, old_file_h, old_section_h, 1);
+
/* Find the old .bss section. Figure out parameters of the new
- * data2 and bss sections.
- */
+ data2 and bss sections. */
- for (old_bss_index = 1; old_bss_index < (int) old_file_h->e_shnum;
- old_bss_index++)
- {
-#ifdef DEBUG
- fprintf (stderr, "Looking for .bss - found %s\n",
- old_section_names + OLD_SECTION_H (old_bss_index).sh_name);
-#endif
- if (!strcmp (old_section_names + OLD_SECTION_H (old_bss_index).sh_name,
- ELF_BSS_SECTION_NAME))
- break;
- }
- if (old_bss_index == old_file_h->e_shnum)
- fatal ("Can't find .bss in %s.\n", old_name, 0);
+ old_bss_index = find_section (".bss", old_section_names,
+ old_name, old_file_h, old_section_h, 0);
- for (old_sbss_index = 1; old_sbss_index < (int) old_file_h->e_shnum;
- old_sbss_index++)
- {
-#ifdef DEBUG
- fprintf (stderr, "Looking for .sbss - found %s\n",
- old_section_names + OLD_SECTION_H (old_sbss_index).sh_name);
-#endif
- if (!strcmp (old_section_names + OLD_SECTION_H (old_sbss_index).sh_name,
- ".sbss"))
- break;
- }
- if (old_sbss_index == old_file_h->e_shnum)
- {
+ old_sbss_index = find_section (".sbss", old_section_names,
+ old_name, old_file_h, old_section_h, 1);
+ if (old_sbss_index != -1)
+ if (OLD_SECTION_H (old_sbss_index).sh_type == SHT_PROGBITS)
old_sbss_index = -1;
- old_bss_addr = OLD_SECTION_H(old_bss_index).sh_addr;
- old_bss_size = OLD_SECTION_H(old_bss_index).sh_size;
- new_data2_offset = OLD_SECTION_H(old_bss_index).sh_offset;
+
+ if (old_sbss_index == -1)
+ {
+ old_bss_addr = OLD_SECTION_H (old_bss_index).sh_addr;
+ old_bss_size = OLD_SECTION_H (old_bss_index).sh_size;
new_data2_index = old_bss_index;
}
else
{
- old_bss_addr = OLD_SECTION_H(old_sbss_index).sh_addr;
- old_bss_size = OLD_SECTION_H(old_bss_index).sh_size
- + OLD_SECTION_H(old_sbss_index).sh_size;
- new_data2_offset = OLD_SECTION_H(old_sbss_index).sh_offset;
+ old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr;
+ old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
+ + OLD_SECTION_H (old_sbss_index).sh_size;
new_data2_index = old_sbss_index;
}
- for (old_mdebug_index = 1; old_mdebug_index < (int) old_file_h->e_shnum;
- old_mdebug_index++)
- {
-#ifdef DEBUG
- fprintf (stderr, "Looking for .mdebug - found %s\n",
- old_section_names + OLD_SECTION_H (old_mdebug_index).sh_name);
-#endif
- if (!strcmp (old_section_names + OLD_SECTION_H (old_mdebug_index).sh_name,
- ".mdebug"))
- break;
- }
- if (old_mdebug_index == old_file_h->e_shnum)
- old_mdebug_index = 0;
+ /* Find the old .data section. Figure out parameters of
+ the new data2 and bss sections. */
+
+ old_data_index = find_section (".data", old_section_names,
+ old_name, old_file_h, old_section_h, 0);
#if defined (emacs) || !defined (DEBUG)
new_bss_addr = (ElfW(Addr)) sbrk (0);
#endif
new_data2_addr = old_bss_addr;
new_data2_size = new_bss_addr - old_bss_addr;
+ new_data2_offset = OLD_SECTION_H (old_data_index).sh_offset +
+ (new_data2_addr - OLD_SECTION_H (old_data_index).sh_addr);
#ifdef DEBUG
fprintf (stderr, "old_bss_index %d\n", old_bss_index);
if ((unsigned) new_bss_addr < (unsigned) old_bss_addr + old_bss_size)
fatal (".bss shrank when undumping???\n", 0, 0);
- /* Set the output file to the right size and mmap it. Set
- * pointers to various interesting objects. stat_buf still has
- * old_file data.
- */
+ /* 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. stat_buf still has old_file data. */
new_file = open (new_name, O_RDWR | O_CREAT, 0666);
if (new_file < 0)
if (ftruncate (new_file, new_file_size))
fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
-#ifdef UNEXEC_USE_MAP_PRIVATE
- new_base = mmap ((caddr_t) 0, new_file_size, PROT_READ | PROT_WRITE,
- MAP_PRIVATE, new_file, 0);
-#else
- new_base = mmap ((caddr_t) 0, new_file_size, PROT_READ | PROT_WRITE,
- MAP_SHARED, new_file, 0);
-#endif
-
- if (new_base == (caddr_t) -1)
- fatal ("Can't mmap (%s): errno %d\n", new_name, 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\n", old_name);
new_file_h = (ElfW(Ehdr) *) new_base;
new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
((byte *) new_base + old_file_h->e_shoff + new_data2_size);
/* Make our new file, program and section headers as copies of the
- * originals.
- */
+ originals. */
memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
memcpy (new_program_h, old_program_h,
PATCH_INDEX (new_file_h->e_shstrndx);
/* Fix up file header. We'll add one section. Section header is
- * further away now.
- */
+ further away now. */
new_file_h->e_shoff += new_data2_size;
new_file_h->e_shnum += 1;
#endif
/* Fix up a new program header. Extend the writable data segment so
- * that the bss area is covered too. Find that segment by looking
- * for a segment that ends just before the .bss area. Make sure
- * that no segments are above the new .data2. Put a loop at the end
- * to adjust the offset and address of any segment that is above
- * data2, just in case we decide to allow this later.
- */
+ that the bss area is covered too. Find that segment by looking
+ for a segment that ends just before the .bss area. Make sure
+ that no segments are above the new .data2. Put a loop at the end
+ to adjust the offset and address of any segment that is above
+ data2, just in case we decide to allow this later. */
for (n = new_file_h->e_phnum - 1; n >= 0; n--)
{
if ((OLD_SECTION_H (old_bss_index)).sh_addralign > alignment)
alignment = OLD_SECTION_H (old_bss_index).sh_addralign;
-#ifdef __mips
+#ifdef __sgi
/* According to r02kar@x4u2.desy.de (Karsten Kuenne)
and oliva@gnu.org (Alexandre Oliva), on IRIX 5.2, we
always get "Program segment above .bss" when dumping
when the executable doesn't have an sbss section. */
if (old_sbss_index != -1)
-#endif /* __mips */
+#endif /* __sgi */
if (NEW_PROGRAM_H (n).p_vaddr + NEW_PROGRAM_H (n).p_filesz
> (old_sbss_index == -1
? old_bss_addr
#endif
/* Fix up section headers based on new .data2 section. Any section
- * whose offset or virtual address is after the new .data2 section
- * gets its value adjusted. .bss size becomes zero and new address
- * is set. data2 section header gets added by copying the existing
- * .data header and modifying the offset, address and size.
- */
+ whose offset or virtual address is after the new .data2 section
+ gets its value adjusted. .bss size becomes zero and new address
+ is set. data2 section header gets added by copying the existing
+ .data header and modifying the offset, address and size. */
for (old_data_index = 1; old_data_index < (int) old_file_h->e_shnum;
old_data_index++)
if (!strcmp (old_section_names + OLD_SECTION_H (old_data_index).sh_name,
>= OLD_SECTION_H (old_bss_index-1).sh_offset)
NEW_SECTION_H (nn).sh_offset += new_data2_size;
#else
- /* The idea of this is that the bss section's sh_offset
- may need rounding up to compare with new_data2_offset.
- So we cannot simply compare the sh_offset.
- However, another small section could exist just before
- the bss section, and we need to know that is before. */
- if (round_up (NEW_SECTION_H (nn).sh_offset
- + NEW_SECTION_H (nn).sh_size,
+ if (round_up (NEW_SECTION_H (nn).sh_offset,
OLD_SECTION_H (old_bss_index).sh_addralign)
- > new_data2_offset)
+ >= new_data2_offset)
NEW_SECTION_H (nn).sh_offset += new_data2_size;
#endif
/* Any section that was originally placed after the section
if (NEW_SECTION_H (nn).sh_type != SHT_SYMTAB
&& NEW_SECTION_H (nn).sh_type != SHT_DYNSYM)
PATCH_INDEX (NEW_SECTION_H (nn).sh_info);
+
+ if (old_sbss_index != -1)
+ if (!strcmp (old_section_names + NEW_SECTION_H (nn).sh_name, ".sbss"))
+ {
+ NEW_SECTION_H (nn).sh_offset =
+ round_up (NEW_SECTION_H (nn).sh_offset,
+ NEW_SECTION_H (nn).sh_addralign);
+ NEW_SECTION_H (nn).sh_type = SHT_PROGBITS;
+ }
/* Now, start to copy the content of sections. */
if (NEW_SECTION_H (nn).sh_type == SHT_NULL
".lit4")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".lit8")
- || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
- ".got")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
".sdata1")
|| !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
- ".data1"))
+ ".data1")
+ || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
+ ".sbss"))
src = (caddr_t) OLD_SECTION_H (n).sh_addr;
else
src = old_base + OLD_SECTION_H (n).sh_offset;
#endif /* __alpha__ */
#if defined (__sony_news) && defined (_SYSTYPE_SYSV)
- if (NEW_SECTION_H (nn).sh_type == SHT_MIPS_DEBUG && old_mdebug_index)
+ if (NEW_SECTION_H (nn).sh_type == SHT_MIPS_DEBUG
+ && old_mdebug_index != -1)
{
int diff = NEW_SECTION_H(nn).sh_offset
- OLD_SECTION_H(old_mdebug_index).sh_offset;
".lit4")
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".lit8")
- || !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
- ".got")
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
".sdata1")
|| !strcmp ((old_section_names + NEW_SECTION_H (nn).sh_name),
}
}
-#ifdef UNEXEC_USE_MAP_PRIVATE
- if (lseek (new_file, 0, SEEK_SET) == -1)
- fatal ("Can't rewind (%s): errno %d\n", new_name, errno);
+ /* Write out new_file, and free the buffers. */
if (write (new_file, new_base, new_file_size) != new_file_size)
- fatal ("Can't write (%s): errno %d\n", new_name, errno);
-#endif
+ fatal ("Didn't write %d bytes to %s: errno %d\n",
+ new_file_size, new_base, 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
+ close (mmap_fd);
+#endif
+
if (close (old_file))
fatal ("Can't close (%s): errno %d\n", old_name, errno);