|
|
1.1 root 1: /* Modified version of unexec for convex machines.
2: Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc.
3:
4: Note that the GNU project considers support for the peculiarities
5: of the Convex operating system a peripheral activity which should
6: not be allowed to divert effort from development of the GNU system.
7: Changes in this code will be installed when Convex system
8: maintainers send them in, but aside from that we don't plan to
9: think about it, or about whether other Emacs maintenance might
10: break it.
11:
12: This program is free software; you can redistribute it and/or modify
13: it under the terms of the GNU General Public License as published by
14: the Free Software Foundation; either version 1, or (at your option)
15: any later version.
16:
17: This program is distributed in the hope that it will be useful,
18: but WITHOUT ANY WARRANTY; without even the implied warranty of
19: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20: GNU General Public License for more details.
21:
22: You should have received a copy of the GNU General Public License
23: along with this program; if not, write to the Free Software
24: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25:
26: In other words, you are welcome to use, share and improve this program.
27: You are forbidden to forbid anyone else to use, share and improve
28: what you give them. Help stamp out software-hoarding! */
29:
30:
31: /* modifyed for C-1 arch by jthomp@convex 871103 */
32: /* Corrected to support convex SOFF object file formats and thread specific
33: * regions. streepy@convex 890302
34: */
35:
36: /*
37: * unexec.c - Convert a running program into an a.out file.
38: *
39: * Author: Spencer W. Thomas
40: * Computer Science Dept.
41: * University of Utah
42: * Date: Tue Mar 2 1982
43: * Modified heavily since then.
44: *
45: * Synopsis:
46: * unexec (new_name, a_name, data_start, bss_start, entry_address)
47: * char *new_name, *a_name;
48: * unsigned data_start, bss_start, entry_address;
49: *
50: * Takes a snapshot of the program and makes an a.out format file in the
51: * file named by the string argument new_name.
52: * If a_name is non-NULL, the symbol table will be taken from the given file.
53: * On some machines, an existing a_name file is required.
54: *
55: * The boundaries within the a.out file may be adjusted with the data_start
56: * and bss_start arguments. Either or both may be given as 0 for defaults.
57: *
58: * Data_start gives the boundary between the text segment and the data
59: * segment of the program. The text segment can contain shared, read-only
60: * program code and literal data, while the data segment is always unshared
61: * and unprotected. Data_start gives the lowest unprotected address.
62: * The value you specify may be rounded down to a suitable boundary
63: * as required by the machine you are using.
64: *
65: * Specifying zero for data_start means the boundary between text and data
66: * should not be the same as when the program was loaded.
67: * If NO_REMAP is defined, the argument data_start is ignored and the
68: * segment boundaries are never changed.
69: *
70: * Bss_start indicates how much of the data segment is to be saved in the
71: * a.out file and restored when the program is executed. It gives the lowest
72: * unsaved address, and is rounded up to a page boundary. The default when 0
73: * is given assumes that the entire data segment is to be stored, including
74: * the previous data and bss as well as any additional storage allocated with
75: * break (2).
76: *
77: * The new file is set up to start at entry_address.
78: *
79: * If you make improvements I'd like to get them too.
80: * harpo!utah-cs!thomas, thomas@Utah-20
81: *
82: */
83:
84: /* There are several compilation parameters affecting unexec:
85:
86: * COFF
87:
88: Define this if your system uses COFF for executables.
89: Otherwise we assume you use Berkeley format.
90:
91: * NO_REMAP
92:
93: Define this if you do not want to try to save Emacs's pure data areas
94: as part of the text segment.
95:
96: Saving them as text is good because it allows users to share more.
97:
98: However, on machines that locate the text area far from the data area,
99: the boundary cannot feasibly be moved. Such machines require
100: NO_REMAP.
101:
102: Also, remapping can cause trouble with the built-in startup routine
103: /lib/crt0.o, which defines `environ' as an initialized variable.
104: Dumping `environ' as pure does not work! So, to use remapping,
105: you must write a startup routine for your machine in Emacs's crt0.c.
106: If NO_REMAP is defined, Emacs uses the system's crt0.o.
107:
108: * SECTION_ALIGNMENT
109:
110: Some machines that use COFF executables require that each section
111: start on a certain boundary *in the COFF file*. Such machines should
112: define SECTION_ALIGNMENT to a mask of the low-order bits that must be
113: zero on such a boundary. This mask is used to control padding between
114: segments in the COFF file.
115:
116: If SECTION_ALIGNMENT is not defined, the segments are written
117: consecutively with no attempt at alignment. This is right for
118: unmodified system V.
119:
120: * SEGMENT_MASK
121:
122: Some machines require that the beginnings and ends of segments
123: *in core* be on certain boundaries. For most machines, a page
124: boundary is sufficient. That is the default. When a larger
125: boundary is needed, define SEGMENT_MASK to a mask of
126: the bits that must be zero on such a boundary.
127:
128: * A_TEXT_OFFSET(HDR)
129:
130: Some machines count the a.out header as part of the size of the text
131: segment (a_text); they may actually load the header into core as the
132: first data in the text segment. Some have additional padding between
133: the header and the real text of the program that is counted in a_text.
134:
135: For these machines, define A_TEXT_OFFSET(HDR) to examine the header
136: structure HDR and return the number of bytes to add to `a_text'
137: before writing it (above and beyond the number of bytes of actual
138: program text). HDR's standard fields are already correct, except that
139: this adjustment to the `a_text' field has not yet been made;
140: thus, the amount of offset can depend on the data in the file.
141:
142: * A_TEXT_SEEK(HDR)
143:
144: If defined, this macro specifies the number of bytes to seek into the
145: a.out file before starting to write the text segment.a
146:
147: * EXEC_MAGIC
148:
149: For machines using COFF, this macro, if defined, is a value stored
150: into the magic number field of the output file.
151:
152: * ADJUST_EXEC_HEADER
153:
154: This macro can be used to generate statements to adjust or
155: initialize nonstandard fields in the file header
156:
157: * ADDR_CORRECT(ADDR)
158:
159: Macro to correct an int which is the bit pattern of a pointer to a byte
160: into an int which is the number of a byte.
161:
162: This macro has a default definition which is usually right.
163: This default definition is a no-op on most machines (where a
164: pointer looks like an int) but not on all machines.
165:
166: */
167:
168: #include "config.h"
169: #define PERROR(file) report_error (file, new)
170:
171: #include <a.out.h>
172: /* Define getpagesize () if the system does not.
173: Note that this may depend on symbols defined in a.out.h
174: */
175: #include "getpagesize.h"
176:
177: #include <sys/types.h>
178: #include <stdio.h>
179: #include <sys/stat.h>
180: #include <errno.h>
181:
182: extern char *start_of_text (); /* Start of text */
183: extern char *start_of_data (); /* Start of initialized data */
184:
185: #include <machine/filehdr.h>
186: #include <machine/opthdr.h>
187: #include <machine/scnhdr.h>
188: #include <machine/pte.h>
189:
190: static long block_copy_start; /* Old executable start point */
191: static struct filehdr f_hdr; /* File header */
192: static struct opthdr f_ohdr; /* Optional file header (a.out) */
193: long bias; /* Bias to add for growth */
194: #define SYMS_START block_copy_start
195:
196: static long text_scnptr;
197: static long data_scnptr;
198:
199: static int pagemask;
200: static int pagesz;
201:
202: static
203: report_error (file, fd)
204: char *file;
205: int fd;
206: {
207: if (fd)
208: close (fd);
209: error ("Failure operating on %s", file);
210: }
211:
212: #define ERROR0(msg) report_error_1 (new, msg, 0, 0); return -1
213: #define ERROR1(msg,x) report_error_1 (new, msg, x, 0); return -1
214: #define ERROR2(msg,x,y) report_error_1 (new, msg, x, y); return -1
215:
216: static
217: report_error_1 (fd, msg, a1, a2)
218: int fd;
219: char *msg;
220: int a1, a2;
221: {
222: close (fd);
223: error (msg, a1, a2);
224: }
225:
226: /* ****************************************************************
227: * unexec
228: *
229: * driving logic.
230: */
231: unexec (new_name, a_name, data_start, bss_start, entry_address)
232: char *new_name, *a_name;
233: unsigned data_start, bss_start, entry_address;
234: {
235: int new, a_out = -1;
236:
237: if (a_name && (a_out = open (a_name, 0)) < 0) {
238: PERROR (a_name);
239: }
240: if ((new = creat (new_name, 0666)) < 0) {
241: PERROR (new_name);
242: }
243:
244: if (make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name) < 0
245: || copy_text_and_data (new) < 0
246: || copy_sym (new, a_out, a_name, new_name) < 0 ) {
247: close (new);
248: return -1;
249: }
250:
251: close (new);
252: if (a_out >= 0)
253: close (a_out);
254: mark_x (new_name);
255: return 0;
256: }
257:
258: /* ****************************************************************
259: * make_hdr
260: *
261: * Make the header in the new a.out from the header in core.
262: * Modify the text and data sizes.
263: */
264:
265: struct scnhdr *stbl; /* Table of all scnhdr's */
266: struct scnhdr *f_thdr; /* Text section header */
267: struct scnhdr *f_dhdr; /* Data section header */
268: struct scnhdr *f_tdhdr; /* Thread Data section header */
269: struct scnhdr *f_bhdr; /* Bss section header */
270: struct scnhdr *f_tbhdr; /* Thread Bss section header */
271:
272: static int
273: make_hdr (new, a_out, data_start, bss_start, entry_address, a_name, new_name)
274: int new, a_out;
275: unsigned data_start, bss_start, entry_address;
276: char *a_name;
277: char *new_name;
278: {
279: register int scns;
280: unsigned int bss_end;
281: unsigned int eo_data; /* End of initialized data in new exec file */
282: int scntype; /* Section type */
283: int i; /* Var for sorting by vaddr */
284: struct scnhdr scntemp; /* For swapping entries in sort */
285: extern char *start_of_data();
286:
287: pagemask = (pagesz = getpagesize()) - 1;
288:
289: /* Adjust text/data boundary. */
290: if (!data_start)
291: data_start = (unsigned) start_of_data ();
292:
293: data_start = data_start & ~pagemask; /* (Down) to page boundary. */
294:
295: bss_end = (sbrk(0) + pagemask) & ~pagemask;
296:
297: /* Adjust data/bss boundary. */
298: if (bss_start != 0) {
299: bss_start = (bss_start + pagemask) & ~pagemask;/* (Up) to page bdry. */
300: if (bss_start > bss_end) {
301: ERROR1 ("unexec: Specified bss_start (%x) is past end of program",
302: bss_start);
303: }
304: } else
305: bss_start = bss_end;
306:
307: if (data_start > bss_start) { /* Can't have negative data size. */
308: ERROR2 ("unexec: data_start (%x) can't be greater than bss_start (%x)",
309: data_start, bss_start);
310: }
311:
312: /* Salvage as much info from the existing file as possible */
313: if (a_out < 0) {
314: ERROR0 ("can't build a COFF file from scratch yet");
315: /*NOTREACHED*/
316: }
317:
318: if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) {
319: PERROR (a_name);
320: }
321: block_copy_start += sizeof (f_hdr);
322: if (f_hdr.h_opthdr > 0) {
323: if (read (a_out, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) {
324: PERROR (a_name);
325: }
326: block_copy_start += sizeof (f_ohdr);
327: }
328:
329: /* Allocate room for scn headers */
330: stbl = (struct scnhdr *)malloc( sizeof(struct scnhdr) * f_hdr.h_nscns );
331: if( stbl == NULL ) {
332: ERROR0( "unexec: malloc of stbl failed" );
333: }
334:
335: f_tdhdr = f_tbhdr = NULL;
336:
337: /* Loop through section headers, copying them in */
338: for (scns = 0; scns < f_hdr.h_nscns; scns++) {
339:
340: if( read( a_out, &stbl[scns], sizeof(*stbl)) != sizeof(*stbl)) {
341: PERROR (a_name);
342: }
343:
344: scntype = stbl[scns].s_flags & S_TYPMASK; /* What type of section */
345:
346: if( stbl[scns].s_scnptr > 0L) {
347: if( block_copy_start < stbl[scns].s_scnptr + stbl[scns].s_size )
348: block_copy_start = stbl[scns].s_scnptr + stbl[scns].s_size;
349: }
350:
351: if( scntype == S_TEXT) {
352: f_thdr = &stbl[scns];
353: } else if( scntype == S_DATA) {
354: f_dhdr = &stbl[scns];
355: #ifdef S_TDATA
356: } else if( scntype == S_TDATA ) {
357: f_tdhdr = &stbl[scns];
358: } else if( scntype == S_TBSS ) {
359: f_tbhdr = &stbl[scns];
360: #endif /* S_TDATA (thread stuff) */
361:
362: } else if( scntype == S_BSS) {
363: f_bhdr = &stbl[scns];
364: }
365:
366: }
367:
368: /* We will now convert TEXT and DATA into TEXT, BSS into DATA, and leave
369: * all thread stuff alone.
370: */
371:
372: /* Now we alter the contents of all the f_*hdr variables
373: to correspond to what we want to dump. */
374:
375: f_thdr->s_vaddr = (long) start_of_text ();
376: f_thdr->s_size = data_start - f_thdr->s_vaddr;
377: f_thdr->s_scnptr = pagesz;
378: f_thdr->s_relptr = 0;
379: f_thdr->s_nrel = 0;
380:
381: eo_data = f_thdr->s_scnptr + f_thdr->s_size;
382:
383: if( f_tdhdr ) { /* Process thread data */
384:
385: f_tdhdr->s_vaddr = data_start;
386: f_tdhdr->s_size += f_dhdr->s_size - (data_start - f_dhdr->s_vaddr);
387: f_tdhdr->s_scnptr = eo_data;
388: f_tdhdr->s_relptr = 0;
389: f_tdhdr->s_nrel = 0;
390:
391: eo_data += f_tdhdr->s_size;
392:
393: /* And now for DATA */
394:
395: f_dhdr->s_vaddr = f_bhdr->s_vaddr; /* Take BSS start address */
396: f_dhdr->s_size = bss_end - f_bhdr->s_vaddr;
397: f_dhdr->s_scnptr = eo_data;
398: f_dhdr->s_relptr = 0;
399: f_dhdr->s_nrel = 0;
400:
401: eo_data += f_dhdr->s_size;
402:
403: } else {
404:
405: f_dhdr->s_vaddr = data_start;
406: f_dhdr->s_size = bss_start - data_start;
407: f_dhdr->s_scnptr = eo_data;
408: f_dhdr->s_relptr = 0;
409: f_dhdr->s_nrel = 0;
410:
411: eo_data += f_dhdr->s_size;
412:
413: }
414:
415: f_bhdr->s_vaddr = bss_start;
416: f_bhdr->s_size = bss_end - bss_start + pagesz /* fudge */;
417: f_bhdr->s_scnptr = 0;
418: f_bhdr->s_relptr = 0;
419: f_bhdr->s_nrel = 0;
420:
421: text_scnptr = f_thdr->s_scnptr;
422: data_scnptr = f_dhdr->s_scnptr;
423: bias = eo_data - block_copy_start;
424:
425: if (f_ohdr.o_symptr > 0L) {
426: f_ohdr.o_symptr += bias;
427: }
428:
429: if (f_hdr.h_strptr > 0) {
430: f_hdr.h_strptr += bias;
431: }
432:
433: if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) {
434: PERROR (new_name);
435: }
436:
437: if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) {
438: PERROR (new_name);
439: }
440:
441: for( scns = 0; scns < f_hdr.h_nscns; scns++ ) {
442:
443: /* This is a cheesey little loop to write out the section headers
444: * in order of increasing virtual address. Dull but effective.
445: */
446:
447: for( i = scns+1; i < f_hdr.h_nscns; i++ ) {
448: if( stbl[i].s_vaddr < stbl[scns].s_vaddr ) { /* Swap */
449: scntemp = stbl[i];
450: stbl[i] = stbl[scns];
451: stbl[scns] = scntemp;
452: }
453: }
454:
455: }
456:
457: for( scns = 0; scns < f_hdr.h_nscns; scns++ ) {
458:
459: if( write( new, &stbl[scns], sizeof(*stbl)) != sizeof(*stbl)) {
460: PERROR (new_name);
461: }
462:
463: }
464:
465: return (0);
466:
467: }
468:
469: /* ****************************************************************
470: * copy_text_and_data
471: *
472: * Copy the text and data segments from memory to the new a.out
473: */
474: static int
475: copy_text_and_data (new)
476: int new;
477: {
478: register int scns;
479:
480: for( scns = 0; scns < f_hdr.h_nscns; scns++ )
481: write_segment( new, &stbl[scns] );
482:
483: return 0;
484: }
485:
486: write_segment( new, sptr )
487: int new;
488: struct scnhdr *sptr;
489: {
490: register char *ptr, *end;
491: register int nwrite, ret;
492: char buf[80];
493: extern int errno;
494: char zeros[128];
495:
496: if( sptr->s_scnptr == 0 )
497: return; /* Nothing to do */
498:
499: if( lseek( new, (long) sptr->s_scnptr, 0 ) == -1 )
500: PERROR( "unexecing" );
501:
502: bzero (zeros, sizeof zeros);
503:
504: ptr = (char *) sptr->s_vaddr;
505: end = ptr + sptr->s_size;
506:
507: while( ptr < end ) {
508:
509: /* distance to next multiple of 128. */
510: nwrite = (((int) ptr + 128) & -128) - (int) ptr;
511: /* But not beyond specified end. */
512: if (nwrite > end - ptr) nwrite = end - ptr;
513: ret = write (new, ptr, nwrite);
514: /* If write gets a page fault, it means we reached
515: a gap between the old text segment and the old data segment.
516: This gap has probably been remapped into part of the text segment.
517: So write zeros for it. */
518: if (ret == -1 && errno == EFAULT)
519: write (new, zeros, nwrite);
520: else if (nwrite != ret) {
521: sprintf (buf,
522: "unexec write failure: addr 0x%x, fileno %d, size 0x%x, wrote 0x%x, errno %d",
523: ptr, new, nwrite, ret, errno);
524: PERROR (buf);
525: }
526: ptr += nwrite;
527: }
528: }
529:
530: /* ****************************************************************
531: * copy_sym
532: *
533: * Copy the relocation information and symbol table from the a.out to the new
534: */
535: static int
536: copy_sym (new, a_out, a_name, new_name)
537: int new, a_out;
538: char *a_name, *new_name;
539: {
540: char page[1024];
541: int n;
542:
543: if (a_out < 0)
544: return 0;
545:
546: if (SYMS_START == 0L)
547: return 0;
548:
549: lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */
550: lseek( new, (long)f_ohdr.o_symptr, 0 );
551:
552: while ((n = read (a_out, page, sizeof page)) > 0) {
553: if (write (new, page, n) != n) {
554: PERROR (new_name);
555: }
556: }
557: if (n < 0) {
558: PERROR (a_name);
559: }
560: return 0;
561: }
562:
563: /* ****************************************************************
564: * mark_x
565: *
566: * After succesfully building the new a.out, mark it executable
567: */
568: static
569: mark_x (name)
570: char *name;
571: {
572: struct stat sbuf;
573: int um;
574: int new = 0; /* for PERROR */
575:
576: um = umask (777);
577: umask (um);
578: if (stat (name, &sbuf) == -1) {
579: PERROR (name);
580: }
581: sbuf.st_mode |= 0111 & ~um;
582: if (chmod (name, sbuf.st_mode) == -1)
583: PERROR (name);
584: }
585:
586: /* Find the first pty letter. This is usually 'p', as in ptyp0, but
587: is sometimes configured down to 'm', 'n', or 'o' for some reason. */
588:
589: first_pty_letter ()
590: {
591: struct stat buf;
592: char pty_name[16];
593: char c;
594:
595: for (c = 'o'; c >= 'a'; c--)
596: {
597: sprintf (pty_name, "/dev/pty%c0", c);
598: if (stat (pty_name, &buf) < 0)
599: return c + 1;
600: }
601: return 'a';
602: }
603:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.