]> code.delx.au - gnu-emacs/blobdiff - src/unexelf.c
Initial revision.
[gnu-emacs] / src / unexelf.c
index 5519625c783499ffc22ab45b2abad3f86fcab107..548465c0df9805b66676158d86c7eae92bc33ee0 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999, 2000
+/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999, 2000, 2001
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
    Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -404,23 +404,9 @@ Filesz      Memsz       Flags       Align
 
  */
 \f
 
  */
 \f
-/*
- * Modified by rdh@yottayotta.com of Yotta Yotta Incorporated.
- * 
- * The code originally used mmap() to create a memory image of the new
- * and old object files.  This had a few handy features: (1) you get
- * to use a cool system call like mmap, (2) no need to explicitly
- * write out the new file before the close, and (3) no swap space
- * requirements.  Unfortunately, mmap() often fails to work with
- * nfs-mounted file systems.
- *
- * So, instead of relying on the vm subsystem to do the file i/o for
- * us, it's now done explicitly.  A buffer of the right size for the
- * file is dynamically allocated, and either the old_name is read into
- * it, or it is initialized with the correct new executable contents,
- * and then written to new_name.
- */
-\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>
 #ifndef emacs
 #define fatal(a, b, c) fprintf (stderr, a, b, c), exit (1)
 #include <string.h>
@@ -448,6 +434,18 @@ extern void fatal (char *, ...);
 #include <syms.h> /* for HDRR declaration */
 #endif /* __sgi */
 
 #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
 #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
@@ -660,17 +658,22 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
 {
   int new_file, old_file, new_file_size;
 
 {
   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;
 
   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;
 
   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;
   char *old_section_names;
 
   ElfW(Addr) old_bss_addr, new_bss_addr;
@@ -683,9 +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_data_index, new_data2_index;
   int old_mdebug_index;
   struct stat stat_buf;
+  int old_file_size;
 
   /* Open the old file, allocate a buffer of the right size, and read
 
   /* Open the old file, allocate a buffer of the right size, and read
-   * in the file contents. */
+     in the file contents.  */
 
   old_file = open (old_name, O_RDONLY);
 
 
   old_file = open (old_name, O_RDONLY);
 
@@ -695,16 +699,22 @@ 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);
 
   if (fstat (old_file, &stat_buf) == -1)
     fatal ("Can't fstat (%s): errno %d\n", old_name, errno);
 
-  old_base = malloc (stat_buf.st_size);
+#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 == 0)
+  /* 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);
 
     fatal ("Can't allocate buffer for %s\n", old_name);
 
-#ifdef DEBUG
-  fprintf (stderr, "%s: malloc(%d) -> %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);
 
   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);
 
@@ -722,8 +732,7 @@ 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
                                   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_bss_index = find_section (".bss", old_section_names,
                                old_name, old_file_h, old_section_h, 0);
@@ -778,9 +787,8 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
     fatal (".bss shrank when undumping???\n", 0, 0);
 
   /* Set the output file to the right size.  Allocate a buffer to hold
     fatal (".bss shrank when undumping???\n", 0, 0);
 
   /* 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.
-   */
+     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)
 
   new_file = open (new_name, O_RDWR | O_CREAT, 0666);
   if (new_file < 0)
@@ -791,24 +799,18 @@ 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);
 
   if (ftruncate (new_file, new_file_size))
     fatal ("Can't ftruncate (%s): errno %d\n", new_name, errno);
 
-  new_base = malloc (new_file_size);
-
-  if (new_base == 0)
+  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);
 
     fatal ("Can't allocate buffer for %s\n", old_name);
 
-#ifdef DEBUG
-  fprintf (stderr, "%s: malloc(%d) -> %x\n", new_name, new_file_size
-          new_base);
-#endif
-
   new_file_h = (ElfW(Ehdr) *) new_base;
   new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
   new_section_h = (ElfW(Shdr) *)
     ((byte *) new_base + old_file_h->e_shoff + new_data2_size);
 
   /* Make our new file, program and section headers as copies of the
   new_file_h = (ElfW(Ehdr) *) new_base;
   new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
   new_section_h = (ElfW(Shdr) *)
     ((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,
 
   memcpy (new_file_h, old_file_h, old_file_h->e_ehsize);
   memcpy (new_program_h, old_program_h,
@@ -818,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
   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;
 
   new_file_h->e_shoff += new_data2_size;
   new_file_h->e_shnum += 1;
@@ -832,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
 #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--)
     {
 
   for (n = new_file_h->e_phnum - 1; n >= 0; n--)
     {
@@ -887,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
 #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,
   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,
@@ -1017,7 +1016,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
                      ".sdata1")
          || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
                      ".data1")
                      ".sdata1")
          || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
                      ".data1")
-         || !strcmp (old_section_names + NEW_SECTION_H (nn).sh_name,
+         || !strcmp ((old_section_names + NEW_SECTION_H (n).sh_name),
                      ".sbss"))
        src = (caddr_t) OLD_SECTION_H (n).sh_addr;
       else
                      ".sbss"))
        src = (caddr_t) OLD_SECTION_H (n).sh_addr;
       else
@@ -1217,26 +1216,26 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
       }
     }
 
       }
     }
 
-  /* Write out new_file, close it, and free the buffer containing its
-   * contents */
+  /* Write out new_file, and free the buffers.  */
 
   if (write (new_file, new_base, new_file_size) != new_file_size)
     fatal ("Didn't write %d bytes to %s: errno %d\n", 
           new_file_size, new_base, errno);
 
 
   if (write (new_file, new_base, new_file_size) != new_file_size)
     fatal ("Didn't write %d bytes to %s: errno %d\n", 
           new_file_size, new_base, errno);
 
-  if (close (new_file))
-    fatal ("Can't close (%s): errno %d\n", new_name, errno);
+  munmap (old_base, old_file_size);
+  munmap (new_base, new_file_size);
 
 
-  free (new_base);
+  /* Close the files and make the new file executable.  */
 
 
-  /* Close old_file, and free the corresponding buffer */
+#if MAP_ANON == 0
+  close (mmap_fd);
+#endif
 
   if (close (old_file))
     fatal ("Can't close (%s): errno %d\n", old_name, errno);
 
 
   if (close (old_file))
     fatal ("Can't close (%s): errno %d\n", old_name, errno);
 
-  free (old_base);
-
-  /* Make the new file executable */
+  if (close (new_file))
+    fatal ("Can't close (%s): errno %d\n", new_name, errno);
 
   if (stat (new_name, &stat_buf) == -1)
     fatal ("Can't stat (%s): errno %d\n", new_name, errno);
 
   if (stat (new_name, &stat_buf) == -1)
     fatal ("Can't stat (%s): errno %d\n", new_name, errno);