comparison src/unexhp9k800.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children c5d627a313b1
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
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
54 #include <config.h>
55 #include <stdio.h>
56 #include <fcntl.h>
57 #include <errno.h>
58
59 #include <a.out.h>
60
61 /*
62 * Minor modification to enable dumping with shared libraries added by
63 * Dipankar Gupta (dg@hplb.hpl.hp.com). I studied Oliver Laumann's
64 * more elaborate dynamic loading scheme in ELK while implementing
65 * this, but don't use any of his machinery.
66 *
67 * Stores the BRK value at dump time, and uses the RUN_TIME_REMAP hook
68 * to break back to the stored value when the dumped executable is restarted.
69 *
70 * CAVEATS (addenda):
71 * 1. Text area of the shlibs are not stored. Thus, if a shared library is
72 * replaced between the time of dump and execution, all bets are off.
73 *
74 * 2. Assumes that the data and bss area are adjacent, which is true of the
75 * current VM implementation.
76 *
77 * 3. Any setup that defines HPUX_USE_SHLIBS *must* also define
78 * RUN_TIME_REMAP.
79 */
80
81 #ifdef HPUX_USE_SHLIBS
82 #include <dl.h> /* User-space dynamic loader entry points */
83 void Save_Shared_Data();
84 int run_time_remap();
85 #endif
86
87 #define roundup(x,n) ( ( (x)+(n-1) ) & ~(n-1) ) /* n is power of 2 */
88 #define min(x,y) ( ((x)<(y))?(x):(y) )
89
90
91 /* Create a new a.out file, same as old but with current data space */
92
93 unexec(new_name, old_name, new_end_of_text, dummy1, dummy2)
94 char new_name[]; /* name of the new a.out file to be created */
95 char old_name[]; /* name of the old a.out file */
96 char *new_end_of_text; /* ptr to new edata/etext; NOT USED YET */
97 int dummy1, dummy2; /* not used by emacs */
98 {
99 int old, new;
100 int old_size, new_size;
101 struct header hdr;
102 struct som_exec_auxhdr auxhdr;
103 long i;
104
105 /* For the greatest flexibility, should create a temporary file in
106 the same directory as the new file. When everything is complete,
107 rename the temp file to the new name.
108 This way, a program could update its own a.out file even while
109 it is still executing. If problems occur, everything is still
110 intact. NOT implemented. */
111
112 /* Open the input and output a.out files */
113 old = open (old_name, O_RDONLY);
114 if (old < 0)
115 { perror(old_name); exit(1); }
116 new = open (new_name, O_CREAT|O_RDWR|O_TRUNC, 0777);
117 if (new < 0)
118 { perror(new_name); exit(1); }
119
120 /* Read the old headers */
121 read_header(old, &hdr, &auxhdr);
122
123 #ifdef HPUX_USE_SHLIBS
124 Save_Shared_Data(); /* Save break value (added: dg@hplb.hpl.hp.com) */
125 #endif
126 /* Decide how large the new and old data areas are */
127 old_size = auxhdr.exec_dsize;
128 /* I suspect these two statements are separate
129 to avoid a compiler bug in hpux version 8. */
130 i = (long) sbrk (0);
131 new_size = i - auxhdr.exec_dmem;
132
133 /* Copy the old file to the new, up to the data space */
134 lseek(old, 0, 0);
135 copy_file(old, new, auxhdr.exec_dfile);
136
137 /* Skip the old data segment and write a new one */
138 lseek(old, old_size, 1);
139 save_data_space(new, &hdr, &auxhdr, new_size);
140
141 /* Copy the rest of the file */
142 copy_rest(old, new);
143
144 /* Update file pointers since we probably changed size of data area */
145 update_file_ptrs(new, &hdr, &auxhdr, auxhdr.exec_dfile, new_size-old_size);
146
147 /* Save the modified header */
148 write_header(new, &hdr, &auxhdr);
149
150 /* Close the binary file */
151 close (old);
152 close (new);
153 return 0;
154 }
155
156 /* Save current data space in the file, update header. */
157
158 save_data_space(file, hdr, auxhdr, size)
159 int file;
160 struct header *hdr;
161 struct som_exec_auxhdr *auxhdr;
162 int size;
163 {
164 /* Write the entire data space out to the file */
165 if (write(file, (void *)auxhdr->exec_dmem, size) != size)
166 { perror("Can't save new data space"); exit(1); }
167
168 /* Update the header to reflect the new data size */
169 auxhdr->exec_dsize = size;
170 auxhdr->exec_bsize = 0;
171 }
172
173 /* Update the values of file pointers when something is inserted. */
174
175 update_file_ptrs(file, hdr, auxhdr, location, offset)
176 int file;
177 struct header *hdr;
178 struct som_exec_auxhdr *auxhdr;
179 unsigned int location;
180 int offset;
181 {
182 struct subspace_dictionary_record subspace;
183 int i;
184
185 /* Increase the overall size of the module */
186 hdr->som_length += offset;
187
188 /* Update the various file pointers in the header */
189 #define update(ptr) if (ptr > location) ptr = ptr + offset
190 update(hdr->aux_header_location);
191 update(hdr->space_strings_location);
192 update(hdr->init_array_location);
193 update(hdr->compiler_location);
194 update(hdr->symbol_location);
195 update(hdr->fixup_request_location);
196 update(hdr->symbol_strings_location);
197 update(hdr->unloadable_sp_location);
198 update(auxhdr->exec_tfile);
199 update(auxhdr->exec_dfile);
200
201 /* Do for each subspace dictionary entry */
202 lseek(file, hdr->subspace_location, 0);
203 for (i = 0; i < hdr->subspace_total; i++)
204 {
205 if (read(file, &subspace, sizeof(subspace)) != sizeof(subspace))
206 { perror("Can't read subspace record"); exit(1); }
207
208 /* If subspace has a file location, update it */
209 if (subspace.initialization_length > 0
210 && subspace.file_loc_init_value > location)
211 {
212 subspace.file_loc_init_value += offset;
213 lseek(file, -sizeof(subspace), 1);
214 if (write(file, &subspace, sizeof(subspace)) != sizeof(subspace))
215 { perror("Can't update subspace record"); exit(1); }
216 }
217 }
218
219 /* Do for each initialization pointer record */
220 /* (I don't think it applies to executable files, only relocatables) */
221 #undef update
222 }
223
224 /* Read in the header records from an a.out file. */
225
226 read_header(file, hdr, auxhdr)
227 int file;
228 struct header *hdr;
229 struct som_exec_auxhdr *auxhdr;
230 {
231
232 /* Read the header in */
233 lseek(file, 0, 0);
234 if (read(file, hdr, sizeof(*hdr)) != sizeof(*hdr))
235 { perror("Couldn't read header from a.out file"); exit(1); }
236
237 if (hdr->a_magic != EXEC_MAGIC && hdr->a_magic != SHARE_MAGIC
238 && hdr->a_magic != DEMAND_MAGIC)
239 {
240 fprintf(stderr, "a.out file doesn't have legal magic number\n");
241 exit(1);
242 }
243
244 lseek(file, hdr->aux_header_location, 0);
245 if (read(file, auxhdr, sizeof(*auxhdr)) != sizeof(*auxhdr))
246 {
247 perror("Couldn't read auxiliary header from a.out file");
248 exit(1);
249 }
250 }
251
252 /* Write out the header records into an a.out file. */
253
254 write_header(file, hdr, auxhdr)
255 int file;
256 struct header *hdr;
257 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
273 calculate_checksum(hdr)
274 struct header *hdr;
275 {
276 int checksum, i, *ptr;
277
278 checksum = 0; ptr = (int *) hdr;
279
280 for (i=0; i<sizeof(*hdr)/sizeof(int)-1; i++)
281 checksum ^= ptr[i];
282
283 return(checksum);
284 }
285
286 /* Copy size bytes from the old file to the new one. */
287
288 copy_file(old, new, size)
289 int new, old;
290 int size;
291 {
292 int len;
293 int buffer[8192]; /* word aligned will be faster */
294
295 for (; size > 0; size -= len)
296 {
297 len = min(size, sizeof(buffer));
298 if (read(old, buffer, len) != len)
299 { perror("Read failure on a.out file"); exit(1); }
300 if (write(new, buffer, len) != len)
301 { perror("Write failure in a.out file"); exit(1); }
302 }
303 }
304
305 /* Copy the rest of the file, up to EOF. */
306
307 copy_rest(old, new)
308 int new, old;
309 {
310 int buffer[4096];
311 int len;
312
313 /* Copy bytes until end of file or error */
314 while ( (len = read(old, buffer, sizeof(buffer))) > 0)
315 if (write(new, buffer, len) != len) break;
316
317 if (len != 0)
318 { perror("Unable to copy the rest of the file"); exit(1); }
319 }
320
321 #ifdef DEBUG
322 display_header(hdr, auxhdr)
323 struct header *hdr;
324 struct som_exec_auxhdr *auxhdr;
325 {
326 /* Display the header information (debug) */
327 printf("\n\nFILE HEADER\n");
328 printf("magic number %d \n", hdr->a_magic);
329 printf("text loc %.8x size %d \n", auxhdr->exec_tmem, auxhdr->exec_tsize);
330 printf("data loc %.8x size %d \n", auxhdr->exec_dmem, auxhdr->exec_dsize);
331 printf("entry %x \n", auxhdr->exec_entry);
332 printf("Bss segment size %u\n", auxhdr->exec_bsize);
333 printf("\n");
334 printf("data file loc %d size %d\n",
335 auxhdr->exec_dfile, auxhdr->exec_dsize);
336 printf("som_length %d\n", hdr->som_length);
337 printf("unloadable sploc %d size %d\n",
338 hdr->unloadable_sp_location, hdr->unloadable_sp_size);
339 }
340 #endif /* DEBUG */
341
342 #ifdef HPUX_USE_SHLIBS
343 /* Added machinery for shared libs... see comments at the beginning of this file. */
344
345 void *Brk_On_Dump = 0; /* Brk value to restore... stored as a global */
346
347 void Save_Shared_Data () {
348 Brk_On_Dump = sbrk( 0 );
349 }
350
351 void Restore_Shared_Data () {
352 brk ( Brk_On_Dump );
353 }
354
355 int run_time_remap (int d) {
356 Restore_Shared_Data();
357 }
358
359 /* run_time_remap is the magic called by startup code in the dumped executable
360 * if RUN_TIME_REMAP is set.
361 */
362 #endif /* HPUX_USE_SHLIBS */