Update years in copyright notice; nfc.
[bpt/emacs.git] / src / unexconvex.c
CommitLineData
d427b66a
JB
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
0b5538bd 10 Copyright (C) 1985, 1986, 1988, 2002, 2003, 2004,
aaef169d 11 2005, 2006 Free Software Foundation, Inc.
d427b66a
JB
12
13This file is part of GNU Emacs.
14
15GNU Emacs is free software; you can redistribute it and/or modify
16it under the terms of the GNU General Public License as published by
7c938215 17the Free Software Foundation; either version 2, or (at your option)
d427b66a
JB
18any later version.
19
20GNU Emacs is distributed in the hope that it will be useful,
21but WITHOUT ANY WARRANTY; without even the implied warranty of
22MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23GNU General Public License for more details.
24
25You should have received a copy of the GNU General Public License
26along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
27the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
28Boston, MA 02110-1301, USA. */
d427b66a
JB
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
88Define this if your system uses COFF for executables.
89Otherwise we assume you use Berkeley format.
90
91* NO_REMAP
92
93Define this if you do not want to try to save Emacs's pure data areas
94as part of the text segment.
95
96Saving them as text is good because it allows users to share more.
97
98However, on machines that locate the text area far from the data area,
99the boundary cannot feasibly be moved. Such machines require
100NO_REMAP.
101
102Also, remapping can cause trouble with the built-in startup routine
103/lib/crt0.o, which defines `environ' as an initialized variable.
104Dumping `environ' as pure does not work! So, to use remapping,
105you must write a startup routine for your machine in Emacs's crt0.c.
106If NO_REMAP is defined, Emacs uses the system's crt0.o.
107
108* SECTION_ALIGNMENT
109
110Some machines that use COFF executables require that each section
111start on a certain boundary *in the COFF file*. Such machines should
112define SECTION_ALIGNMENT to a mask of the low-order bits that must be
113zero on such a boundary. This mask is used to control padding between
114segments in the COFF file.
115
116If SECTION_ALIGNMENT is not defined, the segments are written
117consecutively with no attempt at alignment. This is right for
118unmodified system V.
119
120* SEGMENT_MASK
121
122Some machines require that the beginnings and ends of segments
123*in core* be on certain boundaries. For most machines, a page
124boundary is sufficient. That is the default. When a larger
125boundary is needed, define SEGMENT_MASK to a mask of
126the bits that must be zero on such a boundary.
127
128* A_TEXT_OFFSET(HDR)
129
130Some machines count the a.out header as part of the size of the text
131segment (a_text); they may actually load the header into core as the
132first data in the text segment. Some have additional padding between
133the header and the real text of the program that is counted in a_text.
134
135For these machines, define A_TEXT_OFFSET(HDR) to examine the header
136structure HDR and return the number of bytes to add to `a_text'
137before writing it (above and beyond the number of bytes of actual
138program text). HDR's standard fields are already correct, except that
139this adjustment to the `a_text' field has not yet been made;
140thus, the amount of offset can depend on the data in the file.
177c0ea7 141
d427b66a
JB
142* A_TEXT_SEEK(HDR)
143
144If defined, this macro specifies the number of bytes to seek into the
145a.out file before starting to write the text segment.a
146
147* EXEC_MAGIC
148
149For machines using COFF, this macro, if defined, is a value stored
150into the magic number field of the output file.
151
152* ADJUST_EXEC_HEADER
153
154This macro can be used to generate statements to adjust or
155initialize nonstandard fields in the file header
156
157* ADDR_CORRECT(ADDR)
158
159Macro to correct an int which is the bit pattern of a pointer to a byte
160into an int which is the number of a byte.
161
162This macro has a default definition which is usually right.
163This default definition is a no-op on most machines (where a
164pointer looks like an int) but not on all machines.
165
166*/
167
18160b98 168#include <config.h>
d427b66a
JB
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
182extern char *start_of_text (); /* Start of text */
183extern 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
190static long block_copy_start; /* Old executable start point */
191static struct filehdr f_hdr; /* File header */
192static struct opthdr f_ohdr; /* Optional file header (a.out) */
193long bias; /* Bias to add for growth */
194#define SYMS_START block_copy_start
195
196static long text_scnptr;
197static long data_scnptr;
198
199static int pagemask;
200static int pagesz;
201
202static
203report_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
216static
217report_error_1 (fd, msg, a1, a2)
218int fd;
219char *msg;
220int a1, a2;
221{
222 close (fd);
223 error (msg, a1, a2);
224}
225\f
226/* ****************************************************************
227 * unexec
228 *
229 * driving logic.
230 */
231unexec (new_name, a_name, data_start, bss_start, entry_address)
232char *new_name, *a_name;
233unsigned 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);
177c0ea7 248 return -1;
d427b66a
JB
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
272static int
273make_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
eb8c3be9 443 /* This is a cheesy little loop to write out the section headers
d427b66a
JB
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 */
474static int
475copy_text_and_data (new)
476int 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
486write_segment( new, sptr )
487int new;
488struct 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 */
535static int
536copy_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 *
eb8c3be9 566 * After successfully building the new a.out, mark it executable
d427b66a
JB
567 */
568static
569mark_x (name)
570char *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
589first_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
ab5796a9
MB
604/* arch-tag: 8199e06d-69b5-4f79-84d8-00f6ea929af9
605 (do not change this comment) */