[comp.text] Porting undump to System V

klr@hadron.UUCP (Kurt L. Reisler) (03/09/87)

A few weeks ago, I posted a "has anyone brought up TeX under System V"
question to comp.text.  The flavor of the responses was a "no, but tell
me how you do it", mixed with a few requests to send the ctex2.tar.Z
file to various individuals.  So, let me rephrase the question, now
that I have had a few more days to work with ctex.

	Has anyone ported undump to System V?

	Is anyone else in the process of porting
	undump to System V?

I realize I can mange to get TeX to behave as LaTeX or SliTeX through
the use of aliases, but I would rather have the performance of a fully
loaded LaTeX.

 Kurt Reisler (703) 359-6100
 ============================================================================
 UNISIG Chairman, DECUS US Chapter                       | Hadron, Inc.
 ..{seismo|sundc|rlgvax|dtix|decuac}!hadron!klr          | 9990 Lee Highway
 Sysop, Fido 109/74  The Bear's Den   (703) 671-0598     | Suite 481
 Sysop, Fido 109/483 The Pot of Gold  (703) 359-6549     | Fairfax, VA 22030
 ============================================================================

jeff@mcnc.UUCP (Jeffrey Copeland) (03/10/87)

In article <485@hadron.UUCP> klr@hadron.UUCP (Kurt L. Reisler) writes:
>A few weeks ago, I posted a "has anyone brought up TeX under System V"
>question to comp.text.  The flavor of the responses was a "no, but tell
>me how you do it", mixed with a few requests to send the ctex2.tar.Z
>file to various individuals.  So, let me rephrase the question, now
>that I have had a few more days to work with ctex.
>
>	Has anyone ported undump to System V?

First, I have a copy (albeit untested since I don't have a SysV handy)
of the GNUemacs unexec for system V that was posted about 18 months
ago.  That should solve your undump problem.  It is attached at the
very bottom of this note.

However, I did some tests on Common TeX when it first was available,
and among other things discovered that it doesn't produce the same
output as Pascal TeX, in particular not passing the TRIP test.  I have
recieved no response to my note to Pat Monardo about this.  That note,
which describes in outline the problems I found, follows immediately.

=========================================
  From jeff Wed Feb 11 16:48:20 1987
  To: monardo@renoir.berkeley.edu
  Subject: Common TeX -- good news and bad news
  Status: RO

  I just finished running a bunch of benchmarks on a copy of Common
  TeX which I ftp'd from UCBVAX last evening (I picked up the one
  in /pub/ctex2.tar.Z).  The good news is that it's reliably 33%
  faster than the standard Unix TeX-in-Pascal.  The bad news is
  that I found three differences in the dvi files:

	The height of rules is consistently one dvi unit higher
		than the corresponding rules in P-TeX.
	Common TeX uses the dvi z register in places where P-TeX 
		just does "down" operations instead.
	Most importantly, the dvi file it produces as output for 
		the trip test is a different length, and has a
		wide range of off-by-one errors in its dvi 
		measurements.  (I also got a length mismatch on
		the dvi files for tex.tex.)

  Now, it *is* possible I've got a version mismatch.  I did my
  comparisons against TeX 1.5 on 4.3BSD.  To which Pascal version does
  C-TeX correspond?  If you've already got fixes for these, I won't
  spend time digging into the code myself to solve them.

  Other than those differences, which may not be that big a deal, it
  works quickly, and well.  A 33% speedup is nothing to be sneezed at.

=========================================

  Article 2772 of net.sources:
  Path: mcnc!philabs!cmcl2!seismo!utah-cs!utah-gr!stride!bruce
  >From: bruce@stride.UUCP (Bruce Robertson)
  Relay-Version: version B 2.10.2 9/18/84; site mcnc.mcnc.UUCP
  Posting-Version: version B 2.10.3 alpha 4/15/85; site stride.stride.UUCP
  Newsgroups: net.sources
  Subject: GNU Emacs unexec() function for System-V
  Message-ID: <522@stride.stride.UUCP>
  Date: 23 Oct 85 17:24:19 GMT
  Article-I.D.: stride.522
  Posted: Wed Oct 23 13:24:19 1985
  Date-Received: 24 Oct 85 11:38:43 GMT
  Reply-To: bruce@stride.UUCP (Bruce Robertson)
  Organization: Stride Micro, Reno, NV.
  Lines: 568


  This should run under any System-V - just defined USG to get the System-V
  code.  Let me know if you have any problems, please.


	Bruce Robertson
	UUCP: cbosgd!utah-cs!utah-gr!stride!bruce


--------- cut here -------------
/* 
 * unexec.c - Convert a running program into an a.out file.
 * 
 * Author:	Spencer W. Thomas
 * 		Computer Science Dept.
 * 		University of Utah
 * Date:	Tue Mar  2 1982
 * Copyright (c) 1982 Spencer W. Thomas
 *
 * Synopsis:
 *	unexec (new_name, a_name, data_start, bss_start, entry_address)
 *	char *new_name, *a_name;
 *	unsigned data_start, bss_start, entry_address;
 *
 * Takes a snapshot of the program and makes an a.out format file in the
 * file named by the string argument new_name.
 * If a_name is non-NULL, the symbol table will be taken from the given file.
 * 
 * The boundaries within the a.out file may be adjusted with the data_start 
 * and bss_start arguments.  Either or both may be given as 0 for defaults.
 * 
 * Data_start gives the boundary between the text segment and the data
 * segment of the program.  The text segment can contain shared, read-only
 * program code and literal data, while the data segment is always unshared
 * and unprotected.  Data_start gives the lowest unprotected address.  Since
 * the granularity of write-protection is on 1k page boundaries on the VAX, a
 * given data_start value which is not on a page boundary is rounded down to
 * the beginning of the page it is on.  The default when 0 is given leaves the
 * number of protected pages the same as it was before.
 * 
 * Bss_start indicates how much of the data segment is to be saved in the
 * a.out file and restored when the program is executed.  It gives the lowest
 * unsaved address, and is rounded up to a page boundary.  The default when 0
 * is given assumes that the entire data segment is to be stored, including
 * the previous data and bss as well as any additional storage allocated with
 * break (2).
 *
 * The new file is set up to start at entry_address.
 *
 * If you make improvements I'd like to get them too.
 * harpo!utah-cs!thomas, thomas@Utah-20
 *
 */

#ifndef emacs
#define PERROR perror
#define ERROR fprintf
#define ERRORF stderr,
#else
#include "config.h"
#define PERROR(file) error ("Failure operating on %s", file)
#define ERROR error
#define ERRORF
#endif

#if defined(USG) || defined(STRIDE)
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <stdio.h>
/* #include <sys/dir.h> */
#include <sys/stat.h>
#include <a.out.h>
#include <errno.h>

#if defined(USG) || defined(STRIDE)

static struct filehdr filehdr;
static struct filehdr old;
static struct aouthdr aouthdr;
static struct scnhdr text, data, bss;

static int pagemask;
extern char etext[];


/* ****************************************************************
 * unexec
 *
 * driving logic.
 */
unexec (new_name, a_name, data_start, bss_start, entry_address)
     char *new_name, *a_name;
     unsigned data_start, bss_start, entry_address;
{
  int new, a_out = -1;

  if (a_name && (a_out = open( a_name, 0 )) < 0)
    {
      PERROR (a_name);
      return -1;
    }
  if ((new = creat (new_name, 0666)) < 0)
    {
      PERROR( new_name );
      return -1;
    }

  pagemask = MMU_PAGESIZE - 1;

  filehdr.f_magic = MC68MAGIC;
  filehdr.f_nscns = 3;		/* text, data and bss */
  time(&filehdr.f_timdat);
  filehdr.f_opthdr = sizeof aouthdr;
  filehdr.f_flags = F_RELFLG | F_EXEC | F_LNNO | F_AR32WR;

  if (make_hdr( new, a_out, data_start, bss_start, entry_address) < 0 ||
      copy_text_and_data( new ) < 0 ||
      copy_sym( new, a_out ) < 0)
    {
      close (new);
      /* unlink( new_name );	    	/* Failed, unlink new a.out */
      return -1;	
    }

  close (new);
  if (a_out >= 0)
    close (a_out);
  mark_x (new_name);
  return 0;
}

/* ****************************************************************
 * make_hdr
 *
 * Make the header in the new a.out from the header in core.
 * Modify the text and data sizes.
 */
static int
make_hdr( new, a_out, data_start, bss_start, entry_address)
int new, a_out;
unsigned data_start, bss_start, entry_address;
{
    /* Adjust data/bss boundary. */
    if ( bss_start != 0 )
    {
/*	bss_start = (bss_start + pagemask) & ~pagemask;	      /* (Up) to page bdry. */
	if ( bss_start > sbrk (0))
	{
	    ERROR( ERRORF
		"unexec: Specified bss_start( %u ) is past end of program.\n",
		bss_start );
	    return -1;
	}
    }
    else
      bss_start = sbrk (0);

    /* Adjust text/data boundary. */
    if (!data_start)
      data_start = (int) etext;
    data_start = data_start & ~pagemask; /* (Down) to page boundary. */

    if ( data_start > bss_start )	/* Can't have negative data size. */
    {
	ERROR( ERRORF
	    "unexec: data_start(%u) can't be greater than bss_start( %u ).\n",
	    data_start, bss_start );
	return -1;
    }

    aouthdr.magic = 0410;
    aouthdr.vstamp = 0;
    aouthdr.text_start = TEXT_START;
    aouthdr.data_start = data_start;
    aouthdr.entry = entry_address;
    aouthdr.bsize = sbrk (0) - bss_start;
    aouthdr.dsize = bss_start - data_start;
    aouthdr.tsize = data_start - TEXT_START;

    strcpy(text.s_name, _TEXT);
    text.s_paddr = text.s_vaddr = aouthdr.text_start;
    text.s_size = aouthdr.tsize;
    text.s_scnptr = sizeof filehdr + sizeof aouthdr + 3 * SCNHSZ;
    text.s_relptr = text.s_lnnoptr = text.s_nreloc = text.s_nlnno = 0;
    text.s_flags = STYP_REG | STYP_TEXT;

    strcpy(data.s_name, _DATA);
    data.s_paddr = data.s_vaddr = aouthdr.data_start;
    data.s_size = aouthdr.dsize;
    data.s_scnptr = text.s_scnptr + text.s_size;
    data.s_relptr = data.s_lnnoptr = data.s_nreloc = data.s_nlnno = 0;
    data.s_flags = STYP_REG | STYP_DATA;

    strcpy(bss.s_name, _BSS);
    bss.s_paddr = bss.s_vaddr = data.s_paddr + data.s_size;
    bss.s_size = aouthdr.bsize;
    bss.s_scnptr = 0;
    bss.s_relptr = bss.s_lnnoptr = bss.s_nreloc = bss.s_nlnno = 0;
    bss.s_flags = STYP_REG | STYP_BSS;

    /* Get symbol table info from header of a.out file if given one. */
    if ( a_out >= 0 )
    {
	if ( read( a_out, &old, sizeof old ) != sizeof old )
	{
	    PERROR( "Couldn't read header from a.out file" );
	    return -1;
	}

	if (old.f_magic != MC68MAGIC)
	{
	    ERROR( ERRORF "a.out file doesn't have legal magic number\n" );
	    return -1;
	}
	filehdr.f_nsyms = old.f_nsyms;
	filehdr.f_symptr = data.s_scnptr + data.s_size;
    }
    else
    {
	filehdr.f_nsyms = 0;		/* No a.out, so no symbol info. */
	filehdr.f_symptr = 0;
    }

    if (write(new, (char *) &filehdr, sizeof filehdr) != sizeof filehdr
     || write(new, (char *) &aouthdr, sizeof aouthdr) != sizeof aouthdr
     || write(new, (char *) &text, sizeof text) != sizeof text
     || write(new, (char *) &data, sizeof data) != sizeof data
     || write(new, (char *) &bss,  sizeof bss)  != sizeof bss)
    {
	PERROR( "Couldn't write header to new a.out file" );
	return -1;
    }

    return 0;
}

/* ****************************************************************
 * copy_text_and_data
 *
 * Copy the text and data segments from memory to the new a.out
 */
static int
copy_text_and_data( new )
int new;
{
    int nwrite, ret;
    int end;
    int i;
    int ptr;
    char buf[80];
    extern int errno;

    end = aouthdr.tsize + aouthdr.dsize;
    for (i = 0, ptr = TEXT_START; i < end;)
      {
	nwrite = 128;
	if (nwrite > end - i) nwrite = end - i;
	ret = write (new, ptr, nwrite);
	if (ret == -1 && errno == EFAULT)
	  {
	    lseek (new, text.s_scnptr + i + nwrite, 0);
	  }
	else if (nwrite != ret)
	  {
	    sprintf(buf, "Write failure in unexec: ptr 0x%x size 0x%x nwrite 0x%x errno %d",
			 ptr, nwrite, ret, errno);
	    PERROR(buf);
	    return -1;
	  }
	i += nwrite;
	ptr += nwrite;
      }

    return 0;
}

/* ****************************************************************
 * copy_sym
 *
 * Copy the relocation information and symbol table from the a.out to the new
 */
static int
copy_sym( new, a_out )
int new, a_out;
{
    char page[1024];
    int n;

    if ( a_out < 0 )
	return 0;

    lseek(a_out, old.f_symptr, 0);
    while ( (n = read( a_out, page, sizeof page )) > 0 )
    {
	if ( write( new, page, n ) != n )
	{
	    PERROR( "Error writing symbol table to new a.out" );
	    ERROR( ERRORF "new a.out should be ok otherwise\n" );
	    return 0;
	}
    }
    if ( n < 0 )
    {
	PERROR( "Error reading symbol table from a.out,\n" );
	ERROR( ERRORF "new a.out should be ok otherwise\n" );
    }
    return 0;
}

/* ****************************************************************
 * mark_x
 *
 * After succesfully building the new a.out, mark it executable
 */
static
mark_x( name )
char *name;
{
    struct stat sbuf;
    int um;

    um = umask( 777 );
    umask( um );
    if ( stat( name, &sbuf ) == -1 )
    {
	PERROR ( "Can't stat new a.out" );
	ERROR( ERRORF "Setting protection to %o\n", 0777 & ~um );
	sbuf.st_mode = 0777;
    }
    sbuf.st_mode |= 0111 & ~um;
    if ( chmod( name, sbuf.st_mode ) == -1 )
	PERROR( "Couldn't change mode of new a.out to executable" );

}

#else	/* USG || STRIDE */

extern char etext;

static struct exec hdr, ohdr;
static int pagemask;

/* ****************************************************************
 * unexec
 *
 * driving logic.
 */
unexec (new_name, a_name, data_start, bss_start, entry_address)
     char *new_name, *a_name;
     unsigned data_start, bss_start, entry_address;
{
  int new, a_out = -1;

  if (a_name && (a_out = open( a_name, 0 )) < 0)
    {
      PERROR (a_name);
      return -1;
    }
  if ((new = creat (new_name, 0666)) < 0)
    {
      PERROR( new_name );
      return -1;
    }

  pagemask = getpagesize () - 1;

  if (make_hdr( new, a_out, data_start, bss_start, entry_address) < 0 ||
      copy_text_and_data( new ) < 0 ||
      copy_sym( new, a_out ) < 0)
    {
      close (new);
      /* unlink( new_name );	    	/* Failed, unlink new a.out */
      return -1;	
    }

  close (new);
  if (a_out >= 0)
    close (a_out);
  mark_x (new_name);
  return 0;
}

/* ****************************************************************
 * make_hdr
 *
 * Make the header in the new a.out from the header in core.
 * Modify the text and data sizes.
 */
static int
make_hdr( new, a_out, data_start, bss_start, entry_address)
int new, a_out;
unsigned data_start, bss_start, entry_address;
{
    /* Get symbol table info from header of a.out file if given one. */
    if ( a_out >= 0 )
    {
	if ( read( a_out, &ohdr, sizeof hdr ) != sizeof hdr )
	{
	    PERROR( "Couldn't read header from a.out file" );
	    return -1;
	}

	if N_BADMAG( ohdr )
	{
	    ERROR( ERRORF "a.out file doesn't have legal magic number\n" );
	    return -1;
	}
	hdr.a_syms = ohdr.a_syms;
    }
    else
	hdr.a_syms = 0;			/* No a.out, so no symbol info. */

    /* Construct header from user structure. */
    hdr.a_magic = ZMAGIC;
    hdr.a_trsize = 0;
    hdr.a_drsize = 0;
    hdr.a_entry = entry_address;

    /* Adjust data/bss boundary. */
    if ( bss_start != 0 )
    {
	bss_start = (bss_start + pagemask) & ~pagemask;	      /* (Up) to page bdry. */
	if ( bss_start > sbrk (0))
	{
	    ERROR( ERRORF
		"unexec: Specified bss_start( %u ) is past end of program.\n",
		bss_start );
	    return -1;
	}
    }
    else
      bss_start = (sbrk (0) + pagemask) & ~pagemask;

    /* Adjust text/data boundary. */
    if (!data_start)
      data_start = (int) &etext;
#ifdef SUN
    data_start = data_start & ~(SEGSIZ - 1); /* (Down) to segment boundary. */
#else
    data_start = data_start & ~pagemask; /* (Down) to page boundary. */
#endif

    if ( data_start > bss_start )	/* Can't have negative data size. */
    {
	ERROR( ERRORF
	    "unexec: data_start(%u) can't be greater than bss_start( %u ).\n",
	    data_start, bss_start );
	return -1;
    }

    hdr.a_bss = sbrk (0) - bss_start;
    hdr.a_data = bss_start - data_start;
    hdr.a_text = data_start - TEXT_START;

    if ( write( new, &hdr, sizeof hdr ) != sizeof hdr )
    {
	PERROR( "Couldn't write header to new a.out file" );
	return -1;
    }
    return 0;
}

/* ****************************************************************
 * copy_text_and_data
 *
 * Copy the text and data segments from memory to the new a.out
 */
static int
copy_text_and_data( new )
int new;
{
    int nwrite, ret;
    int end;
    int i;
    int ptr;
    char buf[80];
    extern int errno;

    lseek (new, (long) N_TXTOFF (hdr), 0);

    end = hdr.a_text + hdr.a_data;
    for (i = 0, ptr = TEXT_START; i < end;)
      {
	nwrite = 128;
	if (nwrite > end - i) nwrite = end - i;
	ret = write (new, ptr, nwrite);
	if (ret == -1 && errno == EFAULT)
	  {
	    lseek (new, (long) (N_TXTOFF (hdr) + i + nwrite), 0);
	  }
	else if (nwrite != ret)
	  {
	    sprintf(buf, "Write failure in unexec: ptr 0x%x size 0x%x nwrite 0x%x errno %d",
			 ptr, nwrite, ret, errno);
	    PERROR(buf);
	    return -1;
	  }
	i += nwrite;
	ptr += nwrite;
      }

    return 0;
}

/* ****************************************************************
 * copy_sym
 *
 * Copy the relocation information and symbol table from the a.out to the new
 */
static int
copy_sym( new, a_out )
int new, a_out;
{
    char page[1024];
    int n;

    if ( a_out < 0 )
	return 0;

    lseek( a_out, (long)N_SYMOFF(ohdr), 0 );	/* Position a.out to symtab.*/
    while ( (n = read( a_out, page, sizeof page )) > 0 )
    {
	if ( write( new, page, n ) != n )
	{
	    PERROR( "Error writing symbol table to new a.out" );
	    ERROR( ERRORF "new a.out should be ok otherwise\n" );
	    return 0;
	}
    }
    if ( n < 0 )
    {
	PERROR( "Error reading symbol table from a.out,\n" );
	ERROR( ERRORF "new a.out should be ok otherwise\n" );
    }
    return 0;
}

/* ****************************************************************
 * mark_x
 *
 * After succesfully building the new a.out, mark it executable
 */
static
mark_x( name )
char *name;
{
    struct stat sbuf;
    int um;

    um = umask( 777 );
    umask( um );
    if ( stat( name, &sbuf ) == -1 )
    {
	PERROR ( "Can't stat new a.out" );
	ERROR( ERRORF "Setting protection to %o\n", 0777 & ~um );
	sbuf.st_mode = 0777;
    }
    sbuf.st_mode |= 0111 & ~um;
    if ( chmod( name, sbuf.st_mode ) == -1 )
	PERROR( "Couldn't change mode of new a.out to executable" );

}
#endif /* USG || STRIDE */