|
|
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.