#ifndef lint
static char rcsid[] = "$Header:cvtsym.c_ca 12.0$";
#endif
/* $Source: /ibm/acis/usr/src/ibm/RCS/cvtsym.c_ca,v $ */
#include <stdio.h>

#define PAGESIZE page_size

#include "a.out.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <debug.h>

int debug;
long old_pos;

#define LSEEK(fd,pos,how) old_pos = lseek(fd,pos,how); \
	TRACEF(("lseek(%d,%ld,%d) => %ld\n",fd,pos,how,old_pos));


/*	a.out.h	4.1	83/05/03	*/
/* NOTE: this header is a modified version of the standard a.out.h
 * header - it reflects the ordering of the structures as they would
 * appear on this machine if generated on the target machine (or visa-versa).
 */


/*
 * Header prepended to each a.out file.
 */
struct xexec {
	long	x_magic;	/* magic number */
unsigned long	x_text;		/* size of text segment */
unsigned long	x_data;		/* size of initialized data */
unsigned long	x_bss;		/* size of uninitialized data */
unsigned long	x_syms;		/* size of symbol table */
unsigned long	x_entry;	/* entry point */
unsigned long	x_trsize;	/* size of text relocation */
unsigned long	x_drsize;	/* size of data relocation */
};

#define	OMAGIC	0407		/* old impure format */
#define	NMAGIC	0410		/* read-only text */
#define	ZMAGIC	0413		/* demand load format */

/*
 * Format of a relocation datum.
 */
struct xrelocation_info {
	int	r_address;	/* address which is relocated */
unsigned int	r_symbolnum:24,	/* local symbol ordinal */
		r_pcrel:1, 	/* was relocated pc relative already */
		r_length:2,	/* 0=byte, 1=word, 2=long */
		r_extern:1,	/* does not include value of sym referenced */
		:4;		/* nothing, yet */
};

/*
 * Format of a symbol table entry; this file is included by <a.out.h>
 * and should be used if you aren't interested the a.out header
 * or relocation information.
 */
struct	xlist {
	union {
		char	*x_name;	/* for use when in-core */
		long	x_strx;		/* index into file string table */
	} x_un;
unsigned char	x_type;		/* type flag, i.e. N_TEXT etc; see below */
	char	x_other;	/* unused */
	short	x_desc;		/* see <stab.h> */
unsigned long	x_value;	/* value of this symbol (or sdb offset) */
};
#define	x_hash	x_desc		/* used internally by ld */

/*
 * program to read in a symbol table on a vax and convert it so that
 * it will work on a byte-reversed machine.
 * arg1 is converted and copied into arg1.
 * the current host system's pagesize is used for ZMAGIC files, 
 * unless PAGESIZE is set into the environment.
 */

int infile, outfile;
char *inname, *outname;
int page_size;		/* the page size */
int flip_header;	/* header must be flipped to be read */
int tflg, dflg;
int sflg;		/* header is in normal Vax format (unflipped) */
int Sflg;		/* copy - don't flip symbol table */
int newmagic;		/* new file magic number */

main(argc,argv) char **argv;
{
struct exec inheader;
struct xexec outheader;
struct exec newheader;
int insize, outsize;
char *getenv();
register char *p = getenv("PAGESIZE");
char *pgname = argv[0];
register char *argp;

page_size = p ? atoi(p) : getpagesize();	/* get page size */

while (argc > 1 && * (argp = argv[1]) == '-')
	{
	--argc;
	++argv;
	switch(argp[1])
		{
	case 'D':	/* debug flag */
		++debug;
		break;
	case 't':	/* remove text */
		++tflg;
		break;
	case 'd':	/* remove data */
		++dflg;
		break;
	case 'n':	/* use NMAGIC */
		newmagic = NMAGIC;
		break;
	case 'N':
		newmagic = OMAGIC;
		break;
	case 'z':
		newmagic = ZMAGIC;
		break;
	case 's':	/* don't swap output header */
		++sflg;
		break;
	case 'S':		/* don't flip the symbol table */
		++Sflg;
		break;
	case 'p':
		page_size = atoi(argp+2);	/* set the page size */
		break;
	default:
		err("switch %s not recognized",argp);
		break;
		}
	}
if (argc < 3)
	err("usage: %s infile outfile",pgname);
inname = argv[1]; outname = argv[2];

if ((infile = open(inname,0)) < 0)
	err("cannot open %s for input",inname);
if ((outfile = creat(outname,0777)) < 0)
	err("cannot creat %s for output",outname);
if (read(infile,&inheader,sizeof inheader) != sizeof inheader)
	err("%s: header too short",inname);

#define CVT(y) outheader.x_/**/y = htonl(inheader.a_/**/y)

CVT(magic); CVT(text); CVT(data); CVT(bss); CVT(syms); CVT(entry); CVT(trsize); CVT(drsize);

if (N_BADMAG(inheader))
	{
#define CVT2(y) inheader.a_/**/y = htonl(inheader.a_/**/y)

	CVT2(magic); CVT2(text); CVT2(data); CVT2(bss); CVT2(syms); CVT2(entry); CVT2(trsize); CVT2(drsize);
	if (N_BADMAG(inheader))
		err("%s: bad header type",inname);
	++flip_header;		/* we have to flip the input */
	}
newheader = inheader;		/* the prototype new header */
if (tflg)
	newheader.a_text = outheader.x_text = 0;  /* don't write the text */
if (dflg)
	{
	newheader.a_data = outheader.x_data = 0;  /* don't write the data */
	newheader.a_bss = outheader.x_bss = 0;    /* don't have the bss */
	}
if (newmagic)
	outheader.x_magic = htonl(newheader.a_magic = newmagic);
if (inheader.a_trsize || inheader.a_drsize)
	printf("%s: sorry - relocation information not converted\n",inname);

if (sflg)
	write(outfile,&newheader,sizeof newheader);
else
	write(outfile,&outheader,sizeof outheader);

LSEEK(infile,(long) N_TXTOFF(inheader),0);
LSEEK(outfile,(long) N_TXTOFF(newheader),0);
if (!tflg)
	copy_file(inheader.a_text);	/* copy the text */
LSEEK(infile,(long) N_TXTOFF(inheader) + inheader.a_text,0);
LSEEK(outfile,(long) N_TXTOFF(newheader) + newheader.a_text,0);
if (!dflg)
	copy_file(inheader.a_data);	/* copy the data */
copy_file(inheader.a_trsize);	/* copy the text relocation info */
copy_file(inheader.a_drsize);	/* copy the data relocation info */

if (Sflg)
	{
	LSEEK(infile,(long) N_SYMOFF(inheader), 0);
	LSEEK(outfile,(long) N_SYMOFF(newheader), 0);
	copy_file(inheader.a_syms);
	}
else
	cvt_symtab(inheader.a_syms,N_SYMOFF(inheader),
		N_SYMOFF(newheader));	/* do the symbol table */

LSEEK(infile,(long) N_STROFF(inheader), 0);
LSEEK(outfile,(long) N_STROFF(newheader), 0);
if (read(infile,&insize,sizeof insize) != sizeof insize)
	err("%s: too short - no string table size found",inname);
if (flip_header)
	insize = htonl(insize);
outsize = Sflg ? insize : htonl(insize);	/* output size */
write(outfile,&outsize,sizeof outsize);
copy_file(insize);
exit(0);			/* we did it! */
}

copy_file(length) register int length;
{
char buff[BUFSIZ];
register int l, n;

TRACEF(("copying %d bytes\n",length));
while (length > 0)
	{
	l = length;
	if (l > BUFSIZ)
		l = BUFSIZ;
	if ((n = read(infile,buff,l)) != l)
		{
		if (n < 0)
			err("%s: read error",inname);
		else
			err("%s: file too short",inname);
		}
	if ((l = write(outfile,buff,n)) != n)
		err("%s: write error",outname);
	length -= n;
	}
}

cvt_symtab(size,inoff,outoff) register int size; long inoff, outoff;
{
register FILE * in = fdopen(infile,"r");
register FILE * out = fdopen(outfile,"w");
struct xlist outsym;
struct nlist insym;
register int i;

fseek(in,inoff,0);
fseek(out,outoff,0);

TRACEF(("converting %d bytes (%d entries) of symtab\n",size,size / sizeof (struct nlist)));

for (i=0; i<size; i += sizeof (struct nlist))
	{
	if (fread(&insym,sizeof (struct nlist),1,in) != 1)
		err("%s: symbol table read got eof",inname);
	TRACEF(("type=%x other=%x desc=%x strx=%x value=%x\n",insym.n_type,
		insym.n_other,insym.n_desc,insym.n_un.n_strx,insym.n_value));
	outsym.x_type = insym.n_type;
	outsym.x_other = insym.n_other;
	outsym.x_desc = htons(insym.n_desc);
	outsym.x_value = htonl(insym.n_value);
	outsym.x_un.x_strx = htonl(insym.n_un.n_strx);
	if (fwrite(&outsym,sizeof (struct xlist),1,out) != 1)
		err("%s: symbol table write got error",outname);
	}
fflush(out);
}

err(s,d1,d2,d3,d4)
char *s;
{
warn(s,d1,d2,d3,d4);
exit(1);
}

warn(s,d1,d2,d3,d4)
char *s;
{
extern errno;

fflush(stdout);
fprintf(stderr,s,d1,d2,d3,d4);
if(errno > 0)
	{
	fprintf(stderr," - ");
	perror("");
	}
else
	fprintf(stderr,"\n");
}
