[comp.sources.misc] v04i126: 680x0 COFF disassembler

alex@umbc3.UUCP (Alex S. Crain) (10/15/88)

Posting-number: Volume 4, Issue 126
Submitted-by: "Alex S. Crain" <alex@umbc3.UUCP>
Archive-name: 68kdisasm/Part2

	This is part 2 of the dissassembler.

					:alex.
					Systems Programmer
nerwin!alex@umbc3.umd.edu		UMBC
alex@umbc3.umd.edu

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  Makefile
#	  README.FIRST
#	  README.orig
#	  README.unixpc
#	  alloc.c
#	  conv.c
#	  doc.nr
#	  file.c
#	  heur.c
#	  main.c
#	  prin.c
#	  unc.h
#
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
XCFLAGS=-O
XLDFLAGS=-s
XOBJS=alloc.o file.o libmtch.o robj.o iset.o prin.o heur.o main.o conv.o
XSHAREDLIB=/lib/shlib.ifile /lib/crt0s.o
X
Xdis:	$(OBJS)
X	$(LD) $(LDFLAGS) -o dis $(OBJS) $(SHAREDLIB) -lld
X
X$(OBJS):	unc.h
SHAR_EOF
chmod 0644 Makefile || echo "restore of Makefile fails"
sed 's/^X//' << 'SHAR_EOF' > README.FIRST &&
X WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING 
X				   
X      The AT&T licence agreement specifically prohibits the dissassembly
X   of propritory AT&T software. Be aware that use of this program on system
X   software is in clear violation of that agreement. The author(s) of this
X  software in no way incourage its use in any way shape or form for any reason
X  whatsoever, and will not be held liable for anything ever if we can help it.
X
X WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING * WARNING 
SHAR_EOF
chmod 0644 README.FIRST || echo "restore of README.FIRST fails"
sed 's/^X//' << 'SHAR_EOF' > README.orig &&
XI have gotten many many requests to email this or post it, because of
Xits size email'ing it screws up most mailers, so i am submitting it to
Xmod.sources to be posted.  Please note a major cavaet with this, it was
Xwritten under Unisoft's port of Unix so the a.out file that it uses
Xmore closely resembles the b.out.h file that most cross assemblers
X(e.g.  greenhills) use. For the obvious reasons i have not included that
Xfile with the posting. I did not write this nor do i make any claim to
Xthat effect.
X
X    turner@imagen.UUCP <talcott!topaz!Shasta!imagen!Jim.Turner>
X
X----------------------------
XThis is the 68000 disassembler mentioned on the net.
XIt is not my final version by any means, but I have found it extremely
Xuseful and it represents several weeks' work.
X
X    John Collins. <jmc@inset.UUCP>
SHAR_EOF
chmod 0644 README.orig || echo "restore of README.orig fails"
sed 's/^X//' << 'SHAR_EOF' > README.unixpc &&
X***** README *****
X
XThis README superceeds all other README's.
X
XProgram History:
X	This started out as the unc program, by John Collins. At that
Xtime it was a 68000 assembler for the UNISOFT unix environment. It was
Xposted to the net as a dissasembler for Suns, I don't know who
Xmodified it for the sun environment or if that was ever done, but
XJanet Walz taught it about COFF, using the existing assembly syntax, I
Xreworked the syntax to match the SGS syntax used by the unixpc (and
Xthe HP9000, I believe). Surprisingly, the code has remained resonably
Xcoherent during this time, and has remained well structured.
X
X
XCurrent Status:
X	At best, dissassemblers are of dubious value to anyone but system
Xhackers and compiler writers. As I am both, I expect that this tool will 
Xget used a great deal on *my* machine.
X
X	The following features are supported
X	1) symbol resolution is done whenever possible. addresses abouve
X0x300000 are considered constants (on a unix-pc, ths shared libraries are
Xmapped in the address space above 0x300000)
X	2) the dissassembler will attempt to convert pc relative addresses
Xto label jumps, in that it will calculate the destination address and insert
Xa label at that point, if one is not already present.
X	3) the dissassembler decodes jump tables by recognising the swbeg
Xpsuedo instuction and treating the table as a list of offsets relative
Xto the start of the table. Again, label insertion is done where neccessary.
X
XTHe idea is that you should be able to do 
X
X	% dis foo > foo.s
X	% as foo.s
X	% ld foo.o
X
XThis is never completely possible, but it will work on some things. Remember
Xthat code originally linked to the shared libraries must be loaded with
X/lib/shlib.ifile. dis output will need a _start symbol inserted at the top
Xof the output file, as in:
X
X	text
X	global _start	# insert this
X_start:			# and this
X	...
X	...
X
XAlso note that the assembly output will already contain any necessary 
Xlibrary routines, so linking to libraries will not be neccessary.
X
XBUGS:
X	THere are certainly bugs present, and I while I offer no support,
XI will gladly accept bug reports and publish fixes as I have time. Send
Xbug reports to:
X
X	alex@umbc3.ume.edu
X	uunet!umbc3!nerwin!alex
X
X					Alex Crain
X
X
SHAR_EOF
chmod 0644 README.unixpc || echo "restore of README.unixpc fails"
sed 's/^X//' << 'SHAR_EOF' > alloc.c &&
X/*
X *	SCCS:	@(#)alloc.c	1.2	11/2/84	14:17:20
X *	Allocate space etc.
X *
X ***********************************************************************
X *	This software is copyright of
X *
X *		John M Collins
X *		47 Cedarwood Drive
X *		St Albans
X *		Herts, AL4 0DN
X *		England			+44 727 57267
X *
X *	and is released into the public domain on the following conditions:
X *
X *		1.  No free maintenance will be guaranteed.
X *		2.  Nothing may be based on this software without
X *		    acknowledgement, including incorporation of this
X *		    notice.
X *
X *	Notwithstanding the above, the author welcomes correspondence and bug
X *	fixes.
X ***********************************************************************
X */
X
X#include <stdio.h>
X#include <a.out.h>
X#include <setjmp.h>
X#include <ldfcn.h>
X#include "unc.h"
X
X#define	STINC	10
X
Xchar	*malloc(), *realloc();
Xchar	*strncpy();
Xvoid	gette(), getde(), setde(), putte(), putde();
Xvoid	unimpl();
Xlong	gettw();
X
Xef_fids	mainfile;
X
X/*
X *	Oops! out of memory.....
X */
X
Xvoid	nomem()
X{
X	(void) fprintf(stderr, "Sorry - run out of memory\n");
X	exit(255);
X}
X
X/*
X *	Look up hash value of symbol.
X */
X
Xunsigned  shash(str)
Xregister  char	*str;
X{
X	register  unsigned  result = 0;
X	register  int	cnt = 0;
X	
X	while  (*str  &&  cnt < MAXCHARS)  {
X		result += *str++;
X		cnt++;
X	}
X	return  result % HASHMOD;
X}
X
X/*
X *	Look up hash value of symbol, possibly allocating a new symbol.
X */
X
Xsymbol	lookup(str)
Xchar	*str;
X{
X	register  symbol  res, *pp;
X	register  int	len;
X	
X	pp = &symbhash[shash(str)];
X	res = *pp;
X	while  (res != NULL)  {
X		if  (strncmp(res->s_name, str, MAXCHARS) == 0)
X			return	res;
X		pp = &res->s_next;
X		res = *pp;
X	}
X	for  (len = 0;  len < MAXCHARS;  len++)
X		if  (str[len] == '\0')
X			break;
X	len++;
X	res = (symbol) malloc(sizeof(struct symstr) + len);
X	if  (res == NULL)
X		nomem();
X	*pp = res;
X	res->s_next = NULL;
X	(void) strncpy(res->s_name, str, len);
X	res->s_name[len] = '\0';		/*  Null-terminate  */
X	res->s_newsym = 1;
X	res->s_glob = 0;
X	res->s_invent = 0;
X	res->s_link = NULL;
X	res->s_used = 0;
X	res->s_defs = 0;
X	res->s_lsymb = 0;
X	return  res;
X}
X
X/*
X *	Invent a symbol, making sure that we don't know it.
X */
X
Xsymbol	inventsymb(prefix)
Xchar	*prefix;
X{
X	static	int  nsymb = 0;
X	char	schars[10];
X	register  symbol  res;
X	
X	do	(void) sprintf(schars, "%s%d", prefix, ++nsymb);
X	while  (!(res = lookup(schars))->s_newsym);
X	
X	res->s_newsym = 0;
X	res->s_invent = 1;
X	return	res;
X}
X	 
X/*
X *	Reallocate symbol table.
X */
X
Xvoid	reallst(outf)
Xregister  ef_fid  outf;
X{
X	outf->ef_stmax += STINC;
X	if  (outf->ef_stvec == NULL)
X		outf->ef_stvec = (symbol *) malloc(outf->ef_stmax * sizeof(symbol));
X	else
X		outf->ef_stvec = (symbol *) realloc(outf->ef_stvec,
X					outf->ef_stmax * sizeof(symbol));
X	if  (outf->ef_stvec == NULL)
X		nomem();
X}
X
X/*
X *	Search through existing symbol table for symbol with given
X *	value.  Invent a new one if needed.
X */
X
Xsymbol	getnsymb(fid, seg, pos)
Xregister  ef_fid  fid;
Xunsigned  seg;
Xlong	pos;
X{
X	register  int	i;
X	register  symbol  res;
X	
X	/***********  MACHINE DEPENDENT  ******************************
X	 *	Convert relocation segment type (argument) to symbol type
X	 *	(as remembered in symbol table).  Don't ask me why they
X	 *	have to be different.....
X	 */
X	
X	/*
X	 *	See if the reference is to an external symbol.
X	 *	If so, use that.
X	 */
X	
X	for  (i = 0;  i < fid->ef_stcnt;  i++)  {
X		res = fid->ef_stvec[i];
X		if  (res->s_type == seg  &&  res->s_value == pos)
X			return	res;
X	}
X	
X	/*
X	 *	Invent a symbol and use that.
X	 */
X	
X	res = inventsymb("RS");
X	if  (fid->ef_stcnt >= fid->ef_stmax)
X		reallst(fid);
X	fid->ef_stvec[fid->ef_stcnt++] = res;
X	res->s_type = seg;
X	res->s_value = pos;
X	if  (seg == S_TEXT)  {
X		t_entry	tent;
X		gette(fid, pos, &tent);
X		tent.t_bdest = 1;
X		tent.t_lab = res;
X		putte(fid, pos, &tent);
X	}
X	else  if  (seg == S_DATA  ||  seg == S_BSS)  {
X		d_entry dent;
X		getde(fid, pos, &dent);
X		dent.d_lab = res;
X		putde(fid, pos, &dent);
X	}
X
X	return	res;
X}
X
X/*
X *	Assuming address given is in text segment, find its label, or invent
X *	one.  Also set where refered from.
X */
X
Xsymbol	textlab(loc, refpos)
Xlong	loc, refpos;
X{
X	t_entry	tent;
X
X	gette(&mainfile, loc, &tent);
X	if  (tent.t_type == T_CONT)
X		return	NULL;
X	if  (tent.t_lab == NULL)  {
X		tent.t_lab = inventsymb("TS");
X		tent.t_lab->s_type = S_TEXT;
X		tent.t_lab->s_value = loc;
X		tent.t_bdest = 1;
X		putte(&mainfile, loc, &tent);
X	}
X	else
X		tent.t_lab->s_used++;
X	if  (tent.t_refhi < refpos)  {
X		tent.t_refhi = refpos;
X		putte(&mainfile, loc, &tent);
X	}
X	if  (tent.t_reflo > refpos)  {
X		tent.t_reflo = refpos;
X		putte(&mainfile, loc, &tent);
X	}
X	return	tent.t_lab;
X}
X
X/*
X *	Note references to data.
X */
X
Xvoid	mkdref(tpos, size)
Xlong	tpos;
Xunsigned  size;
X{
X	t_entry	tent;
X	d_entry	dent;
X	register  symbol  ds;
X	int	dchng = 0;
X	int	wsize;
X	long	dpos;
X	
X	gette(&mainfile, tpos, &tent);
X	if  (tent.t_relsymb != NULL)
X		return;
X		
X	dpos = gettw(&mainfile, tpos, R_LONG);
X	if  (dpos < mainfile.ef_dbase  ||  dpos > mainfile.ef_end)
X		return;
X	
X	switch  (size)  {
X	default:
X		wsize = D_BYTE;
X		break;
X	case  2:
X		wsize = D_WORD;
X		break;
X	case  4:
X		wsize = D_LONG;
X		break;
X	}
X	
X	getde(&mainfile, dpos, &dent);
X	if  ((ds = dent.d_lab) == NULL)  {
X		if  (dpos >= mainfile.ef_bbase)  {
X			ds = inventsymb("BS");
X			ds->s_type = S_BSS;
X		}
X		else  {
X			ds = inventsymb("DS");
X			ds->s_type = S_DATA;
X		}
X		ds->s_value = dpos;
X		dent.d_lab = ds;
X		dchng++;
X	}
X	else
X		ds->s_used++;
X
X	if  (dent.d_type != D_BYTE)  {
X		if  (dent.d_type != wsize)  {
X			if  (dent.d_type == D_ADDR)  {
X				if  (wsize != D_LONG)
X					unimpl("Addr word usage");
X			}
X			else  if  (dent.d_type > wsize)  {
X				dchng++;
X				dent.d_type = wsize;
X				dent.d_lng = size;
X			}
X		}
X	}
X	else  {
X		dent.d_type = wsize;
X		dent.d_lng = size;
X		dchng++;
X	}
X	if  (dchng)  {
X		putde(&mainfile, dpos, &dent);
X		for  (dchng = 1;  dchng < size; dchng++)
X			setde(&mainfile, dpos+dchng, D_CONT, 1);
X	}
X		
X	tent.t_relsymb = ds;
X	putte(&mainfile, tpos, &tent);
X}
X
X/*
X *	Add item to common or abs list.
X */
X
X#define	COMINC	10
X
Xvoid	addit(cp, symb)
Xregister  struct  commit  *cp;
Xsymbol	symb;
X{
X	if  (cp->c_int >= cp->c_max)  {
X		cp->c_max += COMINC;
X		if  (cp->c_symb == NULL)
X			cp->c_symb = (symbol *) malloc(COMINC*sizeof(symbol));
X		else
X			cp->c_symb = (symbol *)
X					realloc(cp->c_symb,
X						cp->c_max * sizeof(symbol));
X		if  (cp->c_symb == NULL)
X			nomem();
X	}
X	cp->c_symb[cp->c_int++] = symb;
X}
SHAR_EOF
chmod 0644 alloc.c || echo "restore of alloc.c fails"
sed 's/^X//' << 'SHAR_EOF' > conv.c &&
X#include <stdio.h>
X#include <a.out.h>
X#include <ldfcn.h>
X#include "unc.h"
X
Xunsigned convtosun(sym)
Xstruct syment *sym;
X{
X    unsigned suntype;
X
X    /*	everything in shlib is an external constant	*/
X    if (sym->n_value >= 0x300000) {
X	sym->n_scnum = N_ABS;
X     	sym->n_sclass = C_EXT;
X    }
X    switch(sym->n_scnum) {
X    case N_UNDEF:
X    case N_DEBUG:	/* call things that don't map well "undefined" */
X    case N_TV:
X    case P_TV:
X	suntype = S_UNDF;
X	break;
X    case N_ABS:
X	suntype = S_ABS;
X	break;
X    case 1:
X	suntype = S_TEXT;
X	break;
X    case 2:
X	suntype = S_DATA;
X	break;
X    case 3:
X	suntype = S_BSS;
X	break;
X    }
X
X    if (sym->n_sclass == C_EXT)
X	suntype = suntype | S_EXT;
X
X    return(suntype);
X}
SHAR_EOF
chmod 0644 conv.c || echo "restore of conv.c fails"
sed 's/^X//' << 'SHAR_EOF' > doc.nr &&
X.\"/*%	nroff -cm -rL72 %|epson|spr -f plain.a -h uncdoc -w
X.nr Hb 7
X.nr Hs 3
X.ds HF 3 3 3 3 3 3 3
X.nr Hu 5
X.nr Hc 1
X.SA 1
X.PH "''A Disassembler''"
X.PF "'Issue %I%'- Page \\\\nP -'%G%'"
X.H 1 "Introduction"
XThis document describes the first release of a disassembler for UNIX
Xexecutable files.
XThe key features are:
X.AL
X.LI
XFor object files the output can be assembled to generate the same
Xobject module, (apart from minor variations in symbol table ordering) as the
Xinput.
X.LI
XFor stripped executable files object modules and libraries may be scanned,
Xmodules in the main input identified and the appropriate names automatically
Xinserted into the output.
X.LI
XAn option is available to convert most non-global names into local symbols,
Xwhich cuts down the symbols in the generated assembler file.
X.LI
XThe disassembler copes reasonably with modules merged with the
X.B "-r"
Xoption to
X.B "ld" ,
Xgenerating a warning message as to the number of modules involved.
X.LE
X.P
XAt present this is available for certain Motorola 68000 ports of UNIX
XSystem III and System V. Dependencies on
X.AL a
X.LI
XInstruction set.
X.LI
XObject module format.
X.LI
XLibrary module format.
X.LI
XAssembler output format.
X.LE
X.P
Xare hopefully sufficiently localised to make the product useful as a
Xbasis for other disassemblers for other versions of UNIX.
X.P
XThe product is thus distributed in source form at present.
X.H 1 "Use"
XThe disassembler is run by entering:
X.DS I
Xunc mainfile lib1 lib2 ...
X.DE
X.P
XThe first named file is the file to be disassembled, which should be
Xa single file, either an object module, a (possibly stripped) executable
Xfile, or a library member. Library members are designated using a
Xparenthesis notation, thus:
X.DS I
Xunc '/lib/libc.a(printf.o)'
X.DE
X.P
XIt is usually necessary to escape the arguments in this case to prevent
Xmisinterpretation by the shell. Libraries in standard places such as
X.I "/lib"
Xand
X.I "/usr/lib"
Xmay be specified in the same way as to
X.B "ld" ,
Xthus
X.DS I
Xunc '-lc(printf.o)'
Xunc '-lcurses(wmove.o)'
X.DE
X.P
XAs an additional facility, the list of directories searched for
Xlibraries may be varied by setting the environment variable
X.B "LDPATH" ,
Xwhich is interpreted similarly to the shell
X.B "PATH"
Xvariable, and of course defaults to
X.DS I
XLDPATH=/lib:/usr/lib
X.DE
X.P
XAs a further facility, the insertion of
X.B "lib"
Xbefore and
X.B ".a"
Xafter the argument may be suppressed by using a capital
X.B "-L"
Xargument, thus to print out the assembler for
X.I "/lib/crt0.o" ,
Xthen the command
X.DS I
Xunc -Lcrt0.o
X.DE
X.P
Xshould have the desired effect.
X.P
XSecond and subsequent file arguments are only referenced for stripped
Xexecutable files, and may consist of single object files and library
Xmembers, using the same syntax as before, or whole libraries of object
Xfiles, thus:
X.DS I
Xunc strippedfile -Lcrt0.o -lcurses -ltermcap '-lm(sqrt.o)' -lc
X.DE
X.P
XIt is advisable to make some effort to put the libraries to be searched
Xin the order in which they were originally loaded. This is because the
Xsearch for each module starts where the previously matched module ended.
XHowever, no harm is done if this rule is not adhered to apart from
Xincreased execution time except in the rare cases where the disassembler
Xis confused by object modules which are very nearly similar.
X.H 1 "Additional options"
XThe following options are available to modify the behaviour of the
Xdisassembler.
X.VL 15 2
X.LI "-o file"
XCauses output to be sent to the specified file instead of the standard
Xoutput.
X.LI "-t prefix"
XCauses temporary files to be created with the given prefix. The default
Xprefix is
X.B "split" ,
Xthus causing two temporary files to be created with this prefix in the
Xcurrent directory. If it is desired, for example, to create the files as
X.B "/tmp/xx*" ,
Xthen the argument
X.B "-t /tmp/xx"
Xshould be given. Note that the temporary files may be very large as a
Xcomplete map of the text and data segments is generated.
X.LI "-a"
XSuppresses the generation of non-global absolute symbols from the
Xoutput. This saves output from C compilations without any obvious
Xproblems, but the symbols are by default included in the name of
Xproducing as nearly identical output as possible to the original source.
X.LI "-s"
XCauses an additional scan to take place where all possible labels are
Xreplaced by local symbols. The local symbols are inserted in strictly
Xascending order, starting at 1.
X.LI "-v"
XCauses a blow-by-blow account of activities to be output on the standard
Xerror.
X.LI "-V"
XCauses shlib symbol values to be printed at the top of the output, if they
Xexist in the symbol table. normally these are ommited because they are constant
Xvalues derived form the file /lib/shlib.ifile
X.LE
X.H 1 "Diagnostics etc"
XTruncated or garbled object and library files usually cause processing
Xto stop with an explanatory message.
X.P
XThe only other kinds of message are some passing warnings concerning
Xobscure constructs not handled, such as the relocation of byte fields,
Xor the relocation of overlapping fields. Occasionally a message
X.DS I
XLibrary clash: message
X.DE
X.P
Xmay appear and processing cease. This message is found where at a late
Xstage in processing libraries, the program discovers that due to the
Xextreme similarity of two or more library members, it has come to the
Xwrong conclusion about which one to use. The remedy here is to spell out
Xto the program which members to take in which order.
X.H 1 "Future development"
XIn the future it is hoped to devise ways of making the disassembler
Xindependent of all the above-mentioned version dependencies, by first
Xreading a files defining these things. This will probably be applied
Xafter the Common Object Format becomes more standard.
X.P
XIn the long term it would be desirable and useful to enhance the product
Xto produce compilable C in addition to assemblable assembler. Stages in
Xthe process are seen as follows:
X.AL
X.LI
XBetter identification of basic blocks in the code. Switch statements are
Xa major problem here, as are constant data held in the text segment.
X.LI
XMarrying of data to the corresponding text. It is in various places hard
Xto divorce static references "on the fly" (e.g. strings, and switch
Xlists in some implementations) from static at the head of a module. This
Xis part of the problem of identifying basic blocks.
X.LI
XCompilation of header files to work out structure references within the
Xtext. At this stage some interaction may be needed.
X.LE
X.P
XMeanwhile the product is one which is a useful tool to the author in its
Xpresent form. Comments and suggestions as to the most practical method
Xof improving the product in the ways suggested or in other ways would be
Xgratefully considered.
SHAR_EOF
chmod 0644 doc.nr || echo "restore of doc.nr fails"
sed 's/^X//' << 'SHAR_EOF' > file.c &&
X/*
X *	SCCS:	@(#)file.c	1.2	11/2/84	14:17:35
X *	Various operations on files.
X *
X ***********************************************************************
X *	This software is copyright of
X *
X *		John M Collins
X *		47 Cedarwood Drive
X *		St Albans
X *		Herts, AL4 0DN
X *		England			+44 727 57267
X *
X *	and is released into the public domain on the following conditions:
X *
X *		1.  No free maintenance will be guaranteed.
X *		2.  Nothing may be based on this software without
X *		    acknowledgement, including incorporation of this
X *		    notice.
X *
X *	Notwithstanding the above, the author welcomes correspondence and bug
X *	fixes.
X ***********************************************************************
X */
X
X#include <stdio.h>
X#include <a.out.h>
X#include <ldfcn.h>
X#include "unc.h"
X	
Xlong	lseek();
Xvoid	unimpl();
X
X/*
X *	Validate addr and get text entry corresponding to it from the given
X *	file.
X */
X
Xvoid	gette(fid, addr, te)
Xregister  ef_fid  fid;
Xregister  long	addr;
Xt_entry	*te;
X{
X	addr -= fid->ef_tbase;
X	if  (addr < 0x300000 && 
X	     (addr < 0  ||  addr > fid->ef_tsize  || (addr & 1) != 0))  
X	 {
X	    (void) fprintf(stderr, "Invalid text address %lx\n", addr);
X	    exit(200);
X	 }
X	(void) lseek(fid->ef_t, (long)(addr * sizeof(t_entry)/2), 0);
X	if  (read(fid->ef_t, (char *) te, sizeof(t_entry)) != sizeof(t_entry))  {
X		(void) fprintf(stderr, "Trouble reading text at %lx\n", addr);
X		exit(201);
X	}
X}
X
X/*
X *	Store a text entry.
X */
X
Xvoid	putte(fid, addr, te)
Xregister  ef_fid  fid;
Xregister  long	addr;
Xt_entry	*te;
X{
X	addr -= fid->ef_tbase;
X	if  (addr < 0x300000 &&
X	     (addr < 0  ||  addr > fid->ef_tsize  ||  (addr & 1) != 0))
X	 {
X	    (void) fprintf(stderr, "Invalid text address %lx\n", addr);
X	    exit(200); 
X	 }
X	(void) lseek(fid->ef_t, (long)(addr * sizeof(t_entry)/2), 0);
X	(void) write(fid->ef_t, (char *) te, sizeof(t_entry));
X}
X
X/*
X *	Validate addr and get data entry corresponding to it from the given
X *	file.
X */
X
Xvoid	getde(fid, addr, de)
Xregister  ef_fid  fid;
Xregister  long	addr;
Xd_entry	*de;
X{
X	if  (addr < 0x300000 && (addr < fid->ef_dbase  ||  addr > fid->ef_end))
X	 {
X	    (void) fprintf(stderr, "Invalid data address %lx\n", addr);
X	    exit(200);
X	 }
X	addr -= fid->ef_dbase;
X	(void) lseek(fid->ef_d, (long)(addr * sizeof(d_entry)), 0);
X	if  (read(fid->ef_d, (char *) de, sizeof(d_entry)) != sizeof(d_entry))  {
X		(void) fprintf(stderr, "Trouble reading data at %lx\n", addr);
X		exit(201);
X	}
X}
X
X/*
X *	Store a data entry.
X */
X
Xvoid	putde(fid, addr, de)
Xregister  ef_fid  fid;
Xregister  long	addr;
Xd_entry	*de;
X{
X	if  (addr < 0x300000 &&
X	     (addr < fid->ef_dbase  ||  addr > fid->ef_end))
X	 {
X	    (void) fprintf(stderr, "Invalid data address %lx\n", addr);
X	    exit(200);
X	 }
X	addr -= fid->ef_dbase;
X	(void) lseek(fid->ef_d, (long)(addr * sizeof(d_entry)), 0);
X	(void) write(fid->ef_d, (char *) de, sizeof(d_entry));
X}
X
X/*
X *	Set type and length of given data entry.
X */
X
Xvoid	setde(fid, addr, type, lng)
Xef_fid	fid;
Xlong	addr;
Xunsigned  type;
Xint	lng;
X{
X	d_entry	dat;
X
X	if  (addr > fid->ef_end)
X		return;
X	getde(fid, addr, &dat);
X	if  (type == D_CONT  &&  dat.d_reloc != R_NONE)  {
X		char	obuf[30];
X		(void) sprintf(obuf, "overlapped reloc 0x%x", addr);
X		unimpl(obuf);
X	}
X	dat.d_type = type;
X	dat.d_lng = lng;
X	putde(fid, addr, &dat);
X}
X	
X/*
X *	Get a word of data file, size as requested.
X */
X
Xlong	getdw(fid, pos, size)
Xregister  ef_fid  fid;
Xlong	pos;
Xint	size;
X{
X	d_entry	dat;
X	register  long	res;
X	register  int	i, lt;
X	
X	getde(fid, pos, &dat);
X	
X	switch  (size)  {
X	case  R_BYTE:
X		return	dat.d_contents;
X		
X	case  R_LONG:
X		lt = 4;
X		goto  rest;
X		
X	case  R_WORD:
X		lt = 2;
X	rest:
X		res = dat.d_contents;
X		for  (i = 1;  i < lt; i++)  {
X			getde(fid, pos+i, &dat);
X			res = (res << 8) + dat.d_contents;
X		}
X		return	res;
X		
X	default:
X		(void) fprintf(stderr, "Data word size error\n");
X		exit(20);
X	}
X	/*NOTREACHED*/
X}
X
X/*
X *	Get a word of text file.
X */
X
Xlong	gettw(fid, pos, size)
Xregister  ef_fid  fid;
Xlong	pos;
Xint	size;
X{
X	t_entry	tex;
X	long	res;
X	
X	gette(fid, pos, &tex);
X	
X	switch  (size)  {
X	case  R_BYTE:
X		return	tex.t_contents >> 8;
X		
X	case  R_WORD:
X		return	tex.t_contents;
X		
X	case  R_LONG:
X		res = tex.t_contents;
X		gette(fid, pos+2, &tex);
X		return	(res << 16) + tex.t_contents;
X	default:
X		(void) fprintf(stderr, "Text< word size error\n");
X		exit(20);
X	}
X	/*NOTREACHED*/
X}
SHAR_EOF
chmod 0644 file.c || echo "restore of file.c fails"
sed 's/^X//' << 'SHAR_EOF' > heur.c &&
X/*
X *	SCCS:	@(#)heur.c	1.2	11/2/84	14:17:46
X *	Attempt to guess things about the file.
X *
X ***********************************************************************
X *	This software is copyright of
X *
X *		John M Collins
X *		47 Cedarwood Drive
X *		St Albans
X *		Herts, AL4 0DN
X *		England			+44 727 57267
X *
X *	and is released into the public domain on the following conditions:
X *
X *		1.  No free maintenance will be guaranteed.
X *		2.  Nothing may be based on this software without
X *		    acknowledgement, including incorporation of this
X *		    notice.
X *
X *	Notwithstanding the above, the author welcomes correspondence and bug
X *	fixes.
X ***********************************************************************
X */
X
X#include <stdio.h>
X#include <a.out.h>
X#include <ldfcn.h>
X#include "unc.h"
X
X#define	INITDAT	256
X#define	INCDAT	128
X
X#define	STRSCNT	3
X#define	STRECNT	3
X
Xchar	*malloc(), *realloc();
X
Xvoid	gette(), getde(), setde(), putte(), putde();
Xvoid	nomem();
Xlong	getdw();
Xsymbol	inventsymb();
X
Xlong	endt;
Xef_fids	mainfile;
X
X/*
X *	Talk about implemented things.....
X */
X
Xvoid	unimpl(msg)
Xchar	*msg;
X{
X	(void) fprintf(stderr, "Warning: handling of \"%s\" not implemented\n", msg);
X}
X
X/*
X *	Return 1 if string char, otherwise 0.
X */
X
Xint	possstr(x)
Xunsigned  x;
X{
X	if  (x >= ' '  &&  x <= '~')
X		return	1;
X	if  (x == '\n'  ||  x == '\t')
X		return	1;
X	return	0;
X}
X
X/*
X *	Guess things about data files.
X */
X
Xvoid	intudat(fid)
Xef_fid  fid;
X{
X	register  int	i, j;
X	int	lt, input, invcnt;
X	long	offs, soffs, endd;
X	d_entry	fdat;
X	unsigned  char	*inbuf;
X	int	ibsize;
X	
X	inbuf = (unsigned  char *)malloc(INITDAT);
X	if  (inbuf == NULL)
X		nomem();
X	ibsize = INITDAT;
X	
X	offs = fid->ef_dbase;
X	endd = fid->ef_bbase;
X
X	while  (offs < endd)  {
X		getde(fid, offs, &fdat);
X		if  (fdat.d_type != D_BYTE)  {
X			offs += fdat.d_lng;
X			continue;
X		}
X		
X		/*
X		 *	Looks like general data.  Read in as much as possible.
X		 */
X		
X		input = 0;
X		soffs = offs;
X		do  {
X			if  (input >= ibsize)  {
X				ibsize += INCDAT;
X				inbuf = (unsigned  char *)
X					realloc((char *)inbuf, (unsigned)ibsize);
X				if  (inbuf == NULL)
X					nomem();
X			}
X			inbuf[input++] = fdat.d_contents;
X			offs++;
X			if  (offs >= endd)
X				break;
X			getde(fid, offs, &fdat);
X		}  while  (fdat.d_type == D_BYTE && fdat.d_lab == NULL);
X		
X		/*
X		 *	Now split up the data.
X		 */
X		
X		for  (i = 0;  i < input;  )  {
X			
X			/*
X			 *	Might be a string.
X			 */
X			
X			if  (possstr(inbuf[i]))  {
X				lt = input;
X				if  (i + STRSCNT < lt)
X					lt = i + STRSCNT;
X				for  (j = i + 1;  j < lt;  j++)  {
X					if  (inbuf[j] == '\0')
X						break;
X					if  (!possstr(inbuf[j]))
X						goto  notstr;
X				}
X				
X				/*
X				 *	Looks like a string then.
X				 */
X				
X				invcnt = 0;
X				for  (j = i + 1; j < input;  j++)  {
X					if  (inbuf[j] == '\0')  {
X						j++;
X						break;
X					}
X					if  (possstr(inbuf[j]))
X						invcnt = 0;
X					else  {
X						invcnt++;
X						if  (invcnt >= STRECNT)  {
X							j -= invcnt - 1;
X							break;
X						}
X					}
X				}
X
X				setde(fid,
X				      soffs+i,
X				      (unsigned)(inbuf[j-1]=='\0'?D_ASCZ:D_ASC),
X				      j - i);
X				for  (i++;  i < j;  i++)
X					setde(fid, soffs+i, D_CONT, 1); 
X				continue;
X			}
X
Xnotstr:
X			/*
X			 *	If on odd boundary, treat as a byte.
X			 */
X			
X			if  ((soffs + i) & 1  ||  i + 1 >= input)  {
X				setde(fid, soffs + i, D_BYTE, 1);
X				i++;
X				continue;
X			}
X
X			/*
X			 *	Treat as longs unless not enough.
X			 */
X			
X			if  (i + 3 >= input)  {
X				setde(fid, soffs + i, D_WORD, 2);
X				setde(fid, soffs + i + 1, D_CONT, -1);
X				i += 2;
X				continue;
X			}
X
X			/*
X			 *	Treat as a long but mark changable.
X			 */
X			
X			setde(fid, soffs + i, D_LONG, 4);
X			for  (j = 1;  j < 4;  j++)
X				setde(fid, soffs + i + j, D_CONT, -j);
X			i += 4;
X		}
X	}
X	free((char *)inbuf);
X	
X	/*
X	 *	Now zap bss segment.
X	 */
X	
X	offs = fid->ef_bbase;
X	endd = fid->ef_end;
X
X	while  (offs < endd)  {
X		getde(fid, offs, &fdat);
X		if  (fdat.d_type != D_BYTE)  {
X			offs += fdat.d_lng;
X			continue;
X		}
X
X		soffs = offs;
X		do  {
X			offs++;
X			if  (offs >= endd)
X				break;
X			getde(fid, offs, &fdat);
X		}  while  (fdat.d_type == D_BYTE && fdat.d_lab == NULL);
X		
X		setde(fid, soffs, D_BYTE, (int)(offs-soffs));
X		for  (i = -1, soffs++;  soffs < offs; i--, soffs++)
X			setde(fid, soffs, D_CONT, i); 
X	}
X}
X
X/*
X *	For non relocatable files, try to identify address pointers in
X *	the data.
X */
X
Xvoid	inturdat(fid)
Xef_fid	fid;
X{
X	register  long	offs = fid->ef_dbase;
X	register  int	i;
X	register  symbol  ds;
X	long  endd = fid->ef_bbase;
X	long  cont;
X	d_entry	dent, refdent;
X
X	while  (offs < endd)  {
X		getde(fid, offs, &dent);
X		if  (dent.d_type != D_LONG)
X			goto  endit;
X		cont = getdw(fid, offs, R_LONG);
X		if  (cont < fid->ef_dbase || cont > fid->ef_end)
X			goto  endit;
X		getde(fid, cont, &refdent);
X		if  (refdent.d_type == D_CONT)  {
X			d_entry	pdent;
X			int	siz;
X			
X			if  (refdent.d_lng >= 0)
X				goto  endit;
X			getde(fid, cont+refdent.d_lng, &pdent);
X			i = -refdent.d_lng;
X			refdent.d_lng += pdent.d_lng;
X			pdent.d_lng = i;
X			if  (pdent.d_type == D_LONG  &&  i == 2)
X				siz = D_WORD;
X			else
X				siz = D_BYTE;
X			refdent.d_type = siz;
X			pdent.d_type = siz;
X			putde(fid, cont - i, &pdent);
X			for  (i = 1;  i < refdent.d_lng;  i++)
X				setde(fid, cont+i, D_CONT, -i);
X		}
X		if  ((ds = refdent.d_lab) == NULL)  {
X			if  (cont >= fid->ef_bbase)  {
X				ds = inventsymb("BS");
X				ds->s_type = S_BSS;
X			}
X			else  {
X				ds = inventsymb("DS");
X				ds->s_type = S_DATA;
X			}
X			ds->s_value = cont;
X			refdent.d_lab = ds;
X			putde(fid, cont, &refdent);
X		}
X		else
X			ds->s_used++;
X		dent.d_type = D_ADDR;
X		dent.d_relsymb = ds;
X		dent.d_rptr = ds->s_type;
X		putde(fid, offs, &dent);
X		for  (i = 1;  i < 4;  i++)
X			setde(fid, offs+i, D_CONT, 1);
Xendit:
X		offs += dent.d_lng;
X	}
X}
X
X/*
X *	Recursively follow through the code, stopping at unconditional
X *	branches and invalid instructions.
X */
X
Xvoid	follseq(pos)
Xlong	pos;
X{
X	t_entry	tent;
X	int	lng;
X	long	npos;
X
X	while  (pos < endt)  {
X		gette(&mainfile, pos, &tent);
X		if  (tent.t_amap)	/*  Been here  */
X			return;
X		tent.t_amap = 1;
X		lng = findinst(&tent, pos);
X		npos = pos + lng*2;
X		if  (npos > endt)  {
X			tent.t_vins = 0;
X			tent.t_lng = 1;
X			tent.t_type = T_UNKNOWN;
X			lng = 0;
X			npos = endt;
X		}
X		putte(&mainfile, pos, &tent);
X		pos = npos;
X		
X		if  (lng <= 0)
X			return;
X
X		switch  (tent.t_bchtyp)  {
X		case  T_UNBR:
X			if  (tent.t_relsymb == NULL)
X				return;
X			pos = tent.t_relsymb->s_value;
X			continue;
X		case  T_JSR:
X			if  (tent.t_relsymb != NULL)
X				follseq(tent.t_relsymb->s_value);
X			continue;
X		case  T_CONDBR:
X			follseq(tent.t_relsymb->s_value);
X		default:
X			continue;
X		}
X	}
X}
X			
X			
X/*
X *	Try to work out things about text files.
X */
X
Xvoid	intutext()
X{
X	long	pos;
X	t_entry	tent;
X	int	lng;
X	
X	endt = mainfile.ef_tbase + mainfile.ef_tsize;
X	pos = mainfile.ef_entry;
Xnextv:
X	for  (;  pos < endt;)  {
X		gette(&mainfile, pos, &tent);
X		if  (!tent.t_amap && tent.t_vins)  {
X			follseq(pos);
X			pos += 2;
X			goto  nextiv;
X		}
X		pos += tent.t_lng * 2;
X		if  (tent.t_bchtyp == T_UNBR)
X			goto  nextiv;
X	}
X	goto	dorest;
Xnextiv:
X	for  (;  pos < endt;  pos += 2)  {
X		gette(&mainfile, pos, &tent);
X		if  (tent.t_bdest)
X			goto  nextv;
X	}
Xdorest:
X	/*
X	 *	Deal with unmapped instructions.
X	 */
X	
X 	for  (pos = mainfile.ef_tbase;  pos < endt;)  {
X		gette(&mainfile, pos, &tent);
X		switch  (tent.t_type)  {
X		case  T_BEGIN:
X			pos += tent.t_lng * 2;
X			continue;
X		case  T_UNKNOWN:
X			if  (tent.t_vins)  {
X				lng = findinst(&tent, pos);
X				putte(&mainfile, pos, &tent);
X				if  (lng > 0)  {
X					pos += lng * 2;
X					continue;
X				}
X			}
X		default:
X			pos += 2;
X			continue;
X		}
X	}
X}
X
X/*
X *	Invent local symbols.
X */
X
Xvoid	intlsym()
X{
X	long	bpos, epos, hiref, hipos;
X	unsigned  llnum;
X	t_entry	tent;
X	register  symbol  tl;
X	
X	endt = mainfile.ef_tbase + mainfile.ef_tsize;
X	epos = mainfile.ef_entry;
X	for  (;;)  {
X		bpos = epos;
X		hiref = bpos;
X		if  (epos >= endt)
X			return;
X		gette(&mainfile, epos, &tent);
X		epos += tent.t_lng * 2;
X		for  (;  epos < endt;)  {
X			gette(&mainfile, epos, &tent);
X			if  (tent.t_gbdest  ||  tent.t_dref)
X				break;
X			if  (tent.t_reflo < bpos)
X				break;
X			if  (tent.t_refhi > hiref)  {
X				hiref = tent.t_refhi;
X				hipos = epos;
X			}
X			epos += tent.t_lng * 2;
X		}
X		if  (hiref > epos)
X			epos = hipos;
X		llnum = 0;
X		for  (hipos = bpos;  hipos < epos;)  {
X			gette(&mainfile, hipos, &tent);
X			if  (!tent.t_gbdest && !tent.t_dref &&
X			 tent.t_reflo >= bpos && tent.t_refhi < epos &&
X			 (tl = tent.t_lab) != NULL)
X				tl->s_lsymb = ++llnum;
X			hipos += tent.t_lng * 2;
X		}
X	}
X}
X
X/*
X *	Given the main file, a possible candidate for matching in the
X *	file and an offset, see if text matches.  Return 1 if matches,
X *	or 0 if no match.
X */
X
Xint	matchup(mf, lf, startpos)
Xregister  ef_fid  mf, lf;
Xlong	startpos;
X{
X	register  int	i, matches = 0;
X	t_entry	ltent, mtent;
X
X	if  (lf->ef_tsize > mf->ef_tsize - startpos + mf->ef_tbase)
X		return	0;	/*  At end - can't fit  */
X
X	for  (i = 0;  i < lf->ef_tsize;  i += 2)  {
X		gette(lf, lf->ef_tbase + i, &ltent);
X		if  (ltent.t_isrel)
X			continue;
X		gette(mf, startpos + i, &mtent);
X		if  (mtent.t_contents != ltent.t_contents)
X			return	0;
X		matches++;
X	}
X	
X	/*
X	 *	Give up on zero length or all relocatable files.
X	 */
X	
X	return	matches > 0;
X}
X
X/*
X *	Scan through main file looking for a match.
X */
X
Xlong	findstart(mf, lf)
Xregister  ef_fid  mf, lf;
X{
X	register  long	res = mf->ef_tbase;
X	long	lim = mf->ef_tbase + mf->ef_tsize - lf->ef_tsize;
X	t_entry	tent;
X	
Xrestart:
X	for  (;  res <= lim;  res += 2)  {
X		gette(mf, res, &tent);
X		if  (tent.t_match != 0)  {
X			res += tent.t_match;
X			goto  restart;
X		}
X		if  (matchup(mf, lf, res))
X			return	res;
X	}
X	return	-1;
X}
X
X/*
X *	Mark the head of a matched module to save searching.
X */
X
Xvoid	markmatch(mf, lf, pos)
Xef_fid	mf, lf;
Xlong	pos;
X{
X	t_entry	tent;
X	
X	gette(mf, pos, &tent);
X	tent.t_match = (unsigned) lf->ef_tsize;
X	putte(mf, pos, &tent);
X}
SHAR_EOF
chmod 0644 heur.c || echo "restore of heur.c fails"
sed 's/^X//' << 'SHAR_EOF' > main.c &&
X/*
X *	SCCS:	@(#)main.c	1.2	11/2/84	14:19:31
X *	Main routine etc.
X *
X ***********************************************************************
X *	This software is copyright of
X *
X *		John M Collins
X *		47 Cedarwood Drive
X *		St Albans
X *		Herts, AL4 0DN
X *		England			+44 727 57267
X *
X *	and is released into the public domain on the following conditions:
X *
X *		1.  No free maintenance will be guaranteed.
X *		2.  Nothing may be based on this software without
X *		    acknowledgement, including incorporation of this
X *		    notice.
X *
X *	Notwithstanding the above, the author welcomes correspondence and bug
X *	fixes.
X ***********************************************************************
X */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <a.out.h>
X#include <ldfcn.h>
X#include "unc.h"
X
X#define	LINELNG	70
X
Xvoid	inturdat(), intutext(), intudat(), intlsym();
Xvoid	ptext(), pdata(), pabs(), pbss(), lscan();
X
Xef_fids	mainfile;
X
Xint	nmods;			/*  Number of modules it looks like  */
X
Xchar	*tfnam = "split";
X
Xchar	lsyms;			/*  Generate local symbols  */
Xchar	verbose;		/*  Tell the world what we are doing  */
Xchar	noabs;			/*  No non-global absolutes  */
Xint	rel;			/*  File being analysed is relocatable  */
Xint	lpos;
Xchar    shlibout;		/*  output values for shlib constants */
X
Xsymbol	dosymb();
Xstruct	libit	*getfnam();
X
X/*
X *	Get hex characters, also allowing for 'k' and 'm'.
X */
X
Xint	ghex(str)
Xregister  char	*str;
X{
X	register  int	result = 0;
X	register  int	lt;
X
X	for  (;;)  {
X		lt = *str++;
X		switch  (lt)  {
X		default:
Xerr:			(void) fprintf(stderr, "Invalid hex digit \'%c\'\n", lt);
X			exit(1);
X			
X		case '\0':
X			return	result;
X			
X		case '0':case '1':case '2':case '3':case '4':
X		case '5':case '6':case '7':case '8':case '9':
X			result = (result << 4) + lt - '0';
X			continue;
X			
X		case 'a':case 'b':case 'c':case 'd':case 'e':case 'f':
X			result = (result << 4) + lt - 'a' + 10;
X			continue;
X
X		case 'A':case 'B':case 'C':case 'D':case 'E':case 'F':
X			result = (result << 4) + lt - 'A' + 10;
X			continue;
X		
X		case 'k':case 'K':
X			if  (*str != '\0')
X				goto  err;
X			return  result << 10;
X			
X		case 'm':case 'M':
X			if  (*str != '\0')
X				goto  err;
X			return  result << 20;
X		}
X	}
X}
X
X/*
X *	Process entry line options.  Return number dealt with.
X */
X
Xint	doopts(av)
Xchar	*av[];
X{
X	register  int	cnt = 0, lt;
X	register  char	*arg;
X	
X	for  (;;)  {
X		arg = *++av;
X		if  (*arg++ != '-')
X			return	cnt;
X		cnt++;
X		
Xnx:		switch  (lt = *arg++)  {
X		default:
X			(void) fprintf(stderr, "Bad option -%c\n", lt);
X			exit(1);
X			
X		case  '\0':
X			continue;
X			
X		case  'l':	/*  A file name  */
X		case  'L':
X			return	cnt - 1;
X			
X		case  's':
X			lsyms++;
X			goto  nx;
X			
X		case  'v':
X			verbose++;
X			goto  nx;
X
X		case  'V':
X			shlibout++;
X			goto  nx;
X
X		case  'a':
X			noabs++;
X			goto  nx;
X
X		case  't':
X			if  (*arg == '\0')  {
X				cnt++;
X				arg = *++av;
X				if  (arg == NULL) {
Xbo:					(void) fprintf(stderr,"Bad -%c option\n",lt);
X					exit(1);
X 				      }
X			}
X			tfnam = arg;
X			continue;
X			
X		case  'o':
X			if  (*arg == '\0')  {
X				cnt++;
X				arg = *++av;
X				if  (arg == NULL)
X					goto  bo;
X			}
X			if  (freopen(arg, "w", stdout) == NULL)  {
X				(void) fprintf(stderr, "Help! cant open %s\n", arg);
X				exit(20);
X			}
X			continue;
X		}
X	}
X}
X	
X/*
X *	Open binary files.  Arrange to erase them when finished.
X */
X
Xvoid	bfopen(nam, fid)
Xchar	*nam;
Xef_fid	fid;
X{
X	char	fnam[80];
X	
X	(void) sprintf(fnam, "%s.tx", nam);
X	if  ((fid->ef_t = open(fnam, O_RDWR|O_CREAT, 0666)) < 0)  {
Xefil:		(void) fprintf(stderr, "Help could not open %s\n", fnam);
X		exit(4);
X	}
X	(void) unlink(fnam);
X	(void) sprintf(fnam, "%s.dt", nam);
X	if  ((fid->ef_d = open(fnam, O_RDWR|O_CREAT, 0666)) < 0)
X		goto  efil;
X	(void) unlink(fnam);
X}
X
X/*
X *	Close binary files.  They should get zapped anyway.
X */
X
Xvoid	bfclose(fid)
Xef_fid	fid;
X{
X	(void) close(fid->ef_t);
X	(void) close(fid->ef_d);
X}
X
X/*
X *	Main routine.
X */
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	int	i;
X	char	*progname = argv[0];
X	char	*msg;
X	register  struct  libit  *lfd;
X	
X	setbuf(stdout,NULL);
X	setbuf(stderr,NULL);
X
X	i = doopts(argv);
X	argc -= i;
X	argv += i;
X	
X	if  (argc < 2)  {
X		(void) fprintf(stderr, "Usage: %s [ options ] file\n", progname);
X		exit(1);
X	}
X	
X	lfd = getfnam(argv[1]);
X	if  (TYPE(lfd->ldptr) == ARTYPE)  {
X		(void) fprintf(stderr, "Main file (%s) cannot be library\n", argv[1]);
X		exit(2);
X	}
X	
X	bfopen(tfnam, &mainfile);
X	if  (verbose)
X		(void) fprintf(stderr, "Scanning text\n");
X	if  (!rtext(lfd->ldptr, &mainfile))  {
X		msg = "text";
Xbf:		(void) fprintf(stderr, "Bad format input file - reading %s\n", msg);
X		exit(5);
X	}
X	if  (verbose)
X		(void) fprintf(stderr, "Scanning data\n");
X	if  (!rdata(lfd->ldptr, &mainfile))  {
X		msg = "data";
X		goto  bf;
X	}
X	if  (verbose)
X		(void) fprintf(stderr, "Scanning symbols\n");
X	if  (!rsymb(lfd->ldptr, dosymb, &mainfile))  {
X		msg = "symbols";
X		goto  bf;
X	}
X	if  (verbose)
X		(void) fprintf(stderr, "Scanning for relocation\n");
X	if  ((rel = rrel(lfd->ldptr, lfd->ldptr2, &mainfile)) < 0)  {
X		msg = "reloc";
X		goto  bf;
X	}
X	
X	if  (rel)  {
X		if  (verbose)
X			(void) fprintf(stderr, "File is relocatable\n");
X		if  (argc > 2)
X			(void) fprintf(stderr, "Sorry - no scan on reloc files\n");
X	}
X	else
X		lscan(argc - 2, &argv[2]);
X
X	if  (verbose)
X		(void) fprintf(stderr, "End of input\n");
X	
X	ldaclose(lfd->ldptr2);
X	ldclose(lfd->ldptr);
X	if  (nmods > 0)
X		(void) fprintf(stderr, "Warning: at least %d merged modules\n",
X			nmods + 1);
X
X	if  (mainfile.ef_stvec != NULL)  {
X		free(mainfile.ef_stvec);
X		mainfile.ef_stvec = NULL;
X		mainfile.ef_stcnt = 0;
X	}
X	
X	if  (verbose)
X		(void) fprintf(stderr, "Text anal 1\n");
X	intutext();
X	if  (verbose)
X		(void) fprintf(stderr, "Data anal 1\n");
X	intudat(&mainfile);
X	if  (!rel)  {
X		if  (verbose)
X			(void) fprintf(stderr, "Data anal 2\n");
X		inturdat(&mainfile);
X	}
X	if  (lsyms)  {
X		if  (verbose)
X			(void) fprintf(stderr, "Local symbol scan\n");
X		intlsym();
X	}
X	pabs();
X	ptext(&mainfile);
X	pdata(&mainfile);
X	pbss(&mainfile);
X	bfclose(&mainfile);
X	exit(0);
X}
SHAR_EOF
chmod 0644 main.c || echo "restore of main.c fails"
sed 's/^X//' << 'SHAR_EOF' > prin.c &&
X/*
X *	SCCS:	@(#)prin.c	1.2	11/2/84	14:19:47
X *	Print stuff.
X *
X ***********************************************************************
X *	This software is copyright of
X *
X *		John M Collins
X *		47 Cedarwood Drive
X *		St Albans
X *		Herts, AL4 0DN
X *		England			+44 727 57267
X *
X *	and is released into the public domain on the following conditions:
X *
X *		1.  No free maintenance will be guaranteed.
X *		2.  Nothing may be based on this software without
X *		    acknowledgement, including incorporation of this
X *		    notice.
X *
X *	Notwithstanding the above, the author welcomes correspondence and bug
X *	fixes.
X ***********************************************************************
X */
X
X#include <stdio.h>
X#include <a.out.h>
X#include <ldfcn.h>
X#include "unc.h"
X
X#define	LINELNG	70
X
Xvoid	gette(), getde();
Xlong	gettw(), getdw();
Xvoid	prinst();
X
Xchar	noabs;			/*  No non-global absolutes  */
Xint	rel;			/*  File being analysed is relocatable  */
Xint	lpos;
X
Xstruct	commit	abstab, comtab;
Xextern char shlibout;
X
X/*
X *	Print absolute and common values.
X */
X
Xvoid	pabs()
X{
X	register  int	i;
X	register  symbol  cs;
X
X	for  (i = 0;  i < abstab.c_int;  i++)
X	
X	for  (i = 0;  i < abstab.c_int;  i++)  {
X		cs = abstab.c_symb[i];
X		if (cs->s_value >= 0x300000 && ! shlibout)
X			continue;
X		if  (cs->s_glob)
X			(void) printf("#\tglobal\t%s\n", cs->s_name);
X		else  if  (noabs)
X			continue;
X		(void) printf("# %s\t= 0x%lx\n", cs->s_name, cs->s_value);
X	}
X	for  (i = 0;  i < comtab.c_int;  i++)  {
X		cs = comtab.c_symb[i];
X		(void) printf("\tcomm\t%s,%d\n", cs->s_name, cs->s_value);
X	}
X}
X
X/*
X *	Print out labels.
X */
X
Xvoid	plabs(ls, seg)
Xregister  symbol  ls;
Xint	seg;
X{
X	for  (; ls != NULL;  ls = ls->s_link)  {
X		if  (ls->s_type != seg)
X			continue;
X		if  (ls->s_lsymb)  {
X			(void) printf("L%%%u:\n", ls->s_lsymb);
X			return;		/*  Set last  */
X		}
X		if  (ls->s_glob)
X			(void) printf("\n\tglobal\t%s", ls->s_name);
X		if (ls->s_name[0] == '.')
X			(void) printf("\n# %s:\n", ls->s_name);
X		else
X			(void) printf("\n%s:\n", ls->s_name);
X	}
X}
X
X/*
X *	Print out text.
X */
X
Xvoid	ptext(fid)
Xregister  ef_fid  fid;
X{
X	register  long	tpos, endt;
X	t_entry	tstr;
X
X	(void) fputs("\ttext\n", stdout);
X	
X	tpos = fid->ef_tbase;
X	endt = tpos + fid->ef_tsize;
Xcontin:	
X	for  (;  tpos < endt;  tpos += tstr.t_lng * 2)  {
X		gette(fid, tpos, &tstr);
X		plabs(tstr.t_lab, S_TEXT);
X		if  (tstr.t_type == T_BEGIN)
X			prinst(&tstr, tpos);
X		else  if  (tstr.t_relsymb != NULL)  {
X			(void) printf("\tlong\t%s", tstr.t_relsymb->s_name);
X			if  (tstr.t_relsymb->s_type!=S_TEXT &&
X				tstr.t_relsymb->s_type!=S_DATA)
X				(void) printf("+0x%x", gettw(fid, tpos, R_LONG));
X			(void) putchar('\n');
X			tpos += 4;
X			goto  contin;
X		}
X		else
X			(void) printf("\tshort\t0x%x\n", tstr.t_contents);
X	}
X
X	/*
X	 *	Print out any trailing label.
X	 */
X	
X	gette(fid, tpos, &tstr);
X	plabs(tstr.t_lab, S_TEXT);
X}
X
X/*
X *	Print out data.
X */
X
Xvoid	pdata(fid)
Xregister  ef_fid  fid;
X{
X	register  long	dpos, endd;
X	register  int	lng, ccnt;
X	unsigned  ctyp;
X	int	had, par, inc;
X	char	*msg;
X	d_entry	dstr;
X	
X	(void) fputs("\n\tdata\n", stdout);
X	
X	dpos = fid->ef_dbase;
X	endd = dpos + fid->ef_dsize;
X
X	while  (dpos < endd)  {
X		
X		getde(fid, dpos, &dstr);
X		plabs(dstr.d_lab, S_DATA);
X			
X		switch  (dstr.d_type)  {
X		case  D_CONT:
X			(void) fprintf(stderr, "Data sync error\n");
X			dpos++;
X			break;
X			
X		case  D_ASC:
X		case  D_ASCZ:
X			ctyp = dstr.d_type;
X			lng = dstr.d_lng;
X		nextline:
X			(void) fputs("\tbyte\t", stdout);
X			ccnt=0;
X			while  (lng > 0)  {
X				if (ccnt) (void) putchar(',');
X				getde(fid, dpos, &dstr);
X				switch  (dstr.d_contents)  {
X				default:
X					if  (dstr.d_contents < ' ' ||
X						dstr.d_contents > '~')
X						ccnt += printf("0x%x", dstr.d_contents);
X					else {
X						(void) putchar('\'');
X						(void)putchar(dstr.d_contents);
X						ccnt += 2;
X					}
X					break;
X				case  '\\':
X					(void) putchar('\'');
X					(void) putchar('\\');
X					(void) putchar('\\');
X					ccnt+=2;
X					break;
X				case  '\b':
X					(void) putchar('\'');
X					(void) putchar('\\');
X					(void) putchar('b');
X					ccnt+=2;
X					break;
X				case  '\n':
X					(void) putchar('\'');
X					(void) putchar('\\');
X					(void) putchar('n');
X					ccnt+=2;
X					break;
X				case  '\r':
X					(void) putchar('\'');
X					(void) putchar('\\');
X					(void) putchar('r');
X					ccnt+=2;
X					break;
X				case  '\f':
X					(void) putchar('\'');
X					(void) putchar('\\');
X					(void) putchar('f');
X					ccnt+=2;
X					break;
X				case  '\t':
X					(void) putchar('\'');
X					(void) putchar('\\');
X					(void) putchar('t');
X					ccnt+=2;
X					break;
X				}
X
X				lng--;
X				dpos++;
X				if (++ccnt > 40 && lng > 0) {
X					(void) putchar('\n');
X					goto nextline;
X				}
X			}
X			(void) putchar('\n');
X			break;
X
X		case  D_BYTE:
X			msg = "byte";
X			par = R_BYTE;
X			inc = 1;
X			goto  wrest;
X			
X		case  D_WORD:
X			msg = "short";
X			par = R_WORD;
X			inc = 2;
X			goto  wrest;
X			
X		case  D_LONG:
X			msg = "long";
X			par = R_LONG;
X			inc = 4;
X		wrest:
X			(void) putchar('\t');
X			(void) fputs(msg, stdout);
X			(void) putchar('\t');
X			lng = dstr.d_lng;
X			lpos = 16;
X			had = 0;
X			while  (lng > 0)  {
X				if  (lpos > LINELNG) {
X					(void) putchar('\n');
X					(void) putchar('\t');
X					(void) fputs(msg, stdout);
X					(void) putchar('\t');
X					lpos = 16;
X				}
X				else  if  (had) {
X					(void) putchar(',');
X					(void) putchar(' ');
X					lpos += 2;
X				}
X				lpos += printf("0x%x", getdw(fid, dpos, par));
X				lng -= inc;
X				dpos += inc;
X				had++;
X			}
X			(void) putchar('\n');
X			break;
X
X		case  D_ADDR:
X			(void) fputs("\tlong\t", stdout);
X			lng = dstr.d_lng;
X			lpos = 16;
X			had = 0;
X			while  (lng > 0)  {
X				if  (lpos > LINELNG)  {
X					(void) fputs("\n\tlong\t", stdout);
X					lpos = 16;
X				}
X				else  if  (had) {
X					(void) putchar(',');
X					(void) putchar(' ');
X					lpos += 2;
X				}
X
X				getde(fid, dpos, &dstr);
X				lpos += printf("%s", dstr.d_relsymb->s_name);
X				lng -= sizeof(long);
X				dpos += sizeof(long);
X				had++;
X			}
X			(void) putchar('\n');
X			break;
X		}
X	}
X	
X	/*
X	 *	Print trailing label.
X	 */
X	
X	getde(fid, dpos, &dstr);
X	plabs(dstr.d_lab, S_DATA);
X}
X
Xvoid	pbss(fid)
Xregister  ef_fid  fid;
X{
X	register  long	bpos = fid->ef_bbase;
X	long	endb = fid->ef_end;
X	d_entry	bstr;
X	
X	(void) fputs("\n# .bss\n", stdout);
X	
X	while  (bpos < endb)  {
X		getde(fid, bpos, &bstr);
X		plabs(bstr.d_lab, S_BSS);
X		(void) printf("\tspace\t%d\n", bstr.d_lng);
X		bpos += bstr.d_lng;
X	}
X	
X	getde(fid, endb, &bstr);
X	plabs(bstr.d_lab, S_BSS);
X}
X
X
SHAR_EOF
chmod 0644 prin.c || echo "restore of prin.c fails"
sed 's/^X//' << 'SHAR_EOF' > unc.h &&
X/*
X *	SCCS:	@(#)unc.h	1.2	11/2/84	14:21:02
X *	Header file for uncompile program.
X *
X ***********************************************************************
X *	This software is copyright of
X *
X *		John M Collins
X *		47 Cedarwood Drive
X *		St Albans
X *		Herts, AL4 0DN
X *		England			+44 727 57267
X *
X *	and is released into the public domain on the following conditions:
X *
X *		1.  No free maintenance will be guaranteed.
X *		2.  Nothing may be based on this software without
X *		    acknowledgement, including incorporation of this
X *		    notice.
X *
X *	Notwithstanding the above, the author welcomes correspondence and bug
X *	fixes.
X ***********************************************************************
X */
X
X#define	MAXCHARS	50
X#define	HASHMOD		97
X
X/*
X *	The following structure is used to keep track of symbols.
X */
X
Xstruct	symstr	{
X	struct	symstr	*s_next;		/*  Next in hash chain  */
X	struct	symstr	*s_link;		/*  Next in duplicate labels */
X	unsigned	s_type	:  5;		/*  Symbol type  */
X	unsigned	s_newsym:  1;		/*  A new symbol  */
X	unsigned	s_invent:  1;		/*  Invented symbol  */
X	unsigned	s_glob	:  1;		/*  Global symbol  */
X	long		s_value;		/*  Value if defined  */
X	short		s_defs;			/*  Defined count  */
X	short		s_used;			/*  Used count  */
X	unsigned short	s_lsymb;		/*  Local symbol  */
X	char		s_name[1];		/*  Chars of name null term */
X};
X
Xtypedef	struct	symstr	*symbol;
X
Xsymbol	symbhash[HASHMOD];
X
Xtypedef	struct	{
X	int	ef_t;			/*  Text file fd  */
X	int	ef_d;			/*  Data file fd  */
X	long	ef_entry;		/*  Entry point  */
X	long	ef_tsize;		/*  Text size  */
X	long	ef_dsize;		/*  Data size  */
X	long	ef_bsize;		/*  Bss size  */
X	long	ef_end;			/*  End of it all  */
X	long	ef_tbase;		/*  Text base  */
X	long	ef_dbase;		/*  Data base  */
X	long	ef_bbase;		/*  Bss base  */
X	int	ef_stcnt;		/*  Number of symbols  */
X	int	ef_stmax;		/*  Max number of symbols  */
X	symbol	*ef_stvec;		/*  Symbol vector  */
X}  ef_fids;
X
Xtypedef	ef_fids	*ef_fid;
X
X/*
X *	Description of word in text file.  This entry is held in the place
X *	corresponding to the address in the text file.
X */
X
Xtypedef	struct	{
X	unsigned  short	t_contents;		/*  Actual contents  */
X	unsigned  short t_iindex;		/*  Index in table  */
X	unsigned	t_type	:  2;		/*  Type  */
X	unsigned	t_vins  :  1;		/*  Valid instruction  */
X	unsigned	t_bdest	:  1;		/*  Is branch dest  */
X	unsigned	t_gbdest:  1;		/*  Is global dest  */
X	unsigned	t_dref	:  1;		/*  Refered to in data  */
X	unsigned	t_bchtyp:  2;		/*  Branch type  */
X	unsigned	t_zilch	:  3;		/*  used to be t_lng */
X	unsigned	t_reloc :  2;		/*  Relocatable  */
X	unsigned	t_rptr	:  2;		/*  Where relocated  */
X	unsigned	t_rdisp :  1;		/*  Relocatable displacement */
X	unsigned	t_isrel :  1;		/*  Relocated  */
X	unsigned	t_amap	:  1;		/*  Worked out  */
X	short		t_lng;			/*  Length in words */
X	symbol		t_relsymb;		/*  Relocation symbol  */
X	long		t_reldisp;		/*  Offset + or - from symb */
X	symbol		t_lab;			/*  Label  */
X	unsigned  short	t_lsymb;		/*  Local symbol  */
X	long		t_reflo;		/*  Lowest place referred  */
X	long		t_refhi;		/*  Highest place referred  */
X	unsigned  short	t_match;		/*  Lib match lng  */
X}  t_entry;
X
X/*
X *	Types ......
X */
X
X#define	T_UNKNOWN	0
X#define	T_BEGIN		1
X#define	T_CONT		2
X
X#define	R_NONE		0		/*  No relocation  */
X#define	R_BYTE		1		/*  Byte relocation  */
X#define	R_WORD		2		/*  Word relocation  */
X#define	R_LONG		3		/*  Long relocation  */
X
X/*
X *	Branch types.
X */
X
X#define	T_NOBR		0
X#define	T_CONDBR	1
X#define	T_UNBR		2
X#define	T_JSR		3
X
Xtypedef	struct	{
X	unsigned  char	d_contents;		/*  Actual contents  */
X	unsigned	d_type  :  4;		/*  Data type  */
X	unsigned	d_reloc :  2;		/*  Relocatable  */
X	unsigned	d_rptr	:  2;		/*  Where relocated  */
X	short		d_lng;			/*  Length -ve for D_CONT */
X	symbol		d_relsymb;		/*  Relocation symbol  */
X	long		d_reldisp;		/*  Offset + or - from symb */
X	symbol		d_lab;			/*  Label  */
X}  d_entry;
X
X/*
X *	Data types.
X */
X
X#define	D_ASC		0		/*  Ascii chars  */
X#define	D_ASCZ		1		/*  Null-term ascii  */
X#define	D_BYTE		2		/*  Decimal bytes  */
X#define	D_WORD		3		/*  Words  */
X#define	D_LONG		4		/*  Longs  */
X#define	D_ADDR		5		/*  Address pointer  */
X#define	D_CONT		6		/*  Continuation of last  */
X
X/*
X *	'Common' items.
X */
X
Xstruct	commit	{
X	symbol	*c_symb;		/*  List of symbols  */
X	int	c_int;			/*  Current number  */
X	int	c_max;			/*  Maximum  */
X};
X
X/*
X *	Library file description.
X */
X
Xstruct	libit	{
X	LDFILE *ldptr,*ldptr2;		/*  independent file pointer packages
X					    for the same file */
X	char	lf_name[14];		/*  Name of item  */
X};
X
X/* magic number stuff like Sun */
X#define OMAGIC 0407
X#define NMAGIC 0410
X#define ZMAGIC 0413
X#define N_BADMAG(x) \
X    (((x).magic)!=OMAGIC && ((x).magic)!=NMAGIC && ((x).magic)!=ZMAGIC)
X
X/* definitions of type for Sun -- used for symstr.type, d_entry.d_rptr */
X#define S_UNDF 0x0		/* undefined */
X#define S_ABS  0x2		/* absolute */
X#define S_TEXT 0x4		/* text */
X#define S_DATA 0x6		/* data */
X#define S_BSS  0x8		/* bss */
X#define S_COMM 0x12		/* common (internal to ld) */
X#define S_FN   0x1f		/* file name symbol */
X#define S_EXT  01		/* external bit, or'ed in */
X#define S_TYPE 0x1e		/* mask for all the type bits */
SHAR_EOF
chmod 0644 unc.h || echo "restore of unc.h fails"
exit 0