home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / unix_c / gnu / unexcsys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-21  |  14.4 KB  |  580 lines

  1. 23-Oct-85 18:14:33-MDT,15303;000000000001
  2. Return-Path: <unix-sources-request@BRL.ARPA>
  3. Received: from BRL-TGR.ARPA by SIMTEL20.ARPA with TCP; Wed 23 Oct 85 18:13:44-MDT
  4. Received: from usenet by TGR.BRL.ARPA id a017613; 23 Oct 85 18:42 EDT
  5. From: Bruce Robertson <bruce@stride.uucp>
  6. Newsgroups: net.sources
  7. Subject: GNU Emacs unexec() function for System-V
  8. Message-ID: <522@stride.stride.UUCP>
  9. Date: 23 Oct 85 17:24:19 GMT
  10. To:       unix-sources@BRL-TGR.ARPA
  11.  
  12.  
  13. This should run under any System-V - just defined USG to get the System-V
  14. code.  Let me know if you have any problems, please.
  15.  
  16.  
  17.     Bruce Robertson
  18.     UUCP: cbosgd!utah-cs!utah-gr!stride!bruce
  19.  
  20.  
  21. --------- cut here -------------
  22. /* 
  23.  * unexec.c - Convert a running program into an a.out file.
  24.  * 
  25.  * Author:    Spencer W. Thomas
  26.  *         Computer Science Dept.
  27.  *         University of Utah
  28.  * Date:    Tue Mar  2 1982
  29.  * Copyright (c) 1982 Spencer W. Thomas
  30.  *
  31.  * Synopsis:
  32.  *    unexec (new_name, a_name, data_start, bss_start, entry_address)
  33.  *    char *new_name, *a_name;
  34.  *    unsigned data_start, bss_start, entry_address;
  35.  *
  36.  * Takes a snapshot of the program and makes an a.out format file in the
  37.  * file named by the string argument new_name.
  38.  * If a_name is non-NULL, the symbol table will be taken from the given file.
  39.  * 
  40.  * The boundaries within the a.out file may be adjusted with the data_start 
  41.  * and bss_start arguments.  Either or both may be given as 0 for defaults.
  42.  * 
  43.  * Data_start gives the boundary between the text segment and the data
  44.  * segment of the program.  The text segment can contain shared, read-only
  45.  * program code and literal data, while the data segment is always unshared
  46.  * and unprotected.  Data_start gives the lowest unprotected address.  Since
  47.  * the granularity of write-protection is on 1k page boundaries on the VAX, a
  48.  * given data_start value which is not on a page boundary is rounded down to
  49.  * the beginning of the page it is on.  The default when 0 is given leaves the
  50.  * number of protected pages the same as it was before.
  51.  * 
  52.  * Bss_start indicates how much of the data segment is to be saved in the
  53.  * a.out file and restored when the program is executed.  It gives the lowest
  54.  * unsaved address, and is rounded up to a page boundary.  The default when 0
  55.  * is given assumes that the entire data segment is to be stored, including
  56.  * the previous data and bss as well as any additional storage allocated with
  57.  * break (2).
  58.  *
  59.  * The new file is set up to start at entry_address.
  60.  *
  61.  * If you make improvements I'd like to get them too.
  62.  * harpo!utah-cs!thomas, thomas@Utah-20
  63.  *
  64.  */
  65.  
  66. #ifndef emacs
  67. #define PERROR perror
  68. #define ERROR fprintf
  69. #define ERRORF stderr,
  70. #else
  71. #include "config.h"
  72. #define PERROR(file) error ("Failure operating on %s", file)
  73. #define ERROR error
  74. #define ERRORF
  75. #endif
  76.  
  77. #if defined(USG) || defined(STRIDE)
  78. #include <sys/types.h>
  79. #endif
  80. #include <sys/param.h>
  81. #include <stdio.h>
  82. /* #include <sys/dir.h> */
  83. #include <sys/stat.h>
  84. #include <a.out.h>
  85. #include <errno.h>
  86.  
  87. #if defined(USG) || defined(STRIDE)
  88.  
  89. static struct filehdr filehdr;
  90. static struct filehdr old;
  91. static struct aouthdr aouthdr;
  92. static struct scnhdr text, data, bss;
  93.  
  94. static int pagemask;
  95. extern char etext[];
  96.  
  97.  
  98. /* ****************************************************************
  99.  * unexec
  100.  *
  101.  * driving logic.
  102.  */
  103. unexec (new_name, a_name, data_start, bss_start, entry_address)
  104.      char *new_name, *a_name;
  105.      unsigned data_start, bss_start, entry_address;
  106. {
  107.   int new, a_out = -1;
  108.  
  109.   if (a_name && (a_out = open( a_name, 0 )) < 0)
  110.     {
  111.       PERROR (a_name);
  112.       return -1;
  113.     }
  114.   if ((new = creat (new_name, 0666)) < 0)
  115.     {
  116.       PERROR( new_name );
  117.       return -1;
  118.     }
  119.  
  120.   pagemask = MMU_PAGESIZE - 1;
  121.  
  122.   filehdr.f_magic = MC68MAGIC;
  123.   filehdr.f_nscns = 3;        /* text, data and bss */
  124.   time(&filehdr.f_timdat);
  125.   filehdr.f_opthdr = sizeof aouthdr;
  126.   filehdr.f_flags = F_RELFLG | F_EXEC | F_LNNO | F_AR32WR;
  127.  
  128.   if (make_hdr( new, a_out, data_start, bss_start, entry_address) < 0 ||
  129.       copy_text_and_data( new ) < 0 ||
  130.       copy_sym( new, a_out ) < 0)
  131.     {
  132.       close (new);
  133.       /* unlink( new_name );            /* Failed, unlink new a.out */
  134.       return -1;    
  135.     }
  136.  
  137.   close (new);
  138.   if (a_out >= 0)
  139.     close (a_out);
  140.   mark_x (new_name);
  141.   return 0;
  142. }
  143.  
  144. /* ****************************************************************
  145.  * make_hdr
  146.  *
  147.  * Make the header in the new a.out from the header in core.
  148.  * Modify the text and data sizes.
  149.  */
  150. static int
  151. make_hdr( new, a_out, data_start, bss_start, entry_address)
  152. int new, a_out;
  153. unsigned data_start, bss_start, entry_address;
  154. {
  155.     /* Adjust data/bss boundary. */
  156.     if ( bss_start != 0 )
  157.     {
  158. /*    bss_start = (bss_start + pagemask) & ~pagemask;          /* (Up) to page bdry. */
  159.     if ( bss_start > sbrk (0))
  160.     {
  161.         ERROR( ERRORF
  162.         "unexec: Specified bss_start( %u ) is past end of program.\n",
  163.         bss_start );
  164.         return -1;
  165.     }
  166.     }
  167.     else
  168.       bss_start = sbrk (0);
  169.  
  170.     /* Adjust text/data boundary. */
  171.     if (!data_start)
  172.       data_start = (int) etext;
  173.     data_start = data_start & ~pagemask; /* (Down) to page boundary. */
  174.  
  175.     if ( data_start > bss_start )    /* Can't have negative data size. */
  176.     {
  177.     ERROR( ERRORF
  178.         "unexec: data_start(%u) can't be greater than bss_start( %u ).\n",
  179.         data_start, bss_start );
  180.     return -1;
  181.     }
  182.  
  183.     aouthdr.magic = 0410;
  184.     aouthdr.vstamp = 0;
  185.     aouthdr.text_start = TEXT_START;
  186.     aouthdr.data_start = data_start;
  187.     aouthdr.entry = entry_address;
  188.     aouthdr.bsize = sbrk (0) - bss_start;
  189.     aouthdr.dsize = bss_start - data_start;
  190.     aouthdr.tsize = data_start - TEXT_START;
  191.  
  192.     strcpy(text.s_name, _TEXT);
  193.     text.s_paddr = text.s_vaddr = aouthdr.text_start;
  194.     text.s_size = aouthdr.tsize;
  195.     text.s_scnptr = sizeof filehdr + sizeof aouthdr + 3 * SCNHSZ;
  196.     text.s_relptr = text.s_lnnoptr = text.s_nreloc = text.s_nlnno = 0;
  197.     text.s_flags = STYP_REG | STYP_TEXT;
  198.  
  199.     strcpy(data.s_name, _DATA);
  200.     data.s_paddr = data.s_vaddr = aouthdr.data_start;
  201.     data.s_size = aouthdr.dsize;
  202.     data.s_scnptr = text.s_scnptr + text.s_size;
  203.     data.s_relptr = data.s_lnnoptr = data.s_nreloc = data.s_nlnno = 0;
  204.     data.s_flags = STYP_REG | STYP_DATA;
  205.  
  206.     strcpy(bss.s_name, _BSS);
  207.     bss.s_paddr = bss.s_vaddr = data.s_paddr + data.s_size;
  208.     bss.s_size = aouthdr.bsize;
  209.     bss.s_scnptr = 0;
  210.     bss.s_relptr = bss.s_lnnoptr = bss.s_nreloc = bss.s_nlnno = 0;
  211.     bss.s_flags = STYP_REG | STYP_BSS;
  212.  
  213.     /* Get symbol table info from header of a.out file if given one. */
  214.     if ( a_out >= 0 )
  215.     {
  216.     if ( read( a_out, &old, sizeof old ) != sizeof old )
  217.     {
  218.         PERROR( "Couldn't read header from a.out file" );
  219.         return -1;
  220.     }
  221.  
  222.     if (old.f_magic != MC68MAGIC)
  223.     {
  224.         ERROR( ERRORF "a.out file doesn't have legal magic number\n" );
  225.         return -1;
  226.     }
  227.     filehdr.f_nsyms = old.f_nsyms;
  228.     filehdr.f_symptr = data.s_scnptr + data.s_size;
  229.     }
  230.     else
  231.     {
  232.     filehdr.f_nsyms = 0;        /* No a.out, so no symbol info. */
  233.     filehdr.f_symptr = 0;
  234.     }
  235.  
  236.     if (write(new, (char *) &filehdr, sizeof filehdr) != sizeof filehdr
  237.      || write(new, (char *) &aouthdr, sizeof aouthdr) != sizeof aouthdr
  238.      || write(new, (char *) &text, sizeof text) != sizeof text
  239.      || write(new, (char *) &data, sizeof data) != sizeof data
  240.      || write(new, (char *) &bss,  sizeof bss)  != sizeof bss)
  241.     {
  242.     PERROR( "Couldn't write header to new a.out file" );
  243.     return -1;
  244.     }
  245.  
  246.     return 0;
  247. }
  248.  
  249. /* ****************************************************************
  250.  * copy_text_and_data
  251.  *
  252.  * Copy the text and data segments from memory to the new a.out
  253.  */
  254. static int
  255. copy_text_and_data( new )
  256. int new;
  257. {
  258.     int nwrite, ret;
  259.     int end;
  260.     int i;
  261.     int ptr;
  262.     char buf[80];
  263.     extern int errno;
  264.  
  265.     end = aouthdr.tsize + aouthdr.dsize;
  266.     for (i = 0, ptr = TEXT_START; i < end;)
  267.       {
  268.     nwrite = 128;
  269.     if (nwrite > end - i) nwrite = end - i;
  270.     ret = write (new, ptr, nwrite);
  271.     if (ret == -1 && errno == EFAULT)
  272.       {
  273.         lseek (new, text.s_scnptr + i + nwrite, 0);
  274.       }
  275.     else if (nwrite != ret)
  276.       {
  277.         sprintf(buf, "Write failure in unexec: ptr 0x%x size 0x%x nwrite 0x%x errno %d",
  278.              ptr, nwrite, ret, errno);
  279.         PERROR(buf);
  280.         return -1;
  281.       }
  282.     i += nwrite;
  283.     ptr += nwrite;
  284.       }
  285.  
  286.     return 0;
  287. }
  288.  
  289. /* ****************************************************************
  290.  * copy_sym
  291.  *
  292.  * Copy the relocation information and symbol table from the a.out to the new
  293.  */
  294. static int
  295. copy_sym( new, a_out )
  296. int new, a_out;
  297. {
  298.     char page[1024];
  299.     int n;
  300.  
  301.     if ( a_out < 0 )
  302.     return 0;
  303.  
  304.     lseek(a_out, old.f_symptr, 0);
  305.     while ( (n = read( a_out, page, sizeof page )) > 0 )
  306.     {
  307.     if ( write( new, page, n ) != n )
  308.     {
  309.         PERROR( "Error writing symbol table to new a.out" );
  310.         ERROR( ERRORF "new a.out should be ok otherwise\n" );
  311.         return 0;
  312.     }
  313.     }
  314.     if ( n < 0 )
  315.     {
  316.     PERROR( "Error reading symbol table from a.out,\n" );
  317.     ERROR( ERRORF "new a.out should be ok otherwise\n" );
  318.     }
  319.     return 0;
  320. }
  321.  
  322. /* ****************************************************************
  323.  * mark_x
  324.  *
  325.  * After succesfully building the new a.out, mark it executable
  326.  */
  327. static
  328. mark_x( name )
  329. char *name;
  330. {
  331.     struct stat sbuf;
  332.     int um;
  333.  
  334.     um = umask( 777 );
  335.     umask( um );
  336.     if ( stat( name, &sbuf ) == -1 )
  337.     {
  338.     PERROR ( "Can't stat new a.out" );
  339.     ERROR( ERRORF "Setting protection to %o\n", 0777 & ~um );
  340.     sbuf.st_mode = 0777;
  341.     }
  342.     sbuf.st_mode |= 0111 & ~um;
  343.     if ( chmod( name, sbuf.st_mode ) == -1 )
  344.     PERROR( "Couldn't change mode of new a.out to executable" );
  345.  
  346. }
  347.  
  348. #else    /* USG || STRIDE */
  349.  
  350. extern char etext;
  351.  
  352. static struct exec hdr, ohdr;
  353. static int pagemask;
  354.  
  355. /* ****************************************************************
  356.  * unexec
  357.  *
  358.  * driving logic.
  359.  */
  360. unexec (new_name, a_name, data_start, bss_start, entry_address)
  361.      char *new_name, *a_name;
  362.      unsigned data_start, bss_start, entry_address;
  363. {
  364.   int new, a_out = -1;
  365.  
  366.   if (a_name && (a_out = open( a_name, 0 )) < 0)
  367.     {
  368.       PERROR (a_name);
  369.       return -1;
  370.     }
  371.   if ((new = creat (new_name, 0666)) < 0)
  372.     {
  373.       PERROR( new_name );
  374.       return -1;
  375.     }
  376.  
  377.   pagemask = getpagesize () - 1;
  378.  
  379.   if (make_hdr( new, a_out, data_start, bss_start, entry_address) < 0 ||
  380.       copy_text_and_data( new ) < 0 ||
  381.       copy_sym( new, a_out ) < 0)
  382.     {
  383.       close (new);
  384.       /* unlink( new_name );            /* Failed, unlink new a.out */
  385.       return -1;    
  386.     }
  387.  
  388.   close (new);
  389.   if (a_out >= 0)
  390.     close (a_out);
  391.   mark_x (new_name);
  392.   return 0;
  393. }
  394.  
  395. /* ****************************************************************
  396.  * make_hdr
  397.  *
  398.  * Make the header in the new a.out from the header in core.
  399.  * Modify the text and data sizes.
  400.  */
  401. static int
  402. make_hdr( new, a_out, data_start, bss_start, entry_address)
  403. int new, a_out;
  404. unsigned data_start, bss_start, entry_address;
  405. {
  406.     /* Get symbol table info from header of a.out file if given one. */
  407.     if ( a_out >= 0 )
  408.     {
  409.     if ( read( a_out, &ohdr, sizeof hdr ) != sizeof hdr )
  410.     {
  411.         PERROR( "Couldn't read header from a.out file" );
  412.         return -1;
  413.     }
  414.  
  415.     if N_BADMAG( ohdr )
  416.     {
  417.         ERROR( ERRORF "a.out file doesn't have legal magic number\n" );
  418.         return -1;
  419.     }
  420.     hdr.a_syms = ohdr.a_syms;
  421.     }
  422.     else
  423.     hdr.a_syms = 0;            /* No a.out, so no symbol info. */
  424.  
  425.     /* Construct header from user structure. */
  426.     hdr.a_magic = ZMAGIC;
  427.     hdr.a_trsize = 0;
  428.     hdr.a_drsize = 0;
  429.     hdr.a_entry = entry_address;
  430.  
  431.     /* Adjust data/bss boundary. */
  432.     if ( bss_start != 0 )
  433.     {
  434.     bss_start = (bss_start + pagemask) & ~pagemask;          /* (Up) to page bdry. */
  435.     if ( bss_start > sbrk (0))
  436.     {
  437.         ERROR( ERRORF
  438.         "unexec: Specified bss_start( %u ) is past end of program.\n",
  439.         bss_start );
  440.         return -1;
  441.     }
  442.     }
  443.     else
  444.       bss_start = (sbrk (0) + pagemask) & ~pagemask;
  445.  
  446.     /* Adjust text/data boundary. */
  447.     if (!data_start)
  448.       data_start = (int) &etext;
  449. #ifdef SUN
  450.     data_start = data_start & ~(SEGSIZ - 1); /* (Down) to segment boundary. */
  451. #else
  452.     data_start = data_start & ~pagemask; /* (Down) to page boundary. */
  453. #endif
  454.  
  455.     if ( data_start > bss_start )    /* Can't have negative data size. */
  456.     {
  457.     ERROR( ERRORF
  458.         "unexec: data_start(%u) can't be greater than bss_start( %u ).\n",
  459.         data_start, bss_start );
  460.     return -1;
  461.     }
  462.  
  463.     hdr.a_bss = sbrk (0) - bss_start;
  464.     hdr.a_data = bss_start - data_start;
  465.     hdr.a_text = data_start - TEXT_START;
  466.  
  467.     if ( write( new, &hdr, sizeof hdr ) != sizeof hdr )
  468.     {
  469.     PERROR( "Couldn't write header to new a.out file" );
  470.     return -1;
  471.     }
  472.     return 0;
  473. }
  474.  
  475. /* ****************************************************************
  476.  * copy_text_and_data
  477.  *
  478.  * Copy the text and data segments from memory to the new a.out
  479.  */
  480. static int
  481. copy_text_and_data( new )
  482. int new;
  483. {
  484.     int nwrite, ret;
  485.     int end;
  486.     int i;
  487.     int ptr;
  488.     char buf[80];
  489.     extern int errno;
  490.  
  491.     lseek (new, (long) N_TXTOFF (hdr), 0);
  492.  
  493.     end = hdr.a_text + hdr.a_data;
  494.     for (i = 0, ptr = TEXT_START; i < end;)
  495.       {
  496.     nwrite = 128;
  497.     if (nwrite > end - i) nwrite = end - i;
  498.     ret = write (new, ptr, nwrite);
  499.     if (ret == -1 && errno == EFAULT)
  500.       {
  501.         lseek (new, (long) (N_TXTOFF (hdr) + i + nwrite), 0);
  502.       }
  503.     else if (nwrite != ret)
  504.       {
  505.         sprintf(buf, "Write failure in unexec: ptr 0x%x size 0x%x nwrite 0x%x errno %d",
  506.              ptr, nwrite, ret, errno);
  507.         PERROR(buf);
  508.         return -1;
  509.       }
  510.     i += nwrite;
  511.     ptr += nwrite;
  512.       }
  513.  
  514.     return 0;
  515. }
  516.  
  517. /* ****************************************************************
  518.  * copy_sym
  519.  *
  520.  * Copy the relocation information and symbol table from the a.out to the new
  521.  */
  522. static int
  523. copy_sym( new, a_out )
  524. int new, a_out;
  525. {
  526.     char page[1024];
  527.     int n;
  528.  
  529.     if ( a_out < 0 )
  530.     return 0;
  531.  
  532.     lseek( a_out, (long)N_SYMOFF(ohdr), 0 );    /* Position a.out to symtab.*/
  533.     while ( (n = read( a_out, page, sizeof page )) > 0 )
  534.     {
  535.     if ( write( new, page, n ) != n )
  536.     {
  537.         PERROR( "Error writing symbol table to new a.out" );
  538.         ERROR( ERRORF "new a.out should be ok otherwise\n" );
  539.         return 0;
  540.     }
  541.     }
  542.     if ( n < 0 )
  543.     {
  544.     PERROR( "Error reading symbol table from a.out,\n" );
  545.     ERROR( ERRORF "new a.out should be ok otherwise\n" );
  546.     }
  547.     return 0;
  548. }
  549.  
  550. /* ****************************************************************
  551.  * mark_x
  552.  *
  553.  * After succesfully building the new a.out, mark it executable
  554.  */
  555. static
  556. mark_x( name )
  557. char *name;
  558. {
  559.     struct stat sbuf;
  560.     int um;
  561.  
  562.     um = umask( 777 );
  563.     umask( um );
  564.     if ( stat( name, &sbuf ) == -1 )
  565.     {
  566.     PERROR ( "Can't stat new a.out" );
  567.     ERROR( ERRORF "Setting protection to %o\n", 0777 & ~um );
  568.     sbuf.st_mode = 0777;
  569.     }
  570.     sbuf.st_mode |= 0111 & ~um;
  571.     if ( chmod( name, sbuf.st_mode ) == -1 )
  572.     PERROR( "Couldn't change mode of new a.out to executable" );
  573.  
  574. }
  575. #endif /* USG || STRIDE */
  576. -- 
  577.  
  578.     Bruce Robertson
  579.     UUCP: cbosgd!utah-cs!utah-gr!stride!bruce
  580.