]> code.delx.au - gnu-emacs/blobdiff - src/unexalpha.c
(window_loop): Test w->dedicated with !NILP instead of EQ Qt.
[gnu-emacs] / src / unexalpha.c
index ac9482d86bd3299e83095fdb63eb8b3de26b7dd2..ead259437f65465c4e5133cf8bc3d01df4dcdbb1 100644 (file)
@@ -1,6 +1,7 @@
 /* Unexec for DEC alpha.  schoepf@sc.ZIB-Berlin.DE (Rainer Schoepf).
 
-   Copyright (C) 1994 Free Software Foundation, Inc.
+   Copyright (C) 1994, 2000, 2002, 2003, 2004,
+                 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -16,7 +17,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
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 \f
 #include <config.h>
@@ -25,14 +27,64 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <stdio.h>
-#include <varargs.h>
+#include <errno.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#if !defined (__NetBSD__) && !defined (__OpenBSD__)
 #include <filehdr.h>
 #include <aouthdr.h>
 #include <scnhdr.h>
 #include <syms.h>
-
-static void fatal_unexec ();
-static void mark_x ();
+#ifndef __linux__
+# include <reloc.h>
+# include <elf_abi.h>
+#endif
+#else /* __NetBSD__ or __OpenBSD__ */
+/*
+ * NetBSD/Alpha does not have 'normal' user-land ECOFF support because
+ * there's no desire to support ECOFF as the executable format in the
+ * long term.
+ */
+#include <sys/exec_ecoff.h>
+
+/* Structures, constants, etc., that NetBSD defines strangely. */
+#define        filehdr         ecoff_filehdr
+#define        aouthdr         ecoff_aouthdr
+#define        scnhdr          ecoff_scnhdr
+#define        HDRR            struct ecoff_symhdr
+#define        pHDRR           HDRR *
+#define        cbHDRR          sizeof(HDRR)
+#ifdef __OpenBSD__
+#define        ALPHAMAGIC      ECOFF_MAGIC_NATIVE_ALPHA
+#else
+#define        ALPHAMAGIC      ECOFF_MAGIC_NETBSD_ALPHA
+#endif
+#define        ZMAGIC          ECOFF_ZMAGIC
+
+/* Misc. constants that NetBSD doesn't define at all. */
+#define        ALPHAUMAGIC     0617
+#define        _MIPS_NSCNS_MAX 35
+#define        STYP_TEXT       0x00000020
+#define        STYP_DATA       0x00000040
+#define        STYP_BSS        0x00000080
+#define        STYP_RDATA      0x00000100
+#define        STYP_SDATA      0x00000200
+#define        STYP_SBSS       0x00000400
+#define        STYP_INIT       0x80000000
+#define        _TEXT           ".text"
+#define        _DATA           ".data"
+#define        _BSS            ".bss"
+#define        _INIT           ".init"
+#define        _RDATA          ".rdata"
+#define        _SDATA          ".sdata"
+#define        _SBSS           ".sbss"
+#endif /* __NetBSD__ || __OpenBSD__ */
+
+static void fatal_unexec __P ((char *, char *));
+static void mark_x __P ((char *));
+
+static void update_dynamic_symbols __P ((char *, char *, int, struct aouthdr));
 
 #define READ(_fd, _buffer, _size, _error_message, _error_arg) \
        errno = EEOF; \
@@ -48,14 +100,18 @@ static void mark_x ();
        if (lseek (_fd, _position, L_SET) != _position) \
          fatal_unexec (_error_message, _error_arg);
 
-extern int errno;
-extern char *strerror ();
-
-void *sbrk();
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+void *sbrk ();
+#endif
 
 #define EEOF -1
 
 static struct scnhdr *text_section;
+static struct scnhdr *rel_dyn_section;
+static struct scnhdr *dynstr_section;
+static struct scnhdr *dynsym_section;
 static struct scnhdr *init_section;
 static struct scnhdr *finit_section;
 static struct scnhdr *rdata_section;
@@ -70,6 +126,8 @@ static struct scnhdr *sdata_section;
 static struct scnhdr *sbss_section;
 static struct scnhdr *bss_section;
 
+static struct scnhdr old_data_scnhdr;
+
 static unsigned long Brk;
 
 struct headers {
@@ -86,6 +144,7 @@ struct headers {
 #define DEFAULT_ENTRY_ADDRESS __start
 #endif
 \f
+void
 unexec (new_name, a_name, data_start, bss_start, entry_address)
      char *new_name, *a_name;
      unsigned long data_start, bss_start, entry_address;
@@ -139,7 +198,7 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
   if (nhdr.fhdr.f_opthdr != sizeof (nhdr.aout))
     {
       fprintf (stderr, "unexec: input a.out header is %d bytes, not %d.\n",
-              nhdr.fhdr.f_opthdr, sizeof (nhdr.aout));
+              nhdr.fhdr.f_opthdr, (int)sizeof (nhdr.aout));
       exit (1);
     }
   if (nhdr.aout.magic != ZMAGIC)
@@ -156,7 +215,7 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 #define CHECK_SCNHDR(ptr, name, flags)                                 \
   ptr = NULL;                                                          \
   for (i = 0; i < nhdr.fhdr.f_nscns && !ptr; i++)                      \
-    if (strcmp (nhdr.section[i].s_name, name) == 0)                    \
+    if (strncmp (nhdr.section[i].s_name, name, 8) == 0)                        \
       {                                                                        \
        if (nhdr.section[i].s_flags != flags)                           \
          fprintf (stderr, "unexec: %x flags (%x expected) in %s section.\n", \
@@ -166,6 +225,15 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 
   CHECK_SCNHDR (text_section,  _TEXT,  STYP_TEXT);
   CHECK_SCNHDR (init_section,  _INIT,  STYP_INIT);
+#ifdef _REL_DYN
+  CHECK_SCNHDR (rel_dyn_section, _REL_DYN,  STYP_REL_DYN);
+#endif /* _REL_DYN */
+#ifdef _DYNSYM
+  CHECK_SCNHDR (dynsym_section, _DYNSYM,  STYP_DYNSYM);
+#endif /* _REL_DYN */
+#ifdef _DYNSTR
+  CHECK_SCNHDR (dynstr_section, _DYNSTR,  STYP_DYNSTR);
+#endif /* _REL_DYN */
 #ifdef _FINI
   CHECK_SCNHDR (finit_section, _FINI,  STYP_FINI);
 #endif /* _FINI */
@@ -175,10 +243,10 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 #endif
 #ifdef _PDATA
   CHECK_SCNHDR (pdata_section, _PDATA, STYP_PDATA);
-#endif _PDATA
+#endif /* _PDATA */
 #ifdef _GOT
   CHECK_SCNHDR (got_section,   _GOT,   STYP_GOT);
-#endif _GOT
+#endif /* _GOT */
   CHECK_SCNHDR (data_section,  _DATA,  STYP_DATA);
 #ifdef _XDATA
   CHECK_SCNHDR (xdata_section, _XDATA, STYP_XDATA);
@@ -199,6 +267,8 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 
   Brk = brk;
 
+  bcopy (data_section, &old_data_scnhdr, sizeof (old_data_scnhdr));
+
   nhdr.aout.dsize = brk - DATA_START;
   nhdr.aout.bsize = 0;
   if (entry_address == 0)
@@ -265,6 +335,8 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 #ifdef _GOT
   if (got_section != NULL)
     {
+      bcopy (got_section, buffer, sizeof (struct scnhdr));
+
       got_section->s_vaddr = vaddr;
       got_section->s_paddr = vaddr;
       got_section->s_size = 0;
@@ -291,6 +363,21 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
   WRITE (new, (char *)DATA_START, nhdr.aout.dsize,
         "writing data section to %s", new_name);
 
+#ifdef _GOT
+#define old_got_section ((struct scnhdr *)buffer)
+
+  if (got_section != NULL)
+    {
+      SEEK (new, old_got_section->s_scnptr,
+           "seeking to start of got_section in %s", new_name);
+      WRITE (new, oldptr + old_got_section->s_scnptr, old_got_section->s_size,
+            "writing new got_section of %s", new_name);
+      SEEK (new, nhdr.aout.tsize + nhdr.aout.dsize,
+           "seeking to end of data section of %s", new_name);
+    }
+
+#undef old_got_section
+#endif
 
   /*
    * Construct new symbol table header
@@ -323,15 +410,9 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
         stat.st_size - ohdr.fhdr.f_symptr - cbHDRR,
         "writing symbol table of %s", new_name);
 
-#if 0
-
-/* Not needed for now */
-
-  update_dynamic_symbols (oldptr, new_name, new, newsyms,
-                         ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->issExtMax,
-                          ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbExtOffset,
-                          ((pHDRR) (oldptr + ohdr.fhdr.f_symptr))->cbSsExtOffset);
-
+#ifdef _REL_DYN
+  if (rel_dyn_section)
+    update_dynamic_symbols (oldptr, new_name, new, nhdr.aout);
 #endif
 
 #undef symhdr
@@ -346,70 +427,86 @@ unexec (new_name, a_name, data_start, bss_start, entry_address)
 }
 
 
-#if 0
+static void
+update_dynamic_symbols (old, new_name, new, aout)
+     char *old;                        /* Pointer to old executable */
+     char *new_name;            /* Name of new executable */
+     int new;                  /* File descriptor for new executable */
+     struct aouthdr aout;      /* a.out info from the file header */
+{
+#if !defined (__linux__) && !defined (__NetBSD__) && !defined (__OpenBSD__)
 
-/* Not needed for now */
+  typedef struct dynrel_info {
+    char * addr;
+    unsigned type:8;
+    unsigned index:24;
+    unsigned info:8;
+    unsigned pad:8;
+  } dr_info;
 
-/* The following function updates the values of some symbols
-   that are used by the dynamic loader:
+  int nsyms = rel_dyn_section->s_size / sizeof (struct dynrel_info);
+  int i;
+  dr_info * rd_base = (dr_info *) (old + rel_dyn_section->s_scnptr);
+  Elf32_Sym * ds_base = (Elf32_Sym *) (old + dynsym_section->s_scnptr);
 
-   _edata
-   _end
+  for (i = 0; i < nsyms; i++) {
+    register Elf32_Sym x;
 
-*/
+    if (rd_base[i].index == 0)
+      continue;
 
+    x = ds_base[rd_base[i].index];
 
-update_dynamic_symbols (old, new_name, new, newsyms, nsyms, symoff, stroff)
-     char *old;                        /* Pointer to old executable */
-     char *new_name;            /* Name of new executable */
-     int new;                  /* File descriptor for new executable */
-     long newsyms;             /* Offset of Symbol table in new executable */
-     int nsyms;                        /* Number of symbol table entries */
-     long symoff;              /* Offset of External Symbols in old file */
-     long stroff;              /* Offset of string table in old file */
-{
-  long i;
-  int found = 0;
-  EXTR n_end, n_edata;
+#if 0
+      fprintf (stderr, "Object inspected: %s, addr = %lx, shndx = %x",
+              old + dynstr_section->s_scnptr + x.st_name, rd_base[i].addr, x.st_shndx);
+#endif
 
-  /* We go through the symbol table entries until we have found the two
-     symbols. */
 
-  /* cbEXTR is the size of an external symbol table entry */
+    if ((ELF32_ST_BIND (x.st_info) == STB_GLOBAL)
+       && (x.st_shndx == 0)
+       /* && (x.st_value == NULL) */
+       ) {
+      /* OK, this is probably a reference to an object in a shared
+        library, so copy the old value. This is done in several steps:
+        1. reladdr is the address of the location in question relative to
+            the start of the data section,
+         2. oldref is the addr is the mapped in temacs executable,
+         3. newref is the address of the location in question in the
+            undumped executable,
+         4. len is the size of the object reference in bytes --
+            currently only 4 (long) and 8 (quad) are supported.
+           */
+      register unsigned long reladdr = (long)rd_base[i].addr - old_data_scnhdr.s_vaddr;
+      char * oldref = old + old_data_scnhdr.s_scnptr + reladdr;
+      unsigned long newref = aout.tsize + reladdr;
+      int len;
 
-  for (i = 0; i < nsyms && found < 2; i += cbEXTR)
-    {
-      register pEXTR x = (pEXTR) (old + symoff + i);
-      char *s;
-  
-      s = old + stroff + x->asym.iss; /* name of the symbol */
-
-      if (!strcmp(s,"_edata"))
-       {
-         found++;
-          bcopy (x, &n_edata, cbEXTR);
-         n_edata.asym.value = Brk;
-         SEEK (new, newsyms + cbHDRR + i,
-               "seeking to symbol _edata in %s", new_name);
-         WRITE (new, &n_edata, cbEXTR,
-                "writing symbol table entry for _edata into %s", new_name);
-       }
-      else if (!strcmp(s,"_end"))
-       {
-         found++;
-          bcopy (x, &n_end, cbEXTR);
-         n_end.asym.value = Brk;
-         SEEK (new, newsyms + cbHDRR + i,
-               "seeking to symbol _end in %s", new_name);
-         WRITE (new, &n_end, cbEXTR,
-                "writing symbol table entry for _end into %s", new_name);
-       }
-    }
+#if 0
+      fprintf (stderr, "...relocated\n");
+#endif
 
-}
+      if (rd_base[i].type == R_REFLONG)
+       len = 4;
+      else if (rd_base[i].type == R_REFQUAD)
+       len = 8;
+      else
+       fatal_unexec ("unrecognized relocation type in .dyn.rel section (symbol #%d)", (char *) i);
+
+      SEEK (new, newref, "seeking to dynamic symbol in %s", new_name);
+      WRITE (new, oldref, len, "writing old dynrel info in %s", new_name);
+    }
 
+#if 0
+    else
+      fprintf (stderr, "...not relocated\n");
 #endif
 
+  }
+
+#endif /* not __linux__ and not __NetBSD__ and not __OpenBSD__ */
+}
+
 \f
 /*
  * mark_x
@@ -444,3 +541,6 @@ fatal_unexec (s, arg)
   fputs (".\n", stderr);
   exit (1);
 }
+
+/* arch-tag: 46316c49-ee08-4aa3-942b-00798902f5bd
+   (do not change this comment) */