]> code.delx.au - gnu-emacs/blobdiff - src/unexelf.c
Initial revision.
[gnu-emacs] / src / unexelf.c
index a90885ba64f4d030054ee576665e383a737886fd..548465c0df9805b66676158d86c7eae92bc33ee0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992
+/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999, 2000, 2001
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -52,11 +52,6 @@ what you give them.   Help stamp out software-hoarding!  */
  * 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
@@ -66,9 +61,6 @@ what you give them.   Help stamp out software-hoarding!  */
  *
  * 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.
@@ -412,11 +404,21 @@ Filesz      Memsz       Flags       Align
 
  */
 \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 *, ...);
+#endif
+
 #include <sys/types.h>
 #include <stdio.h>
 #include <sys/stat.h>
 #include <memory.h>
-#include <string.h>
 #include <errno.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -432,6 +434,18 @@ Filesz      Memsz       Flags       Align
 #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
@@ -471,7 +485,7 @@ typedef struct {
 /*
  * 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
@@ -480,6 +494,9 @@ typedef struct {
 
 # 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
@@ -490,13 +507,18 @@ typedef struct {
 #  define SHN_UNDEF    Elf_eshn_undefined
 #  define SHN_ABS      Elf_eshn_absolute
 #  define SHN_COMMON   Elf_eshn_common
-# endif
+# 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__
@@ -509,17 +531,18 @@ typedef struct {
 
 #ifndef ElfW
 # ifdef __STDC__
-#  define ElfW(type)   Elf32_##type
+#  define ElfBitsW(bits, type) Elf##bits##_##type
 # else
-#  define ElfW(type)   Elf32_/**/type
+#  define ElfBitsW(bits, type) Elf/**/bits/**/_/**/type
 # endif
-#endif
-
-#ifndef emacs
-#define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1)
-#else
-#include <config.h>
-extern void fatal (char *, ...);
+# ifdef _LP64
+#  define ELFSIZE 64
+# else
+#  define ELFSIZE 32
+# endif
+  /* This macro expands `bits' before invoking ElfBitsW.  */
+# define ElfExpandBitsW(bits, type) ElfBitsW (bits, type)
+# define ElfW(type) ElfExpandBitsW (ELFSIZE, type)
 #endif
 
 #ifndef ELF_BSS_SECTION_NAME
@@ -613,7 +636,7 @@ find_section (name, section_names, file_name, old_file_h, old_section_h, noerror
       if (noerror)
        return -1;
       else
-       fatal ("Can't find %s in %s.\n", name, file_name, 0);
+       fatal ("Can't find %s in %s.\n", name, file_name);
     }
 
   return idx;
@@ -635,17 +658,22 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
 {
   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;
@@ -658,8 +686,10 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   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);
 
@@ -669,16 +699,24 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   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 */
 
@@ -694,14 +732,16 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
                                   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.  */
 
   old_bss_index = find_section (".bss", old_section_names,
                                old_name, old_file_h, old_section_h, 0);
 
   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;
 
   if (old_sbss_index == -1)
     {
@@ -746,10 +786,9 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   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)
@@ -760,16 +799,10 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   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);
@@ -777,8 +810,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
     ((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,
@@ -788,8 +820,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   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;
@@ -802,12 +833,11 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
 #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--)
     {
@@ -857,11 +887,10 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
 #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,
@@ -958,6 +987,15 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
       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
@@ -977,7 +1015,9 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
          || !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;
@@ -1176,16 +1216,21 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
       }
     }
 
-#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);