Mercurial > hg > xemacs-beta
comparison src/unexhp9k3.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | ac2d302a0011 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
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 #include <a.out.h> | |
45 #include <unistd.h> | |
46 #include <ctype.h> | |
47 #include <sys/dir.h> | |
48 | |
49 #include "sysdep.h" | |
50 | |
51 /* XEmacs: Richard Cognot <cognot@ensg.u-nancy.fr> says we need these */ | |
52 extern void perror(const char*); | |
53 extern int sys_nerr; | |
54 extern char *sys_errlist[]; | |
55 extern char *strerror (int); | |
56 | |
57 | |
58 /********************** Macros *************************************/ | |
59 | |
60 #define SYS_ERR \ | |
61 ((errno > 0)?((errno < sys_nerr)?(sys_errlist[errno]):\ | |
62 "unknown system error"): "unknown error") | |
63 | |
64 #define MASK_UP(x,p_of_two) \ | |
65 ((((unsigned long) (x)) + ((p_of_two) - 1)) & (~((p_of_two) - 1))) | |
66 | |
67 #define MASK_DOWN(x,p_of_two) (((unsigned long) (x)) & (~((p_of_two) - 1))) | |
68 | |
69 /********************** Function Prototypes/Declarations ***********/ | |
70 | |
71 static void unexec_error (const char *fmt, int use_errno, ...); | |
72 static int unexec_open (char *filename, int flag, int mode); | |
73 static long unexec_seek (int fd, long position); | |
74 static void unexec_read (int fd, long position, char *buf, int bytes); | |
75 static void unexec_write (int fd, long position, char *buf, int bytes); | |
76 static void unexec_copy (int new_fd, int old_fd, long old_pos, long new_pos, | |
77 int bytes); | |
78 static void unexec_pad (int fd, int bytes); | |
79 static void unexec_fstat (int fd, struct stat *statptr); | |
80 static void unexec_fchmod (int fd, int mode); | |
81 int run_time_remap (char *dummy); | |
82 | |
83 /********************** Variables **********************************/ | |
84 | |
85 /* for reporting error messages from system calls */ | |
86 extern int sys_nerr; | |
87 extern int errno; | |
88 extern int _DYNAMIC; | |
89 extern char **environ; | |
90 | |
91 static unsigned long sbrk_of_0_at_unexec; | |
92 | |
93 /*******************************************************************/ | |
94 | |
95 static void | |
96 unexec_error (const char *fmt, int use_errno, ...) | |
97 { | |
98 const char *err_msg = SYS_ERR; | |
99 va_list args; | |
100 | |
101 fprintf (stderr, "unexec - "); | |
102 va_start (args, use_errno); | |
103 vfprintf (stderr, fmt, args); | |
104 va_end (args); | |
105 | |
106 if (use_errno) | |
107 fprintf (stderr, ": %s", err_msg); | |
108 fprintf (stderr, "\n"); | |
109 exit (1); | |
110 return; | |
111 } | |
112 | |
113 static int | |
114 unexec_open (char *filename, int flag, int mode) | |
115 { | |
116 int fd; | |
117 | |
118 errno = 0; | |
119 | |
120 fd = open (filename, flag, mode); | |
121 | |
122 if (fd < 0) | |
123 { | |
124 unexec_error ("Failure opening file %s", 1, (void *) filename, 0, 0); | |
125 return -1; | |
126 } | |
127 else | |
128 return fd; | |
129 } | |
130 | |
131 static long | |
132 unexec_seek (int fd, long position) | |
133 { | |
134 long seek_value; | |
135 | |
136 if (fd <= 0) | |
137 unexec_error ("No file open in which to seek", 0, 0, 0, 0); | |
138 | |
139 errno = 0; | |
140 | |
141 if (position < 0) | |
142 seek_value = (long) lseek (fd, 0, L_INCR); | |
143 else | |
144 seek_value = (long) lseek (fd, position, L_SET); | |
145 | |
146 if (seek_value < 0) | |
147 unexec_error ("Failed to do a seek to 0x%x in %s", 1, | |
148 (char *) position, "unexec() output file", 0); | |
149 | |
150 return seek_value; | |
151 } | |
152 | |
153 static void | |
154 unexec_read (int fd, long position, char *buf, int bytes) | |
155 { | |
156 int n_read; | |
157 int remains = bytes; | |
158 position = unexec_seek (fd, position); | |
159 | |
160 if (bytes < 0) | |
161 unexec_error ("Attempted read of %d bytes", 0, (char *) bytes, 0, 0); | |
162 | |
163 errno = 0; | |
164 | |
165 while (remains > 0) | |
166 { | |
167 n_read = read (fd, buf, remains); | |
168 if (n_read <= 0) | |
169 unexec_error ("Read failed for 0x%x bytes at offset 0x%x in %s", | |
170 1, (char *) bytes, (char *) position, | |
171 "unexec() output file"); | |
172 buf += n_read; | |
173 remains -= n_read; | |
174 } | |
175 | |
176 return; | |
177 } | |
178 | |
179 static void | |
180 unexec_write (int fd, long position, char *buf, int bytes) | |
181 { | |
182 int n_written; | |
183 int remains = bytes; | |
184 position = unexec_seek (fd, position); | |
185 | |
186 if (bytes < 0) | |
187 unexec_error ("Attempted write of %d bytes in %s", | |
188 0, (char *) bytes, "unexec() output file", 0); | |
189 | |
190 errno = 0; | |
191 | |
192 while (remains > 0) | |
193 { | |
194 n_written = write (fd, buf, remains); | |
195 if (n_written <= 0) | |
196 unexec_error ("Write failed for 0x%x bytes at offset 0x%x in %s", | |
197 1, (char *) bytes, (char *) position, | |
198 "unexec() output file"); | |
199 buf += n_written; | |
200 remains -= n_written; | |
201 } | |
202 | |
203 return; | |
204 } | |
205 | |
206 static void | |
207 unexec_copy (int new_fd, int old_fd, long old_pos, long new_pos, int bytes) | |
208 { | |
209 int remains = bytes; | |
210 char buf[128]; | |
211 | |
212 while (remains > 0) | |
213 { | |
214 int n_to_copy = remains > sizeof(buf) ? sizeof(buf) : remains; | |
215 | |
216 unexec_read (old_fd, old_pos, buf, n_to_copy); | |
217 unexec_write (new_fd, new_pos, buf, n_to_copy); | |
218 | |
219 old_pos += n_to_copy; | |
220 new_pos += n_to_copy; | |
221 remains -= n_to_copy; | |
222 } | |
223 | |
224 return; | |
225 } | |
226 | |
227 static void | |
228 unexec_pad (int fd, int bytes) | |
229 { | |
230 if (bytes > 0) | |
231 { | |
232 char buf[1024]; | |
233 int remaining = bytes; | |
234 | |
235 bzero (buf, sizeof(buf)); | |
236 | |
237 while (remaining > 0) | |
238 { | |
239 int this_write = (remaining > sizeof(buf))?sizeof(buf):remaining; | |
240 unexec_write (fd, -1, buf, this_write); | |
241 remaining -= this_write; | |
242 } | |
243 } | |
244 } | |
245 | |
246 static void | |
247 unexec_fstat (int fd, struct stat *statptr) | |
248 { | |
249 errno = 0; | |
250 if (-1 == fstat (fd, statptr)) | |
251 unexec_error ("fstat() failed for descriptor %d", 1, (char *) fd, 0, 0); | |
252 return; | |
253 } | |
254 | |
255 static void | |
256 unexec_fchmod (int fd, int mode) | |
257 { | |
258 errno = 0; | |
259 if (-1 == fchmod (fd, mode)) | |
260 unexec_error ("fchmod() failed for descriptor %d", 1, (char *) fd, 0, 0); | |
261 return; | |
262 } | |
263 | |
264 /* | |
265 * EXPORTED FUNCTIONS | |
266 */ | |
267 | |
268 /* this has to be a global variable to prevent the optimizers from | |
269 * assuming that it can not be 0. | |
270 */ | |
271 static void *dynamic_addr = (void *) &_DYNAMIC; | |
272 | |
273 int | |
274 unexec (char *new_name, char *old_name, | |
275 unsigned int emacs_edata, unsigned int dummy1, unsigned int dummy2) | |
276 { | |
277 /* /dld.sl data */ | |
278 struct dynamic *ld = 0; | |
279 /* old and new state */ | |
280 int old_fd; | |
281 int new_fd; | |
282 struct exec old_hdr; | |
283 struct exec new_hdr; | |
284 struct stat old_buf; | |
285 /* some process specific "constants" */ | |
286 unsigned long n_pagsiz; | |
287 caddr_t dynamic_beg; | |
288 caddr_t current_break = (caddr_t) sbrk (0); | |
289 | |
290 /* dynamically linked image? -- if so, find dld.sl structures */ | |
291 if (dynamic_addr) | |
292 { | |
293 ld = (struct dynamic *) dynamic_addr; | |
294 #ifdef DEBUG | |
295 printf ("dl_text = %#x\n", ld->text); | |
296 printf ("dl_data = %#x\n", ld->data); | |
297 printf ("dl_bss = %#x\n", ld->bss); | |
298 printf ("dl_end = %#x\n", ld->end); | |
299 printf ("dl_dmodule = %#x\n", ld->dmodule); | |
300 printf ("dl_dlt = %#x\n", ld->dlt); | |
301 printf ("dl_plt = %#x\n", ld->plt); | |
302 #endif | |
303 } | |
304 | |
305 /* open the old and new files, figuring out how big the old one is | |
306 so that we can map it in */ | |
307 old_fd = unexec_open (old_name, O_RDONLY, 0); | |
308 new_fd = unexec_open (new_name, O_RDWR | O_CREAT | O_TRUNC, 0666); | |
309 | |
310 /* setup the header and the statbuf for old_fd */ | |
311 unexec_read (old_fd, 0, (char *) &old_hdr, sizeof (old_hdr)); | |
312 unexec_fstat (old_fd, &old_buf); | |
313 | |
314 /* set up some important constants */ | |
315 n_pagsiz = EXEC_PAGESIZE; | |
316 | |
317 /* setup beginning of data to copy from executable */ | |
318 if (ld) | |
319 dynamic_beg = ld->dmodule; | |
320 else | |
321 dynamic_beg = (caddr_t)EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data; | |
322 | |
323 /* set up the new exec */ | |
324 new_hdr = old_hdr; | |
325 new_hdr.a_text = MASK_DOWN (emacs_edata, n_pagsiz); | |
326 new_hdr.a_data = MASK_UP (current_break, n_pagsiz) | |
327 - EXEC_ALIGN(new_hdr.a_text); | |
328 new_hdr.a_bss = 0; | |
329 | |
330 #ifdef DEBUG | |
331 printf ("old text %#x\n", old_hdr.a_text); | |
332 printf ("new text %#x\n", new_hdr.a_text); | |
333 printf ("old data %#x\n", old_hdr.a_data); | |
334 printf ("new data %#x\n", new_hdr.a_data); | |
335 printf ("old bss %#x\n", old_hdr.a_bss); | |
336 printf ("new bss %#x\n", new_hdr.a_bss); | |
337 #endif | |
338 | |
339 /* set up this variable, in case we want to reset "the break" | |
340 when restarting */ | |
341 sbrk_of_0_at_unexec = ((unsigned long) MASK_UP (current_break, n_pagsiz)); | |
342 | |
343 /* Write out the first approximation to the new file. The sizes of | |
344 each section will be correct, but there will be a number of | |
345 corrections that will need to be made. */ | |
346 { | |
347 long old_datoff = DATA_OFFSET (old_hdr); | |
348 long new_datoff = DATA_OFFSET (new_hdr); | |
349 long old_dataddr = EXEC_ALIGN (old_hdr.a_text); | |
350 long new_dataddr = EXEC_ALIGN (new_hdr.a_text); | |
351 long new_mcaloff = MODCAL_OFFSET (new_hdr); | |
352 long old_mcaloff = MODCAL_OFFSET (old_hdr); | |
353 long newtext_size = new_hdr.a_text - old_dataddr; | |
354 long newdata1_size = (unsigned long)dynamic_beg - new_dataddr; | |
355 long dyn_size = (EXEC_ALIGN (old_hdr.a_text) + old_hdr.a_data) | |
356 - (unsigned long)dynamic_beg; | |
357 long newdata2_size = (unsigned long)current_break | |
358 - ((unsigned long)dynamic_beg + dyn_size); | |
359 long pad_size = | |
360 MASK_UP (current_break, n_pagsiz) - ((unsigned long) current_break); | |
361 | |
362 #ifdef DEBUG | |
363 printf ("current break is %#lx\n", current_break); | |
364 | |
365 printf ("old_dataddr = %#lx, dynamic_beg = %#lx\n", | |
366 old_dataddr, dynamic_beg); | |
367 #endif | |
368 | |
369 /* | |
370 * First, write the text segment with new header -- copy | |
371 * everything until the start of the data segment from the old | |
372 * file | |
373 */ | |
374 #ifdef DEBUG | |
375 printf ("copying %#lx bytes of text from 0\n", old_datoff); | |
376 #endif | |
377 unexec_copy (new_fd, old_fd, 0, 0, old_datoff); | |
378 /* pad out the text segment */ | |
379 #ifdef DEBUG | |
380 printf ( "text pad size is %#x\n", old_dataddr - old_hdr.a_text); | |
381 #endif | |
382 unexec_pad (new_fd, old_dataddr - old_hdr.a_text); | |
383 | |
384 /* | |
385 * go back and write the new header. | |
386 */ | |
387 unexec_write (new_fd, 0, (char *) &new_hdr, sizeof (new_hdr)); | |
388 | |
389 | |
390 /* | |
391 * Copy the part of the data segment which becomes text from the | |
392 * running image. | |
393 */ | |
394 #ifdef DEBUG | |
395 printf ("copying %#lx bytes of new text from %#lx to position %#lx\n", | |
396 newtext_size, old_dataddr, TEXT_OFFSET(new_hdr) + old_dataddr); | |
397 #endif | |
398 unexec_write (new_fd, TEXT_OFFSET(new_hdr) + old_dataddr, | |
399 (caddr_t)old_dataddr, newtext_size); | |
400 | |
401 #ifdef DEBUG | |
402 printf ("new DATA_OFFSET is %#lx\n", new_datoff); | |
403 #endif | |
404 | |
405 /* | |
406 * Copy the part of the old data segment which will be data | |
407 * in the new executable (before the dynamic stuff) | |
408 * from the running image. | |
409 */ | |
410 #ifdef DEBUG | |
411 printf ("copying %#lx bytes of data from %#lx to position %#lx\n", | |
412 newdata1_size, new_dataddr, new_datoff); | |
413 #endif | |
414 unexec_write (new_fd, new_datoff, (caddr_t)new_dataddr, newdata1_size); | |
415 | |
416 /* copy the dynamic part of the data segment from the old executable */ | |
417 if (dyn_size) | |
418 { | |
419 #ifdef DEBUG | |
420 printf ("copying %#lx bytes of dyn data from executable" | |
421 " at address %#lx to position %#lx\n", | |
422 dyn_size, dynamic_beg, new_datoff + newdata1_size); | |
423 #endif | |
424 unexec_copy (new_fd, old_fd, old_datoff + newtext_size + newdata1_size, | |
425 new_datoff + newdata1_size, dyn_size); | |
426 } | |
427 | |
428 /* copy remaining data (old bss) from the running image */ | |
429 #ifdef DEBUG | |
430 printf ("copying %#lx bytes of data from %#lx to position %#lx\n", | |
431 newdata2_size, new_dataddr + newdata1_size + dyn_size, | |
432 new_datoff + newdata1_size + dyn_size); | |
433 #endif | |
434 unexec_write (new_fd, new_datoff + newdata1_size + dyn_size, | |
435 (caddr_t)(new_dataddr + newdata1_size + dyn_size), | |
436 newdata2_size); | |
437 | |
438 /* pad out the data segment */ | |
439 #ifdef DEBUG | |
440 printf ( "pad size is %#x\n", pad_size); | |
441 #endif | |
442 unexec_pad (new_fd, pad_size); | |
443 | |
444 /* Finally, copy the rest of the junk from the old file. */ | |
445 #ifdef DEBUG | |
446 printf ("Copying %#lx bytes of junk from %#lx (old) to %#lx (new)\n", | |
447 old_buf.st_size - old_mcaloff, old_mcaloff, new_mcaloff); | |
448 #endif | |
449 unexec_copy (new_fd, old_fd, old_mcaloff, new_mcaloff, | |
450 old_buf.st_size - old_mcaloff); | |
451 } | |
452 | |
453 | |
454 /* make the output file executable -- then quit */ | |
455 unexec_fchmod (new_fd, 0755); | |
456 close (old_fd); | |
457 close (new_fd); | |
458 return 0; | |
459 } | |
460 | |
461 | |
462 int | |
463 run_time_remap (char *dummy) | |
464 { | |
465 unsigned long current_sbrk = (unsigned long) sbrk (0); | |
466 | |
467 if (sbrk_of_0_at_unexec < current_sbrk) | |
468 fprintf (stderr, "Absurd new brk addr = 0x%x (current = 0x%x)\n", | |
469 sbrk_of_0_at_unexec, current_sbrk); | |
470 else | |
471 { | |
472 errno = 0; | |
473 if (brk ((caddr_t) sbrk_of_0_at_unexec)) | |
474 fprintf (stderr, "failed to change brk addr to 0x%x: %s\n", | |
475 sbrk_of_0_at_unexec, SYS_ERR); | |
476 } | |
477 | |
478 return 0; | |
479 } |