xref: /netbsd-src/external/bsd/file/dist/src/readelf.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 /*	$NetBSD: readelf.c,v 1.21 2019/05/22 17:26:05 christos Exp $	*/
2 
3 /*
4  * Copyright (c) Christos Zoulas 2003.
5  * All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice immediately at the beginning of the file, without modification,
12  *    this list of conditions, and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 #include "file.h"
30 
31 #ifndef lint
32 #if 0
33 FILE_RCSID("@(#)$File: readelf.c,v 1.165 2019/05/07 02:27:11 christos Exp $")
34 #else
35 __RCSID("$NetBSD: readelf.c,v 1.21 2019/05/22 17:26:05 christos Exp $");
36 #endif
37 #endif
38 
39 #ifdef BUILTIN_ELF
40 #include <string.h>
41 #include <ctype.h>
42 #include <stdlib.h>
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46 
47 #include "readelf.h"
48 #include "magic.h"
49 
50 #ifdef	ELFCORE
51 private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
52     off_t, int *, uint16_t *);
53 #endif
54 private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
55     off_t, int, int *, uint16_t *);
56 private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
57     off_t, int, int, int *, uint16_t *);
58 private size_t donote(struct magic_set *, void *, size_t, size_t, int,
59     int, size_t, int *, uint16_t *, int, off_t, int, off_t);
60 
61 #define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
62 
63 #define isquote(c) (strchr("'\"`", (c)) != NULL)
64 
65 private uint16_t getu16(int, uint16_t);
66 private uint32_t getu32(int, uint32_t);
67 private uint64_t getu64(int, uint64_t);
68 
69 #define MAX_PHNUM	128
70 #define	MAX_SHNUM	32768
71 #define SIZE_UNKNOWN	CAST(off_t, -1)
72 
73 private int
74 toomany(struct magic_set *ms, const char *name, uint16_t num)
75 {
76 	if (file_printf(ms, ", too many %s (%u)", name, num) == -1)
77 		return -1;
78 	return 1;
79 }
80 
81 private uint16_t
82 getu16(int swap, uint16_t value)
83 {
84 	union {
85 		uint16_t ui;
86 		char c[2];
87 	} retval, tmpval;
88 
89 	if (swap) {
90 		tmpval.ui = value;
91 
92 		retval.c[0] = tmpval.c[1];
93 		retval.c[1] = tmpval.c[0];
94 
95 		return retval.ui;
96 	} else
97 		return value;
98 }
99 
100 private uint32_t
101 getu32(int swap, uint32_t value)
102 {
103 	union {
104 		uint32_t ui;
105 		char c[4];
106 	} retval, tmpval;
107 
108 	if (swap) {
109 		tmpval.ui = value;
110 
111 		retval.c[0] = tmpval.c[3];
112 		retval.c[1] = tmpval.c[2];
113 		retval.c[2] = tmpval.c[1];
114 		retval.c[3] = tmpval.c[0];
115 
116 		return retval.ui;
117 	} else
118 		return value;
119 }
120 
121 private uint64_t
122 getu64(int swap, uint64_t value)
123 {
124 	union {
125 		uint64_t ui;
126 		char c[8];
127 	} retval, tmpval;
128 
129 	if (swap) {
130 		tmpval.ui = value;
131 
132 		retval.c[0] = tmpval.c[7];
133 		retval.c[1] = tmpval.c[6];
134 		retval.c[2] = tmpval.c[5];
135 		retval.c[3] = tmpval.c[4];
136 		retval.c[4] = tmpval.c[3];
137 		retval.c[5] = tmpval.c[2];
138 		retval.c[6] = tmpval.c[1];
139 		retval.c[7] = tmpval.c[0];
140 
141 		return retval.ui;
142 	} else
143 		return value;
144 }
145 
146 #define elf_getu16(swap, value) getu16(swap, value)
147 #define elf_getu32(swap, value) getu32(swap, value)
148 #define elf_getu64(swap, value) getu64(swap, value)
149 
150 #define xsh_addr	(clazz == ELFCLASS32			\
151 			 ? CAST(void *, &sh32)			\
152 			 : CAST(void *, &sh64))
153 #define xsh_sizeof	(clazz == ELFCLASS32			\
154 			 ? sizeof(sh32)				\
155 			 : sizeof(sh64))
156 #define xsh_size	CAST(size_t, (clazz == ELFCLASS32	\
157 			 ? elf_getu32(swap, sh32.sh_size)	\
158 			 : elf_getu64(swap, sh64.sh_size)))
159 #define xsh_offset	CAST(off_t, (clazz == ELFCLASS32	\
160 			 ? elf_getu32(swap, sh32.sh_offset)	\
161 			 : elf_getu64(swap, sh64.sh_offset)))
162 #define xsh_type	(clazz == ELFCLASS32			\
163 			 ? elf_getu32(swap, sh32.sh_type)	\
164 			 : elf_getu32(swap, sh64.sh_type))
165 #define xsh_name    	(clazz == ELFCLASS32			\
166 			 ? elf_getu32(swap, sh32.sh_name)	\
167 			 : elf_getu32(swap, sh64.sh_name))
168 
169 #define xph_addr	(clazz == ELFCLASS32			\
170 			 ? CAST(void *, &ph32)			\
171 			 : CAST(void *, &ph64))
172 #define xph_sizeof	(clazz == ELFCLASS32			\
173 			 ? sizeof(ph32)				\
174 			 : sizeof(ph64))
175 #define xph_type	(clazz == ELFCLASS32			\
176 			 ? elf_getu32(swap, ph32.p_type)	\
177 			 : elf_getu32(swap, ph64.p_type))
178 #define xph_offset	CAST(off_t, (clazz == ELFCLASS32	\
179 			 ? elf_getu32(swap, ph32.p_offset)	\
180 			 : elf_getu64(swap, ph64.p_offset)))
181 #define xph_align	CAST(size_t, (clazz == ELFCLASS32	\
182 			 ? CAST(off_t, (ph32.p_align ? 		\
183 			    elf_getu32(swap, ph32.p_align) : 4))\
184 			 : CAST(off_t, (ph64.p_align ?		\
185 			    elf_getu64(swap, ph64.p_align) : 4))))
186 #define xph_vaddr	CAST(size_t, (clazz == ELFCLASS32	\
187 			 ? CAST(off_t, (ph32.p_vaddr ? 		\
188 			    elf_getu32(swap, ph32.p_vaddr) : 4))\
189 			 : CAST(off_t, (ph64.p_vaddr ?		\
190 			    elf_getu64(swap, ph64.p_vaddr) : 4))))
191 #define xph_filesz	CAST(size_t, (clazz == ELFCLASS32	\
192 			 ? elf_getu32(swap, ph32.p_filesz)	\
193 			 : elf_getu64(swap, ph64.p_filesz)))
194 #define xph_memsz	CAST(size_t, ((clazz == ELFCLASS32	\
195 			 ? elf_getu32(swap, ph32.p_memsz)	\
196 			 : elf_getu64(swap, ph64.p_memsz))))
197 #define xnh_addr	(clazz == ELFCLASS32			\
198 			 ? CAST(void *, &nh32)			\
199 			 : CAST(void *, &nh64))
200 #define xnh_sizeof	(clazz == ELFCLASS32			\
201 			 ? sizeof(nh32)				\
202 			 : sizeof(nh64))
203 #define xnh_type	(clazz == ELFCLASS32			\
204 			 ? elf_getu32(swap, nh32.n_type)	\
205 			 : elf_getu32(swap, nh64.n_type))
206 #define xnh_namesz	(clazz == ELFCLASS32			\
207 			 ? elf_getu32(swap, nh32.n_namesz)	\
208 			 : elf_getu32(swap, nh64.n_namesz))
209 #define xnh_descsz	(clazz == ELFCLASS32			\
210 			 ? elf_getu32(swap, nh32.n_descsz)	\
211 			 : elf_getu32(swap, nh64.n_descsz))
212 
213 #define xdh_addr	(clazz == ELFCLASS32			\
214 			 ? CAST(void *, &dh32)			\
215 			 : CAST(void *, &dh64))
216 #define xdh_sizeof	(clazz == ELFCLASS32			\
217 			 ? sizeof(dh32)				\
218 			 : sizeof(dh64))
219 #define xdh_tag		(clazz == ELFCLASS32			\
220 			 ? elf_getu32(swap, dh32.d_tag)		\
221 			 : elf_getu64(swap, dh64.d_tag))
222 #define xdh_val		(clazz == ELFCLASS32			\
223 			 ? elf_getu32(swap, dh32.d_un.d_val)	\
224 			 : elf_getu64(swap, dh64.d_un.d_val))
225 
226 #define xcap_addr	(clazz == ELFCLASS32			\
227 			 ? CAST(void *, &cap32)			\
228 			 : CAST(void *, &cap64))
229 #define xcap_sizeof	(clazz == ELFCLASS32			\
230 			 ? sizeof(cap32)			\
231 			 : sizeof(cap64))
232 #define xcap_tag	(clazz == ELFCLASS32			\
233 			 ? elf_getu32(swap, cap32.c_tag)	\
234 			 : elf_getu64(swap, cap64.c_tag))
235 #define xcap_val	(clazz == ELFCLASS32			\
236 			 ? elf_getu32(swap, cap32.c_un.c_val)	\
237 			 : elf_getu64(swap, cap64.c_un.c_val))
238 
239 #define xauxv_addr	(clazz == ELFCLASS32			\
240 			 ? CAST(void *, &auxv32)		\
241 			 : CAST(void *, &auxv64))
242 #define xauxv_sizeof	(clazz == ELFCLASS32			\
243 			 ? sizeof(auxv32)			\
244 			 : sizeof(auxv64))
245 #define xauxv_type	(clazz == ELFCLASS32			\
246 			 ? elf_getu32(swap, auxv32.a_type)	\
247 			 : elf_getu64(swap, auxv64.a_type))
248 #define xauxv_val	(clazz == ELFCLASS32			\
249 			 ? elf_getu32(swap, auxv32.a_v)		\
250 			 : elf_getu64(swap, auxv64.a_v))
251 
252 #define prpsoffsets(i)	(clazz == ELFCLASS32			\
253 			 ? prpsoffsets32[i]			\
254 			 : prpsoffsets64[i])
255 
256 #ifdef ELFCORE
257 /*
258  * Try larger offsets first to avoid false matches
259  * from earlier data that happen to look like strings.
260  */
261 static const size_t	prpsoffsets32[] = {
262 #ifdef USE_NT_PSINFO
263 	104,		/* SunOS 5.x (command line) */
264 	88,		/* SunOS 5.x (short name) */
265 #endif /* USE_NT_PSINFO */
266 
267 	100,		/* SunOS 5.x (command line) */
268 	84,		/* SunOS 5.x (short name) */
269 
270 	44,		/* Linux (command line) */
271 	28,		/* Linux (short name) */
272 
273 	48,		/* Linux PowerPC (command line) */
274 	32,		/* Linux PowerPC (short name) */
275 
276 	8,		/* FreeBSD */
277 };
278 
279 static const size_t	prpsoffsets64[] = {
280 #ifdef USE_NT_PSINFO
281 	152,		/* SunOS 5.x (command line) */
282 	136,		/* SunOS 5.x (short name) */
283 #endif /* USE_NT_PSINFO */
284 
285 	136,		/* SunOS 5.x, 64-bit (command line) */
286 	120,		/* SunOS 5.x, 64-bit (short name) */
287 
288 	56,		/* Linux (command line) */
289 	40,             /* Linux (tested on core from 2.4.x, short name) */
290 
291 	16,		/* FreeBSD, 64-bit */
292 };
293 
294 #define	NOFFSETS32	__arraycount(prpsoffsets32)
295 #define NOFFSETS64	__arraycount(prpsoffsets64)
296 
297 #define NOFFSETS	(clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
298 
299 /*
300  * Look through the program headers of an executable image, searching
301  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
302  * "FreeBSD"; if one is found, try looking in various places in its
303  * contents for a 16-character string containing only printable
304  * characters - if found, that string should be the name of the program
305  * that dropped core.  Note: right after that 16-character string is,
306  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
307  * Linux, a longer string (80 characters, in 5.x, probably other
308  * SVR4-flavored systems, and Linux) containing the start of the
309  * command line for that program.
310  *
311  * SunOS 5.x core files contain two PT_NOTE sections, with the types
312  * NT_PRPSINFO (old) and NT_PSINFO (new).  These structs contain the
313  * same info about the command name and command line, so it probably
314  * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
315  * above (see USE_NT_PSINFO), in case we ever decide to do so.  The
316  * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
317  * the SunOS 5.x file command relies on this (and prefers the latter).
318  *
319  * The signal number probably appears in a section of type NT_PRSTATUS,
320  * but that's also rather OS-dependent, in ways that are harder to
321  * dissect with heuristics, so I'm not bothering with the signal number.
322  * (I suppose the signal number could be of interest in situations where
323  * you don't have the binary of the program that dropped core; if you
324  * *do* have that binary, the debugger will probably tell you what
325  * signal it was.)
326  */
327 
328 #define	OS_STYLE_SVR4		0
329 #define	OS_STYLE_FREEBSD	1
330 #define	OS_STYLE_NETBSD		2
331 
332 private const char os_style_names[][8] = {
333 	"SVR4",
334 	"FreeBSD",
335 	"NetBSD",
336 };
337 
338 #define FLAGS_CORE_STYLE		0x0003
339 
340 #define FLAGS_DID_CORE			0x0004
341 #define FLAGS_DID_OS_NOTE		0x0008
342 #define FLAGS_DID_BUILD_ID		0x0010
343 #define FLAGS_DID_CORE_STYLE		0x0020
344 #define FLAGS_DID_NETBSD_PAX		0x0040
345 #define FLAGS_DID_NETBSD_MARCH		0x0080
346 #define FLAGS_DID_NETBSD_CMODEL		0x0100
347 #define FLAGS_DID_NETBSD_EMULATION	0x0200
348 #define FLAGS_DID_NETBSD_UNKNOWN	0x0400
349 #define FLAGS_IS_CORE			0x0800
350 #define FLAGS_DID_AUXV			0x1000
351 
352 private int
353 dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
354     int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
355 {
356 	Elf32_Phdr ph32;
357 	Elf64_Phdr ph64;
358 	size_t offset, len;
359 	unsigned char nbuf[BUFSIZ];
360 	ssize_t bufsize;
361 	off_t ph_off = off;
362 	int ph_num = num;
363 
364 	if (num == 0) {
365 		if (file_printf(ms, ", no program header") == -1)
366 			return -1;
367 		return 0;
368 	}
369 	if (size != xph_sizeof) {
370 		if (file_printf(ms, ", corrupted program header size") == -1)
371 			return -1;
372 		return 0;
373 	}
374 
375 	/*
376 	 * Loop through all the program headers.
377 	 */
378 	for ( ; num; num--) {
379 		if (pread(fd, xph_addr, xph_sizeof, off) <
380 		    CAST(ssize_t, xph_sizeof)) {
381 			file_badread(ms);
382 			return -1;
383 		}
384 		off += size;
385 
386 		if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
387 			/* Perhaps warn here */
388 			continue;
389 		}
390 
391 		if (xph_type != PT_NOTE)
392 			continue;
393 
394 		/*
395 		 * This is a PT_NOTE section; loop through all the notes
396 		 * in the section.
397 		 */
398 		len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
399 		if ((bufsize = pread(fd, nbuf, len, xph_offset)) == -1) {
400 			file_badread(ms);
401 			return -1;
402 		}
403 		offset = 0;
404 		for (;;) {
405 			if (offset >= CAST(size_t, bufsize))
406 				break;
407 			offset = donote(ms, nbuf, offset, CAST(size_t, bufsize),
408 			    clazz, swap, 4, flags, notecount, fd, ph_off,
409 			    ph_num, fsize);
410 			if (offset == 0)
411 				break;
412 
413 		}
414 	}
415 	return 0;
416 }
417 #endif
418 
419 static int
420 do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
421 {
422 	uint32_t desc;
423 	memcpy(&desc, v, sizeof(desc));
424 	desc = elf_getu32(swap, desc);
425 
426 	if (file_printf(ms, ", for NetBSD") == -1)
427 		return -1;
428 	/*
429 	 * The version number used to be stuck as 199905, and was thus
430 	 * basically content-free.  Newer versions of NetBSD have fixed
431 	 * this and now use the encoding of __NetBSD_Version__:
432 	 *
433 	 *	MMmmrrpp00
434 	 *
435 	 * M = major version
436 	 * m = minor version
437 	 * r = release ["",A-Z,Z[A-Z] but numeric]
438 	 * p = patchlevel
439 	 */
440 	if (desc > 100000000U) {
441 		uint32_t ver_patch = (desc / 100) % 100;
442 		uint32_t ver_rel = (desc / 10000) % 100;
443 		uint32_t ver_min = (desc / 1000000) % 100;
444 		uint32_t ver_maj = desc / 100000000;
445 
446 		if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
447 			return -1;
448 		if (ver_rel == 0 && ver_patch != 0) {
449 			if (file_printf(ms, ".%u", ver_patch) == -1)
450 				return -1;
451 		} else if (ver_rel != 0) {
452 			while (ver_rel > 26) {
453 				if (file_printf(ms, "Z") == -1)
454 					return -1;
455 				ver_rel -= 26;
456 			}
457 			if (file_printf(ms, "%c", 'A' + ver_rel - 1)
458 			    == -1)
459 				return -1;
460 		}
461 	}
462 	return 0;
463 }
464 
465 static int
466 do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
467 {
468 	uint32_t desc;
469 
470 	memcpy(&desc, v, sizeof(desc));
471 	desc = elf_getu32(swap, desc);
472 	if (file_printf(ms, ", for FreeBSD") == -1)
473 		return -1;
474 
475 	/*
476 	 * Contents is __FreeBSD_version, whose relation to OS
477 	 * versions is defined by a huge table in the Porter's
478 	 * Handbook.  This is the general scheme:
479 	 *
480 	 * Releases:
481 	 * 	Mmp000 (before 4.10)
482 	 * 	Mmi0p0 (before 5.0)
483 	 * 	Mmm0p0
484 	 *
485 	 * Development branches:
486 	 * 	Mmpxxx (before 4.6)
487 	 * 	Mmp1xx (before 4.10)
488 	 * 	Mmi1xx (before 5.0)
489 	 * 	M000xx (pre-M.0)
490 	 * 	Mmm1xx
491 	 *
492 	 * M = major version
493 	 * m = minor version
494 	 * i = minor version increment (491000 -> 4.10)
495 	 * p = patchlevel
496 	 * x = revision
497 	 *
498 	 * The first release of FreeBSD to use ELF by default
499 	 * was version 3.0.
500 	 */
501 	if (desc == 460002) {
502 		if (file_printf(ms, " 4.6.2") == -1)
503 			return -1;
504 	} else if (desc < 460100) {
505 		if (file_printf(ms, " %d.%d", desc / 100000,
506 		    desc / 10000 % 10) == -1)
507 			return -1;
508 		if (desc / 1000 % 10 > 0)
509 			if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
510 				return -1;
511 		if ((desc % 1000 > 0) || (desc % 100000 == 0))
512 			if (file_printf(ms, " (%d)", desc) == -1)
513 				return -1;
514 	} else if (desc < 500000) {
515 		if (file_printf(ms, " %d.%d", desc / 100000,
516 		    desc / 10000 % 10 + desc / 1000 % 10) == -1)
517 			return -1;
518 		if (desc / 100 % 10 > 0) {
519 			if (file_printf(ms, " (%d)", desc) == -1)
520 				return -1;
521 		} else if (desc / 10 % 10 > 0) {
522 			if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
523 				return -1;
524 		}
525 	} else {
526 		if (file_printf(ms, " %d.%d", desc / 100000,
527 		    desc / 1000 % 100) == -1)
528 			return -1;
529 		if ((desc / 100 % 10 > 0) ||
530 		    (desc % 100000 / 100 == 0)) {
531 			if (file_printf(ms, " (%d)", desc) == -1)
532 				return -1;
533 		} else if (desc / 10 % 10 > 0) {
534 			if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
535 				return -1;
536 		}
537 	}
538 	return 0;
539 }
540 
541 private int
542 /*ARGSUSED*/
543 do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
544     int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
545     size_t noff, size_t doff, int *flags)
546 {
547 	if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "GNU") == 0 &&
548 	    type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) {
549 		uint8_t desc[20];
550 		const char *btype;
551 		uint32_t i;
552 		*flags |= FLAGS_DID_BUILD_ID;
553 		switch (descsz) {
554 		case 8:
555 		    btype = "xxHash";
556 		    break;
557 		case 16:
558 		    btype = "md5/uuid";
559 		    break;
560 		case 20:
561 		    btype = "sha1";
562 		    break;
563 		default:
564 		    btype = "unknown";
565 		    break;
566 		}
567 		if (file_printf(ms, ", BuildID[%s]=", btype) == -1)
568 			return -1;
569 		memcpy(desc, &nbuf[doff], descsz);
570 		for (i = 0; i < descsz; i++)
571 		    if (file_printf(ms, "%02x", desc[i]) == -1)
572 			return -1;
573 		return 1;
574 	}
575 	if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "Go") == 0 &&
576 	    type == NT_GO_BUILD_ID && descsz < 128) {
577 		if (file_printf(ms, ", Go BuildID=%.*s",
578 		    CAST(int, descsz), RCAST(char *, &nbuf[doff])) == -1)
579 			return -1;
580 		return 1;
581 	}
582 	return 0;
583 }
584 
585 private int
586 do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
587     int swap, uint32_t namesz, uint32_t descsz,
588     size_t noff, size_t doff, int *flags)
589 {
590 	const char *name = RCAST(const char *, &nbuf[noff]);
591 
592 	if (namesz == 5 && strcmp(name, "SuSE") == 0 &&
593 		type == NT_GNU_VERSION && descsz == 2) {
594 		*flags |= FLAGS_DID_OS_NOTE;
595 		if (file_printf(ms, ", for SuSE %d.%d", nbuf[doff],
596 		    nbuf[doff + 1]) == -1)
597 		    return -1;
598 	    return 1;
599 	}
600 
601 	if (namesz == 4 && strcmp(name, "GNU") == 0 &&
602 	    type == NT_GNU_VERSION && descsz == 16) {
603 		uint32_t desc[4];
604 		memcpy(desc, &nbuf[doff], sizeof(desc));
605 
606 		*flags |= FLAGS_DID_OS_NOTE;
607 		if (file_printf(ms, ", for GNU/") == -1)
608 			return -1;
609 		switch (elf_getu32(swap, desc[0])) {
610 		case GNU_OS_LINUX:
611 			if (file_printf(ms, "Linux") == -1)
612 				return -1;
613 			break;
614 		case GNU_OS_HURD:
615 			if (file_printf(ms, "Hurd") == -1)
616 				return -1;
617 			break;
618 		case GNU_OS_SOLARIS:
619 			if (file_printf(ms, "Solaris") == -1)
620 				return -1;
621 			break;
622 		case GNU_OS_KFREEBSD:
623 			if (file_printf(ms, "kFreeBSD") == -1)
624 				return -1;
625 			break;
626 		case GNU_OS_KNETBSD:
627 			if (file_printf(ms, "kNetBSD") == -1)
628 				return -1;
629 			break;
630 		default:
631 			if (file_printf(ms, "<unknown>") == -1)
632 				return -1;
633 		}
634 		if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
635 		    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
636 			return -1;
637 		return 1;
638 	}
639 
640 	if (namesz == 7 && strcmp(name, "NetBSD") == 0) {
641 	    	if (type == NT_NETBSD_VERSION && descsz == 4) {
642 			*flags |= FLAGS_DID_OS_NOTE;
643 			if (do_note_netbsd_version(ms, swap, &nbuf[doff]) == -1)
644 				return -1;
645 			return 1;
646 		}
647 	}
648 
649 	if (namesz == 8 && strcmp(name, "FreeBSD") == 0) {
650 	    	if (type == NT_FREEBSD_VERSION && descsz == 4) {
651 			*flags |= FLAGS_DID_OS_NOTE;
652 			if (do_note_freebsd_version(ms, swap, &nbuf[doff])
653 			    == -1)
654 				return -1;
655 			return 1;
656 		}
657 	}
658 
659 	if (namesz == 8 && strcmp(name, "OpenBSD") == 0 &&
660 	    type == NT_OPENBSD_VERSION && descsz == 4) {
661 		*flags |= FLAGS_DID_OS_NOTE;
662 		if (file_printf(ms, ", for OpenBSD") == -1)
663 			return -1;
664 		/* Content of note is always 0 */
665 		return 1;
666 	}
667 
668 	if (namesz == 10 && strcmp(name, "DragonFly") == 0 &&
669 	    type == NT_DRAGONFLY_VERSION && descsz == 4) {
670 		uint32_t desc;
671 		*flags |= FLAGS_DID_OS_NOTE;
672 		if (file_printf(ms, ", for DragonFly") == -1)
673 			return -1;
674 		memcpy(&desc, &nbuf[doff], sizeof(desc));
675 		desc = elf_getu32(swap, desc);
676 		if (file_printf(ms, " %d.%d.%d", desc / 100000,
677 		    desc / 10000 % 10, desc % 10000) == -1)
678 			return -1;
679 		return 1;
680 	}
681 	return 0;
682 }
683 
684 private int
685 do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
686     int swap, uint32_t namesz, uint32_t descsz,
687     size_t noff, size_t doff, int *flags)
688 {
689 	const char *name = RCAST(const char *, &nbuf[noff]);
690 
691 	if (namesz == 4 && strcmp(name, "PaX") == 0 &&
692 	    type == NT_NETBSD_PAX && descsz == 4) {
693 		static const char *pax[] = {
694 		    "+mprotect",
695 		    "-mprotect",
696 		    "+segvguard",
697 		    "-segvguard",
698 		    "+ASLR",
699 		    "-ASLR",
700 		};
701 		uint32_t desc;
702 		size_t i;
703 		int did = 0;
704 
705 		*flags |= FLAGS_DID_NETBSD_PAX;
706 		memcpy(&desc, &nbuf[doff], sizeof(desc));
707 		desc = elf_getu32(swap, desc);
708 
709 		if (desc && file_printf(ms, ", PaX: ") == -1)
710 			return -1;
711 
712 		for (i = 0; i < __arraycount(pax); i++) {
713 			if (((1 << CAST(int, i)) & desc) == 0)
714 				continue;
715 			if (file_printf(ms, "%s%s", did++ ? "," : "",
716 			    pax[i]) == -1)
717 				return -1;
718 		}
719 		return 1;
720 	}
721 	return 0;
722 }
723 
724 private int
725 do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
726     int swap, uint32_t namesz, uint32_t descsz,
727     size_t noff, size_t doff, int *flags, size_t size, int clazz)
728 {
729 #ifdef ELFCORE
730 	const char *name = RCAST(const char *, &nbuf[noff]);
731 
732 	int os_style = -1;
733 	/*
734 	 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
735 	 * least, doesn't correctly implement name
736 	 * sections, in core dumps, as specified by
737 	 * the "Program Linking" section of "UNIX(R) System
738 	 * V Release 4 Programmer's Guide: ANSI C and
739 	 * Programming Support Tools", because my copy
740 	 * clearly says "The first 'namesz' bytes in 'name'
741 	 * contain a *null-terminated* [emphasis mine]
742 	 * character representation of the entry's owner
743 	 * or originator", but the 2.0.36 kernel code
744 	 * doesn't include the terminating null in the
745 	 * name....
746 	 */
747 	if ((namesz == 4 && strncmp(name, "CORE", 4) == 0) ||
748 	    (namesz == 5 && strcmp(name, "CORE") == 0)) {
749 		os_style = OS_STYLE_SVR4;
750 	}
751 
752 	if ((namesz == 8 && strcmp(name, "FreeBSD") == 0)) {
753 		os_style = OS_STYLE_FREEBSD;
754 	}
755 
756 	if ((namesz >= 11 && strncmp(name, "NetBSD-CORE", 11)
757 	    == 0)) {
758 		os_style = OS_STYLE_NETBSD;
759 	}
760 
761 	if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
762 		if (file_printf(ms, ", %s-style", os_style_names[os_style])
763 		    == -1)
764 			return -1;
765 		*flags |= FLAGS_DID_CORE_STYLE;
766 		*flags |= os_style;
767 	}
768 
769 	switch (os_style) {
770 	case OS_STYLE_NETBSD:
771 		if (type == NT_NETBSD_CORE_PROCINFO) {
772 			char sbuf[512];
773 			struct NetBSD_elfcore_procinfo pi;
774 			memset(&pi, 0, sizeof(pi));
775 			memcpy(&pi, nbuf + doff, MIN(descsz, sizeof(pi)));
776 
777 			if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, "
778 			    "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)",
779 			    file_printable(sbuf, sizeof(sbuf),
780 			    RCAST(char *, pi.cpi_name), sizeof(pi.cpi_name)),
781 			    elf_getu32(swap, CAST(uint32_t, pi.cpi_pid)),
782 			    elf_getu32(swap, pi.cpi_euid),
783 			    elf_getu32(swap, pi.cpi_egid),
784 			    elf_getu32(swap, pi.cpi_nlwps),
785 			    elf_getu32(swap, CAST(uint32_t, pi.cpi_siglwp)),
786 			    elf_getu32(swap, pi.cpi_signo),
787 			    elf_getu32(swap, pi.cpi_sigcode)) == -1)
788 				return -1;
789 
790 			*flags |= FLAGS_DID_CORE;
791 			return 1;
792 		}
793 		break;
794 
795 	case OS_STYLE_FREEBSD:
796 		if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
797 			size_t argoff, pidoff;
798 
799 			if (clazz == ELFCLASS32)
800 				argoff = 4 + 4 + 17;
801 			else
802 				argoff = 4 + 4 + 8 + 17;
803 			if (file_printf(ms, ", from '%.80s'", nbuf + doff +
804 			    argoff) == -1)
805 				return -1;
806 			pidoff = argoff + 81 + 2;
807 			if (doff + pidoff + 4 <= size) {
808 				if (file_printf(ms, ", pid=%u",
809 				    elf_getu32(swap, *RCAST(uint32_t *, (nbuf +
810 				    doff + pidoff)))) == -1)
811 					return -1;
812 			}
813 			*flags |= FLAGS_DID_CORE;
814 		}
815 		break;
816 
817 	default:
818 		if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
819 			size_t i, j;
820 			unsigned char c;
821 			/*
822 			 * Extract the program name.  We assume
823 			 * it to be 16 characters (that's what it
824 			 * is in SunOS 5.x and Linux).
825 			 *
826 			 * Unfortunately, it's at a different offset
827 			 * in various OSes, so try multiple offsets.
828 			 * If the characters aren't all printable,
829 			 * reject it.
830 			 */
831 			for (i = 0; i < NOFFSETS; i++) {
832 				unsigned char *cname, *cp;
833 				size_t reloffset = prpsoffsets(i);
834 				size_t noffset = doff + reloffset;
835 				size_t k;
836 				for (j = 0; j < 16; j++, noffset++,
837 				    reloffset++) {
838 					/*
839 					 * Make sure we're not past
840 					 * the end of the buffer; if
841 					 * we are, just give up.
842 					 */
843 					if (noffset >= size)
844 						goto tryanother;
845 
846 					/*
847 					 * Make sure we're not past
848 					 * the end of the contents;
849 					 * if we are, this obviously
850 					 * isn't the right offset.
851 					 */
852 					if (reloffset >= descsz)
853 						goto tryanother;
854 
855 					c = nbuf[noffset];
856 					if (c == '\0') {
857 						/*
858 						 * A '\0' at the
859 						 * beginning is
860 						 * obviously wrong.
861 						 * Any other '\0'
862 						 * means we're done.
863 						 */
864 						if (j == 0)
865 							goto tryanother;
866 						else
867 							break;
868 					} else {
869 						/*
870 						 * A nonprintable
871 						 * character is also
872 						 * wrong.
873 						 */
874 						if (!isprint(c) || isquote(c))
875 							goto tryanother;
876 					}
877 				}
878 				/*
879 				 * Well, that worked.
880 				 */
881 
882 				/*
883 				 * Try next offsets, in case this match is
884 				 * in the middle of a string.
885 				 */
886 				for (k = i + 1 ; k < NOFFSETS; k++) {
887 					size_t no;
888 					int adjust = 1;
889 					if (prpsoffsets(k) >= prpsoffsets(i))
890 						continue;
891 					for (no = doff + prpsoffsets(k);
892 					     no < doff + prpsoffsets(i); no++)
893 						adjust = adjust
894 						         && isprint(nbuf[no]);
895 					if (adjust)
896 						i = k;
897 				}
898 
899 				cname = CAST(unsigned char *,
900 				    &nbuf[doff + prpsoffsets(i)]);
901 				for (cp = cname; cp < nbuf + size && *cp
902 				    && isprint(*cp); cp++)
903 					continue;
904 				/*
905 				 * Linux apparently appends a space at the end
906 				 * of the command line: remove it.
907 				 */
908 				while (cp > cname && isspace(cp[-1]))
909 					cp--;
910 				if (file_printf(ms, ", from '%.*s'",
911 				    CAST(int, cp - cname), cname) == -1)
912 					return -1;
913 				*flags |= FLAGS_DID_CORE;
914 				return 1;
915 
916 			tryanother:
917 				;
918 			}
919 		}
920 		break;
921 	}
922 #endif
923 	return 0;
924 }
925 
926 private off_t
927 get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd,
928     off_t off, int num, off_t fsize, uint64_t virtaddr)
929 {
930 	Elf32_Phdr ph32;
931 	Elf64_Phdr ph64;
932 
933 	/*
934 	 * Loop through all the program headers and find the header with
935 	 * virtual address in which the "virtaddr" belongs to.
936 	 */
937 	for ( ; num; num--) {
938 		if (pread(fd, xph_addr, xph_sizeof, off) <
939 		    CAST(ssize_t, xph_sizeof)) {
940 			file_badread(ms);
941 			return -1;
942 		}
943 		off += xph_sizeof;
944 
945 		if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
946 			/* Perhaps warn here */
947 			continue;
948 		}
949 
950 		if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz)
951 			return xph_offset + (virtaddr - xph_vaddr);
952 	}
953 	return 0;
954 }
955 
956 private size_t
957 get_string_on_virtaddr(struct magic_set *ms,
958     int swap, int clazz, int fd, off_t ph_off, int ph_num,
959     off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen)
960 {
961 	char *bptr;
962 	off_t offset;
963 
964 	if (buflen == 0)
965 		return 0;
966 
967 	offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num,
968 	    fsize, virtaddr);
969 	if (offset < 0 ||
970 	    (buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) {
971 		file_badread(ms);
972 		return 0;
973 	}
974 
975 	buf[buflen - 1] = '\0';
976 
977 	/* We expect only printable characters, so return if buffer contains
978 	 * non-printable character before the '\0' or just '\0'. */
979 	for (bptr = buf; *bptr && isprint(CAST(unsigned char, *bptr)); bptr++)
980 		continue;
981 	if (*bptr != '\0')
982 		return 0;
983 
984 	return bptr - buf;
985 }
986 
987 
988 /*ARGSUSED*/
989 private int
990 do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
991     int swap, uint32_t namesz __attribute__((__unused__)),
992     uint32_t descsz __attribute__((__unused__)),
993     size_t noff __attribute__((__unused__)), size_t doff,
994     int *flags, size_t size __attribute__((__unused__)), int clazz,
995     int fd, off_t ph_off, int ph_num, off_t fsize)
996 {
997 #ifdef ELFCORE
998 	Aux32Info auxv32;
999 	Aux64Info auxv64;
1000 	size_t elsize = xauxv_sizeof;
1001 	const char *tag;
1002 	int is_string;
1003 	size_t nval;
1004 
1005 	if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) !=
1006 	    (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE))
1007 		return 0;
1008 
1009 	switch (*flags & FLAGS_CORE_STYLE) {
1010 	case OS_STYLE_SVR4:
1011 		if (type != NT_AUXV)
1012 			return 0;
1013 		break;
1014 #ifdef notyet
1015 	case OS_STYLE_NETBSD:
1016 		if (type != NT_NETBSD_CORE_AUXV)
1017 			return 0;
1018 		break;
1019 	case OS_STYLE_FREEBSD:
1020 		if (type != NT_FREEBSD_PROCSTAT_AUXV)
1021 			return 0;
1022 		break;
1023 #endif
1024 	default:
1025 		return 0;
1026 	}
1027 
1028 	*flags |= FLAGS_DID_AUXV;
1029 
1030 	nval = 0;
1031 	for (size_t off = 0; off + elsize <= descsz; off += elsize) {
1032 		memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
1033 		/* Limit processing to 50 vector entries to prevent DoS */
1034 		if (nval++ >= 50) {
1035 			file_error(ms, 0, "Too many ELF Auxv elements");
1036 			return 1;
1037 		}
1038 
1039 		switch(xauxv_type) {
1040 		case AT_LINUX_EXECFN:
1041 			is_string = 1;
1042 			tag = "execfn";
1043 			break;
1044 		case AT_LINUX_PLATFORM:
1045 			is_string = 1;
1046 			tag = "platform";
1047 			break;
1048 		case AT_LINUX_UID:
1049 			is_string = 0;
1050 			tag = "real uid";
1051 			break;
1052 		case AT_LINUX_GID:
1053 			is_string = 0;
1054 			tag = "real gid";
1055 			break;
1056 		case AT_LINUX_EUID:
1057 			is_string = 0;
1058 			tag = "effective uid";
1059 			break;
1060 		case AT_LINUX_EGID:
1061 			is_string = 0;
1062 			tag = "effective gid";
1063 			break;
1064 		default:
1065 			is_string = 0;
1066 			tag = NULL;
1067 			break;
1068 		}
1069 
1070 		if (tag == NULL)
1071 			continue;
1072 
1073 		if (is_string) {
1074 			char buf[256];
1075 			ssize_t buflen;
1076 			buflen = get_string_on_virtaddr(ms, swap, clazz, fd,
1077 			    ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf));
1078 
1079 			if (buflen == 0)
1080 				continue;
1081 
1082 			if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
1083 				return -1;
1084 		} else {
1085 			if (file_printf(ms, ", %s: %d", tag,
1086 			    CAST(int, xauxv_val)) == -1)
1087 				return -1;
1088 		}
1089 	}
1090 	return 1;
1091 #else
1092 	return 0;
1093 #endif
1094 }
1095 
1096 private size_t
1097 dodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
1098     int clazz, int swap)
1099 {
1100 	Elf32_Dyn dh32;
1101 	Elf64_Dyn dh64;
1102 	unsigned char *dbuf = CAST(unsigned char *, vbuf);
1103 
1104 	if (xdh_sizeof + offset > size) {
1105 		/*
1106 		 * We're out of note headers.
1107 		 */
1108 		return xdh_sizeof + offset;
1109 	}
1110 
1111 	memcpy(xdh_addr, &dbuf[offset], xdh_sizeof);
1112 	offset += xdh_sizeof;
1113 
1114 	switch (xdh_tag) {
1115 	case DT_FLAGS_1:
1116 		if (xdh_val & DF_1_PIE)
1117 			ms->mode |= 0111;
1118 		else
1119 			ms->mode &= ~0111;
1120 		break;
1121 	default:
1122 		break;
1123 	}
1124 	return offset;
1125 }
1126 
1127 
1128 private size_t
1129 donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
1130     int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
1131     int fd, off_t ph_off, int ph_num, off_t fsize)
1132 {
1133 	Elf32_Nhdr nh32;
1134 	Elf64_Nhdr nh64;
1135 	size_t noff, doff;
1136 	uint32_t namesz, descsz;
1137 	unsigned char *nbuf = CAST(unsigned char *, vbuf);
1138 
1139 	if (*notecount == 0)
1140 		return 0;
1141 	--*notecount;
1142 
1143 	if (xnh_sizeof + offset > size) {
1144 		/*
1145 		 * We're out of note headers.
1146 		 */
1147 		return xnh_sizeof + offset;
1148 	}
1149 
1150 	memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
1151 	offset += xnh_sizeof;
1152 
1153 	namesz = xnh_namesz;
1154 	descsz = xnh_descsz;
1155 
1156 	if ((namesz == 0) && (descsz == 0)) {
1157 		/*
1158 		 * We're out of note headers.
1159 		 */
1160 		return (offset >= size) ? offset : size;
1161 	}
1162 
1163 	if (namesz & 0x80000000) {
1164 		if (file_printf(ms, ", bad note name size %#lx",
1165 		    CAST(unsigned long, namesz)) == -1)
1166 			return 0;
1167 	    return 0;
1168 	}
1169 
1170 	if (descsz & 0x80000000) {
1171 		if (file_printf(ms, ", bad note description size %#lx",
1172 		    CAST(unsigned long, descsz)) == -1)
1173 		    	return 0;
1174 	    return 0;
1175 	}
1176 
1177 	noff = offset;
1178 	doff = ELF_ALIGN(offset + namesz);
1179 
1180 	if (offset + namesz > size) {
1181 		/*
1182 		 * We're past the end of the buffer.
1183 		 */
1184 		return doff;
1185 	}
1186 
1187 	offset = ELF_ALIGN(doff + descsz);
1188 	if (doff + descsz > size) {
1189 		/*
1190 		 * We're past the end of the buffer.
1191 		 */
1192 		return (offset >= size) ? offset : size;
1193 	}
1194 
1195 
1196 	if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
1197 		if (do_os_note(ms, nbuf, xnh_type, swap,
1198 		    namesz, descsz, noff, doff, flags))
1199 			return offset;
1200 	}
1201 
1202 	if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
1203 		if (do_bid_note(ms, nbuf, xnh_type, swap,
1204 		    namesz, descsz, noff, doff, flags))
1205 			return offset;
1206 	}
1207 
1208 	if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
1209 		if (do_pax_note(ms, nbuf, xnh_type, swap,
1210 		    namesz, descsz, noff, doff, flags))
1211 			return offset;
1212 	}
1213 
1214 	if ((*flags & FLAGS_DID_CORE) == 0) {
1215 		if (do_core_note(ms, nbuf, xnh_type, swap,
1216 		    namesz, descsz, noff, doff, flags, size, clazz))
1217 			return offset;
1218 	}
1219 
1220 	if ((*flags & FLAGS_DID_AUXV) == 0) {
1221 		if (do_auxv_note(ms, nbuf, xnh_type, swap,
1222 			namesz, descsz, noff, doff, flags, size, clazz,
1223 			fd, ph_off, ph_num, fsize))
1224 			return offset;
1225 	}
1226 
1227 	if (namesz == 7 && strcmp(RCAST(char *, &nbuf[noff]), "NetBSD") == 0) {
1228 		int descw, flag;
1229 		const char *str, *tag;
1230 		if (descsz > 100)
1231 			descsz = 100;
1232 		switch (xnh_type) {
1233 	    	case NT_NETBSD_VERSION:
1234 			return offset;
1235 		case NT_NETBSD_MARCH:
1236 			flag = FLAGS_DID_NETBSD_MARCH;
1237 			tag = "compiled for";
1238 			break;
1239 		case NT_NETBSD_CMODEL:
1240 			flag = FLAGS_DID_NETBSD_CMODEL;
1241 			tag = "compiler model";
1242 			break;
1243 		case NT_NETBSD_EMULATION:
1244 			flag = FLAGS_DID_NETBSD_EMULATION;
1245 			tag = "emulation:";
1246 			break;
1247 		default:
1248 			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
1249 				return offset;
1250 			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
1251 			if (file_printf(ms, ", note=%u", xnh_type) == -1)
1252 				return offset;
1253 			return offset;
1254 		}
1255 
1256 		if (*flags & flag)
1257 			return offset;
1258 		str = RCAST(const char *, &nbuf[doff]);
1259 		descw = CAST(int, descsz);
1260 		*flags |= flag;
1261 		file_printf(ms, ", %s: %.*s", tag, descw, str);
1262 		return offset;
1263 	}
1264 
1265 	return offset;
1266 }
1267 
1268 /* SunOS 5.x hardware capability descriptions */
1269 typedef struct cap_desc {
1270 	uint64_t cd_mask;
1271 	const char *cd_name;
1272 } cap_desc_t;
1273 
1274 static const cap_desc_t cap_desc_sparc[] = {
1275 	{ AV_SPARC_MUL32,		"MUL32" },
1276 	{ AV_SPARC_DIV32,		"DIV32" },
1277 	{ AV_SPARC_FSMULD,		"FSMULD" },
1278 	{ AV_SPARC_V8PLUS,		"V8PLUS" },
1279 	{ AV_SPARC_POPC,		"POPC" },
1280 	{ AV_SPARC_VIS,			"VIS" },
1281 	{ AV_SPARC_VIS2,		"VIS2" },
1282 	{ AV_SPARC_ASI_BLK_INIT,	"ASI_BLK_INIT" },
1283 	{ AV_SPARC_FMAF,		"FMAF" },
1284 	{ AV_SPARC_FJFMAU,		"FJFMAU" },
1285 	{ AV_SPARC_IMA,			"IMA" },
1286 	{ 0, NULL }
1287 };
1288 
1289 static const cap_desc_t cap_desc_386[] = {
1290 	{ AV_386_FPU,			"FPU" },
1291 	{ AV_386_TSC,			"TSC" },
1292 	{ AV_386_CX8,			"CX8" },
1293 	{ AV_386_SEP,			"SEP" },
1294 	{ AV_386_AMD_SYSC,		"AMD_SYSC" },
1295 	{ AV_386_CMOV,			"CMOV" },
1296 	{ AV_386_MMX,			"MMX" },
1297 	{ AV_386_AMD_MMX,		"AMD_MMX" },
1298 	{ AV_386_AMD_3DNow,		"AMD_3DNow" },
1299 	{ AV_386_AMD_3DNowx,		"AMD_3DNowx" },
1300 	{ AV_386_FXSR,			"FXSR" },
1301 	{ AV_386_SSE,			"SSE" },
1302 	{ AV_386_SSE2,			"SSE2" },
1303 	{ AV_386_PAUSE,			"PAUSE" },
1304 	{ AV_386_SSE3,			"SSE3" },
1305 	{ AV_386_MON,			"MON" },
1306 	{ AV_386_CX16,			"CX16" },
1307 	{ AV_386_AHF,			"AHF" },
1308 	{ AV_386_TSCP,			"TSCP" },
1309 	{ AV_386_AMD_SSE4A,		"AMD_SSE4A" },
1310 	{ AV_386_POPCNT,		"POPCNT" },
1311 	{ AV_386_AMD_LZCNT,		"AMD_LZCNT" },
1312 	{ AV_386_SSSE3,			"SSSE3" },
1313 	{ AV_386_SSE4_1,		"SSE4.1" },
1314 	{ AV_386_SSE4_2,		"SSE4.2" },
1315 	{ 0, NULL }
1316 };
1317 
1318 private int
1319 doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
1320     size_t size, off_t fsize, int mach, int strtab, int *flags,
1321     uint16_t *notecount)
1322 {
1323 	Elf32_Shdr sh32;
1324 	Elf64_Shdr sh64;
1325 	int stripped = 1, has_debug_info = 0;
1326 	size_t nbadcap = 0;
1327 	void *nbuf;
1328 	off_t noff, coff, name_off;
1329 	uint64_t cap_hw1 = 0;	/* SunOS 5.x hardware capabilities */
1330 	uint64_t cap_sf1 = 0;	/* SunOS 5.x software capabilities */
1331 	char name[50];
1332 	ssize_t namesize;
1333 
1334 	if (num == 0) {
1335 		if (file_printf(ms, ", no section header") == -1)
1336 			return -1;
1337 		return 0;
1338 	}
1339 	if (size != xsh_sizeof) {
1340 		if (file_printf(ms, ", corrupted section header size") == -1)
1341 			return -1;
1342 		return 0;
1343 	}
1344 
1345 	/* Read offset of name section to be able to read section names later */
1346 	if (pread(fd, xsh_addr, xsh_sizeof, CAST(off_t, (off + size * strtab)))
1347 	    < CAST(ssize_t, xsh_sizeof)) {
1348 		if (file_printf(ms, ", missing section headers") == -1)
1349 			return -1;
1350 		return 0;
1351 	}
1352 	name_off = xsh_offset;
1353 
1354 	for ( ; num; num--) {
1355 		/* Read the name of this section. */
1356 		if ((namesize = pread(fd, name, sizeof(name) - 1,
1357 		    name_off + xsh_name)) == -1) {
1358 			file_badread(ms);
1359 			return -1;
1360 		}
1361 		name[namesize] = '\0';
1362 		if (strcmp(name, ".debug_info") == 0) {
1363 			has_debug_info = 1;
1364 			stripped = 0;
1365 		}
1366 
1367 		if (pread(fd, xsh_addr, xsh_sizeof, off) <
1368 		    CAST(ssize_t, xsh_sizeof)) {
1369 			file_badread(ms);
1370 			return -1;
1371 		}
1372 		off += size;
1373 
1374 		/* Things we can determine before we seek */
1375 		switch (xsh_type) {
1376 		case SHT_SYMTAB:
1377 #if 0
1378 		case SHT_DYNSYM:
1379 #endif
1380 			stripped = 0;
1381 			break;
1382 		default:
1383 			if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
1384 				/* Perhaps warn here */
1385 				continue;
1386 			}
1387 			break;
1388 		}
1389 
1390 
1391 		/* Things we can determine when we seek */
1392 		switch (xsh_type) {
1393 		case SHT_NOTE:
1394 			if (CAST(uintmax_t, (xsh_size + xsh_offset)) >
1395 			    CAST(uintmax_t, fsize)) {
1396 				if (file_printf(ms,
1397 				    ", note offset/size %#" INTMAX_T_FORMAT
1398 				    "x+%#" INTMAX_T_FORMAT "x exceeds"
1399 				    " file size %#" INTMAX_T_FORMAT "x",
1400 				    CAST(uintmax_t, xsh_offset),
1401 				    CAST(uintmax_t, xsh_size),
1402 				    CAST(uintmax_t, fsize)) == -1)
1403 					return -1;
1404 				return 0;
1405 			}
1406 			if ((nbuf = malloc(xsh_size)) == NULL) {
1407 				file_error(ms, errno, "Cannot allocate memory"
1408 				    " for note");
1409 				return -1;
1410 			}
1411 			if (pread(fd, nbuf, xsh_size, xsh_offset) <
1412 			    CAST(ssize_t, xsh_size)) {
1413 				file_badread(ms);
1414 				free(nbuf);
1415 				return -1;
1416 			}
1417 
1418 			noff = 0;
1419 			for (;;) {
1420 				if (noff >= CAST(off_t, xsh_size))
1421 					break;
1422 				noff = donote(ms, nbuf, CAST(size_t, noff),
1423 				    xsh_size, clazz, swap, 4, flags, notecount,
1424 				    fd, 0, 0, 0);
1425 				if (noff == 0)
1426 					break;
1427 			}
1428 			free(nbuf);
1429 			break;
1430 		case SHT_SUNW_cap:
1431 			switch (mach) {
1432 			case EM_SPARC:
1433 			case EM_SPARCV9:
1434 			case EM_IA_64:
1435 			case EM_386:
1436 			case EM_AMD64:
1437 				break;
1438 			default:
1439 				goto skip;
1440 			}
1441 
1442 			if (nbadcap > 5)
1443 				break;
1444 			if (lseek(fd, xsh_offset, SEEK_SET)
1445 			    == CAST(off_t, -1)) {
1446 				file_badseek(ms);
1447 				return -1;
1448 			}
1449 			coff = 0;
1450 			for (;;) {
1451 				Elf32_Cap cap32;
1452 				Elf64_Cap cap64;
1453 				char cbuf[/*CONSTCOND*/
1454 				    MAX(sizeof(cap32), sizeof(cap64))];
1455 				if ((coff += xcap_sizeof) >
1456 				    CAST(off_t, xsh_size))
1457 					break;
1458 				if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) !=
1459 				    CAST(ssize_t, xcap_sizeof)) {
1460 					file_badread(ms);
1461 					return -1;
1462 				}
1463 				if (cbuf[0] == 'A') {
1464 #ifdef notyet
1465 					char *p = cbuf + 1;
1466 					uint32_t len, tag;
1467 					memcpy(&len, p, sizeof(len));
1468 					p += 4;
1469 					len = getu32(swap, len);
1470 					if (memcmp("gnu", p, 3) != 0) {
1471 					    if (file_printf(ms,
1472 						", unknown capability %.3s", p)
1473 						== -1)
1474 						return -1;
1475 					    break;
1476 					}
1477 					p += strlen(p) + 1;
1478 					tag = *p++;
1479 					memcpy(&len, p, sizeof(len));
1480 					p += 4;
1481 					len = getu32(swap, len);
1482 					if (tag != 1) {
1483 					    if (file_printf(ms, ", unknown gnu"
1484 						" capability tag %d", tag)
1485 						== -1)
1486 						return -1;
1487 					    break;
1488 					}
1489 					// gnu attributes
1490 #endif
1491 					break;
1492 				}
1493 				memcpy(xcap_addr, cbuf, xcap_sizeof);
1494 				switch (xcap_tag) {
1495 				case CA_SUNW_NULL:
1496 					break;
1497 				case CA_SUNW_HW_1:
1498 					cap_hw1 |= xcap_val;
1499 					break;
1500 				case CA_SUNW_SF_1:
1501 					cap_sf1 |= xcap_val;
1502 					break;
1503 				default:
1504 					if (file_printf(ms,
1505 					    ", with unknown capability "
1506 					    "%#" INT64_T_FORMAT "x = %#"
1507 					    INT64_T_FORMAT "x",
1508 					    CAST(unsigned long long, xcap_tag),
1509 					    CAST(unsigned long long, xcap_val))
1510 					    == -1)
1511 						return -1;
1512 					if (nbadcap++ > 2)
1513 						coff = xsh_size;
1514 					break;
1515 				}
1516 			}
1517 			/*FALLTHROUGH*/
1518 		skip:
1519 		default:
1520 			break;
1521 		}
1522 	}
1523 
1524 	if (has_debug_info) {
1525 		if (file_printf(ms, ", with debug_info") == -1)
1526 			return -1;
1527 	}
1528 	if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
1529 		return -1;
1530 	if (cap_hw1) {
1531 		const cap_desc_t *cdp;
1532 		switch (mach) {
1533 		case EM_SPARC:
1534 		case EM_SPARC32PLUS:
1535 		case EM_SPARCV9:
1536 			cdp = cap_desc_sparc;
1537 			break;
1538 		case EM_386:
1539 		case EM_IA_64:
1540 		case EM_AMD64:
1541 			cdp = cap_desc_386;
1542 			break;
1543 		default:
1544 			cdp = NULL;
1545 			break;
1546 		}
1547 		if (file_printf(ms, ", uses") == -1)
1548 			return -1;
1549 		if (cdp) {
1550 			while (cdp->cd_name) {
1551 				if (cap_hw1 & cdp->cd_mask) {
1552 					if (file_printf(ms,
1553 					    " %s", cdp->cd_name) == -1)
1554 						return -1;
1555 					cap_hw1 &= ~cdp->cd_mask;
1556 				}
1557 				++cdp;
1558 			}
1559 			if (cap_hw1)
1560 				if (file_printf(ms,
1561 				    " unknown hardware capability %#"
1562 				    INT64_T_FORMAT "x",
1563 				    CAST(unsigned long long, cap_hw1)) == -1)
1564 					return -1;
1565 		} else {
1566 			if (file_printf(ms,
1567 			    " hardware capability %#" INT64_T_FORMAT "x",
1568 			    CAST(unsigned long long, cap_hw1)) == -1)
1569 				return -1;
1570 		}
1571 	}
1572 	if (cap_sf1) {
1573 		if (cap_sf1 & SF1_SUNW_FPUSED) {
1574 			if (file_printf(ms,
1575 			    (cap_sf1 & SF1_SUNW_FPKNWN)
1576 			    ? ", uses frame pointer"
1577 			    : ", not known to use frame pointer") == -1)
1578 				return -1;
1579 		}
1580 		cap_sf1 &= ~SF1_SUNW_MASK;
1581 		if (cap_sf1)
1582 			if (file_printf(ms,
1583 			    ", with unknown software capability %#"
1584 			    INT64_T_FORMAT "x",
1585 			    CAST(unsigned long long, cap_sf1)) == -1)
1586 				return -1;
1587 	}
1588 	return 0;
1589 }
1590 
1591 /*
1592  * Look through the program headers of an executable image, searching
1593  * for a PT_INTERP section; if one is found, it's dynamically linked,
1594  * otherwise it's statically linked.
1595  */
1596 private int
1597 dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
1598     int num, size_t size, off_t fsize, int sh_num, int *flags,
1599     uint16_t *notecount)
1600 {
1601 	Elf32_Phdr ph32;
1602 	Elf64_Phdr ph64;
1603 	const char *linking_style = "statically";
1604 	unsigned char nbuf[BUFSIZ];
1605 	char ibuf[BUFSIZ];
1606 	char interp[BUFSIZ];
1607 	ssize_t bufsize;
1608 	size_t offset, align, len;
1609 
1610 	if (num == 0) {
1611 		if (file_printf(ms, ", no program header") == -1)
1612 			return -1;
1613 		return 0;
1614 	}
1615 	if (size != xph_sizeof) {
1616 		if (file_printf(ms, ", corrupted program header size") == -1)
1617 			return -1;
1618 		return 0;
1619 	}
1620 
1621 	interp[0] = '\0';
1622   	for ( ; num; num--) {
1623 		int doread;
1624 		if (pread(fd, xph_addr, xph_sizeof, off) <
1625 		    CAST(ssize_t, xph_sizeof)) {
1626 			file_badread(ms);
1627 			return -1;
1628 		}
1629 
1630 		off += size;
1631 		bufsize = 0;
1632 		align = 4;
1633 
1634 		/* Things we can determine before we seek */
1635 		switch (xph_type) {
1636 		case PT_DYNAMIC:
1637 			linking_style = "dynamically";
1638 			doread = 1;
1639 			break;
1640 		case PT_NOTE:
1641 			if (sh_num)	/* Did this through section headers */
1642 				continue;
1643 			if (((align = xph_align) & 0x80000000UL) != 0 ||
1644 			    align < 4) {
1645 				if (file_printf(ms,
1646 				    ", invalid note alignment %#lx",
1647 				    CAST(unsigned long, align)) == -1)
1648 					return -1;
1649 				align = 4;
1650 			}
1651 			/*FALLTHROUGH*/
1652 		case PT_INTERP:
1653 			doread = 1;
1654 			break;
1655 		default:
1656 			doread = 0;
1657 			if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
1658 				/* Maybe warn here? */
1659 				continue;
1660 			}
1661 			break;
1662 		}
1663 
1664 		if (doread) {
1665 			len = xph_filesz < sizeof(nbuf) ? xph_filesz
1666 			    : sizeof(nbuf);
1667 			bufsize = pread(fd, nbuf, len, xph_offset);
1668 			if (bufsize == -1) {
1669 				file_badread(ms);
1670 				return -1;
1671 			}
1672 		} else
1673 			len = 0;
1674 
1675 		/* Things we can determine when we seek */
1676 		switch (xph_type) {
1677 		case PT_DYNAMIC:
1678 			offset = 0;
1679 			// Let DF_1 determine if we are PIE or not.
1680 			ms->mode &= ~0111;
1681 			for (;;) {
1682 				if (offset >= CAST(size_t, bufsize))
1683 					break;
1684 				offset = dodynamic(ms, nbuf, offset,
1685 				    CAST(size_t, bufsize), clazz, swap);
1686 				if (offset == 0)
1687 					break;
1688 			}
1689 			break;
1690 
1691 		case PT_INTERP:
1692 			if (bufsize && nbuf[0]) {
1693 				nbuf[bufsize - 1] = '\0';
1694 				memcpy(interp, nbuf, CAST(size_t, bufsize));
1695 			} else
1696 				strlcpy(interp, "*empty*", sizeof(interp));
1697 			break;
1698 		case PT_NOTE:
1699 			/*
1700 			 * This is a PT_NOTE section; loop through all the notes
1701 			 * in the section.
1702 			 */
1703 			offset = 0;
1704 			for (;;) {
1705 				if (offset >= CAST(size_t, bufsize))
1706 					break;
1707 				offset = donote(ms, nbuf, offset,
1708 				    CAST(size_t, bufsize), clazz, swap, align,
1709 				    flags, notecount, fd, 0, 0, 0);
1710 				if (offset == 0)
1711 					break;
1712 			}
1713 			break;
1714 		default:
1715 			break;
1716 		}
1717 	}
1718 	if (file_printf(ms, ", %s linked", linking_style)
1719 	    == -1)
1720 		return -1;
1721 	if (interp[0])
1722 		if (file_printf(ms, ", interpreter %s",
1723 		    file_printable(ibuf, sizeof(ibuf), interp, sizeof(interp)))
1724 			== -1)
1725 			return -1;
1726 	return 0;
1727 }
1728 
1729 
1730 protected int
1731 file_tryelf(struct magic_set *ms, const struct buffer *b)
1732 {
1733 	int fd = b->fd;
1734 	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
1735 	size_t nbytes = b->flen;
1736 	union {
1737 		int32_t l;
1738 		char c[sizeof(int32_t)];
1739 	} u;
1740 	int clazz;
1741 	int swap;
1742 	struct stat st;
1743 	const struct stat *stp;
1744 	off_t fsize;
1745 	int flags = 0;
1746 	Elf32_Ehdr elf32hdr;
1747 	Elf64_Ehdr elf64hdr;
1748 	uint16_t type, phnum, shnum, notecount;
1749 
1750 	if (ms->flags & (MAGIC_MIME|MAGIC_APPLE|MAGIC_EXTENSION))
1751 		return 0;
1752 	/*
1753 	 * ELF executables have multiple section headers in arbitrary
1754 	 * file locations and thus file(1) cannot determine it from easily.
1755 	 * Instead we traverse thru all section headers until a symbol table
1756 	 * one is found or else the binary is stripped.
1757 	 * Return immediately if it's not ELF (so we avoid pipe2file unless
1758 	 * needed).
1759 	 */
1760 	if (buf[EI_MAG0] != ELFMAG0
1761 	    || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
1762 	    || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
1763 		return 0;
1764 
1765 	/*
1766 	 * If we cannot seek, it must be a pipe, socket or fifo.
1767 	 */
1768 	if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1))
1769 	    && (errno == ESPIPE))
1770 		fd = file_pipe2file(ms, fd, buf, nbytes);
1771 
1772 	if (fd == -1) {
1773 		file_badread(ms);
1774 		return -1;
1775 	}
1776 
1777 	stp = &b->st;
1778 	/*
1779 	 * b->st.st_size != 0 if previous fstat() succeeded,
1780 	 * which is likely, we can avoid extra stat() call.
1781 	 */
1782 	if (b->st.st_size == 0) {
1783 		stp = &st;
1784 		if (fstat(fd, &st) == -1) {
1785 			file_badread(ms);
1786 			return -1;
1787 		}
1788 	}
1789 	if (S_ISREG(stp->st_mode) || stp->st_size != 0)
1790 		fsize = stp->st_size;
1791 	else
1792 		fsize = SIZE_UNKNOWN;
1793 
1794 	clazz = buf[EI_CLASS];
1795 
1796 	switch (clazz) {
1797 	case ELFCLASS32:
1798 #undef elf_getu
1799 #define elf_getu(a, b)	elf_getu32(a, b)
1800 #undef elfhdr
1801 #define elfhdr elf32hdr
1802 #include "elfclass.h"
1803 	case ELFCLASS64:
1804 #undef elf_getu
1805 #define elf_getu(a, b)	elf_getu64(a, b)
1806 #undef elfhdr
1807 #define elfhdr elf64hdr
1808 #include "elfclass.h"
1809 	default:
1810 	    if (file_printf(ms, ", unknown class %d", clazz) == -1)
1811 		    return -1;
1812 	    break;
1813 	}
1814 	return 0;
1815 }
1816 #endif
1817