(mouse-autoselect-window-cancel): Don't cancel for
[bpt/emacs.git] / src / unexelf.c
index d88b8ec..f7d8d22 100644 (file)
@@ -1,11 +1,11 @@
-/* Copyright (C) 1985,86,87,88,90,92,1999,2000,01,2003
-   Free Software Foundation, Inc.
+/* Copyright (C) 1985, 1986, 1987, 1988, 1990, 1992, 1999, 2000, 2001,
+                 2002, 2003, 2004, 2005, 2006, 2007 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
 
 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 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -15,8 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.
 
 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
 
 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
@@ -412,7 +412,7 @@ temacs:
 #include <string.h>
 #else
 #include <config.h>
 #include <string.h>
 #else
 #include <config.h>
-extern void fatal (char *, ...);
+extern void fatal (const char *msgid, ...);
 #endif
 
 #include <sys/types.h>
 #endif
 
 #include <sys/types.h>
@@ -433,6 +433,9 @@ extern void fatal (char *, ...);
 #if __sgi
 #include <syms.h> /* for HDRR declaration */
 #endif /* __sgi */
 #if __sgi
 #include <syms.h> /* for HDRR declaration */
 #endif /* __sgi */
+#ifdef BROKEN_NOCOMBRELOC
+#include <assert.h>
+#endif
 
 #ifndef MAP_ANON
 #ifdef MAP_ANONYMOUS
 
 #ifndef MAP_ANON
 #ifdef MAP_ANONYMOUS
@@ -682,11 +685,14 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   ElfW(Addr) new_data2_addr;
 
   int n, nn;
   ElfW(Addr) new_data2_addr;
 
   int n, nn;
-  int old_bss_index, old_sbss_index;
+  int old_bss_index, old_sbss_index, old_plt_index;
   int old_data_index, new_data2_index;
   int old_mdebug_index;
   struct stat stat_buf;
   int old_file_size;
   int old_data_index, new_data2_index;
   int old_mdebug_index;
   struct stat stat_buf;
   int old_file_size;
+#ifdef BROKEN_NOCOMBRELOC
+  int unreloc_sections[10], n_unreloc_sections;
+#endif
 
   /* Open the old file, allocate a buffer of the right size, and read
      in the file contents.  */
 
   /* Open the old file, allocate a buffer of the right size, and read
      in the file contents.  */
@@ -702,7 +708,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
 #if MAP_ANON == 0
   mmap_fd = open ("/dev/zero", O_RDONLY);
   if (mmap_fd < 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);
+    fatal ("Can't open /dev/zero for reading: errno %d\n", errno, 0);
 #endif
 
   /* We cannot use malloc here because that may use sbrk.  If it does,
 #endif
 
   /* We cannot use malloc here because that may use sbrk.  If it does,
@@ -713,7 +719,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   old_base = mmap (NULL, old_file_size, PROT_READ | PROT_WRITE,
                   MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
   if (old_base == MAP_FAILED)
   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, 0);
 
   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);
@@ -740,15 +746,34 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   old_sbss_index = find_section (".sbss", old_section_names,
                                 old_name, old_file_h, old_section_h, 1);
   if (old_sbss_index != -1)
   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)
+    if (OLD_SECTION_H (old_sbss_index).sh_type != SHT_NOBITS)
       old_sbss_index = -1;
 
       old_sbss_index = -1;
 
-  if (old_sbss_index == -1)
+  /* PowerPC64 has .plt in the BSS section.  */
+  old_plt_index = find_section (".plt", old_section_names,
+                               old_name, old_file_h, old_section_h, 1);
+  if (old_plt_index != -1)
+    if (OLD_SECTION_H (old_plt_index).sh_type != SHT_NOBITS)
+      old_plt_index = -1;
+
+  if (old_sbss_index == -1 && old_plt_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;
     }
     {
       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 if (old_plt_index != -1
+          && (old_sbss_index == -1
+              || (OLD_SECTION_H (old_sbss_index).sh_addr
+                  > OLD_SECTION_H (old_plt_index).sh_addr)))
+    {
+      old_bss_addr = OLD_SECTION_H (old_plt_index).sh_addr;
+      old_bss_size = OLD_SECTION_H (old_bss_index).sh_size
+       + OLD_SECTION_H (old_plt_index).sh_size;
+      if (old_sbss_index != -1)
+       old_bss_size += OLD_SECTION_H (old_sbss_index).sh_size;
+      new_data2_index = old_plt_index;
+    }
   else
     {
       old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr;
   else
     {
       old_bss_addr = OLD_SECTION_H (old_sbss_index).sh_addr;
@@ -802,7 +827,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   new_base = mmap (NULL, new_file_size, PROT_READ | PROT_WRITE,
                   MAP_ANON | MAP_PRIVATE, mmap_fd, 0);
   if (new_base == MAP_FAILED)
   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, 0);
 
   new_file_h = (ElfW(Ehdr) *) new_base;
   new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
 
   new_file_h = (ElfW(Ehdr) *) new_base;
   new_program_h = (ElfW(Phdr) *) ((byte *) new_base + old_file_h->e_phoff);
@@ -934,7 +959,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
       if (n == old_bss_index
          /* The new bss and sbss section's size is zero, and its file offset
             and virtual address should be off by NEW_DATA2_SIZE.  */
       if (n == old_bss_index
          /* The new bss and sbss section's size is zero, and its file offset
             and virtual address should be off by NEW_DATA2_SIZE.  */
-         || n == old_sbss_index
+         || n == old_sbss_index || n == old_plt_index
          )
        {
          /* NN should be `old_s?bss_index + 1' at this point. */
          )
        {
          /* NN should be `old_s?bss_index + 1' at this point. */
@@ -1079,7 +1104,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
          && old_mdebug_index != -1)
         {
          int diff = NEW_SECTION_H(nn).sh_offset
          && old_mdebug_index != -1)
         {
          int diff = NEW_SECTION_H(nn).sh_offset
-               - OLD_SECTION_H(old_mdebug_index).sh_offset;
+               - OLD_SECTION_H(old_mdebug_index).sh_offset;
          HDRR *phdr = (HDRR *)(NEW_SECTION_H (nn).sh_offset + new_base);
 
          if (diff)
          HDRR *phdr = (HDRR *)(NEW_SECTION_H (nn).sh_offset + new_base);
 
          if (diff)
@@ -1199,6 +1224,7 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
 
   /* This loop seeks out relocation sections for the data section, so
      that it can undo relocations performed by the runtime linker.  */
 
   /* This loop seeks out relocation sections for the data section, so
      that it can undo relocations performed by the runtime linker.  */
+#ifndef BROKEN_NOCOMBRELOC
   for (n = new_file_h->e_shnum - 1; n; n--)
     {
       ElfW(Shdr) section = NEW_SECTION_H (n);
   for (n = new_file_h->e_shnum - 1; n; n--)
     {
       ElfW(Shdr) section = NEW_SECTION_H (n);
@@ -1253,13 +1279,92 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
          break;
        }
     }
          break;
        }
     }
+#else /* BROKEN_NOCOMBRELOC */
+  for (n = 1, n_unreloc_sections = 0; n < new_file_h->e_shnum; n++)
+    if (!strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data")
+       || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata")
+       || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit4")
+       || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".lit8")
+#ifdef IRIX6_5                 /* see above */
+       || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".got")
+#endif
+       || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".sdata1")
+       || !strcmp (old_section_names + NEW_SECTION_H (n).sh_name, ".data1"))
+      {
+       assert (n_unreloc_sections
+               < (sizeof (unreloc_sections) / sizeof (unreloc_sections[0])));
+       unreloc_sections[n_unreloc_sections++] = n;
+#ifdef DEBUG
+       fprintf (stderr, "section %d: %s\n", n,
+                old_section_names + NEW_SECTION_H (n).sh_name);
+#endif
+      }
+
+  for (n = new_file_h->e_shnum - 1; n; n--)
+    {
+      ElfW(Shdr) section = NEW_SECTION_H (n);
+      caddr_t reloc, end;
+      ElfW(Addr) addr, offset;
+      int target;
+
+      switch (section.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.  */
+         for (reloc = old_base + section.sh_offset,
+                end = reloc + section.sh_size;
+              reloc < end;
+              reloc += section.sh_entsize)
+           {
+             addr = ((ElfW(Rel) *) reloc)->r_offset;
+#ifdef __alpha__
+             /* The Alpha ELF binutils currently have a bug that
+                sometimes results in relocs that contain all
+                zeroes.  Work around this for now...  */
+             if (addr == 0)
+               continue;
+#endif
+             for (nn = 0; nn < n_unreloc_sections; nn++)
+               {
+                 target = unreloc_sections[nn];
+                 if (NEW_SECTION_H (target).sh_addr <= addr
+                     && addr < (NEW_SECTION_H (target).sh_addr +
+                                NEW_SECTION_H (target).sh_size))
+                   {
+                     offset = (NEW_SECTION_H (target).sh_addr -
+                               NEW_SECTION_H (target).sh_offset);
+                     memcpy (new_base + addr - offset,
+                             old_base + addr - offset,
+                             sizeof (ElfW(Addr)));
+#ifdef DEBUG
+                     fprintf (stderr, "unrelocate: [%08lx] <= %08lx\n",
+                              (long) addr,
+                              (long) *((long *) (new_base + addr - offset)));
+#endif
+                     break;
+                   }
+               }
+           }
+         break;
+       }
+    }
+#endif /* BROKEN_NOCOMBRELOC */
 
   /* Write out new_file, and free the buffers.  */
 
   if (write (new_file, new_base, new_file_size) != new_file_size)
 
   /* Write out new_file, and free the buffers.  */
 
   if (write (new_file, new_base, new_file_size) != new_file_size)
+#ifndef emacs
+    fatal ("Didn't write %d bytes: errno %d\n",
+          new_file_size, errno);
+#else
     fatal ("Didn't write %d bytes to %s: errno %d\n",
           new_file_size, new_base, errno);
     fatal ("Didn't write %d bytes to %s: errno %d\n",
           new_file_size, new_base, errno);
-
+#endif
   munmap (old_base, old_file_size);
   munmap (new_base, new_file_size);
 
   munmap (old_base, old_file_size);
   munmap (new_base, new_file_size);
 
@@ -1284,3 +1389,6 @@ unexec (new_name, old_name, data_start, bss_start, entry_address)
   if (chmod (new_name, stat_buf.st_mode) == -1)
     fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
 }
   if (chmod (new_name, stat_buf.st_mode) == -1)
     fatal ("Can't chmod (%s): errno %d\n", new_name, errno);
 }
+
+/* arch-tag: e02e1512-95e2-4ef0-bba7-b6bce658f1e3
+   (do not change this comment) */