1 /* Unexec for HP 9000 Series 800 machines.
2 Bob Desinger <hpsemc!bd@hplabs.hp.com>
4 This file is part of XEmacs.
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
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
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. */
21 /* Synched up with: Not synched with FSF. */
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.
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.
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.
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.
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.
50 sigsetreturn(_sigreturn);
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.
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.
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.
75 * 2. Assumes that the data and bss area are adjacent, which is true of the
76 * current VM implementation.
78 * 3. Any setup that defines HPUX_USE_SHLIBS *must* also define
82 #ifdef HPUX_USE_SHLIBS
83 #include <dl.h> /* User-space dynamic loader entry points */
84 void Save_Shared_Data(void);
88 #define min(x,y) ( ((x)<(y))?(x):(y) )
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);
101 /* Create a new a.out file, same as old but with current data space */
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 */
109 int old_size, new_size;
111 struct som_exec_auxhdr auxhdr;
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. */
121 /* Open the input and output a.out files */
122 old = open (old_name, O_RDONLY);
124 { perror(old_name); exit(1); }
125 new = open (new_name, O_CREAT|O_RDWR|O_TRUNC, 0777);
127 { perror(new_name); exit(1); }
129 /* Read the old headers */
130 read_header(old, &hdr, &auxhdr);
132 #ifdef HPUX_USE_SHLIBS
133 Save_Shared_Data(); /* Save break value (added: dg@hplb.hpl.hp.com) */
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. */
140 new_size = i - auxhdr.exec_dmem;
142 /* Copy the old file to the new, up to the data space */
144 copy_file(old, new, auxhdr.exec_dfile);
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);
150 /* Copy the rest of the file */
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);
156 /* Save the modified header */
157 write_header(new, &hdr, &auxhdr);
159 /* Close the binary file */
165 /* Save current data space in the file, update header. */
168 save_data_space (int file, struct header *hdr,
169 struct som_exec_auxhdr *auxhdr, int size)
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); }
175 /* Update the header to reflect the new data size */
176 auxhdr->exec_dsize = size;
177 auxhdr->exec_bsize = 0;
180 /* Update the values of file pointers when something is inserted. */
183 update_file_ptrs(int file, struct header *hdr,
184 struct som_exec_auxhdr *auxhdr,
185 unsigned int location, int offset)
187 struct subspace_dictionary_record subspace;
190 /* Increase the overall size of the module */
191 hdr->som_length += offset;
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);
206 /* Do for each subspace dictionary entry */
207 lseek(file, hdr->subspace_location, 0);
208 for (i = 0; i < hdr->subspace_total; i++)
210 if (read(file, &subspace, sizeof(subspace)) != sizeof(subspace))
211 { perror("Can't read subspace record"); exit(1); }
213 /* If subspace has a file location, update it */
214 if (subspace.initialization_length > 0
215 && subspace.file_loc_init_value > location)
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); }
224 /* Do for each initialization pointer record */
225 /* (I don't think it applies to executable files, only relocatables) */
229 /* Read in the header records from an a.out file. */
232 read_header(int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
235 /* Read the header in */
237 if (read(file, hdr, sizeof(*hdr)) != sizeof(*hdr))
238 { perror("Couldn't read header from a.out file"); exit(1); }
240 if (hdr->a_magic != EXEC_MAGIC && hdr->a_magic != SHARE_MAGIC
241 && hdr->a_magic != DEMAND_MAGIC)
243 fprintf(stderr, "a.out file doesn't have legal magic number\n");
247 lseek(file, hdr->aux_header_location, 0);
248 if (read(file, auxhdr, sizeof(*auxhdr)) != sizeof(*auxhdr))
250 perror("Couldn't read auxiliary header from a.out file");
255 /* Write out the header records into an a.out file. */
257 write_header(int file, struct header *hdr, struct som_exec_auxhdr *auxhdr)
259 /* Update the checksum */
260 hdr->checksum = calculate_checksum(hdr);
262 /* Write the header back into the a.out file */
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); }
271 /* Calculate the checksum of a SOM header record. */
273 calculate_checksum(struct header *hdr)
275 int checksum, i, *ptr;
277 checksum = 0; ptr = (int *) hdr;
279 for (i=0; i<sizeof(*hdr)/sizeof(int)-1; i++)
285 /* Copy size bytes from the old file to the new one. */
287 copy_file (int old, int new, int size)
290 int buffer[8192]; /* word aligned will be faster */
292 for (; size > 0; size -= len)
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); }
302 /* Copy the rest of the file, up to EOF. */
304 copy_rest (int old, int new)
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;
314 { perror("Unable to copy the rest of the file"); exit(1); }
318 display_header(struct header *hdr, struct som_exec_auxhdr *auxhdr)
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);
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);
336 #ifdef HPUX_USE_SHLIBS
337 /* Added machinery for shared libs... see comments at the beginning of this file. */
339 void *Brk_On_Dump = 0; /* Brk value to restore... stored as a global */
341 void Save_Shared_Data () {
342 Brk_On_Dump = sbrk( 0 );
345 void Restore_Shared_Data () {
349 int run_time_remap (int d) {
350 Restore_Shared_Data();
353 /* run_time_remap is the magic called by startup code in the dumped executable
354 * if RUN_TIME_REMAP is set.
356 #endif /* HPUX_USE_SHLIBS */