9c2bad9761d5e46bf1c5af3fdb42df39878f422a
[chise/xemacs-chise.git.1] / src / unexhp9k800.c
1 /* Unexec for HP 9000 Series 800 machines.
2    Bob Desinger <hpsemc!bd@hplabs.hp.com>
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* Synched up with: Not synched with FSF. */
22
23 /*
24
25   Unexec creates a copy of the old a.out file, and replaces the old data
26   area with the current data area.  When the new file is executed, the
27   process will see the same data structures and data values that the
28   original process had when unexec was called.
29
30   Unlike other versions of unexec, this one copies symbol table and
31   debug information to the new a.out file.  Thus, the new a.out file
32   may be debugged with symbolic debuggers.
33
34   If you fix any bugs in this, I'd like to incorporate your fixes.
35   Send them to uunet!hpda!hpsemc!jmorris or jmorris%hpsemc@hplabs.HP.COM.
36
37   CAVEATS:
38   This routine saves the current value of all static and external
39   variables.  This means that any data structure that needs to be
40   initialized must be explicitly reset.  Variables will not have their
41   expected default values.
42
43   Unfortunately, the HP-UX signal handler has internal initialization
44   flags which are not explicitly reset.  Thus, for signals to work in
45   conjunction with this routine, the following code must executed when
46   the new process starts up.
47
48   void _sigreturn();
49   ...
50   sigsetreturn(_sigreturn);
51 */
52
53 \f
54 #include <config.h>
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <fcntl.h>
58 #include <errno.h>
59
60 #include <a.out.h>
61
62 /*
63  * Minor modification to enable dumping with shared libraries added by
64  * Dipankar Gupta (dg@hplb.hpl.hp.com). I studied Oliver Laumann's
65  * more elaborate dynamic loading scheme in ELK while implementing
66  * this, but don't use any of his machinery.
67  *
68  * Stores the BRK value at dump time, and uses the RUN_TIME_REMAP hook
69  * to break back to the stored value when the dumped executable is restarted.
70  *
71  * CAVEATS (addenda):
72  * 1. Text area of the shlibs are not stored. Thus, if a shared library is
73  *    replaced between the time of dump and execution, all bets are off.
74  *
75  * 2. Assumes that the data and bss area are adjacent, which is true of the
76  *    current VM implementation.
77  *
78  * 3. Any setup that defines HPUX_USE_SHLIBS *must* also define
79  *    RUN_TIME_REMAP.
80  */
81
82 #ifdef HPUX_USE_SHLIBS
83 #include <dl.h>                 /* User-space dynamic loader entry points */
84 void Save_Shared_Data(void);
85 int run_time_remap();
86 #endif
87
88 #define min(x,y)  ( ((x)<(y))?(x):(y) )
89
90 void write_header(int file, struct header *hdr, struct som_exec_auxhdr *auxhdr);
91 void read_header (int file, struct header *hdr, struct som_exec_auxhdr *auxhdr);
92 void save_data_space (int file, struct header *hdr,
93                       struct som_exec_auxhdr *auxhdr, int size);
94 void copy_rest (int old, int new);
95 void copy_file (int old, int new, int size);
96 void update_file_ptrs(int file, struct header *hdr,
97                       struct som_exec_auxhdr *auxhdr,
98                       unsigned int location, int offset);
99 int calculate_checksum(struct header *hdr);
100
101 /* Create a new a.out file, same as old but with current data space */
102 int
103 unexec(char new_name[],         /* name of the new a.out file to be created */
104        char old_name[],         /* name of the old a.out file */
105        char *new_end_of_text,   /* ptr to new edata/etext; NOT USED YET */
106        int dummy1, int dummy2)  /* not used by emacs */
107 {
108   int old, new;
109   int old_size, new_size;
110   struct header hdr;
111   struct som_exec_auxhdr auxhdr;
112   long i;
113
114   /* For the greatest flexibility, should create a temporary file in
115      the same directory as the new file.  When everything is complete,
116      rename the temp file to the new name.
117      This way, a program could update its own a.out file even while
118      it is still executing.  If problems occur, everything is still
119      intact.  NOT implemented.  */
120
121   /* Open the input and output a.out files */
122   old = open (old_name, O_RDONLY);
123   if (old < 0)
124     { perror(old_name); exit(1); }
125   new = open (new_name, O_CREAT|O_RDWR|O_TRUNC, 0777);
126   if (new < 0)
127     { perror(new_name); exit(1); }
128
129   /* Read the old headers */
130   read_header(old, &hdr, &auxhdr);
131
132 #ifdef HPUX_USE_SHLIBS
133   Save_Shared_Data(); /* Save break value (added: dg@hplb.hpl.hp.com) */
134 #endif
135   /* Decide how large the new and old data areas are */
136   old_size = auxhdr.exec_dsize;
137   /* I suspect these two statements are separate
138      to avoid a compiler bug in hpux version 8.  */
139   i = (long) sbrk (0);
140   new_size = i - auxhdr.exec_dmem;
141
142   /* Copy the old file to the new, up to the data space */
143   lseek(old, 0, 0);
144   copy_file(old, new, auxhdr.exec_dfile);
145
146   /* Skip the old data segment and write a new one */
147   lseek(old, old_size, 1);
148   save_data_space(new, &hdr, &auxhdr, new_size);
149
150   /* Copy the rest of the file */
151   copy_rest(old, new);
152
153   /* Update file pointers since we probably changed size of data area */
154   update_file_ptrs(new, &hdr, &auxhdr, auxhdr.exec_dfile, new_size-old_size);
155
156   /* Save the modified header */
157   write_header(new, &hdr, &auxhdr);
158
159   /* Close the binary file */
160   close (old);
161   close (new);
162   return 0;
163 }
164
165 /* Save current data space in the file, update header.  */
166
167 void
168 save_data_space (int file, struct header *hdr,
169                  struct som_exec_auxhdr *auxhdr, int size)
170 {
171   /* Write the entire data space out to the file */
172   if (write(file, (void *)auxhdr->exec_dmem, size) != size)
173     { perror("Can't save new data space"); exit(1); }
174
175   /* Update the header to reflect the new data size */
176   auxhdr->exec_dsize = size;
177   auxhdr->exec_bsize = 0;
178 }
179
180 /* Update the values of file pointers when something is inserted.  */
181
182 void
183 update_file_ptrs(int file, struct header *hdr,
184                  struct som_exec_auxhdr *auxhdr,
185                  unsigned int location, int offset)
186 {
187   struct subspace_dictionary_record subspace;
188   int i;
189
190   /* Increase the overall size of the module */
191   hdr->som_length += offset;
192
193   /* Update the various file pointers in the header */
194 #define update(ptr) if (ptr > location) ptr = ptr + offset
195   update(hdr->aux_header_location);
196   update(hdr->space_strings_location);
197   update(hdr->init_array_location);
198   update(hdr->compiler_location);
199   update(hdr->symbol_location);
200   update(hdr->fixup_request_location);
201   update(hdr->symbol_strings_location);
202   update(hdr->unloadable_sp_location);
203   update(auxhdr->exec_tfile);
204   update(auxhdr->exec_dfile);
205
206   /* Do for each subspace dictionary entry */
207   lseek(file, hdr->subspace_location, 0);
208   for (i = 0; i < hdr->subspace_total; i++)
209     {
210       if (read(file, &subspace, sizeof(subspace)) != sizeof(subspace))
211         { perror("Can't read subspace record"); exit(1); }
212
213       /* If subspace has a file location, update it */
214       if (subspace.initialization_length > 0
215           && subspace.file_loc_init_value > location)
216         {
217           subspace.file_loc_init_value += offset;
218           lseek(file, -sizeof(subspace), 1);
219           if (write(file, &subspace, sizeof(subspace)) != sizeof(subspace))
220             { perror("Can't update subspace record"); exit(1); }
221         }
222     }
223
224   /* Do for each initialization pointer record */
225   /* (I don't think it applies to executable files, only relocatables) */
226 #undef update
227 }
228
229 /* Read in the header records from an a.out file.  */
230
231 void
232 read_header(int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
233 {
234
235   /* Read the header in */
236   lseek(file, 0, 0);
237   if (read(file, hdr, sizeof(*hdr)) != sizeof(*hdr))
238     { perror("Couldn't read header from a.out file"); exit(1); }
239
240   if (hdr->a_magic != EXEC_MAGIC && hdr->a_magic != SHARE_MAGIC
241       &&  hdr->a_magic != DEMAND_MAGIC)
242     {
243       fprintf(stderr, "a.out file doesn't have legal magic number\n");
244       exit(1);
245     }
246
247   lseek(file, hdr->aux_header_location, 0);
248   if (read(file, auxhdr, sizeof(*auxhdr)) != sizeof(*auxhdr))
249     {
250       perror("Couldn't read auxiliary header from a.out file");
251       exit(1);
252     }
253 }
254
255 /* Write out the header records into an a.out file.  */
256 void
257 write_header(int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
258 {
259   /* Update the checksum */
260   hdr->checksum = calculate_checksum(hdr);
261
262   /* Write the header back into the a.out file */
263   lseek(file, 0, 0);
264   if (write(file, hdr, sizeof(*hdr)) != sizeof(*hdr))
265     { perror("Couldn't write header to a.out file"); exit(1); }
266   lseek(file, hdr->aux_header_location, 0);
267   if (write(file, auxhdr, sizeof(*auxhdr)) != sizeof(*auxhdr))
268     { perror("Couldn't write auxiliary header to a.out file"); exit(1); }
269 }
270
271 /* Calculate the checksum of a SOM header record. */
272 int
273 calculate_checksum(struct header *hdr)
274 {
275   int checksum, i, *ptr;
276
277   checksum = 0;  ptr = (int *) hdr;
278
279   for (i=0; i<sizeof(*hdr)/sizeof(int)-1; i++)
280     checksum ^= ptr[i];
281
282   return(checksum);
283 }
284
285 /* Copy size bytes from the old file to the new one.  */
286 void
287 copy_file (int old, int new, int size)
288 {
289   int len;
290   int buffer[8192];  /* word aligned will be faster */
291
292   for (; size > 0; size -= len)
293     {
294       len = min(size, sizeof(buffer));
295       if (read(old, buffer, len) != len)
296         { perror("Read failure on a.out file"); exit(1); }
297       if (write(new, buffer, len) != len)
298         { perror("Write failure in a.out file"); exit(1); }
299     }
300 }
301
302 /* Copy the rest of the file, up to EOF.  */
303 void
304 copy_rest (int old, int new)
305 {
306   int buffer[4096];
307   int len;
308
309   /* Copy bytes until end of file or error */
310   while ( (len = read(old, buffer, sizeof(buffer))) > 0)
311     if (write(new, buffer, len) != len) break;
312
313   if (len != 0)
314     { perror("Unable to copy the rest of the file"); exit(1); }
315 }
316
317 #ifdef  DEBUG
318 display_header(struct header *hdr, struct som_exec_auxhdr *auxhdr)
319 {
320   /* Display the header information (debug) */
321   printf("\n\nFILE HEADER\n");
322   printf("magic number %d \n", hdr->a_magic);
323   printf("text loc %.8x   size %d \n", auxhdr->exec_tmem, auxhdr->exec_tsize);
324   printf("data loc %.8x   size %d \n", auxhdr->exec_dmem, auxhdr->exec_dsize);
325   printf("entry     %x \n",   auxhdr->exec_entry);
326   printf("Bss  segment size %u\n", auxhdr->exec_bsize);
327   printf("\n");
328   printf("data file loc %d    size %d\n",
329          auxhdr->exec_dfile, auxhdr->exec_dsize);
330   printf("som_length %d\n", hdr->som_length);
331   printf("unloadable sploc %d    size %d\n",
332          hdr->unloadable_sp_location, hdr->unloadable_sp_size);
333 }
334 #endif /* DEBUG */
335
336 #ifdef HPUX_USE_SHLIBS
337 /* Added machinery for shared libs... see comments at the beginning of this file. */
338
339 void *Brk_On_Dump = 0;          /* Brk value to restore... stored as a global */
340
341 void Save_Shared_Data () {
342   Brk_On_Dump = sbrk( 0 );
343 }
344
345 void Restore_Shared_Data () {
346   brk ( Brk_On_Dump );
347 }
348
349 int run_time_remap (int d) {
350   Restore_Shared_Data();
351 }
352
353 /* run_time_remap is the magic called by startup code in the dumped executable
354  * if RUN_TIME_REMAP is set.
355  */
356 #endif /* HPUX_USE_SHLIBS */