|
|
1.1 root 1: /* Copyright (C) 1985 Free Software Foundation, Inc.
2:
3: This file is part of GNU Emacs.
4:
5: GNU Emacs is distributed in the hope that it will be useful,
6: but WITHOUT ANY WARRANTY. No author or distributor
7: accepts responsibility to anyone for the consequences of using it
8: or for whether it serves any particular purpose or works at all,
9: unless he says so in writing. Refer to the GNU Emacs General Public
10: License for full details.
11:
12: Everyone is granted permission to copy, modify and redistribute
13: GNU Emacs, but only under the conditions described in the
14: GNU Emacs General Public License. A copy of this license is
15: supposed to have been given to you along with GNU Emacs so you
16: can know your rights and responsibilities. It should be in a
17: file named COPYING. Among other things, the copyright notice
18: and this notice must be preserved on all copies. */
19:
20:
21: /*
22: * unexec.c - Convert a running program into an a.out file.
23: *
24: * Author: Spencer W. Thomas
25: * Computer Science Dept.
26: * University of Utah
27: * Date: Tue Mar 2 1982
28: * Modified heavily since then.
29: *
30: * Synopsis:
31: * unexec (new_name, a_name, data_start, bss_start, entry_address)
32: * char *new_name, *a_name;
33: * unsigned data_start, bss_start, entry_address;
34: *
35: * Takes a snapshot of the program and makes an a.out format file in the
36: * file named by the string argument new_name.
37: * If a_name is non-NULL, the symbol table will be taken from the given file.
38: *
39: * The boundaries within the a.out file may be adjusted with the data_start
40: * and bss_start arguments. Either or both may be given as 0 for defaults.
41: *
42: * Data_start gives the boundary between the text segment and the data
43: * segment of the program. The text segment can contain shared, read-only
44: * program code and literal data, while the data segment is always unshared
45: * and unprotected. Data_start gives the lowest unprotected address. Since
46: * the granularity of write-protection is on 1k page boundaries on the VAX, a
47: * given data_start value which is not on a page boundary is rounded down to
48: * the beginning of the page it is on. The default when 0 is given leaves the
49: * number of protected pages the same as it was before.
50: *
51: * Bss_start indicates how much of the data segment is to be saved in the
52: * a.out file and restored when the program is executed. It gives the lowest
53: * unsaved address, and is rounded up to a page boundary. The default when 0
54: * is given assumes that the entire data segment is to be stored, including
55: * the previous data and bss as well as any additional storage allocated with
56: * break (2).
57: *
58: * The new file is set up to start at entry_address.
59: *
60: * If you make improvements I'd like to get them too.
61: * harpo!utah-cs!thomas, thomas@Utah-20
62: *
63: */
64:
65: #ifndef emacs
66: #define PERROR(arg) perror (arg); return -1
67: #else
68: #include "config.h"
69: #define PERROR(file) report_error (file, new)
70: #endif
71:
72: #ifndef CANNOT_DUMP /* all rest of file! */
73:
74: #include <sys/param.h>
75: #ifndef makedev /* Try to detect types.h already loaded */
76: #include <sys/types.h>
77: #endif
78: #include <stdio.h>
79: #include <sys/stat.h>
80: #include <errno.h>
81:
82: extern char *start_of_text (); /* Start of text */
83: extern char *start_of_data (); /* Start of initialized data */
84:
85: #ifdef COFF
86: #include <filehdr.h>
87: #include <aouthdr.h>
88: #include <scnhdr.h>
89: #include <syms.h>
90: static long block_copy_start; /* Old executable start point */
91: static struct filehdr f_hdr; /* File header */
92: static struct aouthdr f_ohdr; /* Optional file header (a.out) */
93: long bias; /* Bias to add for growth */
94: long lnnoptr; /* Pointer to line-number info within file */
95: #define SYMS_START block_copy_start
96:
97: static int text_scnptr;
98:
99: #else /* not COFF */
100:
101: extern char *sbrk ();
102:
103: #include <a.out.h>
104: #define SYMS_START ((long) N_SYMOFF (ohdr))
105:
106: #ifdef HPUX
107: #ifdef hp9000s200
108: #define MY_ID HP9000S200_ID
109: #else
110: #include <model.h>
111: #define MY_ID MYSYS
112: #endif /* not hp9000s200 */
113: static MAGIC OLDMAGIC = {MY_ID, SHARE_MAGIC};
114: static MAGIC NEWMAGIC = {MY_ID, DEMAND_MAGIC};
115: #define N_TXTOFF(x) TEXT_OFFSET(x)
116: #define N_SYMOFF(x) LESYM_OFFSET(x)
117: static struct exec hdr, ohdr;
118:
119: #else /* not HPUX */
120:
121: #ifdef USG
122: static struct bhdr hdr, ohdr;
123: #define a_magic fmagic
124: #define a_text tsize
125: #define a_data dsize
126: #define a_bss bsize
127: #define a_syms ssize
128: #define a_trsize rtsize
129: #define a_drsize rdsize
130: #define a_entry entry
131: #define N_BADMAG(x) \
132: (((x).fmagic)!=OMAGIC && ((x).fmagic)!=NMAGIC &&\
133: ((x).fmagic)!=FMAGIC && ((x).fmagic)!=IMAGIC)
134: #define NEWMAGIC FMAGIC
135: #else /* not USG */
136: static struct exec hdr, ohdr;
137: #define NEWMAGIC ZMAGIC
138: #endif /* not USG */
139: #endif /* not HPUX */
140:
141: #endif /* not COFF */
142:
143: static int pagemask;
144:
145: #if defined (BSD4_1) || defined (USG)
146: #ifdef EXEC_PAGESIZE
147: #define getpagesize() EXEC_PAGESIZE
148: #else
149: #ifdef NBPG
150: #define getpagesize() NBPG * CLSIZE
151: #ifndef CLSIZE
152: #define CLSIZE 1
153: #endif /* no CLSIZE */
154: #else /* no NBPG */
155: #define getpagesize() NBPC
156: #endif /* no NBPG */
157: #endif /* no EXEC_PAGESIZE */
158: #endif /* BSD4_1 or USG */
159:
160: /* Correct an int which is the bit pattern of a pointer to a byte
161: into an int which is the number of a byte.
162: This is a no-op on ordinary machines, but not on all. */
163:
164: #ifndef ADDR_CORRECT /* Let m-*.h files override this definition */
165: #define ADDR_CORRECT(x) ((char *)(x) - (char*)0)
166: #endif
167:
168: #ifdef emacs
169:
170: static
171: report_error (file, fd)
172: char *file;
173: int fd;
174: {
175: if (fd)
176: close (fd);
177: error ("Failure operating on %s", file);
178: }
179: #endif /* emacs */
180:
181: #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
182: #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
183: #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
184:
185: static
186: report_error_1 (fd, msg, a1, a2)
187: int fd;
188: char *msg;
189: int a1, a2;
190: {
191: close (fd);
192: #ifdef emacs
193: error (msg, a1, a2);
194: #else
195: fprintf (stderr, msg, a1, a2);
196: fprintf (stderr, "\n");
197: #endif
198: }
199:
200: /* ****************************************************************
201: * unexec
202: *
203: * driving logic.
204: */
205: unexec (new_name, a_name, data_start, bss_start, entry_address)
206: char *new_name, *a_name;
207: unsigned data_start, bss_start, entry_address;
208: {
209: int new, a_out = -1;
210:
211: if (a_name && (a_out = open (a_name, 0)) < 0)
212: {
213: PERROR (a_name);
214: }
215: if ((new = creat (new_name, 0666)) < 0)
216: {
217: PERROR (new_name);
218: }
219: if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
220: || copy_text_and_data (new) < 0
221: || copy_sym (new, a_out, a_name, new_name) < 0
222: #ifdef COFF
223: || adjust_lnnoptrs (new, a_out, new_name) < 0
224: #endif
225: )
226: {
227: close (new);
228: /* unlink (new_name); /* Failed, unlink new a.out */
229: return -1;
230: }
231:
232: close (new);
233: if (a_out >= 0)
234: close (a_out);
235: mark_x (new_name);
236: return 0;
237: }
238:
239: /* ****************************************************************
240: * make_hdr
241: *
242: * Make the header in the new a.out from the header in core.
243: * Modify the text and data sizes.
244: */
245: static int
246: make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
247: int new, a_out;
248: unsigned data_start, bss_start, entry_address;
249: char *a_name;
250: char *new_name;
251: {
252: int tem;
253: #ifdef COFF
254: auto struct scnhdr f_thdr; /* Text section header */
255: auto struct scnhdr f_dhdr; /* Data section header */
256: auto struct scnhdr f_bhdr; /* Bss section header */
257: auto struct scnhdr scntemp; /* Temporary section header */
258: register int scns;
259:
260: /* Salvage as much info from the existing file as possible */
261: if (a_out >= 0)
262: {
263: if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
264: {
265: PERROR (a_name);
266: }
267: block_copy_start += sizeof (f_hdr);
268: if (f_hdr.f_opthdr > 0)
269: {
270: if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
271: {
272: PERROR (a_name);
273: }
274: block_copy_start += sizeof (f_ohdr);
275: }
276: /* Loop through section headers, copying them in */
277: for (scns = f_hdr.f_nscns; scns > 0; scns--) {
278: if (read (a_out, &scntemp, sizeof (scntemp)) != sizeof (scntemp))
279: {
280: PERROR (a_name);
281: }
282: block_copy_start += sizeof (scntemp);
283: if (scntemp.s_scnptr > 0L)
284: {
285: block_copy_start += scntemp.s_size;
286: }
287: if (strcmp (scntemp.s_name, ".text") == 0)
288: {
289: f_thdr = scntemp;
290: }
291: else if (strcmp (scntemp.s_name, ".data") == 0)
292: {
293: f_dhdr = scntemp;
294: }
295: else if (strcmp (scntemp.s_name, ".bss") == 0)
296: {
297: f_bhdr = scntemp;
298: }
299: }
300: }
301: else
302: {
303: ERROR0 ("can't build a COFF file from scratch yet");
304: }
305:
306: pagemask = getpagesize () - 1;
307:
308: #ifdef NO_REMAP
309: data_start = (int) start_of_data ();
310: #else /* not NO_REMAP */
311: if (!data_start)
312: data_start = (int) start_of_data ();
313: #endif /* not NO_REMAP */
314: data_start = ADDR_CORRECT (data_start);
315: data_start = data_start & ~pagemask; /* down to a page boundary */
316:
317: f_hdr.f_flags |= (F_RELFLG | F_EXEC);
318: #ifdef EXEC_MAGIC
319: f_ohdr.magic = EXEC_MAGIC;
320: #endif
321: f_ohdr.text_start = (long) start_of_text ();
322: f_ohdr.tsize = data_start - f_ohdr.text_start;
323: f_ohdr.data_start = data_start;
324: f_ohdr.dsize = (long) sbrk (0) - f_ohdr.data_start;
325: f_ohdr.bsize = 0;
326: f_thdr.s_size = f_ohdr.tsize;
327: f_thdr.s_scnptr = sizeof (f_hdr) + sizeof (f_ohdr);
328: f_thdr.s_scnptr += (f_hdr.f_nscns) * (sizeof (f_thdr));
329: lnnoptr = f_thdr.s_lnnoptr;
330: #ifdef UMAX
331: /* Umax is bsd using coff; it has restrictions on alignment
332: of the sections in the file itself. */
333: f_thdr.s_scnptr = (f_thdr.s_scnptr + pagemask) & ~pagemask; /* round up */
334: #endif /* UMAX */
335: text_scnptr = f_thdr.s_scnptr;
336: f_dhdr.s_paddr = f_ohdr.data_start;
337: f_dhdr.s_vaddr = f_ohdr.data_start;
338: f_dhdr.s_size = f_ohdr.dsize;
339: f_dhdr.s_scnptr = f_thdr.s_scnptr + f_thdr.s_size;
340: #ifdef UMAX
341: f_dhdr.s_scnptr &= ~pagemask; /* round down to page boundary */
342: #endif /* UMAX */
343: f_bhdr.s_paddr = f_ohdr.data_start + f_ohdr.dsize;
344: f_bhdr.s_vaddr = f_ohdr.data_start + f_ohdr.dsize;
345: f_bhdr.s_size = f_ohdr.bsize;
346: f_bhdr.s_scnptr = 0L;
347: bias = f_dhdr.s_scnptr + f_dhdr.s_size - block_copy_start;
348:
349: if (f_hdr.f_symptr > 0L)
350: {
351: f_hdr.f_symptr += bias;
352: }
353:
354: if (f_thdr.s_lnnoptr > 0L)
355: {
356: f_thdr.s_lnnoptr += bias;
357: }
358:
359: if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr))
360: {
361: PERROR (new_name);
362: }
363:
364: if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr))
365: {
366: PERROR (new_name);
367: }
368:
369: if (write (new, &f_thdr, sizeof (f_thdr)) != sizeof (f_thdr))
370: {
371: PERROR (new_name);
372: }
373:
374: if (write (new, &f_dhdr, sizeof (f_dhdr)) != sizeof (f_dhdr))
375: {
376: PERROR (new_name);
377: }
378:
379: if (write (new, &f_bhdr, sizeof (f_bhdr)) != sizeof (f_bhdr))
380: {
381: PERROR (new_name);
382: }
383: return (0);
384:
385: #else /* if not COFF */
386:
387: /* Get symbol table info from header of a.out file if given one. */
388: if (a_out >= 0)
389: {
390: if (read (a_out, &ohdr, sizeof hdr) != sizeof hdr)
391: {
392: PERROR (a_name);
393: }
394:
395: if N_BADMAG (ohdr)
396: {
397: ERROR1 ("invalid magic number in %s", a_name);
398: }
399: #ifdef celerity
400: hdr.a_scovrfl = ohdr.a_scovrfl;
401: #endif
402: #ifdef HPUX
403: hdr.a_lesyms = ohdr.a_lesyms;
404: hdr.a_sltsize = ohdr.a_sltsize;
405: hdr.a_dnttsize = ohdr.a_dnttsize;
406: hdr.a_vtsize = ohdr.a_vtsize;
407: #else /* not HPUX */
408: hdr.a_syms = ohdr.a_syms;
409: #endif /* not HPUX */
410: }
411: else
412: {
413: #ifdef celerity
414: hdr.a_scovrfl = 0;
415: #endif
416: #ifdef HPUX
417: hdr.a_lesyms = 0;
418: hdr.a_sltsize = 0;
419: hdr.a_dnttsize = 0;
420: hdr.a_vtsize = 0;
421: #else /* not HPUX */
422: hdr.a_syms = 0; /* No a.out, so no symbol info. */
423: #endif /* not HPUX */
424: }
425:
426: /* Construct header from user structure. */
427: #ifdef HPUX
428: /* (((MAGIC) ohdr.a_magic) == ((MAGIC) OLDMAGIC)) This does not work */
429: hdr.a_magic = ((ohdr.a_magic.file_type == OLDMAGIC.file_type) ?
430: NEWMAGIC : ohdr.a_magic);
431: #else /* not HPUX */
432: /* hdr.a_magic = NEWMAGIC; */
433: hdr.a_magic = ohdr.a_magic;
434: #endif /* not HPUX */
435:
436: #ifdef sun3
437: hdr.a_machtype = ohdr.a_machtype;
438: #endif /* sun3 */
439: hdr.a_trsize = 0;
440: hdr.a_drsize = 0;
441: hdr.a_entry = entry_address;
442:
443: pagemask = getpagesize () - 1;
444:
445: /* Adjust data/bss boundary. */
446: if (bss_start != 0)
447: {
448: bss_start = (ADDR_CORRECT (bss_start) + pagemask) & ~pagemask; /* (Up) to page bdry. */
449: if (bss_start > ADDR_CORRECT (sbrk (0)))
450: {
451: ERROR1 ("unexec: Specified bss_start (%u) is past end of program",
452: bss_start);
453: }
454: }
455: else
456: {
457: bss_start = ADDR_CORRECT (sbrk (0));
458: bss_start = (bss_start + pagemask) & ~pagemask;
459: }
460:
461: /* Adjust text/data boundary. */
462: #ifdef NO_REMAP
463: data_start = (int) start_of_data ();
464: #else /* not NO_REMAP */
465: if (!data_start)
466: data_start = (int) start_of_data ();
467: #endif /* not NO_REMAP */
468: data_start = ADDR_CORRECT (data_start);
469:
470: #ifdef sun
471: data_start = data_start & ~(SEGSIZ - 1); /* (Down) to segment boundary. */
472: #else
473: data_start = data_start & ~pagemask; /* (Down) to page boundary. */
474: #endif
475:
476: if (data_start > bss_start) /* Can't have negative data size. */
477: {
478: ERROR2 ("unexec: data_start (%u) can't be greater than bss_start (%u)",
479: data_start, bss_start);
480: }
481:
482: tem = ADDR_CORRECT (sbrk (0));
483: hdr.a_bss = tem - bss_start;
484: if (tem < bss_start) /* Note a_bss is unsigned on some systems */
485: hdr.a_bss = 0;
486: hdr.a_data = bss_start - data_start;
487: #if defined(sequent)
488: hdr.a_text = data_start - (long) start_of_text () + sizeof(hdr) + N_ADDRADJ(ohdr);
489: #else
490: hdr.a_text = data_start - (long) start_of_text ();
491: #endif /* not sequent */
492:
493: if (write (new, &hdr, sizeof hdr) != sizeof hdr)
494: {
495: PERROR (new_name);
496: }
497: return 0;
498:
499: #endif /* not COFF */
500: }
501:
502: /* ****************************************************************
503: * copy_text_and_data
504: *
505: * Copy the text and data segments from memory to the new a.out
506: */
507: static int
508: copy_text_and_data (new)
509: int new;
510: {
511: register int nwrite, ret;
512: register char *end;
513: int i;
514: register char *ptr;
515: char buf[80];
516: extern int errno;
517:
518: #ifdef COFF
519: lseek (new, (long) text_scnptr, 0);
520: ptr = (char *) f_ohdr.text_start;
521: end = ptr + f_ohdr.tsize + f_ohdr.dsize;
522: while (ptr < end)
523: {
524: nwrite = 128;
525: if (nwrite > end - ptr) nwrite = end - ptr;
526: ret = write (new, ptr, nwrite);
527: if (nwrite != ret)
528: {
529: sprintf (buf,
530: "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
531: ptr, new, nwrite, ret, errno);
532: PERROR (buf);
533: }
534: ptr += nwrite;
535: }
536: return (0);
537:
538: #else /* if not COFF */
539:
540: #if defined(sun3) || defined(sequent)
541: lseek (new, (long) (N_TXTOFF (hdr) + sizeof (hdr)), 0);
542: #else
543: lseek (new, (long) N_TXTOFF (hdr), 0);
544: #endif
545:
546: ptr = start_of_text ();
547: end = ptr + hdr.a_text + hdr.a_data;
548: #if defined(sequent)
549: end -= (sizeof(hdr) + N_ADDRADJ(hdr));
550: #endif
551: for (i = 0; ptr < end;)
552: {
553: nwrite = 128;
554: if (nwrite > end - ptr) nwrite = end - ptr;
555: ret = write (new, ptr, nwrite);
556: if (ret == -1 && errno == EFAULT)
557: {
558: /* BZS - again, see above about N_TXTOFF on a SUN */
559: #if defined(sun3) || defined(sequent)
560: lseek (new, (long) (N_TXTOFF (hdr) + i + nwrite + sizeof (hdr)), 0);
561: #else
562: lseek (new, (long) (N_TXTOFF (hdr) + i + nwrite), 0);
563: #endif
564: }
565: else if (nwrite != ret)
566: {
567: sprintf (buf,
568: "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
569: ptr, new, nwrite, ret, errno);
570: PERROR (buf);
571: }
572: i += nwrite;
573: ptr += nwrite;
574: }
575:
576: return 0;
577: #endif /* not COFF */
578: }
579:
580: /* ****************************************************************
581: * copy_sym
582: *
583: * Copy the relocation information and symbol table from the a.out to the new
584: */
585: static int
586: copy_sym (new, a_out, a_name, new_name)
587: int new, a_out;
588: char *a_name, *new_name;
589: {
590: char page[1024];
591: int n;
592:
593: if (a_out < 0)
594: return 0;
595:
596: #ifdef COFF
597: if (SYMS_START == 0L)
598: return 0;
599: #endif /* COFF */
600:
601: #ifdef sun3
602: /* BZS - I might be covering a sin with this */
603: lseek (new, N_SYMOFF (hdr), 0);
604: #else
605: #ifdef COFF
606: if (lnnoptr) /* if there is line number info */
607: lseek (a_out, lnnoptr, 0); /* start copying from there */
608: else
609: #endif /* COFF */
610: lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */
611: #endif
612: while ((n = read (a_out, page, sizeof page)) > 0)
613: {
614: if (write (new, page, n) != n)
615: {
616: PERROR (new_name);
617: }
618: }
619: if (n < 0)
620: {
621: PERROR (a_name);
622: }
623: return 0;
624: }
625:
626: /* ****************************************************************
627: * mark_x
628: *
629: * After succesfully building the new a.out, mark it executable
630: */
631: static
632: mark_x (name)
633: char *name;
634: {
635: struct stat sbuf;
636: int um;
637: int new = 0; /* for PERROR */
638:
639: um = umask (777);
640: umask (um);
641: if (stat (name, &sbuf) == -1)
642: {
643: PERROR (name);
644: }
645: sbuf.st_mode |= 0111 & ~um;
646: if (chmod (name, sbuf.st_mode) == -1)
647: PERROR (name);
648: }
649:
650: /*
651: * If the COFF file contains a symbol table and a line number section,
652: * then any auxiliary entries that have values for x_lnnoptr must
653: * be adjusted by the amount that the line number section has moved
654: * in the file (bias computed in make_hdr). The #@$%&* designers of
655: * the auxiliary entry structures used the absolute file offsets for
656: * the line number entry rather than an offset from the start of the
657: * line number section!
658: *
659: * When I figure out how to scan through the symbol table and pick out
660: * the auxiliary entries that need adjustment, this routine will
661: * be fixed. As it is now, all such entries are wrong and sdb
662: * will complain. Fred Fish, UniSoft Systems Inc.
663: */
664:
665: #ifdef COFF
666:
667: /* This function is probably very slow. Instead of reopening the new
668: file for input and output it should copy from the old to the new
669: using the two descriptors already open (WRITEDESC and READDESC).
670: Instead of reading one small structure at a time it should use
671: a reasonable size buffer. But I don't have time to work on such
672: things, so I am installing it as submitted to me. -- RMS. */
673:
674: adjust_lnnoptrs (writedesc, readdesc, new_name)
675: int writedesc;
676: int readdesc;
677: char *new_name;
678: {
679: register int nsyms;
680: register int new;
681: struct syment symentry;
682: struct auxent auxentry;
683:
684: if (!lnnoptr || !f_hdr.f_symptr)
685: return 0;
686:
687: if ((new = open (new_name, 2)) < 0)
688: {
689: PERROR (new_name);
690: return -1;
691: }
692:
693: lseek (new, f_hdr.f_symptr, 0);
694: for (nsyms = 0; nsyms < f_hdr.f_nsyms; nsyms++)
695: {
696: read (new, &symentry, SYMESZ);
697: if (symentry.n_numaux)
698: {
699: read (new, &auxentry, AUXESZ);
700: nsyms++;
701: if (ISFCN (symentry.n_type)) {
702: auxentry.x_sym.x_fcnary.x_fcn.x_lnnoptr += bias;
703: lseek (new, -AUXESZ, 1);
704: write (new, &auxentry, AUXESZ);
705: }
706: }
707: }
708: close (new);
709: }
710:
711: #endif /* COFF */
712:
713: #endif /* not CANNOT_DUMP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.