1/*	$OpenBSD: file.c,v 1.19 2017/10/29 08:45:53 mpi Exp $ */
2
3/*
4 * Copyright (c) 1995-96 Mats O Jansson.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "os.h"
28#include "common.h"
29#include "file.h"
30#include "mopdef.h"
31#include <stddef.h>
32
33#ifndef NOAOUT
34#if defined(__OpenBSD__)
35#include <sys/exec.h>
36#endif
37#if defined(__bsdi__)
38#define NOAOUT
39#endif
40#if defined(__FreeBSD__)
41#include <sys/imgact_aout.h>
42#endif
43#if !defined(MID_I386)
44#define MID_I386 134
45#endif
46#if !defined(MID_SPARC)
47#define MID_SPARC 138
48#endif
49#if !defined(MID_VAX)
50#define MID_VAX 140
51#endif
52#endif
53
54#ifndef NOELF
55#if defined(__OpenBSD__)
56#include <elf.h>
57#else
58#define NOELF
59#endif
60#endif
61
62#ifndef NOELF
63#if !defined(_LP64)
64#define NOELF64
65#endif
66#endif
67
68#ifndef NOAOUT
69static int	getCLBYTES(int);
70static int	getMID(int, int);
71#endif
72
73const char *
74FileTypeName(mopd_imagetype type)
75{
76
77	switch (type) {
78	case IMAGE_TYPE_MOP:
79		return ("MOP");
80
81	case IMAGE_TYPE_ELF32:
82		return ("Elf32");
83
84	case IMAGE_TYPE_ELF64:
85		return ("Elf64");
86
87	case IMAGE_TYPE_AOUT:
88		return ("a.out");
89	}
90
91	abort();
92}
93
94void
95mopFilePutLX(u_char *buf, int idx, u_int32_t value, int cnt)
96{
97	int i;
98	for (i = 0; i < cnt; i++) {
99		buf[idx+i] = value % 256;
100		value = value / 256;
101	}
102}
103
104void
105mopFilePutBX(u_char *buf, int idx, u_int32_t value, int cnt)
106{
107	int i;
108	for (i = 0; i < cnt; i++) {
109		buf[idx+cnt-1-i] = value % 256;
110		value = value / 256;
111	}
112}
113
114u_int32_t
115mopFileGetLX(u_char *buf, int idx, int cnt)
116{
117	u_int32_t ret = 0;
118	int i;
119
120	for (i = 0; i < cnt; i++) {
121		int j = idx + cnt - 1 - i;
122		if (j < 0)
123			abort();
124		ret = ret * 256 + buf[j];
125	}
126
127	return(ret);
128}
129
130u_int32_t
131mopFileGetBX(u_char *buf, int idx, int cnt)
132{
133	u_int32_t ret = 0;
134	int i;
135
136	for (i = 0; i < cnt; i++) {
137		int j = idx + i;
138		if (j < 0)
139			abort();
140		ret = ret * 256 + buf[j];
141	}
142
143	return(ret);
144}
145
146#if !defined(NOELF) && !defined(NOELF64)
147u_int64_t
148mopFileGetLXX(u_char *buf, int idx, int cnt)
149{
150	u_int64_t ret = 0;
151	int i;
152
153	for (i = 0; i < cnt; i++) {
154		int j = idx + cnt - 1 - i;
155		if (j < 0)
156			abort();
157		ret = ret * 256 + buf[j];
158	}
159
160	return(ret);
161}
162
163u_int64_t
164mopFileGetBXX(u_char *buf, int idx, int cnt)
165{
166	u_int64_t ret = 0;
167	int i;
168
169	for (i = 0; i < cnt; i++) {
170		int j = idx + i;
171		if (j < 0)
172			abort();
173		ret = ret * 256 + buf[j];
174	}
175
176	return(ret);
177}
178#endif
179
180void
181mopFileSwapX(u_char *buf, int idx, int cnt)
182{
183	int i;
184	u_char c;
185
186	for (i = 0; i < (cnt / 2); i++) {
187		c = buf[idx+i];
188		buf[idx+i] = buf[idx+cnt-1-i];
189		buf[idx+cnt-1-i] = c;
190	}
191
192}
193
194int
195CheckMopFile(int fd)
196{
197	u_char	header[512];
198	short	image_type;
199
200	if (read(fd, header, 512) != 512)
201		return(-1);
202
203	(void)lseek(fd, (off_t) 0, SEEK_SET);
204
205	image_type = (u_short)(header[IHD_W_ALIAS+1]*256 + header[IHD_W_ALIAS]);
206
207	switch(image_type) {
208	case IHD_C_NATIVE:		/* Native mode image (VAX)   */
209	case IHD_C_RSX:			/* RSX image produced by TKB */
210	case IHD_C_BPA:			/* BASIC plus analog         */
211	case IHD_C_ALIAS:		/* Alias		     */
212	case IHD_C_CLI:			/* Image is CLI		     */
213	case IHD_C_PMAX:		/* PMAX system image	     */
214	case IHD_C_ALPHA:		/* ALPHA system image	     */
215		break;
216	default:
217		return(-1);
218	}
219
220	return(0);
221}
222
223int
224GetMopFileInfo(struct dllist *dl, int info)
225{
226	u_char		header[512];
227	short		image_type;
228	u_int32_t	load_addr, xfr_addr, isd, iha, hbcnt, isize;
229
230	if (read(dl->ldfd, header, 512) != 512)
231		return(-1);
232
233	image_type = (u_short)(header[IHD_W_ALIAS+1]*256 +
234			       header[IHD_W_ALIAS]);
235
236	switch (image_type) {
237	case IHD_C_NATIVE:		/* Native mode image (VAX)   */
238		isd = (header[IHD_W_SIZE+1]*256 +
239		       header[IHD_W_SIZE]);
240		iha = (header[IHD_W_ACTIVOFF+1]*256 +
241		       header[IHD_W_ACTIVOFF]);
242		hbcnt = (header[IHD_B_HDRBLKCNT]);
243		isize = (header[isd+ISD_W_PAGCNT+1]*256 +
244			 header[isd+ISD_W_PAGCNT]) * 512;
245		load_addr = ((header[isd+ISD_V_VPN+1]*256 +
246			      header[isd+ISD_V_VPN]) & ISD_M_VPN)
247				* 512;
248		xfr_addr = (header[iha+IHA_L_TFRADR1+3]*0x1000000 +
249			    header[iha+IHA_L_TFRADR1+2]*0x10000 +
250			    header[iha+IHA_L_TFRADR1+1]*0x100 +
251			    header[iha+IHA_L_TFRADR1]) & 0x7fffffff;
252		if (info == INFO_PRINT) {
253			printf("Native Image (VAX)\n");
254			printf("Header Block Count: %d\n",hbcnt);
255			printf("Image Size:         %08x\n",isize);
256			printf("Load Address:       %08x\n",load_addr);
257			printf("Transfer Address:   %08x\n",xfr_addr);
258		}
259		break;
260	case IHD_C_RSX:			/* RSX image produced by TKB */
261		hbcnt = header[L_BBLK+1]*256 + header[L_BBLK];
262		isize = (header[L_BLDZ+1]*256 + header[L_BLDZ]) * 64;
263		load_addr = header[L_BSA+1]*256 + header[L_BSA];
264		xfr_addr  = header[L_BXFR+1]*256 + header[L_BXFR];
265		if (info == INFO_PRINT) {
266			printf("RSX Image\n");
267			printf("Header Block Count: %d\n",hbcnt);
268			printf("Image Size:         %08x\n",isize);
269			printf("Load Address:       %08x\n",load_addr);
270			printf("Transfer Address:   %08x\n",xfr_addr);
271		}
272		break;
273	case IHD_C_BPA:			/* BASIC plus analog         */
274		if (info == INFO_PRINT) {
275			printf("BASIC-Plus Image, not supported\n");
276		}
277		return(-1);
278		break;
279	case IHD_C_ALIAS:		/* Alias		     */
280		if (info == INFO_PRINT) {
281			printf("Alias, not supported\n");
282		}
283		return(-1);
284		break;
285	case IHD_C_CLI:			/* Image is CLI		     */
286		if (info == INFO_PRINT) {
287			printf("CLI, not supported\n");
288		}
289		return(-1);
290		break;
291	case IHD_C_PMAX:		/* PMAX system image	     */
292		isd = (header[IHD_W_SIZE+1]*256 +
293		       header[IHD_W_SIZE]);
294		iha = (header[IHD_W_ACTIVOFF+1]*256 +
295		       header[IHD_W_ACTIVOFF]);
296		hbcnt = (header[IHD_B_HDRBLKCNT]);
297		isize = (header[isd+ISD_W_PAGCNT+1]*256 +
298			 header[isd+ISD_W_PAGCNT]) * 512;
299		load_addr = (header[isd+ISD_V_VPN+1]*256 +
300			     header[isd+ISD_V_VPN]) * 512;
301		xfr_addr = (header[iha+IHA_L_TFRADR1+3]*0x1000000 +
302			    header[iha+IHA_L_TFRADR1+2]*0x10000 +
303			    header[iha+IHA_L_TFRADR1+1]*0x100 +
304			    header[iha+IHA_L_TFRADR1]);
305		if (info == INFO_PRINT) {
306			printf("PMAX Image \n");
307			printf("Header Block Count: %d\n",hbcnt);
308			printf("Image Size:         %08x\n",isize);
309			printf("Load Address:       %08x\n",load_addr);
310			printf("Transfer Address:   %08x\n",xfr_addr);
311		}
312		break;
313	case IHD_C_ALPHA:		/* ALPHA system image	     */
314		isd = (header[EIHD_L_ISDOFF+3]*0x1000000 +
315		       header[EIHD_L_ISDOFF+2]*0x10000 +
316		       header[EIHD_L_ISDOFF+1]*0x100 +
317		       header[EIHD_L_ISDOFF]);
318		hbcnt = (header[EIHD_L_HDRBLKCNT+3]*0x1000000 +
319			 header[EIHD_L_HDRBLKCNT+2]*0x10000 +
320			 header[EIHD_L_HDRBLKCNT+1]*0x100 +
321			 header[EIHD_L_HDRBLKCNT]);
322		isize = (header[isd+EISD_L_SECSIZE+3]*0x1000000 +
323			 header[isd+EISD_L_SECSIZE+2]*0x10000 +
324			 header[isd+EISD_L_SECSIZE+1]*0x100 +
325			 header[isd+EISD_L_SECSIZE]);
326		load_addr = 0;
327		xfr_addr = 0;
328		if (info == INFO_PRINT) {
329			printf("Alpha Image \n");
330			printf("Header Block Count: %d\n",hbcnt);
331			printf("Image Size:         %08x\n",isize);
332			printf("Load Address:       %08x\n",load_addr);
333			printf("Transfer Address:   %08x\n",xfr_addr);
334		}
335		break;
336	default:
337		if (info == INFO_PRINT) {
338			printf("Unknown Image (%d)\n",image_type);
339		}
340		return(-1);
341	}
342
343	dl->image_type = IMAGE_TYPE_MOP;
344	dl->loadaddr = load_addr;
345	dl->xferaddr = xfr_addr;
346
347	return(0);
348}
349
350#ifndef NOAOUT
351static int
352getMID(int old_mid, int new_mid)
353{
354	int	mid;
355
356	mid = old_mid;
357
358	switch (new_mid) {
359	case MID_I386:
360		mid = MID_I386;
361		break;
362#ifdef MID_M68K
363	case MID_M68K:
364		mid = MID_M68K;
365		break;
366#endif
367#ifdef MID_M68K4K
368	case MID_M68K4K:
369		mid = MID_M68K4K;
370		break;
371#endif
372#ifdef MID_NS32532
373	case MID_NS32532:
374		mid = MID_NS32532;
375		break;
376#endif
377	case MID_SPARC:
378		mid = MID_SPARC;
379		break;
380#ifdef MID_PMAX
381	case MID_PMAX:
382		mid = MID_PMAX;
383		break;
384#endif
385#ifdef MID_VAX
386	case MID_VAX:
387		mid = MID_VAX;
388		break;
389#endif
390#ifdef MID_ALPHA
391	case MID_ALPHA:
392		mid = MID_ALPHA;
393		break;
394#endif
395#ifdef MID_MIPS
396	case MID_MIPS:
397		mid = MID_MIPS;
398		break;
399#endif
400#ifdef MID_ARM6
401	case MID_ARM6:
402		mid = MID_ARM6;
403		break;
404#endif
405	default:
406		break;
407	}
408
409	return(mid);
410}
411
412static int
413getCLBYTES(int mid)
414{
415	int	clbytes;
416
417	switch (mid) {
418#ifdef MID_VAX
419	case MID_VAX:
420		clbytes = 1024;
421		break;
422#endif
423#ifdef MID_I386
424	case MID_I386:
425#endif
426#ifdef MID_M68K4K
427	case MID_M68K4K:
428#endif
429#ifdef MID_NS32532
430	case MID_NS32532:
431#endif
432#ifdef MID_PMAX
433	case MID_PMAX:
434#endif
435#ifdef MID_MIPS
436	case MID_MIPS:
437#endif
438#ifdef MID_ARM6
439	case MID_ARM6:
440#endif
441#if defined(MID_I386) || defined(MID_M68K4K) || defined(MID_NS32532) || \
442    defined(MID_PMAX) || defined(MID_MIPS) || defined(MID_ARM6)
443		clbytes = 4096;
444		break;
445#endif
446#ifdef MID_M68K
447	case MID_M68K:
448#endif
449#ifdef MID_ALPHA
450	case MID_ALPHA:
451#endif
452#ifdef MID_SPARC
453	case MID_SPARC:
454#endif
455#if defined(MID_M68K) || defined(MID_ALPHA) || defined(MID_SPARC)
456		clbytes = 8192;
457		break;
458#endif
459	default:
460		clbytes = 0;
461	}
462
463	return(clbytes);
464}
465#endif
466
467int
468CheckElfFile(int fd)
469{
470#ifdef NOELF
471	return(-1);
472#else
473	Elf32_Ehdr ehdr;
474
475	(void)lseek(fd, (off_t) 0, SEEK_SET);
476
477	if (read(fd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr))
478		return(-1);
479
480	if (ehdr.e_ident[0] != ELFMAG0 ||
481	    ehdr.e_ident[1] != ELFMAG1 ||
482	    ehdr.e_ident[2] != ELFMAG2 ||
483	    ehdr.e_ident[3] != ELFMAG3)
484		return(-1);
485
486	/* Must be Elf32 or Elf64... */
487	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32 &&
488	    ehdr.e_ident[EI_CLASS] != ELFCLASS64)
489		return(-1);
490
491	return(0);
492#endif /* NOELF */
493}
494
495int
496GetElf32FileInfo(struct dllist *dl, int info)
497{
498#ifdef NOELF
499	return(-1);
500#else
501	Elf32_Ehdr ehdr;
502	Elf32_Phdr phdr;
503	uint32_t e_machine, e_entry;
504	uint32_t e_phoff, e_phentsize, e_phnum;
505	int ei_data, i;
506
507	(void)lseek(dl->ldfd, (off_t) 0, SEEK_SET);
508
509	if (read(dl->ldfd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr))
510		return(-1);
511
512	if (ehdr.e_ident[0] != ELFMAG0 ||
513	    ehdr.e_ident[1] != ELFMAG1 ||
514	    ehdr.e_ident[2] != ELFMAG2 ||
515	    ehdr.e_ident[3] != ELFMAG3)
516		return(-1);
517
518	/* Must be Elf32... */
519	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32)
520		return(-1);
521
522	ei_data = ehdr.e_ident[EI_DATA];
523
524	switch (ei_data) {
525	case ELFDATA2LSB:
526		e_machine = mopFileGetLX((u_char *) &ehdr,
527		    offsetof(Elf32_Ehdr, e_machine),
528		    sizeof(ehdr.e_machine));
529		e_entry = mopFileGetLX((u_char *) &ehdr,
530		    offsetof(Elf32_Ehdr, e_entry),
531		    sizeof(ehdr.e_entry));
532
533		e_phoff = mopFileGetLX((u_char *) &ehdr,
534		    offsetof(Elf32_Ehdr, e_phoff),
535		    sizeof(ehdr.e_phoff));
536		e_phentsize = mopFileGetLX((u_char *) &ehdr,
537		    offsetof(Elf32_Ehdr, e_phentsize),
538		    sizeof(ehdr.e_phentsize));
539		e_phnum = mopFileGetLX((u_char *) &ehdr,
540		    offsetof(Elf32_Ehdr, e_phnum),
541		    sizeof(ehdr.e_phnum));
542		break;
543
544	case ELFDATA2MSB:
545		e_machine = mopFileGetBX((u_char *) &ehdr,
546		    offsetof(Elf32_Ehdr, e_machine),
547		    sizeof(ehdr.e_machine));
548		e_entry = mopFileGetBX((u_char *) &ehdr,
549		    offsetof(Elf32_Ehdr, e_entry),
550		    sizeof(ehdr.e_entry));
551
552		e_phoff = mopFileGetBX((u_char *) &ehdr,
553		    offsetof(Elf32_Ehdr, e_phoff),
554		    sizeof(ehdr.e_phoff));
555		e_phentsize = mopFileGetBX((u_char *) &ehdr,
556		    offsetof(Elf32_Ehdr, e_phentsize),
557		    sizeof(ehdr.e_phentsize));
558		e_phnum = mopFileGetBX((u_char *) &ehdr,
559		    offsetof(Elf32_Ehdr, e_phnum),
560		    sizeof(ehdr.e_phnum));
561		break;
562
563	default:
564		return(-1);
565	}
566
567	if (e_phnum > SEC_MAX)
568		return(-1);
569	dl->e_nsec = e_phnum;
570	for (i = 0; i < dl->e_nsec; i++) {
571		if (lseek(dl->ldfd, (off_t) e_phoff + (i * e_phentsize),
572		    SEEK_SET) == (off_t) -1)
573			return(-1);
574		if (read(dl->ldfd, (char *) &phdr, sizeof(phdr)) !=
575		    sizeof(phdr))
576			return(-1);
577
578		switch (ei_data) {
579		case ELFDATA2LSB:
580			dl->e_sections[i].s_foff =
581			    mopFileGetLX((u_char *) &phdr,
582			    offsetof(Elf32_Phdr, p_offset),
583			    sizeof(phdr.p_offset));
584			dl->e_sections[i].s_vaddr =
585			    mopFileGetLX((u_char *) &phdr,
586			    offsetof(Elf32_Phdr, p_vaddr),
587			    sizeof(phdr.p_vaddr));
588			dl->e_sections[i].s_fsize =
589			    mopFileGetLX((u_char *) &phdr,
590			    offsetof(Elf32_Phdr, p_filesz),
591			    sizeof(phdr.p_filesz));
592			dl->e_sections[i].s_msize =
593			    mopFileGetLX((u_char *) &phdr,
594			    offsetof(Elf32_Phdr, p_memsz),
595			    sizeof(phdr.p_memsz));
596			break;
597
598		case ELFDATA2MSB:
599			dl->e_sections[i].s_foff =
600			    mopFileGetBX((u_char *) &phdr,
601			    offsetof(Elf32_Phdr, p_offset),
602			    sizeof(phdr.p_offset));
603			dl->e_sections[i].s_vaddr =
604			    mopFileGetBX((u_char *) &phdr,
605			    offsetof(Elf32_Phdr, p_vaddr),
606			    sizeof(phdr.p_vaddr));
607			dl->e_sections[i].s_fsize =
608			    mopFileGetBX((u_char *) &phdr,
609			    offsetof(Elf32_Phdr, p_filesz),
610			    sizeof(phdr.p_filesz));
611			dl->e_sections[i].s_msize =
612			    mopFileGetBX((u_char *) &phdr,
613			    offsetof(Elf32_Phdr, p_memsz),
614			    sizeof(phdr.p_memsz));
615			break;
616
617		default:
618			return(-1);
619		}
620	}
621	/*
622	 * In addition to padding between segments, this also
623	 * takes care of memsz > filesz.
624	 */
625	for (i = 0; i < dl->e_nsec - 1; i++) {
626		dl->e_sections[i].s_pad =
627		    dl->e_sections[i + 1].s_vaddr -
628		    (dl->e_sections[i].s_vaddr + dl->e_sections[i].s_fsize);
629	}
630	dl->e_sections[dl->e_nsec - 1].s_pad =
631	    dl->e_sections[dl->e_nsec - 1].s_msize -
632	    dl->e_sections[dl->e_nsec - 1].s_fsize;
633	/*
634	 * Now compute the logical offsets for each section.
635	 */
636	dl->e_sections[0].s_loff = 0;
637	for (i = 1; i < dl->e_nsec; i++) {
638		dl->e_sections[i].s_loff =
639		    dl->e_sections[i - 1].s_loff +
640		    dl->e_sections[i - 1].s_fsize +
641		    dl->e_sections[i - 1].s_pad;
642	}
643
644	dl->image_type = IMAGE_TYPE_ELF32;
645	dl->loadaddr = 0;
646#if 0
647	dl->xferaddr = e_entry;		/* will relocate itself if necessary */
648#else
649	dl->xferaddr = e_entry - dl->e_sections[0].s_vaddr;
650#endif
651
652	/* Print info about the image. */
653	if (info == INFO_PRINT) {
654		printf("Elf32 image (");
655		switch (e_machine) {
656#ifdef EM_VAX
657		case EM_VAX:
658			printf("VAX");
659			break;
660#endif
661		default:
662			printf("machine %d", e_machine);
663			break;
664		}
665		printf(")\n");
666		printf("Transfer Address:   %08x\n", dl->xferaddr);
667		printf("Program Sections:   %d\n", dl->e_nsec);
668		for (i = 0; i < dl->e_nsec; i++) {
669			printf(" S%d File Size:      %08x\n", i,
670			    dl->e_sections[i].s_fsize);
671			printf(" S%d Pad Size:       %08x\n", i,
672			    dl->e_sections[i].s_pad);
673		}
674	}
675
676	dl->e_machine = e_machine;
677
678	dl->e_curpos = 0;
679	dl->e_cursec = 0;
680
681	return(0);
682#endif /* NOELF */
683}
684
685int
686GetElf64FileInfo(struct dllist *dl, int info)
687{
688#if defined(NOELF) || defined(NOELF64)
689	return(-1);
690#else
691	Elf64_Ehdr ehdr;
692	Elf64_Phdr phdr;
693	uint32_t e_machine;
694	uint32_t e_phentsize, e_phnum;
695	uint64_t e_entry, e_phoff;
696	int ei_data, i;
697
698	(void)lseek(dl->ldfd, (off_t) 0, SEEK_SET);
699
700	if (read(dl->ldfd, (char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr))
701		return(-1);
702
703	if (ehdr.e_ident[0] != ELFMAG0 ||
704	    ehdr.e_ident[1] != ELFMAG1 ||
705	    ehdr.e_ident[2] != ELFMAG2 ||
706	    ehdr.e_ident[3] != ELFMAG3)
707		return(-1);
708
709	/* Must be Elf64... */
710	if (ehdr.e_ident[EI_CLASS] != ELFCLASS64)
711		return(-1);
712
713	ei_data = ehdr.e_ident[EI_DATA];
714
715	switch (ei_data) {
716	case ELFDATA2LSB:
717		e_machine = mopFileGetLX((u_char *) &ehdr,
718		    offsetof(Elf64_Ehdr, e_machine),
719		    sizeof(ehdr.e_machine));
720		e_entry = mopFileGetLXX((u_char *) &ehdr,
721		    offsetof(Elf64_Ehdr, e_entry),
722		    sizeof(ehdr.e_entry));
723
724		e_phoff = mopFileGetLXX((u_char *) &ehdr,
725		    offsetof(Elf64_Ehdr, e_phoff),
726		    sizeof(ehdr.e_phoff));
727		e_phentsize = mopFileGetLX((u_char *) &ehdr,
728		    offsetof(Elf64_Ehdr, e_phentsize),
729		    sizeof(ehdr.e_phentsize));
730		e_phnum = mopFileGetLX((u_char *) &ehdr,
731		    offsetof(Elf64_Ehdr, e_phnum),
732		    sizeof(ehdr.e_phnum));
733		break;
734
735	case ELFDATA2MSB:
736		e_machine = mopFileGetBX((u_char *) &ehdr,
737		    offsetof(Elf64_Ehdr, e_machine),
738		    sizeof(ehdr.e_machine));
739		e_entry = mopFileGetBXX((u_char *) &ehdr,
740		    offsetof(Elf64_Ehdr, e_entry),
741		    sizeof(ehdr.e_entry));
742
743		e_phoff = mopFileGetBXX((u_char *) &ehdr,
744		    offsetof(Elf64_Ehdr, e_phoff),
745		    sizeof(ehdr.e_phoff));
746		e_phentsize = mopFileGetBX((u_char *) &ehdr,
747		    offsetof(Elf64_Ehdr, e_phentsize),
748		    sizeof(ehdr.e_phentsize));
749		e_phnum = mopFileGetBX((u_char *) &ehdr,
750		    offsetof(Elf64_Ehdr, e_phnum),
751		    sizeof(ehdr.e_phnum));
752		break;
753
754	default:
755		return(-1);
756	}
757
758	if (e_phnum > SEC_MAX)
759		return(-1);
760	dl->e_nsec = e_phnum;
761	for (i = 0; i < dl->e_nsec; i++) {
762		if (lseek(dl->ldfd, (off_t) e_phoff + (i * e_phentsize),
763		    SEEK_SET) == (off_t) -1)
764			return(-1);
765		if (read(dl->ldfd, (char *) &phdr, sizeof(phdr)) !=
766		    sizeof(phdr))
767			return(-1);
768
769		switch (ei_data) {
770		case ELFDATA2LSB:
771			dl->e_sections[i].s_foff =
772			    mopFileGetLX((u_char *) &phdr,
773			    offsetof(Elf64_Phdr, p_offset),
774			    sizeof(phdr.p_offset));
775			dl->e_sections[i].s_vaddr =
776			    mopFileGetLX((u_char *) &phdr,
777			    offsetof(Elf64_Phdr, p_vaddr),
778			    sizeof(phdr.p_vaddr));
779			dl->e_sections[i].s_fsize =
780			    mopFileGetLX((u_char *) &phdr,
781			    offsetof(Elf64_Phdr, p_filesz),
782			    sizeof(phdr.p_filesz));
783			dl->e_sections[i].s_msize =
784			    mopFileGetLX((u_char *) &phdr,
785			    offsetof(Elf64_Phdr, p_memsz),
786			    sizeof(phdr.p_memsz));
787			break;
788
789		case ELFDATA2MSB:
790			dl->e_sections[i].s_foff =
791			    mopFileGetBX((u_char *) &phdr,
792			    offsetof(Elf64_Phdr, p_offset),
793			    sizeof(phdr.p_offset));
794			dl->e_sections[i].s_vaddr =
795			    mopFileGetBX((u_char *) &phdr,
796			    offsetof(Elf64_Phdr, p_vaddr),
797			    sizeof(phdr.p_vaddr));
798			dl->e_sections[i].s_fsize =
799			    mopFileGetBX((u_char *) &phdr,
800			    offsetof(Elf64_Phdr, p_filesz),
801			    sizeof(phdr.p_filesz));
802			dl->e_sections[i].s_msize =
803			    mopFileGetBX((u_char *) &phdr,
804			    offsetof(Elf64_Phdr, p_memsz),
805			    sizeof(phdr.p_memsz));
806			break;
807
808		default:
809			return(-1);
810		}
811	}
812	/*
813	 * In addition to padding between segments, this also
814	 * takes care of memsz > filesz.
815	 */
816	for (i = 0; i < dl->e_nsec - 1; i++) {
817		dl->e_sections[i].s_pad =
818		    dl->e_sections[i + 1].s_vaddr -
819		    (dl->e_sections[i].s_vaddr + dl->e_sections[i].s_fsize);
820	}
821	dl->e_sections[dl->e_nsec - 1].s_pad =
822	    dl->e_sections[dl->e_nsec - 1].s_msize -
823	    dl->e_sections[dl->e_nsec - 1].s_fsize;
824	/*
825	 * Now compute the logical offsets for each section.
826	 */
827	dl->e_sections[0].s_loff = 0;
828	for (i = 1; i < dl->e_nsec; i++) {
829		dl->e_sections[i].s_loff =
830		    dl->e_sections[i - 1].s_loff +
831		    dl->e_sections[i - 1].s_fsize +
832		    dl->e_sections[i - 1].s_pad;
833	}
834
835	dl->image_type = IMAGE_TYPE_ELF64;
836	dl->loadaddr = 0;
837#if 0
838	dl->xferaddr = e_entry;		/* will relocate itself if necessary */
839#else
840	dl->xferaddr = e_entry - dl->e_sections[0].s_vaddr;
841#endif
842
843	/* Print info about the image. */
844	if (info == INFO_PRINT) {
845		printf("Elf64 image (");
846		switch (e_machine) {
847#ifdef EM_ALPHA
848		case EM_ALPHA:
849#endif
850#ifdef EM_ALPHA_EXP
851		case EM_ALPHA_EXP:
852#endif
853#if defined(EM_ALPHA) || defined(EM_ALPHA_EXP)
854			printf("ALPHA");
855			break;
856#endif
857		default:
858			printf("machine %d", e_machine);
859			break;
860		}
861		printf(")\n");
862		printf("Transfer Address:   %08x\n", dl->xferaddr);
863		printf("Program Sections:   %d\n", dl->e_nsec);
864		for (i = 0; i < dl->e_nsec; i++) {
865			printf(" S%d File Size:      %08x\n", i,
866			    dl->e_sections[i].s_fsize);
867			printf(" S%d Pad Size:       %08x\n", i,
868			    dl->e_sections[i].s_pad);
869		}
870	}
871
872	dl->e_machine = e_machine;
873
874	dl->e_curpos = 0;
875	dl->e_cursec = 0;
876
877	return(0);
878#endif /* NOELF || NOELF64 */
879}
880
881int
882CheckAOutFile(int fd)
883{
884#ifdef NOAOUT
885	return(-1);
886#else
887	struct exec ex, ex_swap;
888	int	mid = -1;
889
890	if (read(fd, (char *)&ex, sizeof(ex)) != sizeof(ex))
891		return(-1);
892
893	(void)lseek(fd, (off_t) 0, SEEK_SET);
894
895	if (read(fd, (char *)&ex_swap, sizeof(ex_swap)) != sizeof(ex_swap))
896		return(-1);
897
898	(void)lseek(fd, (off_t) 0, SEEK_SET);
899
900	mid = getMID(mid, N_GETMID (ex));
901
902	if (mid == -1) {
903		mid = getMID(mid, N_GETMID (ex_swap));
904	}
905
906	if (mid != -1) {
907		return(0);
908	} else {
909		return(-1);
910	}
911#endif /* NOAOUT */
912}
913
914int
915GetAOutFileInfo(struct dllist *dl, int info)
916{
917#ifdef NOAOUT
918	return(-1);
919#else
920	struct exec ex, ex_swap;
921	u_int32_t	mid = -1;
922	u_int32_t	magic, clbytes, clofset;
923
924	if (read(dl->ldfd, (char *)&ex, sizeof(ex)) != sizeof(ex))
925		return(-1);
926
927	(void)lseek(dl->ldfd, (off_t) 0, SEEK_SET);
928
929	if (read(dl->ldfd, (char *)&ex_swap,
930		 sizeof(ex_swap)) != sizeof(ex_swap))
931		return(-1);
932
933	mopFileSwapX((u_char *)&ex_swap, 0, 4);
934
935	mid = getMID(mid, N_GETMID (ex));
936
937	if (mid == (uint32_t)-1) {
938		mid = getMID(mid, N_GETMID (ex_swap));
939		if (mid != (uint32_t)-1) {
940			mopFileSwapX((u_char *)&ex, 0, 4);
941		}
942	}
943
944	if (mid == (uint32_t)-1) {
945		return(-1);
946	}
947
948	if (N_BADMAG (ex)) {
949		return(-1);
950	}
951
952	switch (mid) {
953	case MID_I386:
954#ifdef MID_NS32532
955	case MID_NS32532:
956#endif
957#ifdef MID_PMAX
958	case MID_PMAX:
959#endif
960#ifdef MID_VAX
961	case MID_VAX:
962#endif
963#ifdef MID_ALPHA
964	case MID_ALPHA:
965#endif
966#ifdef MID_ARM6
967	case MID_ARM6:
968#endif
969		ex.a_text  = mopFileGetLX((u_char *)&ex_swap,  4, 4);
970		ex.a_data  = mopFileGetLX((u_char *)&ex_swap,  8, 4);
971		ex.a_bss   = mopFileGetLX((u_char *)&ex_swap, 12, 4);
972		ex.a_syms  = mopFileGetLX((u_char *)&ex_swap, 16, 4);
973		ex.a_entry = mopFileGetLX((u_char *)&ex_swap, 20, 4);
974		ex.a_trsize= mopFileGetLX((u_char *)&ex_swap, 24, 4);
975		ex.a_drsize= mopFileGetLX((u_char *)&ex_swap, 28, 4);
976		break;
977#ifdef MID_M68K
978	case MID_M68K:
979#endif
980#ifdef MID_M68K4K
981	case MID_M68K4K:
982#endif
983	case MID_SPARC:
984#ifdef MID_MIPS
985	case MID_MIPS:
986#endif
987		ex.a_text  = mopFileGetBX((u_char *)&ex_swap,  4, 4);
988		ex.a_data  = mopFileGetBX((u_char *)&ex_swap,  8, 4);
989		ex.a_bss   = mopFileGetBX((u_char *)&ex_swap, 12, 4);
990		ex.a_syms  = mopFileGetBX((u_char *)&ex_swap, 16, 4);
991		ex.a_entry = mopFileGetBX((u_char *)&ex_swap, 20, 4);
992		ex.a_trsize= mopFileGetBX((u_char *)&ex_swap, 24, 4);
993		ex.a_drsize= mopFileGetBX((u_char *)&ex_swap, 28, 4);
994		break;
995	default:
996		break;
997	}
998
999	if (info == INFO_PRINT) {
1000		printf("a.out image (");
1001		switch (N_GETMID (ex)) {
1002		case MID_I386:
1003			printf("i386");
1004			break;
1005#ifdef MID_M68K
1006		case MID_M68K:
1007			printf("m68k");
1008			break;
1009#endif
1010#ifdef MID_M68K4K
1011		case MID_M68K4K:
1012			printf("m68k 4k");
1013			break;
1014#endif
1015#ifdef MID_NS32532
1016		case MID_NS32532:
1017			printf("pc532");
1018			break;
1019#endif
1020		case MID_SPARC:
1021			printf("sparc");
1022			break;
1023#ifdef MID_PMAX
1024		case MID_PMAX:
1025			printf("pmax");
1026			break;
1027#endif
1028#ifdef MID_VAX
1029		case MID_VAX:
1030			printf("vax");
1031			break;
1032#endif
1033#ifdef MID_ALPHA
1034		case MID_ALPHA:
1035			printf("alpha");
1036			break;
1037#endif
1038#ifdef MID_MIPS
1039		case MID_MIPS:
1040			printf("mips");
1041			break;
1042#endif
1043#ifdef MID_ARM6
1044		case MID_ARM6:
1045			printf("arm32");
1046			break;
1047#endif
1048		default:
1049			break;
1050		}
1051		printf(") Magic: ");
1052		switch (N_GETMAGIC (ex)) {
1053		case OMAGIC:
1054			printf("OMAGIC");
1055			break;
1056		case NMAGIC:
1057			printf("NMAGIC");
1058			break;
1059		case ZMAGIC:
1060			printf("ZMAGIC");
1061			break;
1062		case QMAGIC:
1063			printf("QMAGIC");
1064			break;
1065		default:
1066			printf("Unknown %ld", (long) N_GETMAGIC (ex));
1067		}
1068		printf("\n");
1069		printf("Size of text:       %08lx\n", (long)ex.a_text);
1070		printf("Size of data:       %08lx\n", (long)ex.a_data);
1071		printf("Size of bss:        %08lx\n", (long)ex.a_bss);
1072		printf("Size of symbol tab: %08lx\n", (long)ex.a_syms);
1073		printf("Transfer Address:   %08lx\n", (long)ex.a_entry);
1074		printf("Size of reloc text: %08lx\n", (long)ex.a_trsize);
1075		printf("Size of reloc data: %08lx\n", (long)ex.a_drsize);
1076	}
1077
1078	magic = N_GETMAGIC (ex);
1079	clbytes = getCLBYTES(mid);
1080	clofset = clbytes - 1;
1081
1082	dl->image_type = IMAGE_TYPE_AOUT;
1083	dl->loadaddr = 0;
1084	dl->xferaddr = ex.a_entry;
1085
1086	dl->a_text = ex.a_text;
1087	if (magic == ZMAGIC || magic == NMAGIC) {
1088		dl->a_text_fill = clbytes - (ex.a_text & clofset);
1089		if (dl->a_text_fill == clbytes)
1090			dl->a_text_fill = 0;
1091	} else
1092		dl->a_text_fill = 0;
1093	dl->a_data = ex.a_data;
1094	if (magic == ZMAGIC || magic == NMAGIC) {
1095		dl->a_data_fill = clbytes - (ex.a_data & clofset);
1096		if (dl->a_data_fill == clbytes)
1097			dl->a_data_fill = 0;
1098	} else
1099		dl->a_data_fill = 0;
1100	dl->a_bss = ex.a_bss;
1101	if (magic == ZMAGIC || magic == NMAGIC) {
1102		dl->a_bss_fill = clbytes - (ex.a_bss & clofset);
1103		if (dl->a_bss_fill == clbytes)
1104			dl->a_bss_fill = 0;
1105	} else {
1106		dl->a_bss_fill = clbytes -
1107		    ((ex.a_text+ex.a_data+ex.a_bss) & clofset);
1108		if (dl->a_bss_fill == clbytes)
1109			dl->a_bss_fill = 0;
1110	}
1111	dl->a_mid = mid;
1112
1113	return(0);
1114#endif /* NOAOUT */
1115}
1116
1117int
1118GetFileInfo(struct dllist *dl, int info)
1119{
1120	int error;
1121
1122	error = CheckElfFile(dl->ldfd);
1123	if (error == 0) {
1124		error = GetElf32FileInfo(dl, info);
1125		if (error != 0)
1126			error = GetElf64FileInfo(dl, info);
1127		if (error != 0) {
1128			return(-1);
1129		}
1130		return (0);
1131	}
1132
1133	error = CheckAOutFile(dl->ldfd);
1134	if (error == 0) {
1135		error = GetAOutFileInfo(dl, info);
1136		if (error != 0) {
1137			return(-1);
1138		}
1139		return (0);
1140	}
1141
1142	error = CheckMopFile(dl->ldfd);
1143	if (error == 0) {
1144		error = GetMopFileInfo(dl, info);
1145		if (error != 0) {
1146			return(-1);
1147		}
1148		return (0);
1149	}
1150
1151	/* Unknown file format. */
1152	return(-1);
1153}
1154
1155ssize_t
1156mopFileRead(struct dllist *dlslot, u_char *buf)
1157{
1158	ssize_t len, outlen;
1159	int	bsz, sec;
1160	int32_t	pos, notdone, total;
1161	uint32_t secoff;
1162
1163	switch (dlslot->image_type) {
1164	case IMAGE_TYPE_MOP:
1165		len = read(dlslot->ldfd,buf,dlslot->dl_bsz);
1166		break;
1167
1168	case IMAGE_TYPE_ELF32:
1169	case IMAGE_TYPE_ELF64:
1170		sec = dlslot->e_cursec;
1171
1172		/*
1173		 * We're pretty simplistic here.  We do only file-backed
1174		 * or only zero-fill.
1175		 */
1176
1177		/* Determine offset into section. */
1178		secoff = dlslot->e_curpos - dlslot->e_sections[sec].s_loff;
1179
1180		/*
1181		 * If we're in the file-backed part of the section,
1182		 * transmit some of the file.
1183		 */
1184		if (secoff < dlslot->e_sections[sec].s_fsize) {
1185			bsz = dlslot->e_sections[sec].s_fsize - secoff;
1186			if (bsz > dlslot->dl_bsz)
1187				bsz = dlslot->dl_bsz;
1188			if (lseek(dlslot->ldfd,
1189			    dlslot->e_sections[sec].s_foff + secoff,
1190			    SEEK_SET) == (off_t) -1)
1191				return (-1);
1192			len = read(dlslot->ldfd, buf, bsz);
1193		}
1194		/*
1195		 * Otherwise, if we're in the zero-fill part of the
1196		 * section, transmit some zeros.
1197		 */
1198		else if (secoff < (dlslot->e_sections[sec].s_fsize +
1199				   dlslot->e_sections[sec].s_pad)) {
1200			bsz = dlslot->e_sections[sec].s_pad -
1201			    (secoff - dlslot->e_sections[sec].s_fsize);
1202			if (bsz > dlslot->dl_bsz)
1203				bsz = dlslot->dl_bsz;
1204			memset(buf, 0, (len = bsz));
1205		}
1206		/*
1207		 * ...and if we haven't hit either of those cases,
1208		 * that's the end of the image.
1209		 */
1210		else {
1211			return (0);
1212		}
1213		/*
1214		 * Advance the logical image pointer.
1215		 */
1216		dlslot->e_curpos += bsz;
1217		if (dlslot->e_curpos >= (dlslot->e_sections[sec].s_loff +
1218					 dlslot->e_sections[sec].s_fsize +
1219					 dlslot->e_sections[sec].s_pad))
1220			if (++sec != dlslot->e_nsec)
1221				dlslot->e_cursec = sec;
1222		break;
1223
1224	case IMAGE_TYPE_AOUT:
1225		bsz = dlslot->dl_bsz;
1226		pos = dlslot->a_lseek;
1227		len = 0;
1228
1229		total = dlslot->a_text;
1230
1231		if (pos < total) {
1232			notdone = total - pos;
1233			if (notdone <= bsz) {
1234				outlen = read(dlslot->ldfd,&buf[len],notdone);
1235			} else {
1236				outlen = read(dlslot->ldfd,&buf[len],bsz);
1237			}
1238			len = len + outlen;
1239			pos = pos + outlen;
1240			bsz = bsz - outlen;
1241		}
1242
1243		total = total + dlslot->a_text_fill;
1244
1245		if ((bsz > 0) && (pos < total)) {
1246			notdone = total - pos;
1247			if (notdone <= bsz) {
1248				outlen = notdone;
1249			} else {
1250				outlen = bsz;
1251			}
1252			memset(&buf[len], 0, outlen);
1253			len = len + outlen;
1254			pos = pos + outlen;
1255			bsz = bsz - outlen;
1256		}
1257
1258		total = total + dlslot->a_data;
1259
1260		if ((bsz > 0) && (pos < total)) {
1261			notdone = total - pos;
1262			if (notdone <= bsz) {
1263				outlen = read(dlslot->ldfd,&buf[len],notdone);
1264			} else {
1265				outlen = read(dlslot->ldfd,&buf[len],bsz);
1266			}
1267			len = len + outlen;
1268			pos = pos + outlen;
1269			bsz = bsz - outlen;
1270		}
1271
1272		total = total + dlslot->a_data_fill;
1273
1274		if ((bsz > 0) && (pos < total)) {
1275			notdone = total - pos;
1276			if (notdone <= bsz) {
1277				outlen = notdone;
1278			} else {
1279				outlen = bsz;
1280			}
1281			memset(&buf[len], 0, outlen);
1282			len = len + outlen;
1283			pos = pos + outlen;
1284			bsz = bsz - outlen;
1285		}
1286
1287		total = total + dlslot->a_bss;
1288
1289		if ((bsz > 0) && (pos < total)) {
1290			notdone = total - pos;
1291			if (notdone <= bsz) {
1292				outlen = notdone;
1293			} else {
1294				outlen = bsz;
1295			}
1296			memset(&buf[len], 0, outlen);
1297			len = len + outlen;
1298			pos = pos + outlen;
1299			bsz = bsz - outlen;
1300		}
1301
1302		total = total + dlslot->a_bss_fill;
1303
1304		if ((bsz > 0) && (pos < total)) {
1305			notdone = total - pos;
1306			if (notdone <= bsz) {
1307				outlen = notdone;
1308			} else {
1309				outlen = bsz;
1310			}
1311			memset(&buf[len], 0, outlen);
1312			len = len + outlen;
1313			pos = pos + outlen;
1314			bsz = bsz - outlen;
1315		}
1316
1317		dlslot->a_lseek = pos;
1318		break;
1319
1320	default:
1321		abort();
1322	}
1323
1324	return(len);
1325}
1326