github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/libmach/executable.c (about)

     1  // Inferno libmach/executable.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/libmach/executable.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.
     5  //	Power PC support Copyright © 1995-2004 C H Forsyth (forsyth@terzarima.net).
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited.
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).
     8  //	Revisions Copyright © 2000-2004 Lucent Technologies Inc. and others.
     9  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    10  //
    11  // Permission is hereby granted, free of charge, to any person obtaining a copy
    12  // of this software and associated documentation files (the "Software"), to deal
    13  // in the Software without restriction, including without limitation the rights
    14  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    15  // copies of the Software, and to permit persons to whom the Software is
    16  // furnished to do so, subject to the following conditions:
    17  //
    18  // The above copyright notice and this permission notice shall be included in
    19  // all copies or substantial portions of the Software.
    20  //
    21  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    22  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    23  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    24  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    25  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    26  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    27  // THE SOFTWARE.
    28  
    29  #include	<u.h>
    30  #include	<libc.h>
    31  #include	<bio.h>
    32  #include	<bootexec.h>
    33  #include	<mach.h>
    34  #include	"elf.h"
    35  #include	"macho.h"
    36  
    37  /*
    38   *	All a.out header types.  The dummy entry allows canonical
    39   *	processing of the union as a sequence of int32s
    40   */
    41  
    42  typedef struct {
    43  	union{
    44  		/*struct { */
    45  			Exec exechdr;		/* a.out.h */
    46  		/*	uvlong hdr[1];*/
    47  		/*};*/
    48  		Ehdr32 elfhdr32;			/* elf.h */
    49  		Ehdr64 elfhdr64;			/* elf.h */
    50  		struct mipsexec mips;	/* bootexec.h */
    51  		struct mips4kexec mipsk4;	/* bootexec.h */
    52  		struct sparcexec sparc;	/* bootexec.h */
    53  		struct nextexec next;	/* bootexec.h */
    54  		Machhdr machhdr;	/* macho.h */
    55  	} e;
    56  	int32 dummy;			/* padding to ensure extra int32 */
    57  } ExecHdr;
    58  
    59  static	int	nextboot(int, Fhdr*, ExecHdr*);
    60  static	int	sparcboot(int, Fhdr*, ExecHdr*);
    61  static	int	mipsboot(int, Fhdr*, ExecHdr*);
    62  static	int	mips4kboot(int, Fhdr*, ExecHdr*);
    63  static	int	common(int, Fhdr*, ExecHdr*);
    64  static	int	commonllp64(int, Fhdr*, ExecHdr*);
    65  static	int	adotout(int, Fhdr*, ExecHdr*);
    66  static	int	elfdotout(int, Fhdr*, ExecHdr*);
    67  static	int	machdotout(int, Fhdr*, ExecHdr*);
    68  static	int	armdotout(int, Fhdr*, ExecHdr*);
    69  static	int	pedotout(int, Fhdr*, ExecHdr*);
    70  static	void	setsym(Fhdr*, vlong, int32, vlong, int32, vlong, int32);
    71  static	void	setdata(Fhdr*, uvlong, int32, vlong, int32);
    72  static	void	settext(Fhdr*, uvlong, uvlong, int32, vlong);
    73  static	void	hswal(void*, int, uint32(*)(uint32));
    74  static	uvlong	_round(uvlong, uint32);
    75  
    76  /*
    77   *	definition of per-executable file type structures
    78   */
    79  
    80  typedef struct Exectable{
    81  	int32	magic;			/* big-endian magic number of file */
    82  	char	*name;			/* executable identifier */
    83  	char	*dlmname;		/* dynamically loadable module identifier */
    84  	uchar	type;			/* Internal code */
    85  	uchar	_magic;			/* _MAGIC() magic */
    86  	Mach	*mach;			/* Per-machine data */
    87  	int32	hsize;			/* header size */
    88  	uint32	(*swal)(uint32);		/* beswal or leswal */
    89  	int	(*hparse)(int, Fhdr*, ExecHdr*);
    90  } ExecTable;
    91  
    92  extern	Mach	mmips;
    93  extern	Mach	mmips2le;
    94  extern	Mach	mmips2be;
    95  extern	Mach	msparc;
    96  extern	Mach	msparc64;
    97  extern	Mach	m68020;
    98  extern	Mach	mi386;
    99  extern	Mach	mamd64;
   100  extern	Mach	marm;
   101  extern	Mach	mpower;
   102  extern	Mach	mpower64;
   103  extern	Mach	malpha;
   104  
   105  /* BUG: FIX THESE WHEN NEEDED */
   106  Mach	mmips;
   107  Mach	mmips2le;
   108  Mach	mmips2be;
   109  Mach	msparc;
   110  Mach	msparc64;
   111  Mach	m68020;
   112  Mach	mpower;
   113  Mach	mpower64;
   114  Mach	malpha;
   115  
   116  ExecTable exectab[] =
   117  {
   118  	{ V_MAGIC,			/* Mips v.out */
   119  		"mips plan 9 executable BE",
   120  		"mips plan 9 dlm BE",
   121  		FMIPS,
   122  		1,
   123  		&mmips,
   124  		sizeof(Exec),
   125  		beswal,
   126  		adotout },
   127  	{ P_MAGIC,			/* Mips 0.out (r3k le) */
   128  		"mips plan 9 executable LE",
   129  		"mips plan 9 dlm LE",
   130  		FMIPSLE,
   131  		1,
   132  		&mmips,
   133  		sizeof(Exec),
   134  		beswal,
   135  		adotout },
   136  	{ M_MAGIC,			/* Mips 4.out */
   137  		"mips 4k plan 9 executable BE",
   138  		"mips 4k plan 9 dlm BE",
   139  		FMIPS2BE,
   140  		1,
   141  		&mmips2be,
   142  		sizeof(Exec),
   143  		beswal,
   144  		adotout },
   145  	{ N_MAGIC,			/* Mips 0.out */
   146  		"mips 4k plan 9 executable LE",
   147  		"mips 4k plan 9 dlm LE",
   148  		FMIPS2LE,
   149  		1,
   150  		&mmips2le,
   151  		sizeof(Exec),
   152  		beswal,
   153  		adotout },
   154  	{ 0x160<<16,			/* Mips boot image */
   155  		"mips plan 9 boot image",
   156  		nil,
   157  		FMIPSB,
   158  		0,
   159  		&mmips,
   160  		sizeof(struct mipsexec),
   161  		beswal,
   162  		mipsboot },
   163  	{ (0x160<<16)|3,		/* Mips boot image */
   164  		"mips 4k plan 9 boot image",
   165  		nil,
   166  		FMIPSB,
   167  		0,
   168  		&mmips2be,
   169  		sizeof(struct mips4kexec),
   170  		beswal,
   171  		mips4kboot },
   172  	{ K_MAGIC,			/* Sparc k.out */
   173  		"sparc plan 9 executable",
   174  		"sparc plan 9 dlm",
   175  		FSPARC,
   176  		1,
   177  		&msparc,
   178  		sizeof(Exec),
   179  		beswal,
   180  		adotout },
   181  	{ 0x01030107, 			/* Sparc boot image */
   182  		"sparc plan 9 boot image",
   183  		nil,
   184  		FSPARCB,
   185  		0,
   186  		&msparc,
   187  		sizeof(struct sparcexec),
   188  		beswal,
   189  		sparcboot },
   190  	{ U_MAGIC,			/* Sparc64 u.out */
   191  		"sparc64 plan 9 executable",
   192  		"sparc64 plan 9 dlm",
   193  		FSPARC64,
   194  		1,
   195  		&msparc64,
   196  		sizeof(Exec),
   197  		beswal,
   198  		adotout },
   199  	{ A_MAGIC,			/* 68020 2.out & boot image */
   200  		"68020 plan 9 executable",
   201  		"68020 plan 9 dlm",
   202  		F68020,
   203  		1,
   204  		&m68020,
   205  		sizeof(Exec),
   206  		beswal,
   207  		common },
   208  	{ 0xFEEDFACE,			/* Next boot image */
   209  		"next plan 9 boot image",
   210  		nil,
   211  		FNEXTB,
   212  		0,
   213  		&m68020,
   214  		sizeof(struct nextexec),
   215  		beswal,
   216  		nextboot },
   217  	{ I_MAGIC,			/* I386 8.out & boot image */
   218  		"386 plan 9 executable",
   219  		"386 plan 9 dlm",
   220  		FI386,
   221  		1,
   222  		&mi386,
   223  		sizeof(Exec),
   224  		beswal,
   225  		common },
   226  	{ S_MAGIC,			/* amd64 6.out & boot image */
   227  		"amd64 plan 9 executable",
   228  		"amd64 plan 9 dlm",
   229  		FAMD64,
   230  		1,
   231  		&mamd64,
   232  		sizeof(Exec)+8,
   233  		nil,
   234  		commonllp64 },
   235  	{ Q_MAGIC,			/* PowerPC q.out & boot image */
   236  		"power plan 9 executable",
   237  		"power plan 9 dlm",
   238  		FPOWER,
   239  		1,
   240  		&mpower,
   241  		sizeof(Exec),
   242  		beswal,
   243  		common },
   244  	{ T_MAGIC,			/* power64 9.out & boot image */
   245  		"power64 plan 9 executable",
   246  		"power64 plan 9 dlm",
   247  		FPOWER64,
   248  		1,
   249  		&mpower64,
   250  		sizeof(Exec)+8,
   251  		nil,
   252  		commonllp64 },
   253  	{ ELF_MAG,			/* any elf32 or elf64 */
   254  		"elf executable",
   255  		nil,
   256  		FNONE,
   257  		0,
   258  		&mi386,
   259  		sizeof(Ehdr64),
   260  		nil,
   261  		elfdotout },
   262  	{ MACH64_MAG,			/* 64-bit MACH (apple mac) */
   263  		"mach executable",
   264  		nil,
   265  		FAMD64,
   266  		0,
   267  		&mamd64,
   268  		sizeof(Machhdr),
   269  		nil,
   270  		machdotout },
   271  	{ MACH32_MAG,			/* 32-bit MACH (apple mac) */
   272  		"mach executable",
   273  		nil,
   274  		FI386,
   275  		0,
   276  		&mi386,
   277  		sizeof(Machhdr),
   278  		nil,
   279  		machdotout },
   280  	{ E_MAGIC,			/* Arm 5.out and boot image */
   281  		"arm plan 9 executable",
   282  		"arm plan 9 dlm",
   283  		FARM,
   284  		1,
   285  		&marm,
   286  		sizeof(Exec),
   287  		beswal,
   288  		common },
   289  	{ (143<<16)|0413,		/* (Free|Net)BSD Arm */
   290  		"arm *bsd executable",
   291  		nil,
   292  		FARM,
   293  		0,
   294  		&marm,
   295  		sizeof(Exec),
   296  		leswal,
   297  		armdotout },
   298  	{ L_MAGIC,			/* alpha 7.out */
   299  		"alpha plan 9 executable",
   300  		"alpha plan 9 dlm",
   301  		FALPHA,
   302  		1,
   303  		&malpha,
   304  		sizeof(Exec),
   305  		beswal,
   306  		common },
   307  	{ 0x0700e0c3,			/* alpha boot image */
   308  		"alpha plan 9 boot image",
   309  		nil,
   310  		FALPHA,
   311  		0,
   312  		&malpha,
   313  		sizeof(Exec),
   314  		beswal,
   315  		common },
   316  	{ 0x4d5a9000,    /* see dosstub[] in pe.c */
   317  		"windows PE executable",
   318  		nil,
   319  		FWINPE,
   320  		0,
   321  		&mi386,
   322  		sizeof(Exec), /* TODO */
   323  		nil,
   324  		pedotout },
   325  	{ 0 },
   326  };
   327  
   328  Mach	*mach = &mi386;			/* Global current machine table */
   329  
   330  static ExecTable*
   331  couldbe4k(ExecTable *mp)
   332  {
   333  	Dir *d;
   334  	ExecTable *f;
   335  
   336  	if((d=dirstat("/proc/1/regs")) == nil)
   337  		return mp;
   338  	if(d->length < 32*8){		/* R3000 */
   339  		free(d);
   340  		return mp;
   341  	}
   342  	free(d);
   343  	for (f = exectab; f->magic; f++)
   344  		if(f->magic == M_MAGIC) {
   345  			f->name = "mips plan 9 executable on mips2 kernel";
   346  			return f;
   347  		}
   348  	return mp;
   349  }
   350  
   351  int
   352  crackhdr(int fd, Fhdr *fp)
   353  {
   354  	ExecTable *mp;
   355  	ExecHdr d;
   356  	int nb, ret;
   357  	uint32 magic;
   358  
   359  	fp->type = FNONE;
   360  	nb = read(fd, (char *)&d.e, sizeof(d.e));
   361  	if (nb <= 0)
   362  		return 0;
   363  
   364  	ret = 0;
   365  	magic = beswal(d.e.exechdr.magic);		/* big-endian */
   366  	for (mp = exectab; mp->magic; mp++) {
   367  		if (nb < mp->hsize)
   368  			continue;
   369  
   370  		/*
   371  		 * The magic number has morphed into something
   372  		 * with fields (the straw was DYN_MAGIC) so now
   373  		 * a flag is needed in Fhdr to distinguish _MAGIC()
   374  		 * magic numbers from foreign magic numbers.
   375  		 *
   376  		 * This code is creaking a bit and if it has to
   377  		 * be modified/extended much more it's probably
   378  		 * time to step back and redo it all.
   379  		 */
   380  		if(mp->_magic){
   381  			if(mp->magic != (magic & ~DYN_MAGIC))
   382  				continue;
   383  
   384  			if(mp->magic == V_MAGIC)
   385  				mp = couldbe4k(mp);
   386  
   387  			if ((magic & DYN_MAGIC) && mp->dlmname != nil)
   388  				fp->name = mp->dlmname;
   389  			else
   390  				fp->name = mp->name;
   391  		}
   392  		else{
   393  			if(mp->magic != magic)
   394  				continue;
   395  			fp->name = mp->name;
   396  		}
   397  		fp->type = mp->type;
   398  		fp->hdrsz = mp->hsize;		/* will be zero on bootables */
   399  		fp->_magic = mp->_magic;
   400  		fp->magic = magic;
   401  
   402  		mach = mp->mach;
   403  		if(mp->swal != nil)
   404  			hswal(&d, sizeof(d.e)/sizeof(uint32), mp->swal);
   405  		ret = mp->hparse(fd, fp, &d);
   406  		seek(fd, mp->hsize, 0);		/* seek to end of header */
   407  		break;
   408  	}
   409  	if(mp->magic == 0)
   410  		werrstr("unknown header type");
   411  	return ret;
   412  }
   413  
   414  /*
   415   * Convert header to canonical form
   416   */
   417  static void
   418  hswal(void *v, int n, uint32 (*swap)(uint32))
   419  {
   420  	uint32 *ulp;
   421  
   422  	for(ulp = v; n--; ulp++)
   423  		*ulp = (*swap)(*ulp);
   424  }
   425  
   426  /*
   427   *	Crack a normal a.out-type header
   428   */
   429  static int
   430  adotout(int fd, Fhdr *fp, ExecHdr *hp)
   431  {
   432  	int32 pgsize;
   433  
   434  	USED(fd);
   435  	pgsize = mach->pgsize;
   436  	settext(fp, hp->e.exechdr.entry, pgsize+sizeof(Exec),
   437  			hp->e.exechdr.text, sizeof(Exec));
   438  	setdata(fp, _round(pgsize+fp->txtsz+sizeof(Exec), pgsize),
   439  		hp->e.exechdr.data, fp->txtsz+sizeof(Exec), hp->e.exechdr.bss);
   440  	setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
   441  	return 1;
   442  }
   443  
   444  static void
   445  commonboot(Fhdr *fp)
   446  {
   447  	if (!(fp->entry & mach->ktmask))
   448  		return;
   449  
   450  	switch(fp->type) {				/* boot image */
   451  	case F68020:
   452  		fp->type = F68020B;
   453  		fp->name = "68020 plan 9 boot image";
   454  		break;
   455  	case FI386:
   456  		fp->type = FI386B;
   457  		fp->txtaddr = (u32int)fp->entry;
   458  		fp->name = "386 plan 9 boot image";
   459  		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
   460  		break;
   461  	case FARM:
   462  		fp->type = FARMB;
   463  		fp->txtaddr = (u32int)fp->entry;
   464  		fp->name = "ARM plan 9 boot image";
   465  		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
   466  		return;
   467  	case FALPHA:
   468  		fp->type = FALPHAB;
   469  		fp->txtaddr = (u32int)fp->entry;
   470  		fp->name = "alpha plan 9 boot image";
   471  		fp->dataddr = fp->txtaddr+fp->txtsz;
   472  		break;
   473  	case FPOWER:
   474  		fp->type = FPOWERB;
   475  		fp->txtaddr = (u32int)fp->entry;
   476  		fp->name = "power plan 9 boot image";
   477  		fp->dataddr = fp->txtaddr+fp->txtsz;
   478  		break;
   479  	case FAMD64:
   480  		fp->type = FAMD64B;
   481  		fp->txtaddr = fp->entry;
   482  		fp->name = "amd64 plan 9 boot image";
   483  		fp->dataddr = _round(fp->txtaddr+fp->txtsz, mach->pgsize);
   484  		break;
   485  	default:
   486  		return;
   487  	}
   488  	fp->hdrsz = 0;			/* header stripped */
   489  }
   490  
   491  /*
   492   *	_MAGIC() style headers and
   493   *	alpha plan9-style bootable images for axp "headerless" boot
   494   *
   495   */
   496  static int
   497  common(int fd, Fhdr *fp, ExecHdr *hp)
   498  {
   499  	adotout(fd, fp, hp);
   500  	if(hp->e.exechdr.magic & DYN_MAGIC) {
   501  		fp->txtaddr = 0;
   502  		fp->dataddr = fp->txtsz;
   503  		return 1;
   504  	}
   505  	commonboot(fp);
   506  	return 1;
   507  }
   508  
   509  static int
   510  commonllp64(int unused, Fhdr *fp, ExecHdr *hp)
   511  {
   512  	int32 pgsize;
   513  	uvlong entry;
   514  
   515  	USED(unused);
   516  
   517  	hswal(&hp->e, sizeof(Exec)/sizeof(int32), beswal);
   518  	if(!(hp->e.exechdr.magic & HDR_MAGIC))
   519  		return 0;
   520  
   521  	/*
   522  	 * There can be more magic here if the
   523  	 * header ever needs more expansion.
   524  	 * For now just catch use of any of the
   525  	 * unused bits.
   526  	 */
   527  	if((hp->e.exechdr.magic & ~DYN_MAGIC)>>16)
   528  		return 0;
   529  	union {
   530  		char *p;
   531  		uvlong *v;
   532  	} u;
   533  	u.p = (char*)&hp->e.exechdr;
   534  	entry = beswav(*u.v);
   535  
   536  	pgsize = mach->pgsize;
   537  	settext(fp, entry, pgsize+fp->hdrsz, hp->e.exechdr.text, fp->hdrsz);
   538  	setdata(fp, _round(pgsize+fp->txtsz+fp->hdrsz, pgsize),
   539  		hp->e.exechdr.data, fp->txtsz+fp->hdrsz, hp->e.exechdr.bss);
   540  	setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
   541  
   542  	if(hp->e.exechdr.magic & DYN_MAGIC) {
   543  		fp->txtaddr = 0;
   544  		fp->dataddr = fp->txtsz;
   545  		return 1;
   546  	}
   547  	commonboot(fp);
   548  	return 1;
   549  }
   550  
   551  /*
   552   *	mips bootable image.
   553   */
   554  static int
   555  mipsboot(int fd, Fhdr *fp, ExecHdr *hp)
   556  {
   557  	USED(fd);
   558  	USED(fp);
   559  	USED(hp);
   560  
   561  abort();
   562  #ifdef unused
   563  	USED(fd);
   564  	fp->type = FMIPSB;
   565  	switch(hp->e.exechdr.amagic) {
   566  	default:
   567  	case 0407:	/* some kind of mips */
   568  		settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
   569  			hp->e.tsize, sizeof(struct mipsexec)+4);
   570  		setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
   571  			fp->txtoff+hp->e.tsize, hp->e.bsize);
   572  		break;
   573  	case 0413:	/* some kind of mips */
   574  		settext(fp, (u32int)hp->e.mentry, (u32int)hp->e.text_start,
   575  			hp->e.tsize, 0);
   576  		setdata(fp, (u32int)hp->e.data_start, hp->e.dsize,
   577  			hp->e.tsize, hp->e.bsize);
   578  		break;
   579  	}
   580  	setsym(fp, hp->e.nsyms, 0, hp->e.pcsize, hp->e.symptr);
   581  	fp->hdrsz = 0;			/* header stripped */
   582  #endif
   583  	return 1;
   584  }
   585  
   586  /*
   587   *	mips4k bootable image.
   588   */
   589  static int
   590  mips4kboot(int fd, Fhdr *fp, ExecHdr *hp)
   591  {
   592  	USED(fd);
   593  	USED(fp);
   594  	USED(hp);
   595  
   596  abort();
   597  #ifdef unused
   598  	USED(fd);
   599  	fp->type = FMIPSB;
   600  	switch(hp->e.h.amagic) {
   601  	default:
   602  	case 0407:	/* some kind of mips */
   603  		settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
   604  			hp->e.h.tsize, sizeof(struct mips4kexec));
   605  		setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
   606  			fp->txtoff+hp->e.h.tsize, hp->e.h.bsize);
   607  		break;
   608  	case 0413:	/* some kind of mips */
   609  		settext(fp, (u32int)hp->e.h.mentry, (u32int)hp->e.h.text_start,
   610  			hp->e.h.tsize, 0);
   611  		setdata(fp, (u32int)hp->e.h.data_start, hp->e.h.dsize,
   612  			hp->e.h.tsize, hp->e.h.bsize);
   613  		break;
   614  	}
   615  	setsym(fp, hp->e.h.nsyms, 0, hp->e.h.pcsize, hp->e.h.symptr);
   616  	fp->hdrsz = 0;			/* header stripped */
   617  #endif
   618  	return 1;
   619  }
   620  
   621  /*
   622   *	sparc bootable image
   623   */
   624  static int
   625  sparcboot(int fd, Fhdr *fp, ExecHdr *hp)
   626  {
   627  	USED(fd);
   628  	USED(fp);
   629  	USED(hp);
   630  
   631  abort();
   632  #ifdef unused
   633  	USED(fd);
   634  	fp->type = FSPARCB;
   635  	settext(fp, hp->e.sentry, hp->e.sentry, hp->e.stext,
   636  		sizeof(struct sparcexec));
   637  	setdata(fp, hp->e.sentry+hp->e.stext, hp->e.sdata,
   638  		fp->txtoff+hp->e.stext, hp->e.sbss);
   639  	setsym(fp, hp->e.ssyms, 0, hp->e.sdrsize, fp->datoff+hp->e.sdata);
   640  	fp->hdrsz = 0;			/* header stripped */
   641  #endif
   642  	return 1;
   643  }
   644  
   645  /*
   646   *	next bootable image
   647   */
   648  static int
   649  nextboot(int fd, Fhdr *fp, ExecHdr *hp)
   650  {
   651  	USED(fd);
   652  	USED(fp);
   653  	USED(hp);
   654  
   655  abort();
   656  #ifdef unused
   657  	USED(fd);
   658  	fp->type = FNEXTB;
   659  	settext(fp, hp->e.textc.vmaddr, hp->e.textc.vmaddr,
   660  		hp->e.texts.size, hp->e.texts.offset);
   661  	setdata(fp, hp->e.datac.vmaddr, hp->e.datas.size,
   662  		hp->e.datas.offset, hp->e.bsss.size);
   663  	setsym(fp, hp->e.symc.nsyms, hp->e.symc.spoff, hp->e.symc.pcoff,
   664  		hp->e.symc.symoff);
   665  	fp->hdrsz = 0;			/* header stripped */
   666  #endif
   667  	return 1;
   668  }
   669  
   670  /*
   671   * Elf32 and Elf64 binaries.
   672   */
   673  static int
   674  elf64dotout(int fd, Fhdr *fp, ExecHdr *hp)
   675  {
   676  	uvlong (*swav)(uvlong);
   677  	uint32 (*swal)(uint32);
   678  	ushort (*swab)(ushort);
   679  	Ehdr64 *ep;
   680  	Phdr64 *ph, *pph;
   681  	Shdr64 *sh;
   682  	int i, it, id, is, phsz, shsz;
   683  
   684  	/* bitswap the header according to the DATA format */
   685  	ep = &hp->e.elfhdr64;
   686  	if(ep->ident[CLASS] != ELFCLASS64) {
   687  		werrstr("bad ELF class - not 32 bit or 64 bit");
   688  		return 0;
   689  	}
   690  	if(ep->ident[DATA] == ELFDATA2LSB) {
   691  		swab = leswab;
   692  		swal = leswal;
   693  		swav = leswav;
   694  	} else if(ep->ident[DATA] == ELFDATA2MSB) {
   695  		swab = beswab;
   696  		swal = beswal;
   697  		swav = beswav;
   698  	} else {
   699  		werrstr("bad ELF encoding - not big or little endian");
   700  		return 0;
   701  	}
   702  
   703  	ep->type = swab(ep->type);
   704  	ep->machine = swab(ep->machine);
   705  	ep->version = swal(ep->version);
   706  	ep->elfentry = swal(ep->elfentry);
   707  	ep->phoff = swav(ep->phoff);
   708  	ep->shoff = swav(ep->shoff);
   709  	ep->flags = swav(ep->flags);
   710  	ep->ehsize = swab(ep->ehsize);
   711  	ep->phentsize = swab(ep->phentsize);
   712  	ep->phnum = swab(ep->phnum);
   713  	ep->shentsize = swab(ep->shentsize);
   714  	ep->shnum = swab(ep->shnum);
   715  	ep->shstrndx = swab(ep->shstrndx);
   716  	if(ep->type != EXEC || ep->version != CURRENT)
   717  		return 0;
   718  
   719  	/* we could definitely support a lot more machines here */
   720  	fp->magic = ELF_MAG;
   721  	fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
   722  	switch(ep->machine) {
   723  	case AMD64:
   724  		mach = &mamd64;
   725  		fp->type = FAMD64;
   726  		break;
   727  	default:
   728  		return 0;
   729  	}
   730  
   731  	if(ep->phentsize != sizeof(Phdr64)) {
   732  		werrstr("bad ELF header size");
   733  		return 0;
   734  	}
   735  	phsz = sizeof(Phdr64)*ep->phnum;
   736  	ph = malloc(phsz);
   737  	if(!ph)
   738  		return 0;
   739  	seek(fd, ep->phoff, 0);
   740  	if(read(fd, ph, phsz) < 0) {
   741  		free(ph);
   742  		return 0;
   743  	}
   744  	hswal(ph, phsz/sizeof(uint32), swal);
   745  
   746  	shsz = sizeof(Shdr64)*ep->shnum;
   747  	sh = malloc(shsz);
   748  	if(sh) {
   749  		seek(fd, ep->shoff, 0);
   750  		if(read(fd, sh, shsz) < 0) {
   751  			free(sh);
   752  			sh = 0;
   753  		} else
   754  			hswal(sh, shsz/sizeof(uint32), swal);
   755  	}
   756  
   757  	/* find text, data and symbols and install them */
   758  	it = id = is = -1;
   759  	for(i = 0; i < ep->phnum; i++) {
   760  		if(ph[i].type == LOAD
   761  		&& (ph[i].flags & (R|X)) == (R|X) && it == -1)
   762  			it = i;
   763  		else if(ph[i].type == LOAD
   764  		&& (ph[i].flags & (R|W)) == (R|W) && id == -1)
   765  			id = i;
   766  		else if(ph[i].type == NOPTYPE && is == -1)
   767  			is = i;
   768  	}
   769  	if(it == -1 || id == -1) {
   770  		/*
   771  		 * The SPARC64 boot image is something of an ELF hack.
   772  		 * Text+Data+BSS are represented by ph[0].  Symbols
   773  		 * are represented by ph[1]:
   774  		 *
   775  		 *		filesz, memsz, vaddr, paddr, off
   776  		 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
   777  		 * ph[1] : symsz, lcsz, 0, 0, symoff
   778  		 */
   779  		if(ep->machine == SPARC64 && ep->phnum == 2) {
   780  			uint32 txtaddr, txtsz, dataddr, bsssz;
   781  
   782  			txtaddr = ph[0].vaddr | 0x80000000;
   783  			txtsz = ph[0].filesz - ph[0].paddr;
   784  			dataddr = txtaddr + txtsz;
   785  			bsssz = ph[0].memsz - ph[0].filesz;
   786  			settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
   787  			setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
   788  			setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
   789  			free(ph);
   790  			return 1;
   791  		}
   792  
   793  		werrstr("No TEXT or DATA sections");
   794  		free(ph);
   795  		free(sh);
   796  		return 0;
   797  	}
   798  
   799  	settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
   800  	pph = ph + id;
   801  	setdata(fp, pph->vaddr, pph->filesz, pph->offset, pph->memsz - pph->filesz);
   802  	if(is != -1)
   803  		setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
   804  	else if(sh != 0){
   805  		char *buf;
   806  		uvlong symsize = 0;
   807  		uvlong symoff = 0;
   808  		uvlong pclnsz = 0;
   809  		uvlong pclnoff = 0;
   810  
   811  		/* load shstrtab names */
   812  		buf = malloc(sh[ep->shstrndx].size);
   813  		if (buf == 0)
   814  			goto done;
   815  		memset(buf, 0, sh[ep->shstrndx].size);
   816  		seek(fd, sh[ep->shstrndx].offset, 0);
   817  		i = read(fd, buf, sh[ep->shstrndx].size);
   818  		USED(i);	// shut up ubuntu gcc
   819  
   820  		for(i = 0; i < ep->shnum; i++) {
   821  			if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
   822  				symsize = sh[i].size;
   823  				symoff = sh[i].offset;
   824  			}
   825  			if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
   826  				pclnsz = sh[i].size;
   827  				pclnoff = sh[i].offset;
   828  			}
   829  		}
   830  		setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsz);
   831  		free(buf);
   832  	}
   833  done:
   834  	free(ph);
   835  	free(sh);
   836  	return 1;
   837  }
   838  
   839  static int
   840  elfdotout(int fd, Fhdr *fp, ExecHdr *hp)
   841  {
   842  
   843  	uint32 (*swal)(uint32);
   844  	ushort (*swab)(ushort);
   845  	Ehdr32 *ep;
   846  	Phdr32 *ph;
   847  	int i, it, id, is, phsz, shsz;
   848  	Shdr32 *sh;
   849  
   850  	/* bitswap the header according to the DATA format */
   851  	ep = &hp->e.elfhdr32;
   852  	if(ep->ident[CLASS] != ELFCLASS32) {
   853  		return elf64dotout(fd, fp, hp);
   854  	}
   855  	if(ep->ident[DATA] == ELFDATA2LSB) {
   856  		swab = leswab;
   857  		swal = leswal;
   858  	} else if(ep->ident[DATA] == ELFDATA2MSB) {
   859  		swab = beswab;
   860  		swal = beswal;
   861  	} else {
   862  		werrstr("bad ELF encoding - not big or little endian");
   863  		return 0;
   864  	}
   865  
   866  	ep->type = swab(ep->type);
   867  	ep->machine = swab(ep->machine);
   868  	ep->version = swal(ep->version);
   869  	ep->elfentry = swal(ep->elfentry);
   870  	ep->phoff = swal(ep->phoff);
   871  	ep->shoff = swal(ep->shoff);
   872  	ep->flags = swal(ep->flags);
   873  	ep->ehsize = swab(ep->ehsize);
   874  	ep->phentsize = swab(ep->phentsize);
   875  	ep->phnum = swab(ep->phnum);
   876  	ep->shentsize = swab(ep->shentsize);
   877  	ep->shnum = swab(ep->shnum);
   878  	ep->shstrndx = swab(ep->shstrndx);
   879  	if(ep->type != EXEC || ep->version != CURRENT)
   880  		return 0;
   881  
   882  	/* we could definitely support a lot more machines here */
   883  	fp->magic = ELF_MAG;
   884  	fp->hdrsz = (ep->ehsize+ep->phnum*ep->phentsize+16)&~15;
   885  	switch(ep->machine) {
   886  	case I386:
   887  		mach = &mi386;
   888  		fp->type = FI386;
   889  		break;
   890  	case MIPS:
   891  		mach = &mmips;
   892  		fp->type = FMIPS;
   893  		break;
   894  	case SPARC64:
   895  		mach = &msparc64;
   896  		fp->type = FSPARC64;
   897  		break;
   898  	case POWER:
   899  		mach = &mpower;
   900  		fp->type = FPOWER;
   901  		break;
   902  	case ARM:
   903  		mach = &marm;
   904  		fp->type = FARM;
   905  		break;
   906  	default:
   907  		return 0;
   908  	}
   909  
   910  	if(ep->phentsize != sizeof(Phdr32)) {
   911  		werrstr("bad ELF header size");
   912  		return 0;
   913  	}
   914  	phsz = sizeof(Phdr32)*ep->phnum;
   915  	ph = malloc(phsz);
   916  	if(!ph)
   917  		return 0;
   918  	seek(fd, ep->phoff, 0);
   919  	if(read(fd, ph, phsz) < 0) {
   920  		free(ph);
   921  		return 0;
   922  	}
   923  	hswal(ph, phsz/sizeof(uint32), swal);
   924  
   925  	shsz = sizeof(Shdr32)*ep->shnum;
   926  	sh = malloc(shsz);
   927  	if(sh) {
   928  		seek(fd, ep->shoff, 0);
   929  		if(read(fd, sh, shsz) < 0) {
   930  			free(sh);
   931  			sh = 0;
   932  		} else
   933  			hswal(sh, shsz/sizeof(uint32), swal);
   934  	}
   935  
   936  	/* find text, data and symbols and install them */
   937  	it = id = is = -1;
   938  	for(i = 0; i < ep->phnum; i++) {
   939  		if(ph[i].type == LOAD
   940  		&& (ph[i].flags & (R|X)) == (R|X) && it == -1)
   941  			it = i;
   942  		else if(ph[i].type == LOAD
   943  		&& (ph[i].flags & (R|W)) == (R|W) && id == -1)
   944  			id = i;
   945  		else if(ph[i].type == NOPTYPE && is == -1)
   946  			is = i;
   947  	}
   948  	if(it == -1 || id == -1) {
   949  		/*
   950  		 * The SPARC64 boot image is something of an ELF hack.
   951  		 * Text+Data+BSS are represented by ph[0].  Symbols
   952  		 * are represented by ph[1]:
   953  		 *
   954  		 *		filesz, memsz, vaddr, paddr, off
   955  		 * ph[0] : txtsz+datsz, txtsz+datsz+bsssz, txtaddr-KZERO, datasize, txtoff
   956  		 * ph[1] : symsz, lcsz, 0, 0, symoff
   957  		 */
   958  		if(ep->machine == SPARC64 && ep->phnum == 2) {
   959  			uint32 txtaddr, txtsz, dataddr, bsssz;
   960  
   961  			txtaddr = ph[0].vaddr | 0x80000000;
   962  			txtsz = ph[0].filesz - ph[0].paddr;
   963  			dataddr = txtaddr + txtsz;
   964  			bsssz = ph[0].memsz - ph[0].filesz;
   965  			settext(fp, ep->elfentry | 0x80000000, txtaddr, txtsz, ph[0].offset);
   966  			setdata(fp, dataddr, ph[0].paddr, ph[0].offset + txtsz, bsssz);
   967  			setsym(fp, ph[1].offset, ph[1].filesz, 0, 0, 0, ph[1].memsz);
   968  			free(ph);
   969  			return 1;
   970  		}
   971  
   972  		werrstr("No TEXT or DATA sections");
   973  		free(sh);
   974  		free(ph);
   975  		return 0;
   976  	}
   977  
   978  	settext(fp, ep->elfentry, ph[it].vaddr, ph[it].memsz, ph[it].offset);
   979  	setdata(fp, ph[id].vaddr, ph[id].filesz, ph[id].offset, ph[id].memsz - ph[id].filesz);
   980  	if(is != -1)
   981  		setsym(fp, ph[is].offset, ph[is].filesz, 0, 0, 0, ph[is].memsz);
   982  	else if(sh != 0){
   983  		char *buf;
   984  		uvlong symsize = 0;
   985  		uvlong symoff = 0;
   986  		uvlong pclnsize = 0;
   987  		uvlong pclnoff = 0;
   988  
   989  		/* load shstrtab names */
   990  		buf = malloc(sh[ep->shstrndx].size);
   991  		if (buf == 0)
   992  			goto done;
   993  		memset(buf, 0, sh[ep->shstrndx].size);
   994  		seek(fd, sh[ep->shstrndx].offset, 0);
   995  		i = read(fd, buf, sh[ep->shstrndx].size);
   996  		USED(i);	// shut up ubuntu gcc
   997  
   998  		for(i = 0; i < ep->shnum; i++) {
   999  			if (strcmp(&buf[sh[i].name], ".gosymtab") == 0) {
  1000  				symsize = sh[i].size;
  1001  				symoff = sh[i].offset;
  1002  			}
  1003  			if (strcmp(&buf[sh[i].name], ".gopclntab") == 0) {
  1004  				pclnsize = sh[i].size;
  1005  				pclnoff = sh[i].offset;
  1006  			}
  1007  		}
  1008  		setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
  1009  		free(buf);
  1010  	}
  1011  done:
  1012  	free(sh);
  1013  	free(ph);
  1014  	return 1;
  1015  }
  1016  
  1017  static int
  1018  machdotout(int fd, Fhdr *fp, ExecHdr *hp)
  1019  {
  1020  	uvlong (*swav)(uvlong);
  1021  	uint32 (*swal)(uint32);
  1022  	Machhdr *mp;
  1023  	MachCmd **cmd;
  1024  	MachSymSeg *symtab;
  1025  	MachSymSeg *pclntab;
  1026  	MachSeg64 *seg;
  1027  	MachSect64 *sect;
  1028  	MachSeg32 *seg32;
  1029  	MachSect32 *sect32;
  1030  	uvlong textsize, datasize, bsssize;
  1031  	uchar *cmdbuf;
  1032  	uchar *cmdp;
  1033  	int i, j, hdrsize;
  1034  	uint32 textva, textoff, datava, dataoff, symoff, symsize, pclnoff, pclnsize;
  1035  
  1036  	mp = &hp->e.machhdr;
  1037  	if (leswal(mp->filetype) != MACH_EXECUTABLE_TYPE) {
  1038  		werrstr("bad MACH executable type %#ux", leswal(mp->filetype));
  1039  		return 0;
  1040  	}
  1041  
  1042  	swal = leswal;
  1043  	swav = leswav;
  1044  
  1045  	mp->magic = swal(mp->magic);
  1046  	mp->cputype = swal(mp->cputype);
  1047  	mp->cpusubtype = swal(mp->cpusubtype);
  1048  	mp->filetype = swal(mp->filetype);
  1049  	mp->ncmds = swal(mp->ncmds);
  1050  	mp->sizeofcmds = swal(mp->sizeofcmds);
  1051  	mp->flags = swal(mp->flags);
  1052  	mp->reserved = swal(mp->reserved);
  1053  
  1054  	switch(mp->magic) {
  1055  	case 0xFEEDFACE:	// 32-bit mach
  1056  		if (mp->cputype != MACH_CPU_TYPE_X86) {
  1057  			werrstr("bad MACH cpu type - not 386");
  1058  			return 0;
  1059  		}
  1060  		if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
  1061  			werrstr("bad MACH cpu subtype - not 386");
  1062  			return 0;
  1063  		}
  1064  		if (mp->filetype != MACH_EXECUTABLE_TYPE) {
  1065  			werrstr("bad MACH executable type");
  1066  			return 0;
  1067  		}
  1068  		mach = &mi386;
  1069  		fp->type = FI386;
  1070  		hdrsize = 28;
  1071  		break;
  1072  
  1073  	case 0xFEEDFACF:	// 64-bit mach
  1074  		if (mp->cputype != MACH_CPU_TYPE_X86_64) {
  1075  			werrstr("bad MACH cpu type - not amd64");
  1076  			return 0;
  1077  		}
  1078  
  1079  		if (mp->cpusubtype != MACH_CPU_SUBTYPE_X86) {
  1080  			werrstr("bad MACH cpu subtype - not amd64");
  1081  			return 0;
  1082  		}
  1083  		mach = &mamd64;
  1084  		fp->type = FAMD64;
  1085  		hdrsize = 32;
  1086  		break;
  1087  
  1088  	default:
  1089  		werrstr("not mach %#ux", mp->magic);
  1090  		return 0;
  1091  	}
  1092  
  1093  	cmdbuf = malloc(mp->sizeofcmds);
  1094  	if(!cmdbuf) {
  1095  		werrstr("out of memory");
  1096  		return 0;
  1097  	}
  1098  	seek(fd, hdrsize, 0);
  1099  	if(read(fd, cmdbuf, mp->sizeofcmds) != mp->sizeofcmds) {
  1100  		free(cmdbuf);
  1101  		return 0;
  1102  	}
  1103  	cmd = malloc(mp->ncmds * sizeof(MachCmd*));
  1104  	if(!cmd) {
  1105  		free(cmdbuf);
  1106  		werrstr("out of memory");
  1107  		return 0;
  1108  	}
  1109  	cmdp = cmdbuf;
  1110  	textva = 0;
  1111  	textoff = 0;
  1112  	dataoff = 0;
  1113  	datava = 0;
  1114  	symtab = 0;
  1115  	pclntab = 0;
  1116  	textsize = 0;
  1117  	datasize = 0;
  1118  	bsssize = 0;
  1119  	symoff = 0;
  1120  	symsize = 0;
  1121  	pclnoff = 0;
  1122  	pclnsize = 0;
  1123  	for (i = 0; i < mp->ncmds; i++) {
  1124  		MachCmd *c;
  1125  
  1126  		cmd[i] = (MachCmd*)cmdp;
  1127  		c = cmd[i];
  1128  		c->type = swal(c->type);
  1129  		c->size = swal(c->size);
  1130  		switch(c->type) {
  1131  		case MACH_SEGMENT_32:
  1132  			if(mp->magic != 0xFEEDFACE) {
  1133  				werrstr("segment 32 in mach 64");
  1134  				goto bad;
  1135  			}
  1136  			seg32 = (MachSeg32*)c;
  1137  			seg32->vmaddr = swav(seg32->vmaddr);
  1138  			seg32->vmsize = swav(seg32->vmsize);
  1139  			seg32->fileoff = swav(seg32->fileoff);
  1140  			seg32->filesize = swav(seg32->filesize);
  1141  			seg32->maxprot = swal(seg32->maxprot);
  1142  			seg32->initprot = swal(seg32->initprot);
  1143  			seg32->nsects = swal(seg32->nsects);
  1144  			seg32->flags = swal(seg32->flags);
  1145  			if (strcmp(seg32->segname, "__TEXT") == 0) {
  1146  				textva = seg32->vmaddr;
  1147  				textoff = seg32->fileoff;
  1148  				textsize = seg32->vmsize;
  1149  				sect32 = (MachSect32*)(cmdp + sizeof(MachSeg32));
  1150  				for(j = 0; j < seg32->nsects; j++, sect32++) {
  1151  					if (strcmp(sect32->sectname, "__gosymtab") == 0) {
  1152  						symoff = swal(sect32->offset);
  1153  						symsize = swal(sect32->size);
  1154  					}
  1155  					if (strcmp(sect32->sectname, "__gopclntab") == 0) {
  1156  						pclnoff = swal(sect32->offset);
  1157  						pclnsize = swal(sect32->size);
  1158  					}
  1159  				}
  1160  			}
  1161  			if (strcmp(seg32->segname, "__DATA") == 0) {
  1162  				datava = seg32->vmaddr;
  1163  				dataoff = seg32->fileoff;
  1164  				datasize = seg32->filesize;
  1165  				bsssize = seg32->vmsize - seg32->filesize;
  1166  			}
  1167  			break;
  1168  
  1169  		case MACH_SEGMENT_64:
  1170  			if(mp->magic != 0xFEEDFACF) {
  1171  				werrstr("segment 32 in mach 64");
  1172  				goto bad;
  1173  			}
  1174  			seg = (MachSeg64*)c;
  1175  			seg->vmaddr = swav(seg->vmaddr);
  1176  			seg->vmsize = swav(seg->vmsize);
  1177  			seg->fileoff = swav(seg->fileoff);
  1178  			seg->filesize = swav(seg->filesize);
  1179  			seg->maxprot = swal(seg->maxprot);
  1180  			seg->initprot = swal(seg->initprot);
  1181  			seg->nsects = swal(seg->nsects);
  1182  			seg->flags = swal(seg->flags);
  1183  			if (strcmp(seg->segname, "__TEXT") == 0) {
  1184  				textva = seg->vmaddr;
  1185  				textoff = seg->fileoff;
  1186  				textsize = seg->vmsize;
  1187  				sect = (MachSect64*)(cmdp + sizeof(MachSeg64));
  1188  				for(j = 0; j < seg->nsects; j++, sect++) {
  1189  					if (strcmp(sect->sectname, "__gosymtab") == 0) {
  1190  						symoff = swal(sect->offset);
  1191  						symsize = swal(sect->size);
  1192  					}
  1193  					if (strcmp(sect->sectname, "__gopclntab") == 0) {
  1194  						pclnoff = swal(sect->offset);
  1195  						pclnsize = swal(sect->size);
  1196  					}
  1197  				}
  1198  			}
  1199  			if (strcmp(seg->segname, "__DATA") == 0) {
  1200  				datava = seg->vmaddr;
  1201  				dataoff = seg->fileoff;
  1202  				datasize = seg->filesize;
  1203  				bsssize = seg->vmsize - seg->filesize;
  1204  			}
  1205  			break;
  1206  		case MACH_UNIXTHREAD:
  1207  			break;
  1208  		case MACH_SYMSEG:
  1209  			if (symtab == 0) {
  1210  				symtab = (MachSymSeg*)c;
  1211  				symoff = swal(symtab->fileoff);
  1212  				symsize = swal(symtab->filesize);
  1213  			} else if (pclntab == 0) {
  1214  				pclntab = (MachSymSeg*)c;
  1215  				pclnoff = swal(pclntab->fileoff);
  1216  				pclnsize = swal(pclntab->filesize);
  1217  			}
  1218  			break;
  1219  		}
  1220  		cmdp += c->size;
  1221  	}
  1222  	if (textva == 0 || datava == 0) {
  1223  		free(cmd);
  1224  		free(cmdbuf);
  1225  		return 0;
  1226  	}
  1227  	/* compute entry by taking address after header - weird - BUG? */
  1228  	settext(fp, textva+sizeof(Machhdr) + mp->sizeofcmds, textva, textsize, textoff);
  1229  	setdata(fp, datava, datasize, dataoff, bsssize);
  1230  	if(symoff > 0)
  1231  		setsym(fp, symoff, symsize, 0, 0, pclnoff, pclnsize);
  1232  	free(cmd);
  1233  	free(cmdbuf);
  1234  	return 1;
  1235  bad:
  1236  	free(cmd);
  1237  	free(cmdbuf);
  1238  	return 0;
  1239  }
  1240  
  1241  /*
  1242   * (Free|Net)BSD ARM header.
  1243   */
  1244  static int
  1245  armdotout(int fd, Fhdr *fp, ExecHdr *hp)
  1246  {
  1247  	uvlong kbase;
  1248  
  1249  	USED(fd);
  1250  	settext(fp, hp->e.exechdr.entry, sizeof(Exec), hp->e.exechdr.text, sizeof(Exec));
  1251  	setdata(fp, fp->txtsz, hp->e.exechdr.data, fp->txtsz, hp->e.exechdr.bss);
  1252  	setsym(fp, fp->datoff+fp->datsz, hp->e.exechdr.syms, 0, hp->e.exechdr.spsz, 0, hp->e.exechdr.pcsz);
  1253  
  1254  	kbase = 0xF0000000;
  1255  	if ((fp->entry & kbase) == kbase) {		/* Boot image */
  1256  		fp->txtaddr = kbase+sizeof(Exec);
  1257  		fp->name = "ARM *BSD boot image";
  1258  		fp->hdrsz = 0;		/* header stripped */
  1259  		fp->dataddr = kbase+fp->txtsz;
  1260  	}
  1261  	return 1;
  1262  }
  1263  
  1264  /*
  1265   * Structures needed to parse PE image.
  1266   */
  1267  typedef struct {
  1268  	uint16 Machine;
  1269  	uint16 NumberOfSections;
  1270  	uint32 TimeDateStamp;
  1271  	uint32 PointerToSymbolTable;
  1272  	uint32 NumberOfSymbols;
  1273  	uint16 SizeOfOptionalHeader;
  1274  	uint16 Characteristics;
  1275  } IMAGE_FILE_HEADER;
  1276  
  1277  typedef struct {
  1278  	uint8  Name[8];
  1279  	uint32 VirtualSize;
  1280  	uint32 VirtualAddress;
  1281  	uint32 SizeOfRawData;
  1282  	uint32 PointerToRawData;
  1283  	uint32 PointerToRelocations;
  1284  	uint32 PointerToLineNumbers;
  1285  	uint16 NumberOfRelocations;
  1286  	uint16 NumberOfLineNumbers;
  1287  	uint32 Characteristics;
  1288  } IMAGE_SECTION_HEADER;
  1289  
  1290  typedef struct {
  1291  	uint32 VirtualAddress;
  1292  	uint32 Size;
  1293  } IMAGE_DATA_DIRECTORY;
  1294  
  1295  typedef struct {
  1296  	uint16 Magic;
  1297  	uint8  MajorLinkerVersion;
  1298  	uint8  MinorLinkerVersion;
  1299  	uint32 SizeOfCode;
  1300  	uint32 SizeOfInitializedData;
  1301  	uint32 SizeOfUninitializedData;
  1302  	uint32 AddressOfEntryPoint;
  1303  	uint32 BaseOfCode;
  1304  	uint32 BaseOfData;
  1305  	uint32 ImageBase;
  1306  	uint32 SectionAlignment;
  1307  	uint32 FileAlignment;
  1308  	uint16 MajorOperatingSystemVersion;
  1309  	uint16 MinorOperatingSystemVersion;
  1310  	uint16 MajorImageVersion;
  1311  	uint16 MinorImageVersion;
  1312  	uint16 MajorSubsystemVersion;
  1313  	uint16 MinorSubsystemVersion;
  1314  	uint32 Win32VersionValue;
  1315  	uint32 SizeOfImage;
  1316  	uint32 SizeOfHeaders;
  1317  	uint32 CheckSum;
  1318  	uint16 Subsystem;
  1319  	uint16 DllCharacteristics;
  1320  	uint32 SizeOfStackReserve;
  1321  	uint32 SizeOfStackCommit;
  1322  	uint32 SizeOfHeapReserve;
  1323  	uint32 SizeOfHeapCommit;
  1324  	uint32 LoaderFlags;
  1325  	uint32 NumberOfRvaAndSizes;
  1326  	IMAGE_DATA_DIRECTORY DataDirectory[16];
  1327  } IMAGE_OPTIONAL_HEADER;
  1328  
  1329  typedef struct {
  1330  	uint16 Magic;
  1331  	uint8  MajorLinkerVersion;
  1332  	uint8  MinorLinkerVersion;
  1333  	uint32 SizeOfCode;
  1334  	uint32 SizeOfInitializedData;
  1335  	uint32 SizeOfUninitializedData;
  1336  	uint32 AddressOfEntryPoint;
  1337  	uint32 BaseOfCode;
  1338  	uint64 ImageBase;
  1339  	uint32 SectionAlignment;
  1340  	uint32 FileAlignment;
  1341  	uint16 MajorOperatingSystemVersion;
  1342  	uint16 MinorOperatingSystemVersion;
  1343  	uint16 MajorImageVersion;
  1344  	uint16 MinorImageVersion;
  1345  	uint16 MajorSubsystemVersion;
  1346  	uint16 MinorSubsystemVersion;
  1347  	uint32 Win32VersionValue;
  1348  	uint32 SizeOfImage;
  1349  	uint32 SizeOfHeaders;
  1350  	uint32 CheckSum;
  1351  	uint16 Subsystem;
  1352  	uint16 DllCharacteristics;
  1353  	uint64 SizeOfStackReserve;
  1354  	uint64 SizeOfStackCommit;
  1355  	uint64 SizeOfHeapReserve;
  1356  	uint64 SizeOfHeapCommit;
  1357  	uint32 LoaderFlags;
  1358  	uint32 NumberOfRvaAndSizes;
  1359  	IMAGE_DATA_DIRECTORY DataDirectory[16];
  1360  } PE64_IMAGE_OPTIONAL_HEADER;
  1361  
  1362  static int
  1363  match8(void *buf, char *cmp)
  1364  {
  1365  	return strncmp((char*)buf, cmp, 8) == 0;
  1366  }
  1367  
  1368  /*
  1369   * Read from Windows PE/COFF .exe file image.
  1370   */
  1371  static int
  1372  pedotout(int fd, Fhdr *fp, ExecHdr *hp)
  1373  {
  1374  	uint32 start, magic;
  1375  	uint32 symtab, esymtab, pclntab, epclntab;
  1376  	IMAGE_FILE_HEADER fh;
  1377  	IMAGE_SECTION_HEADER sh;
  1378  	IMAGE_OPTIONAL_HEADER oh;
  1379  	PE64_IMAGE_OPTIONAL_HEADER oh64;
  1380  	uint8 sym[18];
  1381  	uint32 *valp, ib, entry;
  1382  	int i, ohoffset;
  1383  
  1384  	USED(hp);
  1385  	seek(fd, 0x3c, 0);
  1386  	if (readn(fd, &start, sizeof(start)) != sizeof(start)) {
  1387  		werrstr("crippled PE MSDOS header");
  1388  		return 0;
  1389  	}
  1390  	start = leswal(start);
  1391  
  1392  	seek(fd, start, 0);
  1393  	if (readn(fd, &magic, sizeof(magic)) != sizeof(magic)) {
  1394  		werrstr("no PE magic number found");
  1395  		return 0;
  1396  	}
  1397  	if (beswal(magic) != 0x50450000) {  /* "PE\0\0" */
  1398  		werrstr("incorrect PE magic number");
  1399  		return 0;
  1400  	}
  1401  
  1402  	if (readn(fd, &fh, sizeof(fh)) != sizeof(fh)) {
  1403  		werrstr("crippled PE File Header");
  1404  		return 0;
  1405  	}
  1406  	if (fh.PointerToSymbolTable == 0) {
  1407  		werrstr("zero pointer to COFF symbol table");
  1408  		return 0;
  1409  	}
  1410  
  1411  	ohoffset = seek(fd, 0, 1);
  1412  	if (readn(fd, &oh, sizeof(oh)) != sizeof(oh)) {
  1413  		werrstr("crippled PE Optional Header");
  1414  		return 0;
  1415  	}
  1416  
  1417  	switch(oh.Magic) {
  1418  	case 0x10b:	// PE32
  1419  		fp->type = FI386;
  1420  		ib = leswal(oh.ImageBase);
  1421  		entry = leswal(oh.AddressOfEntryPoint);
  1422  		break;
  1423  	case 0x20b:	// PE32+
  1424  		fp->type = FAMD64;
  1425  		seek(fd, ohoffset, 0);
  1426  		if (readn(fd, &oh64, sizeof(oh64)) != sizeof(oh64)) {
  1427  			werrstr("crippled PE32+ Optional Header");
  1428  			return 0;
  1429  		}
  1430  		ib = leswal(oh64.ImageBase);
  1431  		entry = leswal(oh64.AddressOfEntryPoint);
  1432  		break;
  1433  	default:
  1434  		werrstr("invalid PE Optional Header magic number");
  1435  		return 0;
  1436  	}
  1437  
  1438  	fp->txtaddr = 0;
  1439  	fp->dataddr = 0;
  1440  	for (i=0; i<leswab(fh.NumberOfSections); i++) {
  1441  		if (readn(fd, &sh, sizeof(sh)) != sizeof(sh)) {
  1442  			werrstr("could not read Section Header %d", i+1);
  1443  			return 0;
  1444  		}
  1445  		if (match8(sh.Name, ".text"))
  1446  			settext(fp, ib+entry, ib+leswal(sh.VirtualAddress), leswal(sh.VirtualSize), leswal(sh.PointerToRawData));
  1447  		if (match8(sh.Name, ".data"))
  1448  			setdata(fp, ib+leswal(sh.VirtualAddress), leswal(sh.SizeOfRawData), leswal(sh.PointerToRawData), leswal(sh.VirtualSize)-leswal(sh.SizeOfRawData));
  1449  	}
  1450  	if (fp->txtaddr==0 || fp->dataddr==0) {
  1451  		werrstr("no .text or .data");
  1452  		return 0;
  1453  	}
  1454  
  1455  	seek(fd, leswal(fh.PointerToSymbolTable), 0);
  1456  	symtab = esymtab = pclntab = epclntab = 0;
  1457  	for (i=0; i<leswal(fh.NumberOfSymbols); i++) {
  1458  		if (readn(fd, sym, sizeof(sym)) != sizeof(sym)) {
  1459  			werrstr("crippled COFF symbol %d", i);
  1460  			return 0;
  1461  		}
  1462  		valp = (uint32 *)&sym[8];
  1463  		if (match8(sym, "symtab"))
  1464  			symtab = leswal(*valp);
  1465  		if (match8(sym, "esymtab"))
  1466  			esymtab = leswal(*valp);
  1467  		if (match8(sym, "pclntab"))
  1468  			pclntab = leswal(*valp);
  1469  		if (match8(sym, "epclntab"))
  1470  			epclntab = leswal(*valp);
  1471  	}
  1472  	if (symtab==0 || esymtab==0 || pclntab==0 || epclntab==0) {
  1473  		werrstr("no symtab or esymtab or pclntab or epclntab in COFF symbol table");
  1474  		return 0;
  1475  	}
  1476  	setsym(fp, symtab, esymtab-symtab, 0, 0, pclntab, epclntab-pclntab);
  1477  
  1478  	return 1;
  1479  }
  1480  
  1481  static void
  1482  settext(Fhdr *fp, uvlong e, uvlong a, int32 s, vlong off)
  1483  {
  1484  	fp->txtaddr = a;
  1485  	fp->entry = e;
  1486  	fp->txtsz = s;
  1487  	fp->txtoff = off;
  1488  }
  1489  
  1490  static void
  1491  setdata(Fhdr *fp, uvlong a, int32 s, vlong off, int32 bss)
  1492  {
  1493  	fp->dataddr = a;
  1494  	fp->datsz = s;
  1495  	fp->datoff = off;
  1496  	fp->bsssz = bss;
  1497  }
  1498  
  1499  static void
  1500  setsym(Fhdr *fp, vlong symoff, int32 symsz, vlong sppcoff, int32 sppcsz, vlong lnpcoff, int32 lnpcsz)
  1501  {
  1502  	fp->symoff = symoff;
  1503  	fp->symsz = symsz;
  1504  	
  1505  	if(sppcoff == 0)
  1506  		sppcoff = symoff+symsz;
  1507  	fp->sppcoff = symoff;
  1508  	fp->sppcsz = sppcsz;
  1509  
  1510  	if(lnpcoff == 0)
  1511  		lnpcoff = sppcoff + sppcsz;
  1512  	fp->lnpcoff = lnpcoff;
  1513  	fp->lnpcsz = lnpcsz;
  1514  }
  1515  
  1516  static uvlong
  1517  _round(uvlong a, uint32 b)
  1518  {
  1519  	uvlong w;
  1520  
  1521  	w = (a/b)*b;
  1522  	if (a!=w)
  1523  		w += b;
  1524  	return(w);
  1525  }