!	XO -- Examine SLD object files.
!	Copyright (C) 1998,2000 Nils M Holm
!	See the file LICENSE for conditions of use.

#r5;

interface	readpacked(3) = 11,
		writepacked(3),
		reposition(4),
		rename(2),
		memcopy(3),
		memcomp(3);

!-------------------- IOSTREAM DEFINITIONS START --------------------!
struct IOS =	IOS_FD,
		IOS_BUFFER,
		IOS_FLAGS,
		IOS_LEN,
		IOS_PTR,
		IOS_END;

const		IOF_READ	= 00001,
		IOF_WRITE	= 00002,
		IOF_EOF		= 00004;


ios_create(iostream, fd, buffer, len, mode) do
	iostream[IOS_FD] := fd;
	iostream[IOS_BUFFER] := buffer;
	iostream[IOS_FLAGS] := mode;
	iostream[IOS_LEN] := len;
	iostream[IOS_PTR] := 0;
	iostream[IOS_END] := 0;
	return iostream;
end


ios_more(iostream) do
	var	k;

	if (iostream[IOS_FLAGS] & IOF_READ) do
		k := readpacked(iostream[IOS_FD], iostream[IOS_BUFFER],
			iostream[IOS_LEN]);
		if (k < 0) return %1;
		if (k = 0)
			iostream[IOS_FLAGS] := iostream[IOS_FLAGS] | IOF_EOF;
		iostream[IOS_END] := k;
		iostream[IOS_PTR] := 0;
	end
	return k;
end


ios_rdch(iostream) do
	var	c;

	if (iostream[IOS_FLAGS] & IOF_EOF) return %1;
	if (	iostream[IOS_PTR] >= iostream[IOS_END] /\
		ios_more(iostream) < 1
	)
		return %1;
	c := iostream[IOS_BUFFER]::iostream[IOS_PTR];
	iostream[IOS_PTR] := iostream[IOS_PTR]+1;
	return c;
end


ios__read(iostream, buffer, len, ckln) do
	var	i, p, e, b;

	i := 0;
	p := iostream[IOS_PTR];
	e := iostream[IOS_END];
	b := iostream[IOS_BUFFER];
	while (len) do
		if (p >= e) do
			iostream[IOS_PTR] := p;
			if (ios_more(iostream) < 1) leave;
			p := iostream[IOS_PTR];
			e := iostream[IOS_END];
		end
		buffer::i := b::p;
		p := p+1;
		i := i+1;
		len := len-1;
		if (ckln /\ buffer::(i-1) = '\n') leave;
	end
	if (ckln) buffer::i := 0;
	iostream[IOS_PTR] := p;
	iostream[IOS_END] := e;
	return i;
end


ios_read(iostream, buffer, len) return ios__read(iostream, buffer, len, 0);
!-------------------- IOSTREAM DEFINITIONS END --------------------!


const	HHMAGIC = 0, HLMAGIC = 1, HFLAGS = 2,
	HTEXTLEN = 3, HDATALEN = 4, HBSSLEN = 5,
	HPUBLEN = 6, HEXTLEN = 7, HRLCLEN = 8,
	HDR_LEN = 9;

const	OBJMAGIC_HI = 6513, OBJMAGIC_LO = 1046;


error(msg) do
	select(1,2);
	writes("XO: ");
	writes(msg); newline();
	halt;
end


var	word_buf[6];
word(n) do
	var	digits;

	digits := "0123456789ABCDEF";
	word_buf[0] := '$';
	word_buf[1] := digits[(n>>8) / 16];
	word_buf[2] := digits[(n>>8) mod 16];
	word_buf[3] := digits[(n&255) / 16];
	word_buf[4] := digits[(n&255) mod 16];
	word_buf[5] := 0;
	return word_buf;
end


byte(b, n) do
	var	digits;

	digits := "0123456789ABCDEF";
	b[0] := digits[(n&255) / 16];
	b[1] := digits[(n&255) mod 16];
end


x(buf, off) return buf::(off*2+1)<<8 | buf::(off*2);


prhd(n) do
	writes(word(n));
	writes("\s\s");
	writes(ntoa(n, 0));
end


p_header(hdr) do
	var	m;

	writes("HEADER"); newline();
	writes("Magic: ............... "); writes(word(x(hdr,HHMAGIC)));
		m := word(x(hdr,HLMAGIC)); writes(@m[1]); newline();
	writes("Flags: ............... "); writes(word(x(hdr,HFLAGS)));
	m := x(hdr,HFLAGS);
	writes("  (");
	writes(m&1-> "Pure": "Impure");
	if (m&1 /\ m&3) writes(", Relocatibe");
	writes(")"); newline();
	m := m>>8;
	writes("Machine type: ........ "); writes(word(m));
	writes("  ");
	ie (m = 1)
		writes("8086/8088");
	else
		writes("unknown");
	newline();
	writes("TEXT length: ......... "); prhd(x(hdr,HTEXTLEN)); newline();
	writes("DATA length: ......... "); prhd(x(hdr,HDATALEN)); newline();
	writes("BSS length: .......... "); prhd(x(hdr,HBSSLEN)); newline();
	writes("PUBLIC length: ....... "); prhd(x(hdr,HPUBLEN)); newline();
	writes("EXTERNAL length: ..... "); prhd(x(hdr,HEXTLEN)); newline();
	writes("RELOCATION length: ... "); prhd(x(hdr,HRLCLEN)); newline();
	newline();
end


clear(buf) do
	var	i;

	for (i=0, 79) buf[i] := '\s';
	buf[i] := 0;
end


p_dump(name, obj, len) do
	var	ibuf[16], obuf[81];
	var	i, j, k, l, c;

	writes(name); newline();
	for (i=0, len/16+1) do
		l := (i = len / 16)-> len mod 16: 16;
		if (\l) leave;
		if (ios_read(obj, ibuf, l) \= l)
			error("file read error");
		clear(obuf);
		byte(obuf, i*16>>8);
		byte(@obuf[2], i*16&255);
		obuf[5] := ':';
		k := 7;
		for (j=0, l) do
			byte(@obuf[k+j*3], ibuf::j);
			if (j = 7) do
				k := k+2;
				obuf[k+j*3+1] := '|';
			end
			c := ibuf::j;
			if ('\s' > c \/ c > '~') c := '_';
			obuf[j+58] := c;
		end
		obuf[76] := 0;
		writes(obuf);
		newline();
	end
	newline();
end


p_syms(name, obj, reflist, len) do
	var	ihd[3], hd[3], ref[2];
	var	sname[129];
	var	obuf[81];
	var	i, n, k;

	writes(name); newline();
	while (len) do
		if (ios_read(obj, ihd, 6) \= 6)
			error("file read error");
		hd[0] := ihd::1 << 8 | ihd::0;
		hd[1] := ihd::3 << 8 | ihd::2;
		hd[2] := ihd::5 << 8 | ihd::4;
		len := len-6-hd[0];
		if (ios_read(obj, sname, hd[0]) \= hd[0])
			error("file read error");
		sname::hd[0] := 0;
		clear(obuf);
		obuf[0] := hd[2];
		byte(@obuf[2], hd[1]>>8);
		byte(@obuf[4], hd[1]&255);
		sname::40 := 0;
		k := 8+unpack(sname, @obuf[8]);
		obuf[k] := 0;
		if (reflist) do
			obuf[k] := '\s';
			k := k+10 & ~7;
			obuf[k-2] := '@';
			n := ios_rdch(obj) | (ios_rdch(obj)<<8);
			len := len-n-2;
			for (i=0, n>>2) do
				if (k >= 72) do
					obuf[k] := 0;
					writes(obuf); newline();
					clear(obuf);
					k := 8;
				end
				if (ios_read(obj, ref, 4) \= 4)
					error("file read error");
				obuf[k] := ref::2;
				byte(@obuf[k+1], ref::1);
				byte(@obuf[k+3], ref::0);
				obuf[k+5] := ref::3-> '+': '\s';
				k := k+8;
			end
		end
		writes(obuf); newline();
	end
	newline();
end


p_rloc(obj, len) do
	var	re[2];
	var	i, k;
	var	obuf[81];

	writes("RELOCATION TABLE"); newline();
	k := 0;
	clear(obuf);
	for (i=0, len/4) do
		if (k >= 72) do
			obuf[k] := 0;
			writes(obuf); newline();
			k := 0;
		end
		if (ios_read(obj, re, 4) \= 4)
			error("file read error");
		obuf[k] := re::0;
		obuf[k+1] := re::1;
		byte(@obuf[k+2], re::3);
		byte(@obuf[k+4], re::2);
		k := k+8;
	end
	if (k) do
		obuf[k] := 0;
		writes(obuf); newline();
	end
	newline();
end


do
	var	hdr[HDR_LEN+1];
	var	buffer[512], obj[IOS];

	if (ios_create(obj, 0, buffer, 1024, IOF_READ) = %1)
		error("could not create input stream");
	if (ios_read(obj, hdr, HDR_LEN*2) \= HDR_LEN*2)
		error("short header");

	if(x(hdr,HHMAGIC) \= OBJMAGIC_HI \/ x(hdr,HLMAGIC) \= OBJMAGIC_LO)
		error("magic match failed");

	p_header(hdr);
	p_dump("TEXT SECTION", obj, x(hdr,HTEXTLEN));
	p_dump("DATA SECTION", obj, x(hdr,HDATALEN));
	p_syms("PUBLIC SYMBOLS", obj, 0, x(hdr,HPUBLEN));
	p_syms("EXTERNAL SYMBOLS", obj, 1, x(hdr,HEXTLEN));
	p_rloc(obj, x(hdr,HRLCLEN));
end

