readelf.c revision 68349
168349Sobrien#include "file.h"
268349Sobrien
368349Sobrien#ifdef BUILTIN_ELF
468349Sobrien#include <sys/types.h>
568349Sobrien#include <string.h>
668349Sobrien#include <stdio.h>
768349Sobrien#include <ctype.h>
868349Sobrien#include <stdlib.h>
968349Sobrien#ifdef HAVE_UNISTD_H
1068349Sobrien#include <unistd.h>
1168349Sobrien#endif
1268349Sobrien#include <errno.h>
1368349Sobrien
1468349Sobrien#include "readelf.h"
1568349Sobrien
1668349Sobrien#ifndef lint
1768349SobrienFILE_RCSID("@(#)$Id: readelf.c,v 1.16 2000/08/05 18:18:50 christos Exp $")
1868349Sobrien#endif
1968349Sobrien
2068349Sobrien#ifdef	ELFCORE
2168349Sobrienstatic void dophn_core __P((int, int, int, off_t, int, size_t));
2268349Sobrien#endif
2368349Sobrienstatic void dophn_exec __P((int, int, int, off_t, int, size_t));
2468349Sobrienstatic void doshn __P((int, int, int, off_t, int, size_t));
2568349Sobrien
2668349Sobrienstatic uint16_t getu16 __P((int, int));
2768349Sobrienstatic uint32_t getu32 __P((int, uint32_t));
2868349Sobrienstatic uint64_t getu64 __P((int, uint64_t));
2968349Sobrien
3068349Sobrienstatic uint16_t
3168349Sobriengetu16(swap, value)
3268349Sobrien	int swap;
3368349Sobrien	uint16_t value;
3468349Sobrien{
3568349Sobrien	union {
3668349Sobrien		uint16_t ui;
3768349Sobrien		char c[2];
3868349Sobrien	} retval, tmpval;
3968349Sobrien
4068349Sobrien	if (swap) {
4168349Sobrien		tmpval.ui = value;
4268349Sobrien
4368349Sobrien		retval.c[0] = tmpval.c[1];
4468349Sobrien		retval.c[1] = tmpval.c[0];
4568349Sobrien
4668349Sobrien		return retval.ui;
4768349Sobrien	} else
4868349Sobrien		return value;
4968349Sobrien}
5068349Sobrien
5168349Sobrienstatic uint32_t
5268349Sobriengetu32(swap, value)
5368349Sobrien	int swap;
5468349Sobrien	uint32_t value;
5568349Sobrien{
5668349Sobrien	union {
5768349Sobrien		uint32_t ui;
5868349Sobrien		char c[4];
5968349Sobrien	} retval, tmpval;
6068349Sobrien
6168349Sobrien	if (swap) {
6268349Sobrien		tmpval.ui = value;
6368349Sobrien
6468349Sobrien		retval.c[0] = tmpval.c[3];
6568349Sobrien		retval.c[1] = tmpval.c[2];
6668349Sobrien		retval.c[2] = tmpval.c[1];
6768349Sobrien		retval.c[3] = tmpval.c[0];
6868349Sobrien
6968349Sobrien		return retval.ui;
7068349Sobrien	} else
7168349Sobrien		return value;
7268349Sobrien}
7368349Sobrien
7468349Sobrienstatic uint64_t
7568349Sobriengetu64(swap, value)
7668349Sobrien	int swap;
7768349Sobrien	uint64_t value;
7868349Sobrien{
7968349Sobrien	union {
8068349Sobrien		uint64_t ui;
8168349Sobrien		char c[8];
8268349Sobrien	} retval, tmpval;
8368349Sobrien
8468349Sobrien	if (swap) {
8568349Sobrien		tmpval.ui = value;
8668349Sobrien
8768349Sobrien		retval.c[0] = tmpval.c[7];
8868349Sobrien		retval.c[1] = tmpval.c[6];
8968349Sobrien		retval.c[2] = tmpval.c[5];
9068349Sobrien		retval.c[3] = tmpval.c[4];
9168349Sobrien		retval.c[4] = tmpval.c[3];
9268349Sobrien		retval.c[5] = tmpval.c[2];
9368349Sobrien		retval.c[6] = tmpval.c[1];
9468349Sobrien		retval.c[7] = tmpval.c[0];
9568349Sobrien
9668349Sobrien		return retval.ui;
9768349Sobrien	} else
9868349Sobrien		return value;
9968349Sobrien}
10068349Sobrien
10168349Sobrien#define sh_addr		(class == ELFCLASS32		\
10268349Sobrien			 ? (void *) &sh32		\
10368349Sobrien			 : (void *) &sh64)
10468349Sobrien#define shs_type	(class == ELFCLASS32		\
10568349Sobrien			 ? getu32(swap, sh32.sh_type)	\
10668349Sobrien			 : getu32(swap, sh64.sh_type))
10768349Sobrien#define ph_addr		(class == ELFCLASS32		\
10868349Sobrien			 ? (void *) &ph32		\
10968349Sobrien			 : (void *) &ph64)
11068349Sobrien#define ph_type		(class == ELFCLASS32		\
11168349Sobrien			 ? getu32(swap, ph32.p_type)	\
11268349Sobrien			 : getu32(swap, ph64.p_type))
11368349Sobrien#define ph_offset	(class == ELFCLASS32		\
11468349Sobrien			 ? getu32(swap, ph32.p_offset)	\
11568349Sobrien			 : getu64(swap, ph64.p_offset))
11668349Sobrien#define nh_size		(class == ELFCLASS32		\
11768349Sobrien			 ? sizeof *nh32			\
11868349Sobrien			 : sizeof *nh64)
11968349Sobrien#define nh_type		(class == ELFCLASS32		\
12068349Sobrien			 ? getu32(swap, nh32->n_type)	\
12168349Sobrien			 : getu32(swap, nh64->n_type))
12268349Sobrien#define nh_namesz	(class == ELFCLASS32		\
12368349Sobrien			 ? getu32(swap, nh32->n_namesz)	\
12468349Sobrien			 : getu32(swap, nh64->n_namesz))
12568349Sobrien#define nh_descsz	(class == ELFCLASS32		\
12668349Sobrien			 ? getu32(swap, nh32->n_descsz)	\
12768349Sobrien			 : getu32(swap, nh64->n_descsz))
12868349Sobrien#define prpsoffsets(i)	(class == ELFCLASS32		\
12968349Sobrien			 ? prpsoffsets32[i]		\
13068349Sobrien			 : prpsoffsets64[i])
13168349Sobrien
13268349Sobrienstatic void
13368349Sobriendoshn(class, swap, fd, off, num, size)
13468349Sobrien	int class;
13568349Sobrien	int swap;
13668349Sobrien	int fd;
13768349Sobrien	off_t off;
13868349Sobrien	int num;
13968349Sobrien	size_t size;
14068349Sobrien{
14168349Sobrien	Elf32_Shdr sh32;
14268349Sobrien	Elf64_Shdr sh64;
14368349Sobrien
14468349Sobrien	if (lseek(fd, off, SEEK_SET) == -1)
14568349Sobrien		error("lseek failed (%s).\n", strerror(errno));
14668349Sobrien
14768349Sobrien	for ( ; num; num--) {
14868349Sobrien		if (read(fd, sh_addr, size) == -1)
14968349Sobrien			error("read failed (%s).\n", strerror(errno));
15068349Sobrien		if (shs_type == SHT_SYMTAB /* || shs_type == SHT_DYNSYM */) {
15168349Sobrien			(void) printf (", not stripped");
15268349Sobrien			return;
15368349Sobrien		}
15468349Sobrien	}
15568349Sobrien	(void) printf (", stripped");
15668349Sobrien}
15768349Sobrien
15868349Sobrien/*
15968349Sobrien * Look through the program headers of an executable image, searching
16068349Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked,
16168349Sobrien * otherwise it's statically linked.
16268349Sobrien */
16368349Sobrienstatic void
16468349Sobriendophn_exec(class, swap, fd, off, num, size)
16568349Sobrien	int class;
16668349Sobrien	int swap;
16768349Sobrien	int fd;
16868349Sobrien	off_t off;
16968349Sobrien	int num;
17068349Sobrien	size_t size;
17168349Sobrien{
17268349Sobrien	Elf32_Phdr ph32;
17368349Sobrien	Elf64_Phdr ph64;
17468349Sobrien	char *linking_style = "statically";
17568349Sobrien	char *shared_libraries = "";
17668349Sobrien
17768349Sobrien	if (lseek(fd, off, SEEK_SET) == -1)
17868349Sobrien		error("lseek failed (%s).\n", strerror(errno));
17968349Sobrien
18068349Sobrien  	for ( ; num; num--) {
18168349Sobrien  		if (read(fd, ph_addr, size) == -1)
18268349Sobrien  			error("read failed (%s).\n", strerror(errno));
18368349Sobrien
18468349Sobrien		switch (ph_type) {
18568349Sobrien		case PT_DYNAMIC:
18668349Sobrien			linking_style = "dynamically";
18768349Sobrien			break;
18868349Sobrien		case PT_INTERP:
18968349Sobrien			shared_libraries = " (uses shared libs)";
19068349Sobrien			break;
19168349Sobrien		}
19268349Sobrien	}
19368349Sobrien	printf(", %s linked%s", linking_style, shared_libraries);
19468349Sobrien}
19568349Sobrien
19668349Sobrien#ifdef ELFCORE
19768349Sobriensize_t	prpsoffsets32[] = {
19868349Sobrien	8,		/* FreeBSD */
19968349Sobrien	28,		/* Linux 2.0.36 */
20068349Sobrien	32,		/* Linux (I forget which kernel version) */
20168349Sobrien	84,		/* SunOS 5.x */
20268349Sobrien};
20368349Sobrien
20468349Sobriensize_t	prpsoffsets64[] = {
20568349Sobrien       120,		/* SunOS 5.x, 64-bit */
20668349Sobrien};
20768349Sobrien
20868349Sobrien#define	NOFFSETS32	(sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
20968349Sobrien#define NOFFSETS64	(sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
21068349Sobrien
21168349Sobrien#define NOFFSETS	(class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
21268349Sobrien
21368349Sobrien/*
21468349Sobrien * Look through the program headers of an executable image, searching
21568349Sobrien * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
21668349Sobrien * "FreeBSD"; if one is found, try looking in various places in its
21768349Sobrien * contents for a 16-character string containing only printable
21868349Sobrien * characters - if found, that string should be the name of the program
21968349Sobrien * that dropped core.  Note: right after that 16-character string is,
22068349Sobrien * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
22168349Sobrien * Linux, a longer string (80 characters, in 5.x, probably other
22268349Sobrien * SVR4-flavored systems, and Linux) containing the start of the
22368349Sobrien * command line for that program.
22468349Sobrien *
22568349Sobrien * The signal number probably appears in a section of type NT_PRSTATUS,
22668349Sobrien * but that's also rather OS-dependent, in ways that are harder to
22768349Sobrien * dissect with heuristics, so I'm not bothering with the signal number.
22868349Sobrien * (I suppose the signal number could be of interest in situations where
22968349Sobrien * you don't have the binary of the program that dropped core; if you
23068349Sobrien * *do* have that binary, the debugger will probably tell you what
23168349Sobrien * signal it was.)
23268349Sobrien */
23368349Sobrienstatic void
23468349Sobriendophn_core(class, swap, fd, off, num, size)
23568349Sobrien	int class;
23668349Sobrien	int swap;
23768349Sobrien	int fd;
23868349Sobrien	off_t off;
23968349Sobrien	int num;
24068349Sobrien	size_t size;
24168349Sobrien{
24268349Sobrien	Elf32_Phdr ph32;
24368349Sobrien	Elf32_Nhdr *nh32;
24468349Sobrien	Elf64_Phdr ph64;
24568349Sobrien	Elf64_Nhdr *nh64;
24668349Sobrien	size_t offset, nameoffset, noffset, reloffset;
24768349Sobrien	unsigned char c;
24868349Sobrien	int i, j;
24968349Sobrien	char nbuf[BUFSIZ];
25068349Sobrien	int bufsize;
25168349Sobrien	int is_freebsd;
25268349Sobrien
25368349Sobrien	/*
25468349Sobrien	 * Loop through all the program headers.
25568349Sobrien	 */
25668349Sobrien	for ( ; num; num--) {
25768349Sobrien		if (lseek(fd, off, SEEK_SET) == -1)
25868349Sobrien			error("lseek failed (%s).\n", strerror(errno));
25968349Sobrien		if (read(fd, ph_addr, size) == -1)
26068349Sobrien			error("read failed (%s).\n", strerror(errno));
26168349Sobrien		off += size;
26268349Sobrien		if (ph_type != PT_NOTE)
26368349Sobrien			continue;
26468349Sobrien
26568349Sobrien		/*
26668349Sobrien		 * This is a PT_NOTE section; loop through all the notes
26768349Sobrien		 * in the section.
26868349Sobrien		 */
26968349Sobrien		if (lseek(fd, (off_t) ph_offset, SEEK_SET) == -1)
27068349Sobrien			error("lseek failed (%s).\n", strerror(errno));
27168349Sobrien		bufsize = read(fd, nbuf, BUFSIZ);
27268349Sobrien		if (bufsize == -1)
27368349Sobrien			error(": " "read failed (%s).\n", strerror(errno));
27468349Sobrien		offset = 0;
27568349Sobrien		for (;;) {
27668349Sobrien			if (offset >= bufsize)
27768349Sobrien				break;
27868349Sobrien			if (class == ELFCLASS32)
27968349Sobrien				nh32 = (Elf32_Nhdr *)&nbuf[offset];
28068349Sobrien			else
28168349Sobrien				nh64 = (Elf64_Nhdr *)&nbuf[offset];
28268349Sobrien			offset += nh_size;
28368349Sobrien
28468349Sobrien			/*
28568349Sobrien			 * Check whether this note has the name "CORE" or
28668349Sobrien			 * "FreeBSD".
28768349Sobrien			 */
28868349Sobrien			if (offset + nh_namesz >= bufsize) {
28968349Sobrien				/*
29068349Sobrien				 * We're past the end of the buffer.
29168349Sobrien				 */
29268349Sobrien				break;
29368349Sobrien			}
29468349Sobrien
29568349Sobrien			nameoffset = offset;
29668349Sobrien			offset += nh_namesz;
29768349Sobrien			offset = ((offset + 3)/4)*4;
29868349Sobrien
29968349Sobrien			/*
30068349Sobrien			 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
30168349Sobrien			 * least, doesn't correctly implement name
30268349Sobrien			 * sections, in core dumps, as specified by
30368349Sobrien			 * the "Program Linking" section of "UNIX(R) System
30468349Sobrien			 * V Release 4 Programmer's Guide: ANSI C and
30568349Sobrien			 * Programming Support Tools", because my copy
30668349Sobrien			 * clearly says "The first 'namesz' bytes in 'name'
30768349Sobrien			 * contain a *null-terminated* [emphasis mine]
30868349Sobrien			 * character representation of the entry's owner
30968349Sobrien			 * or originator", but the 2.0.36 kernel code
31068349Sobrien			 * doesn't include the terminating null in the
31168349Sobrien			 * name....
31268349Sobrien			 */
31368349Sobrien			if ((nh_namesz == 4 &&
31468349Sobrien			      strncmp(&nbuf[nameoffset], "CORE", 4) == 0) ||
31568349Sobrien			    (nh_namesz == 5 &&
31668349Sobrien			      strcmp(&nbuf[nameoffset], "CORE") == 0))
31768349Sobrien				is_freebsd = 0;
31868349Sobrien			else if ((nh_namesz == 8 &&
31968349Sobrien			      strcmp(&nbuf[nameoffset], "FreeBSD") == 0))
32068349Sobrien				is_freebsd = 1;
32168349Sobrien			else
32268349Sobrien				continue;
32368349Sobrien			if (nh_type == NT_PRPSINFO) {
32468349Sobrien				/*
32568349Sobrien				 * Extract the program name.  We assume
32668349Sobrien				 * it to be 16 characters (that's what it
32768349Sobrien				 * is in SunOS 5.x and Linux).
32868349Sobrien				 *
32968349Sobrien				 * Unfortunately, it's at a different offset
33068349Sobrien				 * in varous OSes, so try multiple offsets.
33168349Sobrien				 * If the characters aren't all printable,
33268349Sobrien				 * reject it.
33368349Sobrien				 */
33468349Sobrien				for (i = 0; i < NOFFSETS; i++) {
33568349Sobrien					reloffset = prpsoffsets(i);
33668349Sobrien					noffset = offset + reloffset;
33768349Sobrien					for (j = 0; j < 16;
33868349Sobrien					    j++, noffset++, reloffset++) {
33968349Sobrien						/*
34068349Sobrien						 * Make sure we're not past
34168349Sobrien						 * the end of the buffer; if
34268349Sobrien						 * we are, just give up.
34368349Sobrien						 */
34468349Sobrien						if (noffset >= bufsize)
34568349Sobrien							goto tryanother;
34668349Sobrien
34768349Sobrien						/*
34868349Sobrien						 * Make sure we're not past
34968349Sobrien						 * the end of the contents;
35068349Sobrien						 * if we are, this obviously
35168349Sobrien						 * isn't the right offset.
35268349Sobrien						 */
35368349Sobrien						if (reloffset >= nh_descsz)
35468349Sobrien							goto tryanother;
35568349Sobrien
35668349Sobrien						c = nbuf[noffset];
35768349Sobrien						if (c == '\0') {
35868349Sobrien							/*
35968349Sobrien							 * A '\0' at the
36068349Sobrien							 * beginning is
36168349Sobrien							 * obviously wrong.
36268349Sobrien							 * Any other '\0'
36368349Sobrien							 * means we're done.
36468349Sobrien							 */
36568349Sobrien							if (j == 0)
36668349Sobrien								goto tryanother;
36768349Sobrien							else
36868349Sobrien								break;
36968349Sobrien						} else {
37068349Sobrien							/*
37168349Sobrien							 * A nonprintable
37268349Sobrien							 * character is also
37368349Sobrien							 * wrong.
37468349Sobrien							 */
37568349Sobrien#define isquote(c) (strchr("'\"`", (c)) != NULL)
37668349Sobrien							if (!isprint(c) ||
37768349Sobrien							     isquote(c))
37868349Sobrien								goto tryanother;
37968349Sobrien						}
38068349Sobrien					}
38168349Sobrien
38268349Sobrien					/*
38368349Sobrien					 * Well, that worked.
38468349Sobrien					 */
38568349Sobrien					printf(", from '%.16s'",
38668349Sobrien					    &nbuf[offset + prpsoffsets(i)]);
38768349Sobrien					break;
38868349Sobrien
38968349Sobrien				tryanother:
39068349Sobrien					;
39168349Sobrien				}
39268349Sobrien				break;
39368349Sobrien			}
39468349Sobrien			offset += nh_descsz;
39568349Sobrien			offset = ((offset + 3)/4)*4;
39668349Sobrien		}
39768349Sobrien	out:
39868349Sobrien		;
39968349Sobrien	}
40068349Sobrien}
40168349Sobrien#endif
40268349Sobrien
40368349Sobrienvoid
40468349Sobrientryelf(fd, buf, nbytes)
40568349Sobrien	int fd;
40668349Sobrien	unsigned char *buf;
40768349Sobrien	int nbytes;
40868349Sobrien{
40968349Sobrien	union {
41068349Sobrien		int32 l;
41168349Sobrien		char c[sizeof (int32)];
41268349Sobrien	} u;
41368349Sobrien	int class;
41468349Sobrien	int swap;
41568349Sobrien
41668349Sobrien	/*
41768349Sobrien	 * ELF executables have multiple section headers in arbitrary
41868349Sobrien	 * file locations and thus file(1) cannot determine it from easily.
41968349Sobrien	 * Instead we traverse thru all section headers until a symbol table
42068349Sobrien	 * one is found or else the binary is stripped.
42168349Sobrien	 */
42268349Sobrien	if (buf[EI_MAG0] != ELFMAG0
42368349Sobrien	    || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
42468349Sobrien	    || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
42568349Sobrien	    return;
42668349Sobrien
42768349Sobrien
42868349Sobrien	class = buf[4];
42968349Sobrien
43068349Sobrien	if (class == ELFCLASS32) {
43168349Sobrien		Elf32_Ehdr elfhdr;
43268349Sobrien		if (nbytes <= sizeof (Elf32_Ehdr))
43368349Sobrien			return;
43468349Sobrien
43568349Sobrien
43668349Sobrien		u.l = 1;
43768349Sobrien		(void) memcpy(&elfhdr, buf, sizeof elfhdr);
43868349Sobrien		swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5];
43968349Sobrien
44068349Sobrien		if (getu16(swap, elfhdr.e_type) == ET_CORE)
44168349Sobrien#ifdef ELFCORE
44268349Sobrien			dophn_core(class, swap,
44368349Sobrien				   fd,
44468349Sobrien				   getu32(swap, elfhdr.e_phoff),
44568349Sobrien				   getu16(swap, elfhdr.e_phnum),
44668349Sobrien				   getu16(swap, elfhdr.e_phentsize));
44768349Sobrien#else
44868349Sobrien			;
44968349Sobrien#endif
45068349Sobrien		else {
45168349Sobrien			if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
45268349Sobrien				dophn_exec(class, swap,
45368349Sobrien					   fd,
45468349Sobrien					   getu32(swap, elfhdr.e_phoff),
45568349Sobrien					   getu16(swap, elfhdr.e_phnum),
45668349Sobrien					   getu16(swap, elfhdr.e_phentsize));
45768349Sobrien			}
45868349Sobrien			doshn(class, swap,
45968349Sobrien			      fd,
46068349Sobrien			      getu32(swap, elfhdr.e_shoff),
46168349Sobrien			      getu16(swap, elfhdr.e_shnum),
46268349Sobrien			      getu16(swap, elfhdr.e_shentsize));
46368349Sobrien		}
46468349Sobrien		return;
46568349Sobrien	}
46668349Sobrien
46768349Sobrien        if (class == ELFCLASS64) {
46868349Sobrien		Elf64_Ehdr elfhdr;
46968349Sobrien		if (nbytes <= sizeof (Elf64_Ehdr))
47068349Sobrien			return;
47168349Sobrien
47268349Sobrien
47368349Sobrien		u.l = 1;
47468349Sobrien		(void) memcpy(&elfhdr, buf, sizeof elfhdr);
47568349Sobrien		swap = (u.c[sizeof(int32) - 1] + 1) != elfhdr.e_ident[5];
47668349Sobrien
47768349Sobrien		if (getu16(swap, elfhdr.e_type) == ET_CORE)
47868349Sobrien#ifdef ELFCORE
47968349Sobrien			dophn_core(class, swap,
48068349Sobrien				   fd,
48168349Sobrien#ifdef USE_ARRAY_FOR_64BIT_TYPES
48268349Sobrien				   getu32(swap, elfhdr.e_phoff[1]),
48368349Sobrien#else
48468349Sobrien				   getu64(swap, elfhdr.e_phoff),
48568349Sobrien#endif
48668349Sobrien				   getu16(swap, elfhdr.e_phnum),
48768349Sobrien				   getu16(swap, elfhdr.e_phentsize));
48868349Sobrien#else
48968349Sobrien			;
49068349Sobrien#endif
49168349Sobrien		else
49268349Sobrien		{
49368349Sobrien			if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
49468349Sobrien				dophn_exec(class, swap,
49568349Sobrien					   fd,
49668349Sobrien#ifdef USE_ARRAY_FOR_64BIT_TYPES
49768349Sobrien					   getu32(swap, elfhdr.e_phoff[1]),
49868349Sobrien#else
49968349Sobrien					   getu64(swap, elfhdr.e_phoff),
50068349Sobrien#endif
50168349Sobrien					   getu16(swap, elfhdr.e_phnum),
50268349Sobrien					   getu16(swap, elfhdr.e_phentsize));
50368349Sobrien			}
50468349Sobrien			doshn(class, swap,
50568349Sobrien			      fd,
50668349Sobrien#ifdef USE_ARRAY_FOR_64BIT_TYPES
50768349Sobrien			      getu32(swap, elfhdr.e_shoff[1]),
50868349Sobrien#else
50968349Sobrien			      getu64(swap, elfhdr.e_shoff),
51068349Sobrien#endif
51168349Sobrien			      getu16(swap, elfhdr.e_shnum),
51268349Sobrien			      getu16(swap, elfhdr.e_shentsize));
51368349Sobrien		}
51468349Sobrien		return;
51568349Sobrien	}
51668349Sobrien}
51768349Sobrien#endif
518