// Inferno libmach/a.out.h and libmach/mach.h
// http://code.google.com/p/inferno-os/source/browse/utils/libmach/a.out.h
// http://code.google.com/p/inferno-os/source/browse/utils/libmach/mach.h
//
// 	Copyright © 1994-1999 Lucent Technologies Inc.
// 	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
// 	Portions Copyright © 1997-1999 Vita Nuova Limited.
// 	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
// 	Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/*
 *	Architecture-dependent application data
 */

typedef	struct	Exec	Exec;
struct	Exec
{
	int32	magic;		/* magic number */
	int32	text;	 	/* size of text segment */
	int32	data;	 	/* size of initialized data */
	int32	bss;	  	/* size of uninitialized data */
	int32	syms;	 	/* size of symbol table */
	int32	entry;	 	/* entry point */
	int32	spsz;		/* size of pc/sp offset table */
	int32	pcsz;		/* size of pc/line number table */
};

#define HDR_MAGIC	0x00008000		/* header expansion */

#define	_MAGIC(f, b)	((f)|((((4*(b))+0)*(b))+7))
#define	A_MAGIC		_MAGIC(0, 8)		/* 68020 */
#define	I_MAGIC		_MAGIC(0, 11)		/* intel 386 */
#define	J_MAGIC		_MAGIC(0, 12)		/* intel 960 (retired) */
#define	K_MAGIC		_MAGIC(0, 13)		/* sparc */
#define	V_MAGIC		_MAGIC(0, 16)		/* mips 3000 BE */
#define	X_MAGIC		_MAGIC(0, 17)		/* att dsp 3210 (retired) */
#define	M_MAGIC		_MAGIC(0, 18)		/* mips 4000 BE */
#define	D_MAGIC		_MAGIC(0, 19)		/* amd 29000 (retired) */
#define	E_MAGIC		_MAGIC(0, 20)		/* arm */
#define	Q_MAGIC		_MAGIC(0, 21)		/* powerpc */
#define	N_MAGIC		_MAGIC(0, 22)		/* mips 4000 LE */
#define	L_MAGIC		_MAGIC(0, 23)		/* dec alpha */
#define	P_MAGIC		_MAGIC(0, 24)		/* mips 3000 LE */
#define	U_MAGIC		_MAGIC(0, 25)		/* sparc64 */
#define	S_MAGIC		_MAGIC(HDR_MAGIC, 26)	/* amd64 */
#define	T_MAGIC		_MAGIC(HDR_MAGIC, 27)	/* powerpc64 */

#define	MIN_MAGIC	8
#define	MAX_MAGIC	27			/* <= 90 */

#define	DYN_MAGIC	0x80000000		/* dlm */

typedef	struct	Sym	Sym;
struct	Sym
{
	vlong	value;
	uint	sig;
	char	type;
	char	*name;
	vlong	gotype;
	int	sequence;	// order in file
};


/*
 *	Supported architectures:
 *		mips,
 *		68020,
 *		i386,
 *		amd64,
 *		sparc,
 *		sparc64,
 *		mips2 (R4000)
 *		arm
 *		powerpc,
 *		powerpc64
 *		alpha
 */
enum
{
	MMIPS,			/* machine types */
	MSPARC,
	M68020,
	MI386,
	MI960,			/* retired */
	M3210,			/* retired */
	MMIPS2,
	NMIPS2,
	M29000,			/* retired */
	MARM,
	MPOWER,
	MALPHA,
	NMIPS,
	MSPARC64,
	MAMD64,
	MPOWER64,
				/* types of executables */
	FNONE = 0,		/* unidentified */
	FMIPS,			/* v.out */
	FMIPSB,			/* mips bootable */
	FSPARC,			/* k.out */
	FSPARCB,		/* Sparc bootable */
	F68020,			/* 2.out */
	F68020B,		/* 68020 bootable */
	FNEXTB,			/* Next bootable */
	FI386,			/* 8.out */
	FI386B,			/* I386 bootable */
	FI960,			/* retired */
	FI960B,			/* retired */
	F3210,			/* retired */
	FMIPS2BE,		/* 4.out */
	F29000,			/* retired */
	FARM,			/* 5.out */
	FARMB,			/* ARM bootable */
	FPOWER,			/* q.out */
	FPOWERB,		/* power pc bootable */
	FMIPS2LE,		/* 0.out */
	FALPHA,			/* 7.out */
	FALPHAB,		/* DEC Alpha bootable */
	FMIPSLE,		/* 3k little endian */
	FSPARC64,		/* u.out */
	FAMD64,			/* 6.out */
	FAMD64B,		/* 6.out bootable */
	FPOWER64,		/* 9.out */
	FPOWER64B,		/* 9.out bootable */

	ANONE = 0,		/* dissembler types */
	AMIPS,
	AMIPSCO,		/* native mips */
	ASPARC,
	ASUNSPARC,		/* native sun */
	A68020,
	AI386,
	AI8086,			/* oh god */
	AI960,			/* retired */
	A29000,			/* retired */
	AARM,
	APOWER,
	AALPHA,
	ASPARC64,
	AAMD64,
	APOWER64,
				/* object file types */
	Obj68020 = 0,		/* .2 */
	ObjSparc,		/* .k */
	ObjMips,		/* .v */
	Obj386,			/* .8 */
	Obj960,			/* retired */
	Obj3210,		/* retired */
	ObjMips2,		/* .4 */
	Obj29000,		/* retired */
	ObjArm,			/* .5 */
	ObjPower,		/* .q */
	ObjMips2le,		/* .0 */
	ObjAlpha,		/* .7 */
	ObjSparc64,		/* .u */
	ObjAmd64,		/* .6 */
	ObjSpim,		/* .0 */
	ObjPower64,		/* .9 */
	Maxobjtype,

	CNONE  = 0,		/* symbol table classes */
	CAUTO,
	CPARAM,
	CSTAB,
	CTEXT,
	CDATA,
	CANY,			/* to look for any class */
};

typedef	struct	Map	Map;
typedef	struct	Symbol	Symbol;
typedef	struct	Reglist	Reglist;
typedef	struct	Mach	Mach;
typedef	struct	Machdata Machdata;
typedef	struct	Seg	Seg;

typedef int Maprw(Map *m, Seg *s, uvlong addr, void *v, uint n, int isread);

struct Seg {
	char	*name;		/* the segment name */
	int	fd;		/* file descriptor */
	int	inuse;		/* in use - not in use */
	int	cache;		/* should cache reads? */
	uvlong	b;		/* base */
	uvlong	e;		/* end */
	vlong	f;		/* offset within file */
	Maprw	*rw;		/* read/write fn for seg */
};

/*
 * 	Structure to map a segment to data
 */
struct Map {
	int	pid;
	int	tid;
	int	nsegs;	/* number of segments */
	Seg	seg[1];	/* actually n of these */
};

/*
 *	Internal structure describing a symbol table entry
 */
struct Symbol {
	void 	*handle;		/* used internally - owning func */
	struct {
		char	*name;
		vlong	value;		/* address or stack offset */
		char	type;		/* as in a.out.h */
		char	class;		/* as above */
		int	index;		/* in findlocal, globalsym, textsym */
	};
};

/*
 *	machine register description
 */
struct Reglist {
	char	*rname;			/* register name */
	short	roffs;			/* offset in u-block */
	char	rflags;			/* INTEGER/FLOAT, WRITABLE */
	char	rformat;		/* print format: 'x', 'X', 'f', '8', '3', 'Y', 'W' */
};

enum {					/* bits in rflags field */
	RINT	= (0<<0),
	RFLT	= (1<<0),
	RRDONLY	= (1<<1),
};

/*
 *	Machine-dependent data is stored in two structures:
 *		Mach  - miscellaneous general parameters
 *		Machdata - jump vector of service functions used by debuggers
 *
 *	Mach is defined in ?.c and set in executable.c
 *
 *	Machdata is defined in ?db.c
 *		and set in the debugger startup.
 */
struct Mach{
	char	*name;
	int	mtype;			/* machine type code */
	Reglist *reglist;		/* register set */
	int32	regsize;		/* sizeof registers in bytes */
	int32	fpregsize;		/* sizeof fp registers in bytes */
	char	*pc;			/* pc name */
	char	*sp;			/* sp name */
	char	*link;			/* link register name */
	char	*sbreg;			/* static base register name */
	uvlong	sb;			/* static base register value */
	int	pgsize;			/* page size */
	uvlong	kbase;			/* kernel base address */
	uvlong	ktmask;			/* ktzero = kbase & ~ktmask */
	uvlong	utop;			/* user stack top */
	int	pcquant;		/* quantization of pc */
	int	szaddr;			/* sizeof(void*) */
	int	szreg;			/* sizeof(register) */
	int	szfloat;		/* sizeof(float) */
	int	szdouble;		/* sizeof(double) */
};

extern	Mach	*mach;			/* Current machine */

typedef uvlong	(*Rgetter)(Map*, char*);
typedef	void	(*Tracer)(Map*, uvlong, uvlong, Symbol*);

struct	Machdata {		/* Machine-dependent debugger support */
	uchar	bpinst[4];			/* break point instr. */
	short	bpsize;				/* size of break point instr. */

	ushort	(*swab)(ushort);		/* ushort to local byte order */
	uint32	(*swal)(uint32);			/* uint32 to local byte order */
	uvlong	(*swav)(uvlong);		/* uvlong to local byte order */
	int	(*ctrace)(Map*, uvlong, uvlong, uvlong, Tracer); /* C traceback */
	uvlong	(*findframe)(Map*, uvlong, uvlong, uvlong, uvlong);/* frame finder */
	char*	(*excep)(Map*, Rgetter);	/* last exception */
	uint32	(*bpfix)(uvlong);		/* breakpoint fixup */
	int	(*sftos)(char*, int, void*);	/* single precision float */
	int	(*dftos)(char*, int, void*);	/* double precision float */
	int	(*foll)(Map*, uvlong, Rgetter, uvlong*);/* follow set */
	int	(*das)(Map*, uvlong, char, char*, int);	/* symbolic disassembly */
	int	(*hexinst)(Map*, uvlong, char*, int); 	/* hex disassembly */
	int	(*instsize)(Map*, uvlong);	/* instruction size */
};

/*
 *	Common a.out header describing all architectures
 */
typedef struct Fhdr
{
	char	*name;		/* identifier of executable */
	uchar	type;		/* file type - see codes above */
	uchar	hdrsz;		/* header size */
	uchar	_magic;		/* _MAGIC() magic */
	uchar	spare;
	int32	magic;		/* magic number */
	uvlong	txtaddr;	/* text address */
	vlong	txtoff;		/* start of text in file */
	uvlong	dataddr;	/* start of data segment */
	vlong	datoff;		/* offset to data seg in file */
	vlong	symoff;		/* offset of symbol table in file */
	uvlong	entry;		/* entry point */
	vlong	sppcoff;	/* offset of sp-pc table in file */
	vlong	lnpcoff;	/* offset of line number-pc table in file */
	int32	txtsz;		/* text size */
	int32	datsz;		/* size of data seg */
	int32	bsssz;		/* size of bss */
	int32	symsz;		/* size of symbol table */
	int32	sppcsz;		/* size of sp-pc table */
	int32	lnpcsz;		/* size of line number-pc table */
} Fhdr;

extern	int	asstype;	/* dissembler type - machdata.c */
extern	Machdata *machdata;	/* jump vector - machdata.c */

int		beieee80ftos(char*, int, void*);
int		beieeesftos(char*, int, void*);
int		beieeedftos(char*, int, void*);
ushort		beswab(ushort);
uint32		beswal(uint32);
uvlong		beswav(uvlong);
uvlong		ciscframe(Map*, uvlong, uvlong, uvlong, uvlong);
int		cisctrace(Map*, uvlong, uvlong, uvlong, Tracer);
int		crackhdr(int fd, Fhdr*);
uvlong		file2pc(char*, int32);
int		fileelem(Sym**, uchar *, char*, int);
int32		fileline(char*, int, uvlong);
int		filesym(int, char*, int);
int		findlocal(Symbol*, char*, Symbol*);
int		findseg(Map*, char*);
int		findsym(uvlong, int, Symbol *);
int		fnbound(uvlong, uvlong*);
int		fpformat(Map*, Reglist*, char*, int, int);
int		get1(Map*, uvlong, uchar*, int);
int		get2(Map*, uvlong, ushort*);
int		get4(Map*, uvlong, uint32*);
int		get8(Map*, uvlong, uvlong*);
int		geta(Map*, uvlong, uvlong*);
int		getauto(Symbol*, int, int, Symbol*);
Sym*		getsym(int);
int		globalsym(Symbol *, int);
char*		_hexify(char*, uint32, int);
int		ieeesftos(char*, int, uint32);
int		ieeedftos(char*, int, uint32, uint32);
int		isar(Biobuf*);
int		leieee80ftos(char*, int, void*);
int		leieeesftos(char*, int, void*);
int		leieeedftos(char*, int, void*);
ushort		leswab(ushort);
uint32		leswal(uint32);
uvlong		leswav(uvlong);
uvlong		line2addr(int32, uvlong, uvlong);
Map*		loadmap(Map*, int, Fhdr*);
int		localaddr(Map*, char*, char*, uvlong*, Rgetter);
int		localsym(Symbol*, int);
int		lookup(char*, char*, Symbol*);
void		machbytype(int);
int		machbyname(char*);
int		nextar(Biobuf*, int, char*);
Map*		newmap(Map*, int);
void		objtraverse(void(*)(Sym*, void*), void*);
int		objtype(Biobuf*, char**);
uvlong		pc2sp(uvlong);
int32		pc2line(uvlong);
int		put1(Map*, uvlong, uchar*, int);
int		put2(Map*, uvlong, ushort);
int		put4(Map*, uvlong, uint32);
int		put8(Map*, uvlong, uvlong);
int		puta(Map*, uvlong, uvlong);
int		readar(Biobuf*, int, vlong, int);
int		readobj(Biobuf*, int);
uvlong		riscframe(Map*, uvlong, uvlong, uvlong, uvlong);
int		risctrace(Map*, uvlong, uvlong, uvlong, Tracer);
int		setmap(Map*, int, uvlong, uvlong, vlong, char*, Maprw *rw);
Sym*		symbase(int32*);
int		syminit(int, Fhdr*);
int		symoff(char*, int, uvlong, int);
void		textseg(uvlong, Fhdr*);
int		textsym(Symbol*, int);
void		unusemap(Map*, int);

Map*		attachproc(int pid, Fhdr *fp);
int		ctlproc(int pid, char *msg);
void		detachproc(Map *m);
int		procnotes(int pid, char ***pnotes);
char*		proctextfile(int pid);
int		procthreadpids(int pid, int *tid, int ntid);
char*	procstatus(int);

Maprw	fdrw;
