root/src/unexhp9k800.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. run_time_remap
  2. unexec_error
  3. check_lseek
  4. save_data_space
  5. update_file_ptrs
  6. read_header
  7. write_header
  8. calculate_checksum
  9. copy_file
  10. copy_rest
  11. display_header
  12. unexec

     1 /* Unexec for HP 9000 Series 800 machines.
     2 
     3   This file is in the public domain.
     4 
     5   Author: John V. Morris
     6 
     7   This file was written by John V. Morris at Hewlett Packard.
     8   Both the author and Hewlett Packard Co. have disclaimed the
     9   copyright on this file, and it is therefore in the public domain.
    10   (Search for "hp9k800" in copyright.list.)
    11 */
    12 
    13 /*
    14    Bob Desinger <hpsemc!bd@hplabs.hp.com>
    15 
    16    Note that the GNU project considers support for HP operation a
    17    peripheral activity which should not be allowed to divert effort
    18    from development of the GNU system.  Changes in this code will be
    19    installed when users send them in, but aside from that we don't
    20    plan to think about it, or about whether other Emacs maintenance
    21    might break it.
    22 
    23 
    24   Unexec creates a copy of the old a.out file, and replaces the old data
    25   area with the current data area.  When the new file is executed, the
    26   process will see the same data structures and data values that the
    27   original process had when unexec was called.
    28 
    29   Unlike other versions of unexec, this one copies symbol table and
    30   debug information to the new a.out file.  Thus, the new a.out file
    31   may be debugged with symbolic debuggers.
    32 
    33   If you fix any bugs in this, I'd like to incorporate your fixes.
    34   Send them to uunet!hpda!hpsemc!jmorris or jmorris%hpsemc@hplabs.HP.COM.
    35 
    36   CAVEATS:
    37   This routine saves the current value of all static and external
    38   variables.  This means that any data structure that needs to be
    39   initialized must be explicitly reset.  Variables will not have their
    40   expected default values.
    41 
    42   Unfortunately, the HP-UX signal handler has internal initialization
    43   flags which are not explicitly reset.  Thus, for signals to work in
    44   conjunction with this routine, the following code must executed when
    45   the new process starts up.
    46 
    47   void _sigreturn ();
    48   ...
    49   sigsetreturn (_sigreturn);
    50 */
    51 
    52 #include <config.h>
    53 #include "unexec.h"
    54 #include "lisp.h"
    55 #include "sysstdio.h"
    56 
    57 #include <fcntl.h>
    58 #include <errno.h>
    59 #include <a.out.h>
    60 #include <dl.h>
    61 
    62 /* brk value to restore, stored as a global.
    63    This is really used only if we used shared libraries.  */
    64 static long brk_on_dump = 0;
    65 
    66 /* Called from main, if we use shared libraries.  */
    67 int
    68 run_time_remap (char *ignored)
    69 {
    70   brk ((char *) brk_on_dump);
    71 }
    72 
    73 #undef roundup
    74 #define roundup(x,n) (((x) + ((n) - 1)) & ~((n) - 1))  /* n is power of 2 */
    75 
    76 /* Report a fatal error and exit.  */
    77 static _Noreturn void
    78 unexec_error (char const *msg)
    79 {
    80   perror (msg);
    81   exit (1);
    82 }
    83 
    84 /* Do an lseek and check the result.  */
    85 static void
    86 check_lseek (int fd, off_t offset, int whence)
    87 {
    88   if (lseek (fd, offset, whence) < 0)
    89     unexec_error ("Cannot lseek");
    90 }
    91 
    92 /* Save current data space in the file, update header.  */
    93 
    94 static void
    95 save_data_space (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr,
    96                  int size)
    97 {
    98   /* Write the entire data space out to the file */
    99   if (write (file, auxhdr->exec_dmem, size) != size)
   100     unexec_error ("Can't save new data space");
   101 
   102   /* Update the header to reflect the new data size */
   103   auxhdr->exec_dsize = size;
   104   auxhdr->exec_bsize = 0;
   105 }
   106 
   107 /* Update the values of file pointers when something is inserted.  */
   108 
   109 static void
   110 update_file_ptrs (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr,
   111                   unsigned int location, int offset)
   112 {
   113   struct subspace_dictionary_record subspace;
   114   int i;
   115 
   116   /* Increase the overall size of the module */
   117   hdr->som_length += offset;
   118 
   119   /* Update the various file pointers in the header */
   120 #define update(ptr) if (ptr > location) ptr = ptr + offset
   121   update (hdr->aux_header_location);
   122   update (hdr->space_strings_location);
   123   update (hdr->init_array_location);
   124   update (hdr->compiler_location);
   125   update (hdr->symbol_location);
   126   update (hdr->fixup_request_location);
   127   update (hdr->symbol_strings_location);
   128   update (hdr->unloadable_sp_location);
   129   update (auxhdr->exec_tfile);
   130   update (auxhdr->exec_dfile);
   131 
   132   /* Do for each subspace dictionary entry */
   133   check_lseek (file, hdr->subspace_location, 0);
   134   for (i = 0; i < hdr->subspace_total; i++)
   135     {
   136       ptrdiff_t subspace_size = sizeof subspace;
   137       if (read (file, &subspace, subspace_size) != subspace_size)
   138         unexec_error ("Can't read subspace record");
   139 
   140       /* If subspace has a file location, update it */
   141       if (subspace.initialization_length > 0
   142           && subspace.file_loc_init_value > location)
   143         {
   144           subspace.file_loc_init_value += offset;
   145           check_lseek (file, -subspace_size, 1);
   146           if (write (file, &subspace, subspace_size) != subspace_size)
   147             unexec_error ("Can't update subspace record");
   148         }
   149     }
   150 
   151   /* Do for each initialization pointer record */
   152   /* (I don't think it applies to executable files, only relocatables) */
   153 #undef update
   154 }
   155 
   156 /* Read in the header records from an a.out file.  */
   157 
   158 static void
   159 read_header (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
   160 {
   161 
   162   /* Read the header in */
   163   check_lseek (file, 0, 0);
   164   if (read (file, hdr, sizeof (*hdr)) != sizeof (*hdr))
   165     unexec_error ("Couldn't read header from a.out file");
   166 
   167   if (hdr->a_magic != EXEC_MAGIC && hdr->a_magic != SHARE_MAGIC
   168       &&  hdr->a_magic != DEMAND_MAGIC)
   169     {
   170       fputs ("a.out file doesn't have valid magic number\n", stderr);
   171       exit (1);
   172     }
   173 
   174   check_lseek (file, hdr->aux_header_location, 0);
   175   if (read (file, auxhdr, sizeof (*auxhdr)) != sizeof (*auxhdr))
   176     unexec_error ("Couldn't read auxiliary header from a.out file");
   177 }
   178 
   179 /* Write out the header records into an a.out file.  */
   180 
   181 static void
   182 write_header (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
   183 {
   184   /* Update the checksum */
   185   hdr->checksum = calculate_checksum (hdr);
   186 
   187   /* Write the header back into the a.out file */
   188   check_lseek (file, 0, 0);
   189   if (write (file, hdr, sizeof (*hdr)) != sizeof (*hdr))
   190     unexec_error ("Couldn't write header to a.out file");
   191   check_lseek (file, hdr->aux_header_location, 0);
   192   if (write (file, auxhdr, sizeof (*auxhdr)) != sizeof (*auxhdr))
   193     unexec_error ("Couldn't write auxiliary header to a.out file");
   194 }
   195 
   196 /* Calculate the checksum of a SOM header record. */
   197 
   198 static int
   199 calculate_checksum (struct header *hdr)
   200 {
   201   int checksum, i, *ptr;
   202 
   203   checksum = 0;  ptr = (int *) hdr;
   204 
   205   for (i = 0; i < sizeof (*hdr) / sizeof (int) - 1; i++)
   206     checksum ^= ptr[i];
   207 
   208   return (checksum);
   209 }
   210 
   211 /* Copy size bytes from the old file to the new one.  */
   212 
   213 static void
   214 copy_file (int old, int new, int size)
   215 {
   216   int len;
   217   int buffer[8192];  /* word aligned will be faster */
   218 
   219   for (; size > 0; size -= len)
   220     {
   221       len = min (size, sizeof (buffer));
   222       if (read (old, buffer, len) != len)
   223         unexec_error ("Read failure on a.out file");
   224       if (write (new, buffer, len) != len)
   225         unexec_error ("Write failure in a.out file");
   226     }
   227 }
   228 
   229 /* Copy the rest of the file, up to EOF.  */
   230 
   231 static void
   232 copy_rest (int old, int new)
   233 {
   234   int buffer[4096];
   235   int len;
   236 
   237   /* Copy bytes until end of file or error */
   238   while ((len = read (old, buffer, sizeof (buffer))) > 0)
   239     if (write (new, buffer, len) != len) break;
   240 
   241   if (len != 0)
   242     unexec_error ("Unable to copy the rest of the file");
   243 }
   244 
   245 #ifdef  DEBUG
   246 static void
   247 display_header (struct header *hdr, struct som_exec_auxhdr *auxhdr)
   248 {
   249   /* Display the header information (debug) */
   250   printf ("\n\nFILE HEADER\n");
   251   printf ("magic number %d \n", hdr->a_magic);
   252   printf ("text loc %.8x   size %d \n", auxhdr->exec_tmem, auxhdr->exec_tsize);
   253   printf ("data loc %.8x   size %d \n", auxhdr->exec_dmem, auxhdr->exec_dsize);
   254   printf ("entry     %x \n",   auxhdr->exec_entry);
   255   printf ("Bss  segment size %u\n", auxhdr->exec_bsize);
   256   printf ("\n");
   257   printf ("data file loc %d    size %d\n",
   258           auxhdr->exec_dfile, auxhdr->exec_dsize);
   259   printf ("som_length %d\n", hdr->som_length);
   260   printf ("unloadable sploc %d    size %d\n",
   261           hdr->unloadable_sp_location, hdr->unloadable_sp_size);
   262 }
   263 #endif /* DEBUG */
   264 
   265 
   266 /* Create a new a.out file, same as old but with current data space */
   267 void
   268 unexec (const char *new_name,      /* name of the new a.out file to be created */
   269         const char *old_name)       /* name of the old a.out file */
   270 {
   271   int old, new;
   272   int old_size, new_size;
   273   struct header hdr;
   274   struct som_exec_auxhdr auxhdr;
   275   long i;
   276 
   277   /* For the greatest flexibility, should create a temporary file in
   278      the same directory as the new file.  When everything is complete,
   279      rename the temp file to the new name.
   280      This way, a program could update its own a.out file even while
   281      it is still executing.  If problems occur, everything is still
   282      intact.  NOT implemented.  */
   283 
   284   /* Open the input and output a.out files.  */
   285   old = emacs_open (old_name, O_RDONLY, 0);
   286   if (old < 0)
   287     unexec_error (old_name);
   288   new = emacs_open (new_name, O_CREAT | O_RDWR | O_TRUNC, 0777);
   289   if (new < 0)
   290     unexec_error (new_name);
   291 
   292   /* Read the old headers.  */
   293   read_header (old, &hdr, &auxhdr);
   294 
   295   brk_on_dump = (long) sbrk (0);
   296 
   297   /* Decide how large the new and old data areas are.  */
   298   old_size = auxhdr.exec_dsize;
   299   /* I suspect these two statements are separate
   300      to avoid a compiler bug in hpux version 8.  */
   301   i = (long) sbrk (0);
   302   new_size = i - auxhdr.exec_dmem;
   303 
   304   /* Copy the old file to the new, up to the data space.  */
   305   check_lseek (old, 0, 0);
   306   copy_file (old, new, auxhdr.exec_dfile);
   307 
   308   /* Skip the old data segment and write a new one.  */
   309   check_lseek (old, old_size, 1);
   310   save_data_space (new, &hdr, &auxhdr, new_size);
   311 
   312   /* Copy the rest of the file.  */
   313   copy_rest (old, new);
   314 
   315   /* Update file pointers since we probably changed size of data area.  */
   316   update_file_ptrs (new, &hdr, &auxhdr, auxhdr.exec_dfile, new_size-old_size);
   317 
   318   /* Save the modified header.  */
   319   write_header (new, &hdr, &auxhdr);
   320 
   321   /* Close the binary file.  */
   322   emacs_close (old);
   323   emacs_close (new);
   324 }

/* [<][>][^][v][top][bottom][index][help] */