]> code.delx.au - gnu-emacs/blob - src/unexconvex.c
(lgrep, rgrep): Use add-to-history.
[gnu-emacs] / src / unexconvex.c
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.
9
10 Copyright (C) 1985, 1986, 1988, 2002, 2003, 2004,
11 2005, 2006 Free Software Foundation, Inc.
12
13 This file is part of GNU Emacs.
14
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 2, or (at your option)
18 any later version.
19
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.
24
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. */
29
30
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
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 \f
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 cheesy 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 \f
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 \f
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 \f
563 /* ****************************************************************
564 * mark_x
565 *
566 * After successfully 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 \f
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
604 /* arch-tag: 8199e06d-69b5-4f79-84d8-00f6ea929af9
605 (do not change this comment) */