readelf.c revision 159764
1/*
2 * Copyright (c) Christos Zoulas 2003.
3 * All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice immediately at the beginning of the file, without modification,
10 *    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 AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27#include "file.h"
28
29#ifdef BUILTIN_ELF
30#include <string.h>
31#include <ctype.h>
32#include <stdlib.h>
33#ifdef HAVE_UNISTD_H
34#include <unistd.h>
35#endif
36
37#include "readelf.h"
38
39#ifndef lint
40FILE_RCSID("@(#)$Id: readelf.c,v 1.54 2006/01/13 00:45:21 christos Exp $")
41#endif
42
43#ifdef	ELFCORE
44private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t);
45#endif
46private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t);
47private int doshn(struct magic_set *, int, int, int, off_t, int, size_t);
48private size_t donote(struct magic_set *, unsigned char *, size_t, size_t, int,
49    int, size_t, int *);
50
51#define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
52
53#define isquote(c) (strchr("'\"`", (c)) != NULL)
54
55private uint16_t getu16(int, uint16_t);
56private uint32_t getu32(int, uint32_t);
57private uint64_t getu64(int, uint64_t);
58
59private uint16_t
60getu16(int swap, uint16_t value)
61{
62	union {
63		uint16_t ui;
64		char c[2];
65	} retval, tmpval;
66
67	if (swap) {
68		tmpval.ui = value;
69
70		retval.c[0] = tmpval.c[1];
71		retval.c[1] = tmpval.c[0];
72
73		return retval.ui;
74	} else
75		return value;
76}
77
78private uint32_t
79getu32(int swap, uint32_t value)
80{
81	union {
82		uint32_t ui;
83		char c[4];
84	} retval, tmpval;
85
86	if (swap) {
87		tmpval.ui = value;
88
89		retval.c[0] = tmpval.c[3];
90		retval.c[1] = tmpval.c[2];
91		retval.c[2] = tmpval.c[1];
92		retval.c[3] = tmpval.c[0];
93
94		return retval.ui;
95	} else
96		return value;
97}
98
99private uint64_t
100getu64(int swap, uint64_t value)
101{
102	union {
103		uint64_t ui;
104		char c[8];
105	} retval, tmpval;
106
107	if (swap) {
108		tmpval.ui = value;
109
110		retval.c[0] = tmpval.c[7];
111		retval.c[1] = tmpval.c[6];
112		retval.c[2] = tmpval.c[5];
113		retval.c[3] = tmpval.c[4];
114		retval.c[4] = tmpval.c[3];
115		retval.c[5] = tmpval.c[2];
116		retval.c[6] = tmpval.c[1];
117		retval.c[7] = tmpval.c[0];
118
119		return retval.ui;
120	} else
121		return value;
122}
123
124#ifdef USE_ARRAY_FOR_64BIT_TYPES
125# define elf_getu64(swap, array) \
126	((swap ? ((uint64_t)getu32(swap, array[0])) << 32 : getu32(swap, array[0])) + \
127	 (swap ? getu32(swap, array[1]) : ((uint64_t)getu32(swap, array[1]) << 32)))
128#else
129# define elf_getu64(swap, value) getu64(swap, value)
130#endif
131
132#define xsh_addr	(class == ELFCLASS32		\
133			 ? (void *) &sh32		\
134			 : (void *) &sh64)
135#define xsh_sizeof	(class == ELFCLASS32		\
136			 ? sizeof sh32			\
137			 : sizeof sh64)
138#define xsh_size	(class == ELFCLASS32		\
139			 ? getu32(swap, sh32.sh_size)	\
140			 : getu64(swap, sh64.sh_size))
141#define xsh_offset	(class == ELFCLASS32		\
142			 ? getu32(swap, sh32.sh_offset)	\
143			 : getu64(swap, sh64.sh_offset))
144#define xsh_type	(class == ELFCLASS32		\
145			 ? getu32(swap, sh32.sh_type)	\
146			 : getu32(swap, sh64.sh_type))
147#define xph_addr	(class == ELFCLASS32		\
148			 ? (void *) &ph32		\
149			 : (void *) &ph64)
150#define xph_sizeof	(class == ELFCLASS32		\
151			 ? sizeof ph32			\
152			 : sizeof ph64)
153#define xph_type	(class == ELFCLASS32		\
154			 ? getu32(swap, ph32.p_type)	\
155			 : getu32(swap, ph64.p_type))
156#define xph_offset	(class == ELFCLASS32		\
157			 ? getu32(swap, ph32.p_offset)	\
158			 : getu64(swap, ph64.p_offset))
159#define xph_align	(size_t)((class == ELFCLASS32	\
160			 ? (off_t) (ph32.p_align ? 	\
161			    getu32(swap, ph32.p_align) : 4) \
162			 : (off_t) (ph64.p_align ?	\
163			    getu64(swap, ph64.p_align) : 4)))
164#define xph_filesz	(size_t)((class == ELFCLASS32	\
165			 ? getu32(swap, ph32.p_filesz)	\
166			 : getu64(swap, ph64.p_filesz)))
167#define xnh_addr	(class == ELFCLASS32		\
168			 ? (void *) &nh32		\
169			 : (void *) &nh64)
170#define xph_memsz	(size_t)((class == ELFCLASS32	\
171			 ? getu32(swap, ph32.p_memsz)	\
172			 : getu64(swap, ph64.p_memsz)))
173#define xnh_sizeof	(class == ELFCLASS32		\
174			 ? sizeof nh32			\
175			 : sizeof nh64)
176#define xnh_type	(class == ELFCLASS32		\
177			 ? getu32(swap, nh32.n_type)	\
178			 : getu32(swap, nh64.n_type))
179#define xnh_namesz	(class == ELFCLASS32		\
180			 ? getu32(swap, nh32.n_namesz)	\
181			 : getu32(swap, nh64.n_namesz))
182#define xnh_descsz	(class == ELFCLASS32		\
183			 ? getu32(swap, nh32.n_descsz)	\
184			 : getu32(swap, nh64.n_descsz))
185#define prpsoffsets(i)	(class == ELFCLASS32		\
186			 ? prpsoffsets32[i]		\
187			 : prpsoffsets64[i])
188
189#ifdef ELFCORE
190size_t	prpsoffsets32[] = {
191	8,		/* FreeBSD */
192	28,		/* Linux 2.0.36 */
193	32,		/* Linux (I forget which kernel version) */
194	84,		/* SunOS 5.x */
195};
196
197size_t	prpsoffsets64[] = {
198	16,		/* FreeBSD, 64-bit */
199	40,             /* Linux (tested on core from 2.4.x) */
200       120,		/* SunOS 5.x, 64-bit */
201};
202
203#define	NOFFSETS32	(sizeof prpsoffsets32 / sizeof prpsoffsets32[0])
204#define NOFFSETS64	(sizeof prpsoffsets64 / sizeof prpsoffsets64[0])
205
206#define NOFFSETS	(class == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
207
208/*
209 * Look through the program headers of an executable image, searching
210 * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
211 * "FreeBSD"; if one is found, try looking in various places in its
212 * contents for a 16-character string containing only printable
213 * characters - if found, that string should be the name of the program
214 * that dropped core.  Note: right after that 16-character string is,
215 * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
216 * Linux, a longer string (80 characters, in 5.x, probably other
217 * SVR4-flavored systems, and Linux) containing the start of the
218 * command line for that program.
219 *
220 * The signal number probably appears in a section of type NT_PRSTATUS,
221 * but that's also rather OS-dependent, in ways that are harder to
222 * dissect with heuristics, so I'm not bothering with the signal number.
223 * (I suppose the signal number could be of interest in situations where
224 * you don't have the binary of the program that dropped core; if you
225 * *do* have that binary, the debugger will probably tell you what
226 * signal it was.)
227 */
228
229#define	OS_STYLE_SVR4		0
230#define	OS_STYLE_FREEBSD	1
231#define	OS_STYLE_NETBSD		2
232
233private const char *os_style_names[] = {
234	"SVR4",
235	"FreeBSD",
236	"NetBSD",
237};
238
239#define FLAGS_DID_CORE		1
240
241private int
242dophn_core(struct magic_set *ms, int class, int swap, int fd, off_t off,
243    int num, size_t size)
244{
245	Elf32_Phdr ph32;
246	Elf64_Phdr ph64;
247	size_t offset;
248	unsigned char nbuf[BUFSIZ];
249	ssize_t bufsize;
250	int flags = 0;
251
252	if (size != xph_sizeof) {
253		if (file_printf(ms, ", corrupted program header size") == -1)
254			return -1;
255		return 0;
256	}
257
258	/*
259	 * Loop through all the program headers.
260	 */
261	for ( ; num; num--) {
262		if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
263			file_badseek(ms);
264			return -1;
265		}
266		if (read(fd, xph_addr, xph_sizeof) == -1) {
267			file_badread(ms);
268			return -1;
269		}
270		off += size;
271		if (xph_type != PT_NOTE)
272			continue;
273
274		/*
275		 * This is a PT_NOTE section; loop through all the notes
276		 * in the section.
277		 */
278		if (lseek(fd, (off_t)xph_offset, SEEK_SET) == (off_t)-1) {
279			file_badseek(ms);
280			return -1;
281		}
282		bufsize = read(fd, nbuf,
283		    ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf)));
284		if (bufsize == -1) {
285			file_badread(ms);
286			return -1;
287		}
288		offset = 0;
289		for (;;) {
290			if (offset >= (size_t)bufsize)
291				break;
292			offset = donote(ms, nbuf, offset, (size_t)bufsize,
293			    class, swap, 4, &flags);
294			if (offset == 0)
295				break;
296
297		}
298	}
299	return 0;
300}
301#endif
302
303private size_t
304donote(struct magic_set *ms, unsigned char *nbuf, size_t offset, size_t size,
305    int class, int swap, size_t align, int *flags)
306{
307	Elf32_Nhdr nh32;
308	Elf64_Nhdr nh64;
309	size_t noff, doff;
310#ifdef ELFCORE
311	int os_style = -1;
312#endif
313	uint32_t namesz, descsz;
314
315	(void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
316	offset += xnh_sizeof;
317
318	namesz = xnh_namesz;
319	descsz = xnh_descsz;
320	if ((namesz == 0) && (descsz == 0)) {
321		/*
322		 * We're out of note headers.
323		 */
324		return offset;
325	}
326
327	if (namesz & 0x80000000) {
328	    (void)file_printf(ms, ", bad note name size 0x%lx",
329		(unsigned long)namesz);
330	    return offset;
331	}
332
333	if (descsz & 0x80000000) {
334	    (void)file_printf(ms, ", bad note description size 0x%lx",
335		(unsigned long)descsz);
336	    return offset;
337	}
338
339
340	noff = offset;
341	doff = ELF_ALIGN(offset + namesz);
342
343	if (offset + namesz > size) {
344		/*
345		 * We're past the end of the buffer.
346		 */
347		return doff;
348	}
349
350	offset = ELF_ALIGN(doff + descsz);
351	if (doff + descsz > size) {
352		return offset;
353	}
354
355	if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 &&
356	    xnh_type == NT_GNU_VERSION && descsz == 16) {
357		uint32_t desc[4];
358		(void)memcpy(desc, &nbuf[doff], sizeof(desc));
359
360		if (file_printf(ms, ", for GNU/") == -1)
361			return size;
362		switch (getu32(swap, desc[0])) {
363		case GNU_OS_LINUX:
364			if (file_printf(ms, "Linux") == -1)
365				return size;
366			break;
367		case GNU_OS_HURD:
368			if (file_printf(ms, "Hurd") == -1)
369				return size;
370			break;
371		case GNU_OS_SOLARIS:
372			if (file_printf(ms, "Solaris") == -1)
373				return size;
374			break;
375		default:
376			if (file_printf(ms, "<unknown>") == -1)
377				return size;
378		}
379		if (file_printf(ms, " %d.%d.%d", getu32(swap, desc[1]),
380		    getu32(swap, desc[2]), getu32(swap, desc[3])) == -1)
381			return size;
382		return size;
383	}
384
385	if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 &&
386	    xnh_type == NT_NETBSD_VERSION && descsz == 4) {
387		uint32_t desc;
388		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
389		desc = getu32(swap, desc);
390
391		if (file_printf(ms, ", for NetBSD") == -1)
392			return size;
393		/*
394		 * The version number used to be stuck as 199905, and was thus
395		 * basically content-free.  Newer versions of NetBSD have fixed
396		 * this and now use the encoding of __NetBSD_Version__:
397		 *
398		 *	MMmmrrpp00
399		 *
400		 * M = major version
401		 * m = minor version
402		 * r = release ["",A-Z,Z[A-Z] but numeric]
403		 * p = patchlevel
404		 */
405		if (desc > 100000000U) {
406			u_int ver_patch = (desc / 100) % 100;
407			u_int ver_rel = (desc / 10000) % 100;
408			u_int ver_min = (desc / 1000000) % 100;
409			u_int ver_maj = desc / 100000000;
410
411			if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
412				return size;
413			if (ver_rel == 0 && ver_patch != 0) {
414				if (file_printf(ms, ".%u", ver_patch) == -1)
415					return size;
416			} else if (ver_rel != 0) {
417				while (ver_rel > 26) {
418					file_printf(ms, "Z");
419					ver_rel -= 26;
420				}
421				file_printf(ms, "%c", 'A' + ver_rel - 1);
422			}
423		}
424		return size;
425	}
426
427	if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 &&
428	    xnh_type == NT_FREEBSD_VERSION && descsz == 4) {
429		uint32_t desc;
430		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
431		desc = getu32(swap, desc);
432		if (file_printf(ms, ", for FreeBSD") == -1)
433			return size;
434
435		/*
436		 * Contents is __FreeBSD_version, whose relation to OS
437		 * versions is defined by a huge table in the Porter's
438		 * Handbook.  This is the general scheme:
439		 *
440		 * Releases:
441		 * 	Mmp000 (before 4.10)
442		 * 	Mmi0p0 (before 5.0)
443		 * 	Mmm0p0
444		 *
445		 * Development branches:
446		 * 	Mmpxxx (before 4.6)
447		 * 	Mmp1xx (before 4.10)
448		 * 	Mmi1xx (before 5.0)
449		 * 	M000xx (pre-M.0)
450		 * 	Mmm1xx
451		 *
452		 * M = major version
453		 * m = minor version
454		 * i = minor version increment (491000 -> 4.10)
455		 * p = patchlevel
456		 * x = revision
457		 *
458		 * The first release of FreeBSD to use ELF by default
459		 * was version 3.0.
460		 */
461		if (desc == 460002) {
462			if (file_printf(ms, " 4.6.2") == -1)
463				return size;
464		} else if (desc < 460100) {
465			if (file_printf(ms, " %d.%d", desc / 100000,
466			    desc / 10000 % 10) == -1)
467				return size;
468			if (desc / 1000 % 10 > 0)
469				if (file_printf(ms, ".%d", desc / 1000 % 10)
470				    == -1)
471					return size;
472			if ((desc % 1000 > 0) || (desc % 100000 == 0))
473				if (file_printf(ms, " (%d)", desc) == -1)
474					return size;
475		} else if (desc < 500000) {
476			if (file_printf(ms, " %d.%d", desc / 100000,
477			    desc / 10000 % 10 + desc / 1000 % 10) == -1)
478				return size;
479			if (desc / 100 % 10 > 0) {
480				if (file_printf(ms, " (%d)", desc) == -1)
481					return size;
482			} else if (desc / 10 % 10 > 0) {
483				if (file_printf(ms, ".%d", desc / 10 % 10)
484				    == -1)
485					return size;
486			}
487		} else {
488			if (file_printf(ms, " %d.%d", desc / 100000,
489			    desc / 1000 % 100) == -1)
490				return size;
491			if ((desc / 100 % 10 > 0) ||
492			    (desc % 100000 / 100 == 0)) {
493				if (file_printf(ms, " (%d)", desc) == -1)
494					return size;
495			} else if (desc / 10 % 10 > 0) {
496				if (file_printf(ms, ".%d", desc / 10 % 10)
497				    == -1)
498					return size;
499			}
500		}
501		return size;
502	}
503
504	if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 &&
505	    xnh_type == NT_OPENBSD_VERSION && descsz == 4) {
506		if (file_printf(ms, ", for OpenBSD") == -1)
507			return size;
508		/* Content of note is always 0 */
509		return size;
510	}
511
512	if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 &&
513	    xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) {
514		uint32_t desc;
515		if (file_printf(ms, ", for DragonFly") == -1)
516			return size;
517		(void)memcpy(&desc, &nbuf[doff], sizeof(desc));
518		desc = getu32(swap, desc);
519		if (file_printf(ms, " %d.%d.%d", desc / 100000,
520		    desc / 10000 % 10, desc % 10000) == -1)
521			return size;
522		return size;
523	}
524
525	/*
526	 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
527	 * least, doesn't correctly implement name
528	 * sections, in core dumps, as specified by
529	 * the "Program Linking" section of "UNIX(R) System
530	 * V Release 4 Programmer's Guide: ANSI C and
531	 * Programming Support Tools", because my copy
532	 * clearly says "The first 'namesz' bytes in 'name'
533	 * contain a *null-terminated* [emphasis mine]
534	 * character representation of the entry's owner
535	 * or originator", but the 2.0.36 kernel code
536	 * doesn't include the terminating null in the
537	 * name....
538	 */
539	if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) ||
540	    (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) {
541		os_style = OS_STYLE_SVR4;
542	}
543
544	if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) {
545		os_style = OS_STYLE_FREEBSD;
546	}
547
548	if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11)
549	    == 0)) {
550		os_style = OS_STYLE_NETBSD;
551	}
552
553#ifdef ELFCORE
554	if (os_style != -1) {
555		if ((*flags & FLAGS_DID_CORE) == 0) {
556			if (file_printf(ms, ", %s-style",
557			    os_style_names[os_style]) == -1)
558				return size;
559			*flags |= FLAGS_DID_CORE;
560		}
561	}
562
563	switch (os_style) {
564	case OS_STYLE_NETBSD:
565		if (xnh_type == NT_NETBSD_CORE_PROCINFO) {
566			uint32_t signo;
567			/*
568			 * Extract the program name.  It is at
569			 * offset 0x7c, and is up to 32-bytes,
570			 * including the terminating NUL.
571			 */
572			if (file_printf(ms, ", from '%.31s'",
573			    &nbuf[doff + 0x7c]) == -1)
574				return size;
575
576			/*
577			 * Extract the signal number.  It is at
578			 * offset 0x08.
579			 */
580			(void)memcpy(&signo, &nbuf[doff + 0x08],
581			    sizeof(signo));
582			if (file_printf(ms, " (signal %u)",
583			    getu32(swap, signo)) == -1)
584				return size;
585			return size;
586		}
587		break;
588
589	default:
590		if (xnh_type == NT_PRPSINFO) {
591			size_t i, j;
592			unsigned char c;
593			/*
594			 * Extract the program name.  We assume
595			 * it to be 16 characters (that's what it
596			 * is in SunOS 5.x and Linux).
597			 *
598			 * Unfortunately, it's at a different offset
599			 * in varous OSes, so try multiple offsets.
600			 * If the characters aren't all printable,
601			 * reject it.
602			 */
603			for (i = 0; i < NOFFSETS; i++) {
604				size_t reloffset = prpsoffsets(i);
605				size_t noffset = doff + reloffset;
606				for (j = 0; j < 16; j++, noffset++,
607				    reloffset++) {
608					/*
609					 * Make sure we're not past
610					 * the end of the buffer; if
611					 * we are, just give up.
612					 */
613					if (noffset >= size)
614						goto tryanother;
615
616					/*
617					 * Make sure we're not past
618					 * the end of the contents;
619					 * if we are, this obviously
620					 * isn't the right offset.
621					 */
622					if (reloffset >= descsz)
623						goto tryanother;
624
625					c = nbuf[noffset];
626					if (c == '\0') {
627						/*
628						 * A '\0' at the
629						 * beginning is
630						 * obviously wrong.
631						 * Any other '\0'
632						 * means we're done.
633						 */
634						if (j == 0)
635							goto tryanother;
636						else
637							break;
638					} else {
639						/*
640						 * A nonprintable
641						 * character is also
642						 * wrong.
643						 */
644						if (!isprint(c) || isquote(c))
645							goto tryanother;
646					}
647				}
648				/*
649				 * Well, that worked.
650				 */
651				if (file_printf(ms, ", from '%.16s'",
652				    &nbuf[doff + prpsoffsets(i)]) == -1)
653					return size;
654				return size;
655
656			tryanother:
657				;
658			}
659		}
660		break;
661	}
662#endif
663	return offset;
664}
665
666private int
667doshn(struct magic_set *ms, int class, int swap, int fd, off_t off, int num,
668    size_t size)
669{
670	Elf32_Shdr sh32;
671	Elf64_Shdr sh64;
672	int stripped = 1;
673	int flags = 0;
674	void *nbuf;
675	off_t noff;
676
677	if (size != xsh_sizeof) {
678		if (file_printf(ms, ", corrupted section header size") == -1)
679			return -1;
680		return 0;
681	}
682
683	if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
684		file_badseek(ms);
685		return -1;
686	}
687
688	for ( ; num; num--) {
689		if (read(fd, xsh_addr, xsh_sizeof) == -1) {
690			file_badread(ms);
691			return -1;
692		}
693		switch (xsh_type) {
694		case SHT_SYMTAB:
695#if 0
696		case SHT_DYNSYM:
697#endif
698			stripped = 0;
699			break;
700		case SHT_NOTE:
701			if ((off = lseek(fd, (off_t)0, SEEK_CUR)) ==
702			    (off_t)-1) {
703				file_badread(ms);
704				return -1;
705			}
706			if ((nbuf = malloc((size_t)xsh_size)) == NULL) {
707				file_error(ms, errno, "Cannot allocate memory"
708				    " for note");
709				return -1;
710			}
711			if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) ==
712			    (off_t)-1) {
713				file_badread(ms);
714				free(nbuf);
715				return -1;
716			}
717			if (read(fd, nbuf, (size_t)xsh_size) !=
718			    (ssize_t)xsh_size) {
719				free(nbuf);
720				file_badread(ms);
721				return -1;
722			}
723
724			noff = 0;
725			for (;;) {
726				if (noff >= (size_t)xsh_size)
727					break;
728				noff = donote(ms, nbuf, (size_t)noff,
729				    (size_t)xsh_size, class, swap, 4,
730				    &flags);
731				if (noff == 0)
732					break;
733			}
734			if ((lseek(fd, off, SEEK_SET)) == (off_t)-1) {
735				free(nbuf);
736				file_badread(ms);
737				return -1;
738			}
739			free(nbuf);
740			break;
741		}
742	}
743	if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
744		return -1;
745	return 0;
746}
747
748/*
749 * Look through the program headers of an executable image, searching
750 * for a PT_INTERP section; if one is found, it's dynamically linked,
751 * otherwise it's statically linked.
752 */
753private int
754dophn_exec(struct magic_set *ms, int class, int swap, int fd, off_t off,
755    int num, size_t size)
756{
757	Elf32_Phdr ph32;
758	Elf64_Phdr ph64;
759	const char *linking_style = "statically";
760	const char *shared_libraries = "";
761	unsigned char nbuf[BUFSIZ];
762	int bufsize;
763	size_t offset, align;
764	off_t savedoffset;
765	int flags = 0;
766
767	if (size != xph_sizeof) {
768		if (file_printf(ms, ", corrupted program header size") == -1)
769		    return -1;
770		return 0;
771	}
772	if (lseek(fd, off, SEEK_SET) == (off_t)-1) {
773		file_badseek(ms);
774		return -1;
775	}
776
777  	for ( ; num; num--) {
778  		if (read(fd, xph_addr, xph_sizeof) == -1) {
779  			file_badread(ms);
780			return -1;
781		}
782		if ((savedoffset = lseek(fd, (off_t)0, SEEK_CUR)) == (off_t)-1) {
783  			file_badseek(ms);
784			return -1;
785		}
786
787		switch (xph_type) {
788		case PT_DYNAMIC:
789			linking_style = "dynamically";
790			break;
791		case PT_INTERP:
792			shared_libraries = " (uses shared libs)";
793			break;
794		case PT_NOTE:
795			if ((align = xph_align) & 0x80000000) {
796				if (file_printf(ms,
797				    ", invalid note alignment 0x%lx",
798				    (unsigned long)align) == -1)
799					return -1;
800				align = 4;
801			}
802			/*
803			 * This is a PT_NOTE section; loop through all the notes
804			 * in the section.
805			 */
806			if (lseek(fd, (off_t)xph_offset, SEEK_SET)
807			    == (off_t)-1) {
808				file_badseek(ms);
809				return -1;
810			}
811			bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ?
812			    xph_filesz : sizeof(nbuf)));
813			if (bufsize == -1) {
814				file_badread(ms);
815				return -1;
816			}
817			offset = 0;
818			for (;;) {
819				if (offset >= (size_t)bufsize)
820					break;
821				offset = donote(ms, nbuf, offset,
822				    (size_t)bufsize, class, swap, align,
823				    &flags);
824				if (offset == 0)
825					break;
826			}
827			if (lseek(fd, savedoffset, SEEK_SET) == (off_t)-1) {
828				file_badseek(ms);
829				return -1;
830			}
831			break;
832		}
833	}
834	if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries)
835	    == -1)
836	    return -1;
837	return 0;
838}
839
840
841protected int
842file_tryelf(struct magic_set *ms, int fd, const unsigned char *buf,
843    size_t nbytes)
844{
845	union {
846		int32_t l;
847		char c[sizeof (int32_t)];
848	} u;
849	int class;
850	int swap;
851
852	/*
853	 * If we cannot seek, it must be a pipe, socket or fifo.
854	 */
855	if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE))
856		fd = file_pipe2file(ms, fd, buf, nbytes);
857
858	/*
859	 * ELF executables have multiple section headers in arbitrary
860	 * file locations and thus file(1) cannot determine it from easily.
861	 * Instead we traverse thru all section headers until a symbol table
862	 * one is found or else the binary is stripped.
863	 */
864	if (buf[EI_MAG0] != ELFMAG0
865	    || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
866	    || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
867	    return 0;
868
869
870	class = buf[4];
871
872	if (class == ELFCLASS32) {
873		Elf32_Ehdr elfhdr;
874		if (nbytes <= sizeof (Elf32_Ehdr))
875			return 0;
876
877
878		u.l = 1;
879		(void) memcpy(&elfhdr, buf, sizeof elfhdr);
880		swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5];
881
882		if (getu16(swap, elfhdr.e_type) == ET_CORE) {
883#ifdef ELFCORE
884			if (dophn_core(ms, class, swap, fd,
885			    (off_t)getu32(swap, elfhdr.e_phoff),
886			    getu16(swap, elfhdr.e_phnum),
887			    (size_t)getu16(swap, elfhdr.e_phentsize)) == -1)
888				return -1;
889#else
890			;
891#endif
892		} else {
893			if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
894				if (dophn_exec(ms, class, swap,
895				    fd, (off_t)getu32(swap, elfhdr.e_phoff),
896				    getu16(swap, elfhdr.e_phnum),
897				    (size_t)getu16(swap, elfhdr.e_phentsize))
898				    == -1)
899					return -1;
900			}
901			if (doshn(ms, class, swap, fd,
902			    (off_t)getu32(swap, elfhdr.e_shoff),
903			    getu16(swap, elfhdr.e_shnum),
904			    (size_t)getu16(swap, elfhdr.e_shentsize)) == -1)
905				return -1;
906		}
907		return 1;
908	}
909
910        if (class == ELFCLASS64) {
911		Elf64_Ehdr elfhdr;
912		if (nbytes <= sizeof (Elf64_Ehdr))
913			return 0;
914
915
916		u.l = 1;
917		(void) memcpy(&elfhdr, buf, sizeof elfhdr);
918		swap = (u.c[sizeof(int32_t) - 1] + 1) != elfhdr.e_ident[5];
919
920		if (getu16(swap, elfhdr.e_type) == ET_CORE) {
921#ifdef ELFCORE
922			if (dophn_core(ms, class, swap, fd,
923			    (off_t)elf_getu64(swap, elfhdr.e_phoff),
924			    getu16(swap, elfhdr.e_phnum),
925			    (size_t)getu16(swap, elfhdr.e_phentsize)) == -1)
926				return -1;
927#else
928			;
929#endif
930		} else {
931			if (getu16(swap, elfhdr.e_type) == ET_EXEC) {
932				if (dophn_exec(ms, class, swap, fd,
933				    (off_t)elf_getu64(swap, elfhdr.e_phoff),
934				    getu16(swap, elfhdr.e_phnum),
935				    (size_t)getu16(swap, elfhdr.e_phentsize))
936				    == -1)
937					return -1;
938			}
939			if (doshn(ms, class, swap, fd,
940			    (off_t)elf_getu64(swap, elfhdr.e_shoff),
941			    getu16(swap, elfhdr.e_shnum),
942			    (size_t)getu16(swap, elfhdr.e_shentsize)) == -1)
943				return -1;
944		}
945		return 1;
946	}
947	return 0;
948}
949#endif
950