Merge from gnus--rel--5.10
[emacs.git] / src / unexconvex.c
blobb6ebebd9ae0d5b27dad61025c7692717b4679a0c
1 /* Modified version of unexec for convex machines.
2 Note that the GNU project considers support for the peculiarities
3 of the Convex operating system a peripheral activity which should
4 not be allowed to divert effort from development of the GNU system.
5 Changes in this code will be installed when Convex system
6 maintainers send them in, but aside from that we don't plan to
7 think about it, or about whether other Emacs maintenance might
8 break it.
10 Copyright (C) 1985, 1986, 1988, 2001, 2002, 2003, 2004,
11 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
13 This file is part of GNU Emacs.
15 GNU Emacs is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 3, or (at your option)
18 any later version.
20 GNU Emacs is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with GNU Emacs; see the file COPYING. If not, write to
27 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28 Boston, MA 02110-1301, USA. */
31 /* modified 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
37 * unexec.c - Convert a running program into an a.out file.
39 * Author: Spencer W. Thomas
40 * Computer Science Dept.
41 * University of Utah
42 * Date: Tue Mar 2 1982
43 * Modified heavily since then.
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;
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.
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.
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.
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.
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).
77 * The new file is set up to start at entry_address.
79 * If you make improvements I'd like to get them too.
80 * harpo!utah-cs!thomas, thomas@Utah-20
84 /* There are several compilation parameters affecting unexec:
86 * COFF
88 Define this if your system uses COFF for executables.
89 Otherwise we assume you use Berkeley format.
91 * NO_REMAP
93 Define this if you do not want to try to save Emacs's pure data areas
94 as part of the text segment.
96 Saving them as text is good because it allows users to share more.
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.
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.
108 * SECTION_ALIGNMENT
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.
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.
120 * SEGMENT_MASK
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.
128 * A_TEXT_OFFSET(HDR)
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.
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.
142 * A_TEXT_SEEK(HDR)
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
147 * EXEC_MAGIC
149 For machines using COFF, this macro, if defined, is a value stored
150 into the magic number field of the output file.
152 * ADJUST_EXEC_HEADER
154 This macro can be used to generate statements to adjust or
155 initialize nonstandard fields in the file header
157 * ADDR_CORRECT(ADDR)
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.
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.
168 #include <config.h>
169 #define PERROR(file) report_error (file, new)
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
175 #include "getpagesize.h"
177 #include <sys/types.h>
178 #include <stdio.h>
179 #include <sys/stat.h>
180 #include <errno.h>
182 extern char *start_of_text (); /* Start of text */
183 extern char *start_of_data (); /* Start of initialized data */
185 #include <machine/filehdr.h>
186 #include <machine/opthdr.h>
187 #include <machine/scnhdr.h>
188 #include <machine/pte.h>
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
196 static long text_scnptr;
197 static long data_scnptr;
199 static int pagemask;
200 static int pagesz;
202 static
203 report_error (file, fd)
204 char *file;
205 int fd;
207 if (fd)
208 close (fd);
209 error ("Failure operating on %s", file);
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
216 static
217 report_error_1 (fd, msg, a1, a2)
218 int fd;
219 char *msg;
220 int a1, a2;
222 close (fd);
223 error (msg, a1, a2);
226 /* ****************************************************************
227 * unexec
229 * driving logic.
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;
235 int new, a_out = -1;
237 if (a_name && (a_out = open (a_name, 0)) < 0) {
238 PERROR (a_name);
240 if ((new = creat (new_name, 0666)) < 0) {
241 PERROR (new_name);
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;
251 close (new);
252 if (a_out >= 0)
253 close (a_out);
254 mark_x (new_name);
255 return 0;
258 /* ****************************************************************
259 * make_hdr
261 * Make the header in the new a.out from the header in core.
262 * Modify the text and data sizes.
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 */
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;
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();
287 pagemask = (pagesz = getpagesize()) - 1;
289 /* Adjust text/data boundary. */
290 if (!data_start)
291 data_start = (unsigned) start_of_data ();
293 data_start = data_start & ~pagemask; /* (Down) to page boundary. */
295 bss_end = (sbrk(0) + pagemask) & ~pagemask;
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);
304 } else
305 bss_start = bss_end;
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);
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*/
318 if (read (a_out, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) {
319 PERROR (a_name);
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);
326 block_copy_start += sizeof (f_ohdr);
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" );
335 f_tdhdr = f_tbhdr = NULL;
337 /* Loop through section headers, copying them in */
338 for (scns = 0; scns < f_hdr.h_nscns; scns++) {
340 if( read( a_out, &stbl[scns], sizeof(*stbl)) != sizeof(*stbl)) {
341 PERROR (a_name);
344 scntype = stbl[scns].s_flags & S_TYPMASK; /* What type of section */
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;
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) */
362 } else if( scntype == S_BSS) {
363 f_bhdr = &stbl[scns];
368 /* We will now convert TEXT and DATA into TEXT, BSS into DATA, and leave
369 * all thread stuff alone.
372 /* Now we alter the contents of all the f_*hdr variables
373 to correspond to what we want to dump. */
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;
381 eo_data = f_thdr->s_scnptr + f_thdr->s_size;
383 if( f_tdhdr ) { /* Process thread data */
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;
391 eo_data += f_tdhdr->s_size;
393 /* And now for DATA */
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;
401 eo_data += f_dhdr->s_size;
403 } else {
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;
411 eo_data += f_dhdr->s_size;
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;
421 text_scnptr = f_thdr->s_scnptr;
422 data_scnptr = f_dhdr->s_scnptr;
423 bias = eo_data - block_copy_start;
425 if (f_ohdr.o_symptr > 0L) {
426 f_ohdr.o_symptr += bias;
429 if (f_hdr.h_strptr > 0) {
430 f_hdr.h_strptr += bias;
433 if (write (new, &f_hdr, sizeof (f_hdr)) != sizeof (f_hdr)) {
434 PERROR (new_name);
437 if (write (new, &f_ohdr, sizeof (f_ohdr)) != sizeof (f_ohdr)) {
438 PERROR (new_name);
441 for( scns = 0; scns < f_hdr.h_nscns; scns++ ) {
443 /* This is a cheesy little loop to write out the section headers
444 * in order of increasing virtual address. Dull but effective.
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;
457 for( scns = 0; scns < f_hdr.h_nscns; scns++ ) {
459 if( write( new, &stbl[scns], sizeof(*stbl)) != sizeof(*stbl)) {
460 PERROR (new_name);
465 return (0);
469 /* ****************************************************************
470 * copy_text_and_data
472 * Copy the text and data segments from memory to the new a.out
474 static int
475 copy_text_and_data (new)
476 int new;
478 register int scns;
480 for( scns = 0; scns < f_hdr.h_nscns; scns++ )
481 write_segment( new, &stbl[scns] );
483 return 0;
486 write_segment( new, sptr )
487 int new;
488 struct scnhdr *sptr;
490 register char *ptr, *end;
491 register int nwrite, ret;
492 char buf[80];
493 extern int errno;
494 char zeros[128];
496 if( sptr->s_scnptr == 0 )
497 return; /* Nothing to do */
499 if( lseek( new, (long) sptr->s_scnptr, 0 ) == -1 )
500 PERROR( "unexecing" );
502 bzero (zeros, sizeof zeros);
504 ptr = (char *) sptr->s_vaddr;
505 end = ptr + sptr->s_size;
507 while( ptr < end ) {
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);
526 ptr += nwrite;
530 /* ****************************************************************
531 * copy_sym
533 * Copy the relocation information and symbol table from the a.out to the new
535 static int
536 copy_sym (new, a_out, a_name, new_name)
537 int new, a_out;
538 char *a_name, *new_name;
540 char page[1024];
541 int n;
543 if (a_out < 0)
544 return 0;
546 if (SYMS_START == 0L)
547 return 0;
549 lseek (a_out, SYMS_START, 0); /* Position a.out to symtab. */
550 lseek( new, (long)f_ohdr.o_symptr, 0 );
552 while ((n = read (a_out, page, sizeof page)) > 0) {
553 if (write (new, page, n) != n) {
554 PERROR (new_name);
557 if (n < 0) {
558 PERROR (a_name);
560 return 0;
563 /* ****************************************************************
564 * mark_x
566 * After successfully building the new a.out, mark it executable
568 static
569 mark_x (name)
570 char *name;
572 struct stat sbuf;
573 int um;
574 int new = 0; /* for PERROR */
576 um = umask (777);
577 umask (um);
578 if (stat (name, &sbuf) == -1) {
579 PERROR (name);
581 sbuf.st_mode |= 0111 & ~um;
582 if (chmod (name, sbuf.st_mode) == -1)
583 PERROR (name);
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. */
589 first_pty_letter ()
591 struct stat buf;
592 char pty_name[16];
593 char c;
595 for (c = 'o'; c >= 'a'; c--)
597 sprintf (pty_name, "/dev/pty%c0", c);
598 if (stat (pty_name, &buf) < 0)
599 return c + 1;
601 return 'a';
604 /* arch-tag: 8199e06d-69b5-4f79-84d8-00f6ea929af9
605 (do not change this comment) */