Mercurial > hg > xemacs-beta
comparison src/unexhp9k3.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 84b14dcb0985 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* | |
2 * Code to do an unexec for HPUX 8.0 on an HP9000/[34]00 for a | |
3 * dynamically linked temacs. | |
4 | |
5 Copyright (C) 1992-1993 Free Software Foundation, Inc. | |
6 | |
7 This file is part of XEmacs. | |
8 | |
9 XEmacs is free software; you can redistribute it and/or modify it | |
10 under the terms of the GNU General Public License as published by the | |
11 Free Software Foundation; either version 2, or (at your option) any | |
12 later version. | |
13 | |
14 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
17 for more details. | |
18 | |
19 You should have received a copy of the GNU General Public License | |
20 along with XEmacs; see the file COPYING. If not, write to | |
21 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
22 Boston, MA 02111-1307, USA. */ | |
23 | |
24 /* Synched up with: Not in FSF. */ | |
25 | |
26 /* | |
27 Created 29-Oct-92 by Harlan Sexton for SunOS | |
28 | |
29 Modified Jan 93 by Hamish Macdonald for HPUX | |
30 */ | |
31 | |
32 /********************** Included .h Files **************************/ | |
33 | |
34 #include <config.h> | |
35 | |
36 #include <stdarg.h> | |
37 #include <sys/param.h> | |
38 #include <sys/file.h> | |
39 #include <sys/stat.h> | |
40 #include <sys/types.h> | |
41 #include <string.h> | |
42 #include <stdio.h> | |
43 #include <signal.h> | |
44 #ifdef __hp9000s300 | |
45 # include </usr/include/debug.h> | |
46 #endif | |
47 #include <a.out.h> | |
48 #include <unistd.h> | |
49 #include <ctype.h> | |
50 #include <sys/dir.h> | |
51 | |
52 #include "sysdep.h" | |
53 | |
54 /* XEmacs: Richard Cognot <cognot@ensg.u-nancy.fr> says we need these */ | |
55 extern void perror(const char*); | |
56 extern int sys_nerr; | |
57 extern char *sys_errlist[]; | |
58 extern char *strerror (int); | |
59 | |
60 | |
61 /********************** Macros *************************************/ | |
62 | |
63 #define SYS_ERR \ | |
64 ((errno > 0)?((errno < sys_nerr)?(sys_errlist[errno]):\ | |
65 "unknown system error"): "unknown error") | |
66 | |
67 #define MASK_UP(x,p_of_two) \ | |
68 ((((unsigned long) (x)) + ((p_of_two) - 1)) & (~((p_of_two) - 1))) | |
69 | |
70 #define MASK_DOWN(x,p_of_two) (((unsigned long) (x)) & (~((p_of_two) - 1))) | |
71 | |
72 /********************** Function Prototypes/Declarations ***********/ | |
73 | |
74 static void unexec_error (CONST char *fmt, int use_errno, ...); | |
75 static int unexec_open (char *filename, int flag, int mode); | |
76 static long unexec_seek (int fd, long position); | |
77 static void unexec_read (int fd, long position, char *buf, int bytes); | |
78 static void unexec_write (int fd, long position, char *buf, int bytes); | |
79 static void unexec_copy (int new_fd, int old_fd, long old_pos, long new_pos, | |
80 int bytes); | |
81 static void unexec_pad (int fd, int bytes); | |
82 static void unexec_fstat (int fd, struct stat *statptr); | |
83 static void unexec_fchmod (int fd, int mode); | |
84 int run_time_remap (char *dummy); | |
85 | |
86 /********************** Variables **********************************/ | |
87 | |
88 /* for reporting error messages from system calls */ | |
89 extern int sys_nerr; | |
90 extern int errno; | |
91 extern int _DYNAMIC; | |
92 extern char **environ; | |
93 | |
94 static unsigned long sbrk_of_0_at_unexec; | |
95 | |
96 /*******************************************************************/ | |
97 | |
98 static void | |
99 unexec_error (CONST char *fmt, int use_errno, ...) | |
100 { | |
101 CONST char *err_msg = SYS_ERR; | |
102 va_list args; | |
103 | |
104 fprintf (stderr, "unexec - "); | |
105 va_start (args, use_errno); | |
106 vfprintf (stderr, fmt, args); | |
107 va_end (args); | |
108 | |
109 if (use_errno) | |
110 fprintf (stderr, ": %s", err_msg); | |
111 fprintf (stderr, "\n"); | |
112 exit (1); | |
113 return; | |
114 } | |
115 | |
116 static int | |
117 unexec_open (char *filename, int flag, int mode) | |
118 { | |
119 int fd; | |
120 | |
121 errno = 0; | |
122 | |
123 fd = open (filename, flag, mode); | |
124 | |
125 if (fd < 0) | |
126 { | |
127 unexec_error ("Failure opening file %s", 1, (void *) filename, 0, 0); | |
128 return -1; | |
129 } | |
130 else | |
131 return fd; | |
132 } | |
133 | |
134 static long | |
135 unexec_seek (int fd, long position) | |
136 { | |
137 long seek_value; | |
138 | |
139 if (fd <= 0) | |
140 unexec_error ("No file open in which to seek", 0, 0, 0, 0); | |
141 | |
142 errno = 0; | |
143 | |
144 if (position < 0) | |
145 seek_value = (long) lseek (fd, 0, L_INCR); | |
146 else | |
147 seek_value = (long) lseek (fd, position, L_SET); | |
148 | |
149 if (seek_value < 0) | |
150 unexec_error ("Failed to do a seek to 0x%x in %s", 1, | |
151 (char *) position, "unexec() output file", 0); | |
152 | |
153 return seek_value; | |
154 } | |
155 | |
156 static void | |
157 unexec_read (int fd, long position, char *buf, int bytes) | |
158 { | |
159 int n_read; | |
160 int remains = bytes; | |
161 position = unexec_seek (fd, position); | |
162 | |
163 if (bytes < 0) | |
164 unexec_error ("Attempted read of %d bytes", 0, (char *) bytes, 0, 0); | |
165 | |
166 errno = 0; | |
167 | |
168 while (remains > 0) | |
169 { | |
170 n_read = read (fd, buf, remains); | |
171 if (n_read <= 0) | |
172 unexec_error ("Read failed for 0x%x bytes at offset 0x%x in %s", | |
173 1, (char *) bytes, (char *) position, | |
174 "unexec() output file"); | |
175 buf += n_read; | |
176 remains -= n_read; | |
177 } | |
178 | |
179 return; | |
180 } | |
181 | |
182 static void | |
183 unexec_write (int fd, long position, char *buf, int bytes) | |
184 { | |
185 int n_written; | |
186 int remains = bytes; | |
187 position = unexec_seek (fd, position); | |
188 | |
189 if (bytes < 0) | |
190 unexec_error ("Attempted write of %d bytes in %s", | |
191 0, (char *) bytes, "unexec() output file", 0); | |
192 | |
193 errno = 0; | |
194 | |
195 while (remains > 0) | |
196 { | |
197 n_written = write (fd, buf, remains); | |
198 if (n_written <= 0) | |
199 unexec_error ("Write failed for 0x%x bytes at offset 0x%x in %s", | |
200 1, (char *) bytes, (char *) position, | |
201 "unexec() output file"); | |
202 buf += n_written; | |
203 remains -= n_written; | |
204 } | |
205 | |
206 return; | |
207 } | |
208 | |
209 static void | |
210 unexec_copy (int new_fd, int old_fd, long old_pos, long new_pos, int bytes) | |
211 { | |
212 int remains = bytes; | |
213 char buf[128]; | |
214 | |
215 while (remains > 0) | |
216 { | |
217 int n_to_copy = remains > sizeof(buf) ? sizeof(buf) : remains; | |
218 | |
219 unexec_read (old_fd, old_pos, buf, n_to_copy); | |
220 unexec_write (new_fd, new_pos, buf, n_to_copy); | |
221 | |
222 old_pos += n_to_copy; | |
223 new_pos += n_to_copy; | |
224 remains -= n_to_copy; | |
225 } | |
226 | |
227 return; | |
228 } | |
229 | |
230 static void | |
231 unexec_pad (int fd, int bytes) | |
232 { | |
233 if (bytes > 0) | |
234 { | |
235 char buf[1024]; | |
236 int remaining = bytes; | |
237 | |
238 memset (buf, 0, sizeof(buf)); | |
239 | |
240 while (remaining > 0) | |
241 { | |
242 int this_write = (remaining > sizeof(buf))?sizeof(buf):remaining; | |
243 unexec_write (fd, -1, buf, this_write); | |
244 remaining -= this_write; | |
245 } | |
246 } | |
247 } | |
248 | |
249 static void | |
250 unexec_fstat (int fd, struct stat *statptr) | |
251 { | |
252 errno = 0; | |
253 if (-1 == fstat (fd, statptr)) | |
254 unexec_error ("fstat() failed for descriptor %d", 1, (char *) fd, 0, 0); | |
255 return; | |
256 } | |
257 | |
258 static void | |
259 unexec_fchmod (int fd, int mode) | |
260 { | |
261 errno = 0; | |
262 if (-1 == fchmod (fd, mode)) | |
263 unexec_error ("fchmod() failed for descriptor %d", 1, (char *) fd, 0, 0); | |
264 return; | |
265 } | |
266 | |
267 /* | |
268 * EXPORTED FUNCTIONS | |
269 */ | |
270 | |
271 /* this has to be a global variable to prevent the optimizers from | |
272 * assuming that it can not be 0. | |
273 */ | |
274 static void *dynamic_addr = (void *) &_DYNAMIC; | |
275 | |
276 int | |
277 unexec (char *new_name, char *old_name, | |
278 unsigned int emacs_edata, unsigned int dummy1, unsigned int dummy2) | |
279 { | |
280 /* /dld.sl data */ | |
281 struct dynamic *ld = 0; | |
282 /* old and new state */ | |
283 int old_fd; | |
284 int new_fd; | |
285 struct exec old_hdr; | |
286 struct exec new_hdr; | |
287 struct stat old_buf; | |
288 /* some process specific "constants" */ | |
289 unsigned long n_pagsiz; | |
290 caddr_t dynamic_beg; | |
291 caddr_t current_break = (caddr_t) sbrk (0); | |
292 | |
293 /* dynamically linked image? -- if so, find dld.sl structures */ | |
294 if (dynamic_addr) | |
295 { | |
296 ld = (struct dynamic *) dynamic_addr; | |
297 #ifdef DEBUG | |
298 printf ("dl_text = %#x\n", ld->text); | |
299 printf ("dl_data = %#x\n", ld->data); | |
300 printf ("dl_bss = %#x\n", ld->bss); | |
301 printf ("dl_end = %#x\n", ld->end); | |
302 printf ("dl_dmodule = %#x\n", ld->dmodule); | |
303 printf ("dl_dlt = %#x\n", ld->dlt); | |
304 printf ("dl_plt = %#x\n", ld->plt); | |
305 #endif | |
306 } | |
307 | |
308 /* open the old and new files, figuring out how big the old one is | |
309 so that we can map it in */ | |
310 old_fd = unexec_open (old_name, O_RDONLY, 0); | |
311 new_fd = unexec_open (new_name, O_RDWR | O_CREAT | O_TRUNC, 0666); | |
312 | |
313 /* setup the header and the statbuf for old_fd */ | |
314 unexec_read (old_fd, 0, (char *) &old_hdr, sizeof (old_hdr)); | |
315 unexec_fstat (old_fd, &old_buf); | |
316 | |
317 /* set up some important constants */ | |
318 n_pagsiz = EXEC_PAGESIZE; | |
319 | |
320 /* setup beginning of data to copy from executable */ | |
321 if (ld) | |
322 dynamic_beg = ld->dmodule; | |
323 else | |
324 dynamic_beg = (caddr_t)EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data; | |
325 | |
326 /* set up the new exec */ | |
327 new_hdr = old_hdr; | |
328 new_hdr.a_text = MASK_DOWN (emacs_edata, n_pagsiz); | |
329 new_hdr.a_data = MASK_UP (current_break, n_pagsiz) | |
330 - EXEC_ALIGN(new_hdr.a_text); | |
331 new_hdr.a_bss = 0; | |
332 | |
333 #ifdef DEBUG | |
334 printf ("old text %#x\n", old_hdr.a_text); | |
335 printf ("new text %#x\n", new_hdr.a_text); | |
336 printf ("old data %#x\n", old_hdr.a_data); | |
337 printf ("new data %#x\n", new_hdr.a_data); | |
338 printf ("old bss %#x\n", old_hdr.a_bss); | |
339 printf ("new bss %#x\n", new_hdr.a_bss); | |
340 #endif | |
341 | |
342 /* set up this variable, in case we want to reset "the break" | |
343 when restarting */ | |
344 sbrk_of_0_at_unexec = ((unsigned long) MASK_UP (current_break, n_pagsiz)); | |
345 | |
346 /* Write out the first approximation to the new file. The sizes of | |
347 each section will be correct, but there will be a number of | |
348 corrections that will need to be made. */ | |
349 { | |
350 long old_datoff = DATA_OFFSET (old_hdr); | |
351 long new_datoff = DATA_OFFSET (new_hdr); | |
352 long old_dataddr = EXEC_ALIGN (old_hdr.a_text); | |
353 long new_dataddr = EXEC_ALIGN (new_hdr.a_text); | |
354 long new_mcaloff = MODCAL_OFFSET (new_hdr); | |
355 long old_mcaloff = MODCAL_OFFSET (old_hdr); | |
356 long newtext_size = new_hdr.a_text - old_dataddr; | |
357 long newdata1_size = (unsigned long)dynamic_beg - new_dataddr; | |
358 long dyn_size = (EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data) | |
359 - (unsigned long)dynamic_beg; | |
360 long newdata2_size = (unsigned long)current_break | |
361 - ((unsigned long)dynamic_beg + dyn_size); | |
362 long pad_size = | |
363 MASK_UP (current_break, n_pagsiz) - ((unsigned long) current_break); | |
364 | |
365 #ifdef DEBUG | |
366 printf ("current break is %#lx\n", current_break); | |
367 | |
368 printf ("old_dataddr = %#lx, dynamic_beg = %#lx\n", | |
369 old_dataddr, dynamic_beg); | |
370 #endif | |
371 | |
372 /* | |
373 * First, write the text segment with new header -- copy | |
374 * everything until the start of the data segment from the old | |
375 * file | |
376 */ | |
377 #ifdef DEBUG | |
378 printf ("copying %#lx bytes of text from 0\n", old_datoff); | |
379 #endif | |
380 unexec_copy (new_fd, old_fd, 0, 0, old_datoff); | |
381 /* pad out the text segment */ | |
382 #ifdef DEBUG | |
383 printf ( "text pad size is %#x\n", old_dataddr - old_hdr.a_text); | |
384 #endif | |
385 unexec_pad (new_fd, old_dataddr - old_hdr.a_text); | |
386 | |
387 /* | |
388 * Update debug header spoo | |
389 */ | |
390 if (new_hdr.a_extension > 0) | |
391 { | |
392 new_hdr.a_extension += LESYM_OFFSET(new_hdr) - LESYM_OFFSET(old_hdr); | |
393 } | |
394 | |
395 /* | |
396 * go back and write the new header. | |
397 */ | |
398 unexec_write (new_fd, 0, (char *) &new_hdr, sizeof (new_hdr)); | |
399 | |
400 | |
401 /* | |
402 * Copy the part of the data segment which becomes text from the | |
403 * running image. | |
404 */ | |
405 #ifdef DEBUG | |
406 printf ("copying %#lx bytes of new text from %#lx to position %#lx\n", | |
407 newtext_size, old_dataddr, TEXT_OFFSET(new_hdr) + old_dataddr); | |
408 #endif | |
409 unexec_write (new_fd, TEXT_OFFSET(new_hdr) + old_dataddr, | |
410 (caddr_t)old_dataddr, newtext_size); | |
411 | |
412 #ifdef DEBUG | |
413 printf ("new DATA_OFFSET is %#lx\n", new_datoff); | |
414 #endif | |
415 | |
416 /* | |
417 * Copy the part of the old data segment which will be data | |
418 * in the new executable (before the dynamic stuff) | |
419 * from the running image. | |
420 */ | |
421 #ifdef DEBUG | |
422 printf ("copying %#lx bytes of data from %#lx to position %#lx\n", | |
423 newdata1_size, new_dataddr, new_datoff); | |
424 #endif | |
425 unexec_write (new_fd, new_datoff, (caddr_t)new_dataddr, newdata1_size); | |
426 | |
427 /* copy the dynamic part of the data segment from the old executable */ | |
428 if (dyn_size) | |
429 { | |
430 #ifdef DEBUG | |
431 printf ("copying %#lx bytes of dyn data from executable" | |
432 " at address %#lx to position %#lx\n", | |
433 dyn_size, dynamic_beg, new_datoff + newdata1_size); | |
434 #endif | |
435 unexec_copy (new_fd, old_fd, old_datoff + newtext_size + newdata1_size, | |
436 new_datoff + newdata1_size, dyn_size); | |
437 } | |
438 | |
439 /* copy remaining data (old bss) from the running image */ | |
440 #ifdef DEBUG | |
441 printf ("copying %#lx bytes of data from %#lx to position %#lx\n", | |
442 newdata2_size, new_dataddr + newdata1_size + dyn_size, | |
443 new_datoff + newdata1_size + dyn_size); | |
444 #endif | |
445 unexec_write (new_fd, new_datoff + newdata1_size + dyn_size, | |
446 (caddr_t)(new_dataddr + newdata1_size + dyn_size), | |
447 newdata2_size); | |
448 | |
449 /* pad out the data segment */ | |
450 #ifdef DEBUG | |
451 printf ( "pad size is %#x\n", pad_size); | |
452 #endif | |
453 unexec_pad (new_fd, pad_size); | |
454 | |
455 /* Finally, copy the rest of the junk from the old file. */ | |
456 #ifdef DEBUG | |
457 printf ("Copying %#lx bytes of junk from %#lx (old) to %#lx (new)\n", | |
458 old_buf.st_size - old_mcaloff, old_mcaloff, new_mcaloff); | |
459 #endif | |
460 unexec_copy (new_fd, old_fd, old_mcaloff, new_mcaloff, | |
461 old_buf.st_size - old_mcaloff); | |
462 | |
463 { | |
464 long curpos, offset; | |
465 struct _debug_header dhdr; | |
466 int new_header_delta; | |
467 | |
468 new_header_delta = LESYM_OFFSET(new_hdr) - LESYM_OFFSET(old_hdr); | |
469 if ((new_header_delta > 0) && | |
470 ((offset = EXT_OFFSET(old_hdr)) > 0)) | |
471 { | |
472 curpos = lseek(new_fd, 0, SEEK_CUR); | |
473 lseek(old_fd, offset, 0); | |
474 if (read(old_fd, &dhdr, sizeof(dhdr)) == sizeof(dhdr)) | |
475 { | |
476 dhdr.header_offset += new_header_delta; | |
477 dhdr.gntt_offset += new_header_delta; | |
478 dhdr.lntt_offset += new_header_delta; | |
479 dhdr.slt_offset += new_header_delta; | |
480 dhdr.vt_offset += new_header_delta; | |
481 dhdr.xt_offset += new_header_delta; | |
482 lseek(new_fd, EXT_OFFSET(new_hdr), SEEK_SET); | |
483 if (write(new_fd, &dhdr, sizeof(dhdr)) != sizeof(dhdr)) | |
484 { | |
485 unexec_error("Unable to write debug information to \"%s\"\n", | |
486 1, new_name); | |
487 } | |
488 lseek(new_fd, curpos, SEEK_SET); | |
489 } | |
490 else | |
491 { | |
492 unexec_error("Unable to read debug information from \"%s\"\n", | |
493 1, old_name); | |
494 } | |
495 } | |
496 } | |
497 } | |
498 | |
499 | |
500 /* make the output file executable -- then quit */ | |
501 unexec_fchmod (new_fd, 0755); | |
502 close (old_fd); | |
503 close (new_fd); | |
504 return 0; | |
505 } | |
506 | |
507 | |
508 int | |
509 run_time_remap (char *dummy) | |
510 { | |
511 unsigned long current_sbrk = (unsigned long) sbrk (0); | |
512 | |
513 if (sbrk_of_0_at_unexec < current_sbrk) | |
514 fprintf (stderr, "Absurd new brk addr = 0x%x (current = 0x%x)\n", | |
515 sbrk_of_0_at_unexec, current_sbrk); | |
516 else | |
517 { | |
518 errno = 0; | |
519 if (brk ((caddr_t) sbrk_of_0_at_unexec)) | |
520 fprintf (stderr, "failed to change brk addr to 0x%x: %s\n", | |
521 sbrk_of_0_at_unexec, SYS_ERR); | |
522 } | |
523 | |
524 return 0; | |
525 } |