xref: /dflybsd-src/contrib/file/src/readelf.c (revision 739f0ef867128a933e021db3d831e906fcafd825)
1327e51cbSPeter Avalos /*
2327e51cbSPeter Avalos  * Copyright (c) Christos Zoulas 2003.
3327e51cbSPeter Avalos  * All Rights Reserved.
4327e51cbSPeter Avalos  *
5327e51cbSPeter Avalos  * Redistribution and use in source and binary forms, with or without
6327e51cbSPeter Avalos  * modification, are permitted provided that the following conditions
7327e51cbSPeter Avalos  * are met:
8327e51cbSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
9327e51cbSPeter Avalos  *    notice immediately at the beginning of the file, without modification,
10327e51cbSPeter Avalos  *    this list of conditions, and the following disclaimer.
11327e51cbSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
12327e51cbSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
13327e51cbSPeter Avalos  *    documentation and/or other materials provided with the distribution.
14327e51cbSPeter Avalos  *
15327e51cbSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16327e51cbSPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17327e51cbSPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18327e51cbSPeter Avalos  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19327e51cbSPeter Avalos  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20327e51cbSPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21327e51cbSPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22327e51cbSPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23327e51cbSPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24327e51cbSPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25327e51cbSPeter Avalos  * SUCH DAMAGE.
26327e51cbSPeter Avalos  */
27327e51cbSPeter Avalos #include "file.h"
28327e51cbSPeter Avalos 
2979343712SPeter Avalos #ifndef lint
30*3b9cdfa3SAntonio Huete Jimenez FILE_RCSID("@(#)$File: readelf.c,v 1.182 2022/07/31 16:01:01 christos Exp $")
3179343712SPeter Avalos #endif
3279343712SPeter Avalos 
33327e51cbSPeter Avalos #ifdef BUILTIN_ELF
34327e51cbSPeter Avalos #include <string.h>
35327e51cbSPeter Avalos #include <ctype.h>
36327e51cbSPeter Avalos #include <stdlib.h>
37327e51cbSPeter Avalos #ifdef HAVE_UNISTD_H
38327e51cbSPeter Avalos #include <unistd.h>
39327e51cbSPeter Avalos #endif
40327e51cbSPeter Avalos 
41327e51cbSPeter Avalos #include "readelf.h"
4279343712SPeter Avalos #include "magic.h"
43327e51cbSPeter Avalos 
44327e51cbSPeter Avalos #ifdef	ELFCORE
45327e51cbSPeter Avalos private int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t,
4682c5fa3eSPeter Avalos     off_t, int *, uint16_t *);
47327e51cbSPeter Avalos #endif
48327e51cbSPeter Avalos private int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t,
4982c5fa3eSPeter Avalos     off_t, int, int *, uint16_t *);
50a96e001bSPeter Avalos private int doshn(struct magic_set *, int, int, int, off_t, int, size_t,
5182c5fa3eSPeter Avalos     off_t, int, int, int *, uint16_t *);
5279343712SPeter Avalos private size_t donote(struct magic_set *, void *, size_t, size_t, int,
53c30bd091SSascha Wildner     int, size_t, int *, uint16_t *, int, off_t, int, off_t);
54327e51cbSPeter Avalos 
55327e51cbSPeter Avalos #define	ELF_ALIGN(a)	((((a) + align - 1) / align) * align)
56327e51cbSPeter Avalos 
57327e51cbSPeter Avalos #define isquote(c) (strchr("'\"`", (c)) != NULL)
58327e51cbSPeter Avalos 
59327e51cbSPeter Avalos private uint16_t getu16(int, uint16_t);
60327e51cbSPeter Avalos private uint32_t getu32(int, uint32_t);
61327e51cbSPeter Avalos private uint64_t getu64(int, uint64_t);
62327e51cbSPeter Avalos 
6382c5fa3eSPeter Avalos #define MAX_PHNUM	128
6482c5fa3eSPeter Avalos #define	MAX_SHNUM	32768
65*3b9cdfa3SAntonio Huete Jimenez #define MAX_SHSIZE	(64 * 1024 * 1024)
666fca56fbSSascha Wildner #define SIZE_UNKNOWN	CAST(off_t, -1)
6782c5fa3eSPeter Avalos 
6882c5fa3eSPeter Avalos private int
toomany(struct magic_set * ms,const char * name,uint16_t num)6982c5fa3eSPeter Avalos toomany(struct magic_set *ms, const char *name, uint16_t num)
7082c5fa3eSPeter Avalos {
71c990e5baSDaniel Fojt 	if (ms->flags & MAGIC_MIME)
72c990e5baSDaniel Fojt 		return 1;
736fca56fbSSascha Wildner 	if (file_printf(ms, ", too many %s (%u)", name, num) == -1)
7482c5fa3eSPeter Avalos 		return -1;
756fca56fbSSascha Wildner 	return 1;
7682c5fa3eSPeter Avalos }
7782c5fa3eSPeter Avalos 
78327e51cbSPeter Avalos private uint16_t
getu16(int swap,uint16_t value)79327e51cbSPeter Avalos getu16(int swap, uint16_t value)
80327e51cbSPeter Avalos {
81327e51cbSPeter Avalos 	union {
82327e51cbSPeter Avalos 		uint16_t ui;
83327e51cbSPeter Avalos 		char c[2];
84327e51cbSPeter Avalos 	} retval, tmpval;
85327e51cbSPeter Avalos 
86327e51cbSPeter Avalos 	if (swap) {
87327e51cbSPeter Avalos 		tmpval.ui = value;
88327e51cbSPeter Avalos 
89327e51cbSPeter Avalos 		retval.c[0] = tmpval.c[1];
90327e51cbSPeter Avalos 		retval.c[1] = tmpval.c[0];
91327e51cbSPeter Avalos 
92327e51cbSPeter Avalos 		return retval.ui;
93327e51cbSPeter Avalos 	} else
94327e51cbSPeter Avalos 		return value;
95327e51cbSPeter Avalos }
96327e51cbSPeter Avalos 
97327e51cbSPeter Avalos private uint32_t
getu32(int swap,uint32_t value)98327e51cbSPeter Avalos getu32(int swap, uint32_t value)
99327e51cbSPeter Avalos {
100327e51cbSPeter Avalos 	union {
101327e51cbSPeter Avalos 		uint32_t ui;
102327e51cbSPeter Avalos 		char c[4];
103327e51cbSPeter Avalos 	} retval, tmpval;
104327e51cbSPeter Avalos 
105327e51cbSPeter Avalos 	if (swap) {
106327e51cbSPeter Avalos 		tmpval.ui = value;
107327e51cbSPeter Avalos 
108327e51cbSPeter Avalos 		retval.c[0] = tmpval.c[3];
109327e51cbSPeter Avalos 		retval.c[1] = tmpval.c[2];
110327e51cbSPeter Avalos 		retval.c[2] = tmpval.c[1];
111327e51cbSPeter Avalos 		retval.c[3] = tmpval.c[0];
112327e51cbSPeter Avalos 
113327e51cbSPeter Avalos 		return retval.ui;
114327e51cbSPeter Avalos 	} else
115327e51cbSPeter Avalos 		return value;
116327e51cbSPeter Avalos }
117327e51cbSPeter Avalos 
118327e51cbSPeter Avalos private uint64_t
getu64(int swap,uint64_t value)119327e51cbSPeter Avalos getu64(int swap, uint64_t value)
120327e51cbSPeter Avalos {
121327e51cbSPeter Avalos 	union {
122327e51cbSPeter Avalos 		uint64_t ui;
123327e51cbSPeter Avalos 		char c[8];
124327e51cbSPeter Avalos 	} retval, tmpval;
125327e51cbSPeter Avalos 
126327e51cbSPeter Avalos 	if (swap) {
127327e51cbSPeter Avalos 		tmpval.ui = value;
128327e51cbSPeter Avalos 
129327e51cbSPeter Avalos 		retval.c[0] = tmpval.c[7];
130327e51cbSPeter Avalos 		retval.c[1] = tmpval.c[6];
131327e51cbSPeter Avalos 		retval.c[2] = tmpval.c[5];
132327e51cbSPeter Avalos 		retval.c[3] = tmpval.c[4];
133327e51cbSPeter Avalos 		retval.c[4] = tmpval.c[3];
134327e51cbSPeter Avalos 		retval.c[5] = tmpval.c[2];
135327e51cbSPeter Avalos 		retval.c[6] = tmpval.c[1];
136327e51cbSPeter Avalos 		retval.c[7] = tmpval.c[0];
137327e51cbSPeter Avalos 
138327e51cbSPeter Avalos 		return retval.ui;
139327e51cbSPeter Avalos 	} else
140327e51cbSPeter Avalos 		return value;
141327e51cbSPeter Avalos }
142327e51cbSPeter Avalos 
14379343712SPeter Avalos #define elf_getu16(swap, value) getu16(swap, value)
14479343712SPeter Avalos #define elf_getu32(swap, value) getu32(swap, value)
145327e51cbSPeter Avalos #define elf_getu64(swap, value) getu64(swap, value)
146327e51cbSPeter Avalos 
14779343712SPeter Avalos #define xsh_addr	(clazz == ELFCLASS32			\
1486fca56fbSSascha Wildner 			 ? CAST(void *, &sh32)			\
1496fca56fbSSascha Wildner 			 : CAST(void *, &sh64))
15079343712SPeter Avalos #define xsh_sizeof	(clazz == ELFCLASS32			\
151e8af9738SPeter Avalos 			 ? sizeof(sh32)				\
152e8af9738SPeter Avalos 			 : sizeof(sh64))
1536fca56fbSSascha Wildner #define xsh_size	CAST(size_t, (clazz == ELFCLASS32	\
15479343712SPeter Avalos 			 ? elf_getu32(swap, sh32.sh_size)	\
1556fca56fbSSascha Wildner 			 : elf_getu64(swap, sh64.sh_size)))
1566fca56fbSSascha Wildner #define xsh_offset	CAST(off_t, (clazz == ELFCLASS32	\
15779343712SPeter Avalos 			 ? elf_getu32(swap, sh32.sh_offset)	\
1586fca56fbSSascha Wildner 			 : elf_getu64(swap, sh64.sh_offset)))
15979343712SPeter Avalos #define xsh_type	(clazz == ELFCLASS32			\
16079343712SPeter Avalos 			 ? elf_getu32(swap, sh32.sh_type)	\
16179343712SPeter Avalos 			 : elf_getu32(swap, sh64.sh_type))
162e8af9738SPeter Avalos #define xsh_name    	(clazz == ELFCLASS32			\
163e8af9738SPeter Avalos 			 ? elf_getu32(swap, sh32.sh_name)	\
164e8af9738SPeter Avalos 			 : elf_getu32(swap, sh64.sh_name))
1656fca56fbSSascha Wildner 
16679343712SPeter Avalos #define xph_addr	(clazz == ELFCLASS32			\
1676fca56fbSSascha Wildner 			 ? CAST(void *, &ph32)			\
1686fca56fbSSascha Wildner 			 : CAST(void *, &ph64))
16979343712SPeter Avalos #define xph_sizeof	(clazz == ELFCLASS32			\
170e8af9738SPeter Avalos 			 ? sizeof(ph32)				\
171e8af9738SPeter Avalos 			 : sizeof(ph64))
17279343712SPeter Avalos #define xph_type	(clazz == ELFCLASS32			\
17379343712SPeter Avalos 			 ? elf_getu32(swap, ph32.p_type)	\
17479343712SPeter Avalos 			 : elf_getu32(swap, ph64.p_type))
1756fca56fbSSascha Wildner #define xph_offset	CAST(off_t, (clazz == ELFCLASS32	\
17679343712SPeter Avalos 			 ? elf_getu32(swap, ph32.p_offset)	\
1776fca56fbSSascha Wildner 			 : elf_getu64(swap, ph64.p_offset)))
1786fca56fbSSascha Wildner #define xph_align	CAST(size_t, (clazz == ELFCLASS32	\
1796fca56fbSSascha Wildner 			 ? CAST(off_t, (ph32.p_align ? 		\
1806fca56fbSSascha Wildner 			    elf_getu32(swap, ph32.p_align) : 4))\
1816fca56fbSSascha Wildner 			 : CAST(off_t, (ph64.p_align ?		\
1826fca56fbSSascha Wildner 			    elf_getu64(swap, ph64.p_align) : 4))))
1836fca56fbSSascha Wildner #define xph_vaddr	CAST(size_t, (clazz == ELFCLASS32	\
1846fca56fbSSascha Wildner 			 ? CAST(off_t, (ph32.p_vaddr ? 		\
1856fca56fbSSascha Wildner 			    elf_getu32(swap, ph32.p_vaddr) : 4))\
1866fca56fbSSascha Wildner 			 : CAST(off_t, (ph64.p_vaddr ?		\
1876fca56fbSSascha Wildner 			    elf_getu64(swap, ph64.p_vaddr) : 4))))
1886fca56fbSSascha Wildner #define xph_filesz	CAST(size_t, (clazz == ELFCLASS32	\
18979343712SPeter Avalos 			 ? elf_getu32(swap, ph32.p_filesz)	\
19079343712SPeter Avalos 			 : elf_getu64(swap, ph64.p_filesz)))
1916fca56fbSSascha Wildner #define xph_memsz	CAST(size_t, ((clazz == ELFCLASS32	\
19279343712SPeter Avalos 			 ? elf_getu32(swap, ph32.p_memsz)	\
1936fca56fbSSascha Wildner 			 : elf_getu64(swap, ph64.p_memsz))))
1946fca56fbSSascha Wildner #define xnh_addr	(clazz == ELFCLASS32			\
1956fca56fbSSascha Wildner 			 ? CAST(void *, &nh32)			\
1966fca56fbSSascha Wildner 			 : CAST(void *, &nh64))
19779343712SPeter Avalos #define xnh_sizeof	(clazz == ELFCLASS32			\
198c30bd091SSascha Wildner 			 ? sizeof(nh32)				\
199c30bd091SSascha Wildner 			 : sizeof(nh64))
20079343712SPeter Avalos #define xnh_type	(clazz == ELFCLASS32			\
20179343712SPeter Avalos 			 ? elf_getu32(swap, nh32.n_type)	\
20279343712SPeter Avalos 			 : elf_getu32(swap, nh64.n_type))
20379343712SPeter Avalos #define xnh_namesz	(clazz == ELFCLASS32			\
20479343712SPeter Avalos 			 ? elf_getu32(swap, nh32.n_namesz)	\
20579343712SPeter Avalos 			 : elf_getu32(swap, nh64.n_namesz))
20679343712SPeter Avalos #define xnh_descsz	(clazz == ELFCLASS32			\
20779343712SPeter Avalos 			 ? elf_getu32(swap, nh32.n_descsz)	\
20879343712SPeter Avalos 			 : elf_getu32(swap, nh64.n_descsz))
2096fca56fbSSascha Wildner 
2106fca56fbSSascha Wildner #define xdh_addr	(clazz == ELFCLASS32			\
2116fca56fbSSascha Wildner 			 ? CAST(void *, &dh32)			\
2126fca56fbSSascha Wildner 			 : CAST(void *, &dh64))
2136fca56fbSSascha Wildner #define xdh_sizeof	(clazz == ELFCLASS32			\
2146fca56fbSSascha Wildner 			 ? sizeof(dh32)				\
2156fca56fbSSascha Wildner 			 : sizeof(dh64))
2166fca56fbSSascha Wildner #define xdh_tag		(clazz == ELFCLASS32			\
2176fca56fbSSascha Wildner 			 ? elf_getu32(swap, dh32.d_tag)		\
2186fca56fbSSascha Wildner 			 : elf_getu64(swap, dh64.d_tag))
2196fca56fbSSascha Wildner #define xdh_val		(clazz == ELFCLASS32			\
2206fca56fbSSascha Wildner 			 ? elf_getu32(swap, dh32.d_un.d_val)	\
2216fca56fbSSascha Wildner 			 : elf_getu64(swap, dh64.d_un.d_val))
2226fca56fbSSascha Wildner 
22379343712SPeter Avalos #define xcap_addr	(clazz == ELFCLASS32			\
2246fca56fbSSascha Wildner 			 ? CAST(void *, &cap32)			\
2256fca56fbSSascha Wildner 			 : CAST(void *, &cap64))
22679343712SPeter Avalos #define xcap_sizeof	(clazz == ELFCLASS32			\
2276fca56fbSSascha Wildner 			 ? sizeof(cap32)			\
2286fca56fbSSascha Wildner 			 : sizeof(cap64))
22979343712SPeter Avalos #define xcap_tag	(clazz == ELFCLASS32			\
23079343712SPeter Avalos 			 ? elf_getu32(swap, cap32.c_tag)	\
23179343712SPeter Avalos 			 : elf_getu64(swap, cap64.c_tag))
23279343712SPeter Avalos #define xcap_val	(clazz == ELFCLASS32			\
23379343712SPeter Avalos 			 ? elf_getu32(swap, cap32.c_un.c_val)	\
23479343712SPeter Avalos 			 : elf_getu64(swap, cap64.c_un.c_val))
2356fca56fbSSascha Wildner 
236c30bd091SSascha Wildner #define xauxv_addr	(clazz == ELFCLASS32			\
2376fca56fbSSascha Wildner 			 ? CAST(void *, &auxv32)		\
2386fca56fbSSascha Wildner 			 : CAST(void *, &auxv64))
239c30bd091SSascha Wildner #define xauxv_sizeof	(clazz == ELFCLASS32			\
240c30bd091SSascha Wildner 			 ? sizeof(auxv32)			\
241c30bd091SSascha Wildner 			 : sizeof(auxv64))
242c30bd091SSascha Wildner #define xauxv_type	(clazz == ELFCLASS32			\
243c30bd091SSascha Wildner 			 ? elf_getu32(swap, auxv32.a_type)	\
244c30bd091SSascha Wildner 			 : elf_getu64(swap, auxv64.a_type))
245c30bd091SSascha Wildner #define xauxv_val	(clazz == ELFCLASS32			\
246c30bd091SSascha Wildner 			 ? elf_getu32(swap, auxv32.a_v)		\
247c30bd091SSascha Wildner 			 : elf_getu64(swap, auxv64.a_v))
248327e51cbSPeter Avalos 
2496fca56fbSSascha Wildner #define prpsoffsets(i)	(clazz == ELFCLASS32			\
2506fca56fbSSascha Wildner 			 ? prpsoffsets32[i]			\
2516fca56fbSSascha Wildner 			 : prpsoffsets64[i])
2526fca56fbSSascha Wildner 
253327e51cbSPeter Avalos #ifdef ELFCORE
25479343712SPeter Avalos /*
25579343712SPeter Avalos  * Try larger offsets first to avoid false matches
25679343712SPeter Avalos  * from earlier data that happen to look like strings.
25779343712SPeter Avalos  */
25879343712SPeter Avalos static const size_t	prpsoffsets32[] = {
25979343712SPeter Avalos #ifdef USE_NT_PSINFO
26079343712SPeter Avalos 	104,		/* SunOS 5.x (command line) */
26179343712SPeter Avalos 	88,		/* SunOS 5.x (short name) */
26279343712SPeter Avalos #endif /* USE_NT_PSINFO */
26379343712SPeter Avalos 
26479343712SPeter Avalos 	100,		/* SunOS 5.x (command line) */
26579343712SPeter Avalos 	84,		/* SunOS 5.x (short name) */
26679343712SPeter Avalos 
26779343712SPeter Avalos 	44,		/* Linux (command line) */
2686fca56fbSSascha Wildner 	28,		/* Linux (short name) */
2696fca56fbSSascha Wildner 
2706fca56fbSSascha Wildner 	48,		/* Linux PowerPC (command line) */
2716fca56fbSSascha Wildner 	32,		/* Linux PowerPC (short name) */
27279343712SPeter Avalos 
27379343712SPeter Avalos 	8,		/* FreeBSD */
274327e51cbSPeter Avalos };
275327e51cbSPeter Avalos 
27679343712SPeter Avalos static const size_t	prpsoffsets64[] = {
27779343712SPeter Avalos #ifdef USE_NT_PSINFO
27879343712SPeter Avalos 	152,		/* SunOS 5.x (command line) */
27979343712SPeter Avalos 	136,		/* SunOS 5.x (short name) */
28079343712SPeter Avalos #endif /* USE_NT_PSINFO */
28179343712SPeter Avalos 
28279343712SPeter Avalos 	136,		/* SunOS 5.x, 64-bit (command line) */
28379343712SPeter Avalos 	120,		/* SunOS 5.x, 64-bit (short name) */
28479343712SPeter Avalos 
28579343712SPeter Avalos 	56,		/* Linux (command line) */
286327e51cbSPeter Avalos 	40,             /* Linux (tested on core from 2.4.x, short name) */
28779343712SPeter Avalos 
28879343712SPeter Avalos 	16,		/* FreeBSD, 64-bit */
289327e51cbSPeter Avalos };
290327e51cbSPeter Avalos 
2916fca56fbSSascha Wildner #define	NOFFSETS32	__arraycount(prpsoffsets32)
2926fca56fbSSascha Wildner #define NOFFSETS64	__arraycount(prpsoffsets64)
293327e51cbSPeter Avalos 
29479343712SPeter Avalos #define NOFFSETS	(clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64)
295327e51cbSPeter Avalos 
296327e51cbSPeter Avalos /*
297327e51cbSPeter Avalos  * Look through the program headers of an executable image, searching
298327e51cbSPeter Avalos  * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or
299327e51cbSPeter Avalos  * "FreeBSD"; if one is found, try looking in various places in its
300327e51cbSPeter Avalos  * contents for a 16-character string containing only printable
301327e51cbSPeter Avalos  * characters - if found, that string should be the name of the program
302327e51cbSPeter Avalos  * that dropped core.  Note: right after that 16-character string is,
303327e51cbSPeter Avalos  * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and
304327e51cbSPeter Avalos  * Linux, a longer string (80 characters, in 5.x, probably other
305327e51cbSPeter Avalos  * SVR4-flavored systems, and Linux) containing the start of the
306327e51cbSPeter Avalos  * command line for that program.
307327e51cbSPeter Avalos  *
30879343712SPeter Avalos  * SunOS 5.x core files contain two PT_NOTE sections, with the types
30979343712SPeter Avalos  * NT_PRPSINFO (old) and NT_PSINFO (new).  These structs contain the
31079343712SPeter Avalos  * same info about the command name and command line, so it probably
31179343712SPeter Avalos  * isn't worthwhile to look for NT_PSINFO, but the offsets are provided
31279343712SPeter Avalos  * above (see USE_NT_PSINFO), in case we ever decide to do so.  The
31379343712SPeter Avalos  * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent;
31479343712SPeter Avalos  * the SunOS 5.x file command relies on this (and prefers the latter).
31579343712SPeter Avalos  *
316327e51cbSPeter Avalos  * The signal number probably appears in a section of type NT_PRSTATUS,
317327e51cbSPeter Avalos  * but that's also rather OS-dependent, in ways that are harder to
318327e51cbSPeter Avalos  * dissect with heuristics, so I'm not bothering with the signal number.
319327e51cbSPeter Avalos  * (I suppose the signal number could be of interest in situations where
320327e51cbSPeter Avalos  * you don't have the binary of the program that dropped core; if you
321327e51cbSPeter Avalos  * *do* have that binary, the debugger will probably tell you what
322327e51cbSPeter Avalos  * signal it was.)
323327e51cbSPeter Avalos  */
324327e51cbSPeter Avalos 
325327e51cbSPeter Avalos #define	OS_STYLE_SVR4		0
326327e51cbSPeter Avalos #define	OS_STYLE_FREEBSD	1
327327e51cbSPeter Avalos #define	OS_STYLE_NETBSD		2
328327e51cbSPeter Avalos 
32979343712SPeter Avalos private const char os_style_names[][8] = {
330327e51cbSPeter Avalos 	"SVR4",
331327e51cbSPeter Avalos 	"FreeBSD",
332327e51cbSPeter Avalos 	"NetBSD",
333327e51cbSPeter Avalos };
334327e51cbSPeter Avalos 
3356fca56fbSSascha Wildner #define FLAGS_CORE_STYLE		0x0003
336c30bd091SSascha Wildner 
3376fca56fbSSascha Wildner #define FLAGS_DID_CORE			0x0004
3386fca56fbSSascha Wildner #define FLAGS_DID_OS_NOTE		0x0008
3396fca56fbSSascha Wildner #define FLAGS_DID_BUILD_ID		0x0010
3406fca56fbSSascha Wildner #define FLAGS_DID_CORE_STYLE		0x0020
3416fca56fbSSascha Wildner #define FLAGS_DID_NETBSD_PAX		0x0040
3426fca56fbSSascha Wildner #define FLAGS_DID_NETBSD_MARCH		0x0080
3436fca56fbSSascha Wildner #define FLAGS_DID_NETBSD_CMODEL		0x0100
3446fca56fbSSascha Wildner #define FLAGS_DID_NETBSD_EMULATION	0x0200
3456fca56fbSSascha Wildner #define FLAGS_DID_NETBSD_UNKNOWN	0x0400
3466fca56fbSSascha Wildner #define FLAGS_IS_CORE			0x0800
3476fca56fbSSascha Wildner #define FLAGS_DID_AUXV			0x1000
348327e51cbSPeter Avalos 
349327e51cbSPeter Avalos private int
dophn_core(struct magic_set * ms,int clazz,int swap,int fd,off_t off,int num,size_t size,off_t fsize,int * flags,uint16_t * notecount)35079343712SPeter Avalos dophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
35182c5fa3eSPeter Avalos     int num, size_t size, off_t fsize, int *flags, uint16_t *notecount)
352327e51cbSPeter Avalos {
353327e51cbSPeter Avalos 	Elf32_Phdr ph32;
354327e51cbSPeter Avalos 	Elf64_Phdr ph64;
355e8af9738SPeter Avalos 	size_t offset, len;
356327e51cbSPeter Avalos 	unsigned char nbuf[BUFSIZ];
357327e51cbSPeter Avalos 	ssize_t bufsize;
358970935fdSSascha Wildner 	off_t ph_off = off, offs;
359c30bd091SSascha Wildner 	int ph_num = num;
360327e51cbSPeter Avalos 
361c990e5baSDaniel Fojt 	if (ms->flags & MAGIC_MIME)
362c990e5baSDaniel Fojt 		return 0;
363c990e5baSDaniel Fojt 
3646fca56fbSSascha Wildner 	if (num == 0) {
3656fca56fbSSascha Wildner 		if (file_printf(ms, ", no program header") == -1)
3666fca56fbSSascha Wildner 			return -1;
3676fca56fbSSascha Wildner 		return 0;
3686fca56fbSSascha Wildner 	}
369327e51cbSPeter Avalos 	if (size != xph_sizeof) {
370327e51cbSPeter Avalos 		if (file_printf(ms, ", corrupted program header size") == -1)
371327e51cbSPeter Avalos 			return -1;
372327e51cbSPeter Avalos 		return 0;
373327e51cbSPeter Avalos 	}
374327e51cbSPeter Avalos 
375327e51cbSPeter Avalos 	/*
376327e51cbSPeter Avalos 	 * Loop through all the program headers.
377327e51cbSPeter Avalos 	 */
378327e51cbSPeter Avalos 	for ( ; num; num--) {
3796fca56fbSSascha Wildner 		if (pread(fd, xph_addr, xph_sizeof, off) <
3806fca56fbSSascha Wildner 		    CAST(ssize_t, xph_sizeof)) {
381970935fdSSascha Wildner 			if (file_printf(ms,
382970935fdSSascha Wildner 			    ", can't read elf program headers at %jd",
383970935fdSSascha Wildner 			    (intmax_t)off) == -1)
384327e51cbSPeter Avalos 				return -1;
385970935fdSSascha Wildner 			return 0;
386327e51cbSPeter Avalos 		}
387a96e001bSPeter Avalos 		off += size;
388a96e001bSPeter Avalos 
38982c5fa3eSPeter Avalos 		if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
390a96e001bSPeter Avalos 			/* Perhaps warn here */
391327e51cbSPeter Avalos 			continue;
392327e51cbSPeter Avalos 		}
393327e51cbSPeter Avalos 
394327e51cbSPeter Avalos 		if (xph_type != PT_NOTE)
395327e51cbSPeter Avalos 			continue;
396327e51cbSPeter Avalos 
397327e51cbSPeter Avalos 		/*
398327e51cbSPeter Avalos 		 * This is a PT_NOTE section; loop through all the notes
399327e51cbSPeter Avalos 		 * in the section.
400327e51cbSPeter Avalos 		 */
401e8af9738SPeter Avalos 		len = xph_filesz < sizeof(nbuf) ? xph_filesz : sizeof(nbuf);
402970935fdSSascha Wildner 		offs = xph_offset;
403970935fdSSascha Wildner 		if ((bufsize = pread(fd, nbuf, len, offs)) == -1) {
404970935fdSSascha Wildner 			if (file_printf(ms, " can't read note section at %jd",
405970935fdSSascha Wildner 			    (intmax_t)offs) == -1)
406327e51cbSPeter Avalos 				return -1;
407970935fdSSascha Wildner 			return 0;
408327e51cbSPeter Avalos 		}
409327e51cbSPeter Avalos 		offset = 0;
410327e51cbSPeter Avalos 		for (;;) {
4116fca56fbSSascha Wildner 			if (offset >= CAST(size_t, bufsize))
412327e51cbSPeter Avalos 				break;
4136fca56fbSSascha Wildner 			offset = donote(ms, nbuf, offset, CAST(size_t, bufsize),
414c30bd091SSascha Wildner 			    clazz, swap, 4, flags, notecount, fd, ph_off,
415c30bd091SSascha Wildner 			    ph_num, fsize);
416327e51cbSPeter Avalos 			if (offset == 0)
417327e51cbSPeter Avalos 				break;
418327e51cbSPeter Avalos 
419327e51cbSPeter Avalos 		}
420327e51cbSPeter Avalos 	}
421327e51cbSPeter Avalos 	return 0;
422327e51cbSPeter Avalos }
423327e51cbSPeter Avalos #endif
424327e51cbSPeter Avalos 
4256fca56fbSSascha Wildner static int
do_note_netbsd_version(struct magic_set * ms,int swap,void * v)426e8af9738SPeter Avalos do_note_netbsd_version(struct magic_set *ms, int swap, void *v)
427e8af9738SPeter Avalos {
428e8af9738SPeter Avalos 	uint32_t desc;
4296fca56fbSSascha Wildner 	memcpy(&desc, v, sizeof(desc));
430e8af9738SPeter Avalos 	desc = elf_getu32(swap, desc);
431e8af9738SPeter Avalos 
432e8af9738SPeter Avalos 	if (file_printf(ms, ", for NetBSD") == -1)
4336fca56fbSSascha Wildner 		return -1;
434e8af9738SPeter Avalos 	/*
435e8af9738SPeter Avalos 	 * The version number used to be stuck as 199905, and was thus
436e8af9738SPeter Avalos 	 * basically content-free.  Newer versions of NetBSD have fixed
437e8af9738SPeter Avalos 	 * this and now use the encoding of __NetBSD_Version__:
438e8af9738SPeter Avalos 	 *
439e8af9738SPeter Avalos 	 *	MMmmrrpp00
440e8af9738SPeter Avalos 	 *
441e8af9738SPeter Avalos 	 * M = major version
442e8af9738SPeter Avalos 	 * m = minor version
443e8af9738SPeter Avalos 	 * r = release ["",A-Z,Z[A-Z] but numeric]
444e8af9738SPeter Avalos 	 * p = patchlevel
445e8af9738SPeter Avalos 	 */
446e8af9738SPeter Avalos 	if (desc > 100000000U) {
447e8af9738SPeter Avalos 		uint32_t ver_patch = (desc / 100) % 100;
448e8af9738SPeter Avalos 		uint32_t ver_rel = (desc / 10000) % 100;
449e8af9738SPeter Avalos 		uint32_t ver_min = (desc / 1000000) % 100;
450e8af9738SPeter Avalos 		uint32_t ver_maj = desc / 100000000;
451e8af9738SPeter Avalos 
452e8af9738SPeter Avalos 		if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1)
4536fca56fbSSascha Wildner 			return -1;
454e8af9738SPeter Avalos 		if (ver_rel == 0 && ver_patch != 0) {
455e8af9738SPeter Avalos 			if (file_printf(ms, ".%u", ver_patch) == -1)
4566fca56fbSSascha Wildner 				return -1;
457e8af9738SPeter Avalos 		} else if (ver_rel != 0) {
458e8af9738SPeter Avalos 			while (ver_rel > 26) {
459e8af9738SPeter Avalos 				if (file_printf(ms, "Z") == -1)
4606fca56fbSSascha Wildner 					return -1;
461e8af9738SPeter Avalos 				ver_rel -= 26;
462e8af9738SPeter Avalos 			}
463e8af9738SPeter Avalos 			if (file_printf(ms, "%c", 'A' + ver_rel - 1)
464e8af9738SPeter Avalos 			    == -1)
4656fca56fbSSascha Wildner 				return -1;
466e8af9738SPeter Avalos 		}
467e8af9738SPeter Avalos 	}
4686fca56fbSSascha Wildner 	return 0;
469e8af9738SPeter Avalos }
470e8af9738SPeter Avalos 
4716fca56fbSSascha Wildner static int
do_note_freebsd_version(struct magic_set * ms,int swap,void * v)472e8af9738SPeter Avalos do_note_freebsd_version(struct magic_set *ms, int swap, void *v)
473e8af9738SPeter Avalos {
474e8af9738SPeter Avalos 	uint32_t desc;
475e8af9738SPeter Avalos 
4766fca56fbSSascha Wildner 	memcpy(&desc, v, sizeof(desc));
477e8af9738SPeter Avalos 	desc = elf_getu32(swap, desc);
478e8af9738SPeter Avalos 	if (file_printf(ms, ", for FreeBSD") == -1)
4796fca56fbSSascha Wildner 		return -1;
480e8af9738SPeter Avalos 
481e8af9738SPeter Avalos 	/*
482e8af9738SPeter Avalos 	 * Contents is __FreeBSD_version, whose relation to OS
483e8af9738SPeter Avalos 	 * versions is defined by a huge table in the Porter's
484e8af9738SPeter Avalos 	 * Handbook.  This is the general scheme:
485e8af9738SPeter Avalos 	 *
486e8af9738SPeter Avalos 	 * Releases:
487e8af9738SPeter Avalos 	 * 	Mmp000 (before 4.10)
488e8af9738SPeter Avalos 	 * 	Mmi0p0 (before 5.0)
489e8af9738SPeter Avalos 	 * 	Mmm0p0
490e8af9738SPeter Avalos 	 *
491e8af9738SPeter Avalos 	 * Development branches:
492e8af9738SPeter Avalos 	 * 	Mmpxxx (before 4.6)
493e8af9738SPeter Avalos 	 * 	Mmp1xx (before 4.10)
494e8af9738SPeter Avalos 	 * 	Mmi1xx (before 5.0)
495e8af9738SPeter Avalos 	 * 	M000xx (pre-M.0)
496e8af9738SPeter Avalos 	 * 	Mmm1xx
497e8af9738SPeter Avalos 	 *
498e8af9738SPeter Avalos 	 * M = major version
499e8af9738SPeter Avalos 	 * m = minor version
500e8af9738SPeter Avalos 	 * i = minor version increment (491000 -> 4.10)
501e8af9738SPeter Avalos 	 * p = patchlevel
502e8af9738SPeter Avalos 	 * x = revision
503e8af9738SPeter Avalos 	 *
504e8af9738SPeter Avalos 	 * The first release of FreeBSD to use ELF by default
505e8af9738SPeter Avalos 	 * was version 3.0.
506e8af9738SPeter Avalos 	 */
507e8af9738SPeter Avalos 	if (desc == 460002) {
508e8af9738SPeter Avalos 		if (file_printf(ms, " 4.6.2") == -1)
5096fca56fbSSascha Wildner 			return -1;
510e8af9738SPeter Avalos 	} else if (desc < 460100) {
511e8af9738SPeter Avalos 		if (file_printf(ms, " %d.%d", desc / 100000,
512e8af9738SPeter Avalos 		    desc / 10000 % 10) == -1)
5136fca56fbSSascha Wildner 			return -1;
514e8af9738SPeter Avalos 		if (desc / 1000 % 10 > 0)
515e8af9738SPeter Avalos 			if (file_printf(ms, ".%d", desc / 1000 % 10) == -1)
5166fca56fbSSascha Wildner 				return -1;
517e8af9738SPeter Avalos 		if ((desc % 1000 > 0) || (desc % 100000 == 0))
518e8af9738SPeter Avalos 			if (file_printf(ms, " (%d)", desc) == -1)
5196fca56fbSSascha Wildner 				return -1;
520e8af9738SPeter Avalos 	} else if (desc < 500000) {
521e8af9738SPeter Avalos 		if (file_printf(ms, " %d.%d", desc / 100000,
522e8af9738SPeter Avalos 		    desc / 10000 % 10 + desc / 1000 % 10) == -1)
5236fca56fbSSascha Wildner 			return -1;
524e8af9738SPeter Avalos 		if (desc / 100 % 10 > 0) {
525e8af9738SPeter Avalos 			if (file_printf(ms, " (%d)", desc) == -1)
5266fca56fbSSascha Wildner 				return -1;
527e8af9738SPeter Avalos 		} else if (desc / 10 % 10 > 0) {
528e8af9738SPeter Avalos 			if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
5296fca56fbSSascha Wildner 				return -1;
530e8af9738SPeter Avalos 		}
531e8af9738SPeter Avalos 	} else {
532e8af9738SPeter Avalos 		if (file_printf(ms, " %d.%d", desc / 100000,
533e8af9738SPeter Avalos 		    desc / 1000 % 100) == -1)
5346fca56fbSSascha Wildner 			return -1;
535e8af9738SPeter Avalos 		if ((desc / 100 % 10 > 0) ||
536e8af9738SPeter Avalos 		    (desc % 100000 / 100 == 0)) {
537e8af9738SPeter Avalos 			if (file_printf(ms, " (%d)", desc) == -1)
5386fca56fbSSascha Wildner 				return -1;
539e8af9738SPeter Avalos 		} else if (desc / 10 % 10 > 0) {
540e8af9738SPeter Avalos 			if (file_printf(ms, ".%d", desc / 10 % 10) == -1)
5416fca56fbSSascha Wildner 				return -1;
542e8af9738SPeter Avalos 		}
543e8af9738SPeter Avalos 	}
5446fca56fbSSascha Wildner 	return 0;
545e8af9738SPeter Avalos }
546e8af9738SPeter Avalos 
54782c5fa3eSPeter Avalos private int
548c30bd091SSascha Wildner /*ARGSUSED*/
do_bid_note(struct magic_set * ms,unsigned char * nbuf,uint32_t type,int swap,uint32_t namesz,uint32_t descsz,size_t noff,size_t doff,int * flags)54982c5fa3eSPeter Avalos do_bid_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
55082c5fa3eSPeter Avalos     int swap __attribute__((__unused__)), uint32_t namesz, uint32_t descsz,
55182c5fa3eSPeter Avalos     size_t noff, size_t doff, int *flags)
552327e51cbSPeter Avalos {
5536fca56fbSSascha Wildner 	if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "GNU") == 0 &&
554c30bd091SSascha Wildner 	    type == NT_GNU_BUILD_ID && (descsz >= 4 && descsz <= 20)) {
555e8af9738SPeter Avalos 		uint8_t desc[20];
556c30bd091SSascha Wildner 		const char *btype;
557e8af9738SPeter Avalos 		uint32_t i;
55882c5fa3eSPeter Avalos 		*flags |= FLAGS_DID_BUILD_ID;
559c30bd091SSascha Wildner 		switch (descsz) {
560c30bd091SSascha Wildner 		case 8:
561c30bd091SSascha Wildner 		    btype = "xxHash";
562c30bd091SSascha Wildner 		    break;
563c30bd091SSascha Wildner 		case 16:
564c30bd091SSascha Wildner 		    btype = "md5/uuid";
565c30bd091SSascha Wildner 		    break;
566c30bd091SSascha Wildner 		case 20:
567c30bd091SSascha Wildner 		    btype = "sha1";
568c30bd091SSascha Wildner 		    break;
569c30bd091SSascha Wildner 		default:
570c30bd091SSascha Wildner 		    btype = "unknown";
571c30bd091SSascha Wildner 		    break;
572c30bd091SSascha Wildner 		}
573c30bd091SSascha Wildner 		if (file_printf(ms, ", BuildID[%s]=", btype) == -1)
5746fca56fbSSascha Wildner 			return -1;
5756fca56fbSSascha Wildner 		memcpy(desc, &nbuf[doff], descsz);
576e8af9738SPeter Avalos 		for (i = 0; i < descsz; i++)
577e8af9738SPeter Avalos 		    if (file_printf(ms, "%02x", desc[i]) == -1)
5786fca56fbSSascha Wildner 			return -1;
57982c5fa3eSPeter Avalos 		return 1;
5806fca56fbSSascha Wildner 	}
5816fca56fbSSascha Wildner 	if (namesz == 4 && strcmp(RCAST(char *, &nbuf[noff]), "Go") == 0 &&
5826fca56fbSSascha Wildner 	    type == NT_GO_BUILD_ID && descsz < 128) {
583c990e5baSDaniel Fojt 		char buf[256];
584c990e5baSDaniel Fojt 		if (file_printf(ms, ", Go BuildID=%s",
585c990e5baSDaniel Fojt 		    file_copystr(buf, sizeof(buf), descsz,
586c990e5baSDaniel Fojt 		    RCAST(const char *, &nbuf[doff]))) == -1)
5876fca56fbSSascha Wildner 			return -1;
58882c5fa3eSPeter Avalos 		return 1;
58982c5fa3eSPeter Avalos 	}
59082c5fa3eSPeter Avalos 	return 0;
591a96e001bSPeter Avalos }
592a96e001bSPeter Avalos 
59382c5fa3eSPeter Avalos private int
do_os_note(struct magic_set * ms,unsigned char * nbuf,uint32_t type,int swap,uint32_t namesz,uint32_t descsz,size_t noff,size_t doff,int * flags)59482c5fa3eSPeter Avalos do_os_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
59582c5fa3eSPeter Avalos     int swap, uint32_t namesz, uint32_t descsz,
59682c5fa3eSPeter Avalos     size_t noff, size_t doff, int *flags)
59782c5fa3eSPeter Avalos {
5986fca56fbSSascha Wildner 	const char *name = RCAST(const char *, &nbuf[noff]);
5996fca56fbSSascha Wildner 
6006fca56fbSSascha Wildner 	if (namesz == 5 && strcmp(name, "SuSE") == 0 &&
60182c5fa3eSPeter Avalos 		type == NT_GNU_VERSION && descsz == 2) {
60282c5fa3eSPeter Avalos 		*flags |= FLAGS_DID_OS_NOTE;
6036fca56fbSSascha Wildner 		if (file_printf(ms, ", for SuSE %d.%d", nbuf[doff],
6046fca56fbSSascha Wildner 		    nbuf[doff + 1]) == -1)
6056fca56fbSSascha Wildner 		    return -1;
60682c5fa3eSPeter Avalos 	    return 1;
60782c5fa3eSPeter Avalos 	}
60882c5fa3eSPeter Avalos 
6096fca56fbSSascha Wildner 	if (namesz == 4 && strcmp(name, "GNU") == 0 &&
61082c5fa3eSPeter Avalos 	    type == NT_GNU_VERSION && descsz == 16) {
61182c5fa3eSPeter Avalos 		uint32_t desc[4];
6126fca56fbSSascha Wildner 		memcpy(desc, &nbuf[doff], sizeof(desc));
61382c5fa3eSPeter Avalos 
61482c5fa3eSPeter Avalos 		*flags |= FLAGS_DID_OS_NOTE;
61582c5fa3eSPeter Avalos 		if (file_printf(ms, ", for GNU/") == -1)
6166fca56fbSSascha Wildner 			return -1;
61782c5fa3eSPeter Avalos 		switch (elf_getu32(swap, desc[0])) {
61882c5fa3eSPeter Avalos 		case GNU_OS_LINUX:
61982c5fa3eSPeter Avalos 			if (file_printf(ms, "Linux") == -1)
6206fca56fbSSascha Wildner 				return -1;
62182c5fa3eSPeter Avalos 			break;
62282c5fa3eSPeter Avalos 		case GNU_OS_HURD:
62382c5fa3eSPeter Avalos 			if (file_printf(ms, "Hurd") == -1)
6246fca56fbSSascha Wildner 				return -1;
62582c5fa3eSPeter Avalos 			break;
62682c5fa3eSPeter Avalos 		case GNU_OS_SOLARIS:
62782c5fa3eSPeter Avalos 			if (file_printf(ms, "Solaris") == -1)
6286fca56fbSSascha Wildner 				return -1;
62982c5fa3eSPeter Avalos 			break;
63082c5fa3eSPeter Avalos 		case GNU_OS_KFREEBSD:
63182c5fa3eSPeter Avalos 			if (file_printf(ms, "kFreeBSD") == -1)
6326fca56fbSSascha Wildner 				return -1;
63382c5fa3eSPeter Avalos 			break;
63482c5fa3eSPeter Avalos 		case GNU_OS_KNETBSD:
63582c5fa3eSPeter Avalos 			if (file_printf(ms, "kNetBSD") == -1)
6366fca56fbSSascha Wildner 				return -1;
63782c5fa3eSPeter Avalos 			break;
63882c5fa3eSPeter Avalos 		default:
63982c5fa3eSPeter Avalos 			if (file_printf(ms, "<unknown>") == -1)
6406fca56fbSSascha Wildner 				return -1;
64182c5fa3eSPeter Avalos 		}
64282c5fa3eSPeter Avalos 		if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
64382c5fa3eSPeter Avalos 		    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1)
6446fca56fbSSascha Wildner 			return -1;
64582c5fa3eSPeter Avalos 		return 1;
64682c5fa3eSPeter Avalos 	}
64782c5fa3eSPeter Avalos 
6486fca56fbSSascha Wildner 	if (namesz == 7 && strcmp(name, "NetBSD") == 0) {
64982c5fa3eSPeter Avalos 	    	if (type == NT_NETBSD_VERSION && descsz == 4) {
65082c5fa3eSPeter Avalos 			*flags |= FLAGS_DID_OS_NOTE;
6516fca56fbSSascha Wildner 			if (do_note_netbsd_version(ms, swap, &nbuf[doff]) == -1)
6526fca56fbSSascha Wildner 				return -1;
65382c5fa3eSPeter Avalos 			return 1;
65482c5fa3eSPeter Avalos 		}
65582c5fa3eSPeter Avalos 	}
65682c5fa3eSPeter Avalos 
6576fca56fbSSascha Wildner 	if (namesz == 8 && strcmp(name, "FreeBSD") == 0) {
65882c5fa3eSPeter Avalos 	    	if (type == NT_FREEBSD_VERSION && descsz == 4) {
65982c5fa3eSPeter Avalos 			*flags |= FLAGS_DID_OS_NOTE;
6606fca56fbSSascha Wildner 			if (do_note_freebsd_version(ms, swap, &nbuf[doff])
6616fca56fbSSascha Wildner 			    == -1)
6626fca56fbSSascha Wildner 				return -1;
66382c5fa3eSPeter Avalos 			return 1;
66482c5fa3eSPeter Avalos 		}
66582c5fa3eSPeter Avalos 	}
66682c5fa3eSPeter Avalos 
6676fca56fbSSascha Wildner 	if (namesz == 8 && strcmp(name, "OpenBSD") == 0 &&
66882c5fa3eSPeter Avalos 	    type == NT_OPENBSD_VERSION && descsz == 4) {
66982c5fa3eSPeter Avalos 		*flags |= FLAGS_DID_OS_NOTE;
67082c5fa3eSPeter Avalos 		if (file_printf(ms, ", for OpenBSD") == -1)
6716fca56fbSSascha Wildner 			return -1;
67282c5fa3eSPeter Avalos 		/* Content of note is always 0 */
67382c5fa3eSPeter Avalos 		return 1;
67482c5fa3eSPeter Avalos 	}
67582c5fa3eSPeter Avalos 
6766fca56fbSSascha Wildner 	if (namesz == 10 && strcmp(name, "DragonFly") == 0 &&
67782c5fa3eSPeter Avalos 	    type == NT_DRAGONFLY_VERSION && descsz == 4) {
67882c5fa3eSPeter Avalos 		uint32_t desc;
67982c5fa3eSPeter Avalos 		*flags |= FLAGS_DID_OS_NOTE;
68082c5fa3eSPeter Avalos 		if (file_printf(ms, ", for DragonFly") == -1)
6816fca56fbSSascha Wildner 			return -1;
6826fca56fbSSascha Wildner 		memcpy(&desc, &nbuf[doff], sizeof(desc));
68382c5fa3eSPeter Avalos 		desc = elf_getu32(swap, desc);
68482c5fa3eSPeter Avalos 		if (file_printf(ms, " %d.%d.%d", desc / 100000,
68582c5fa3eSPeter Avalos 		    desc / 10000 % 10, desc % 10000) == -1)
6866fca56fbSSascha Wildner 			return -1;
68782c5fa3eSPeter Avalos 		return 1;
68882c5fa3eSPeter Avalos 	}
68982c5fa3eSPeter Avalos 	return 0;
69082c5fa3eSPeter Avalos }
69182c5fa3eSPeter Avalos 
69282c5fa3eSPeter Avalos private int
do_pax_note(struct magic_set * ms,unsigned char * nbuf,uint32_t type,int swap,uint32_t namesz,uint32_t descsz,size_t noff,size_t doff,int * flags)69382c5fa3eSPeter Avalos do_pax_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
69482c5fa3eSPeter Avalos     int swap, uint32_t namesz, uint32_t descsz,
69582c5fa3eSPeter Avalos     size_t noff, size_t doff, int *flags)
69682c5fa3eSPeter Avalos {
6976fca56fbSSascha Wildner 	const char *name = RCAST(const char *, &nbuf[noff]);
6986fca56fbSSascha Wildner 
6996fca56fbSSascha Wildner 	if (namesz == 4 && strcmp(name, "PaX") == 0 &&
70082c5fa3eSPeter Avalos 	    type == NT_NETBSD_PAX && descsz == 4) {
701e8af9738SPeter Avalos 		static const char *pax[] = {
702e8af9738SPeter Avalos 		    "+mprotect",
703e8af9738SPeter Avalos 		    "-mprotect",
704e8af9738SPeter Avalos 		    "+segvguard",
705e8af9738SPeter Avalos 		    "-segvguard",
706e8af9738SPeter Avalos 		    "+ASLR",
707e8af9738SPeter Avalos 		    "-ASLR",
708e8af9738SPeter Avalos 		};
709327e51cbSPeter Avalos 		uint32_t desc;
710e8af9738SPeter Avalos 		size_t i;
711e8af9738SPeter Avalos 		int did = 0;
712e8af9738SPeter Avalos 
71382c5fa3eSPeter Avalos 		*flags |= FLAGS_DID_NETBSD_PAX;
7146fca56fbSSascha Wildner 		memcpy(&desc, &nbuf[doff], sizeof(desc));
71579343712SPeter Avalos 		desc = elf_getu32(swap, desc);
716327e51cbSPeter Avalos 
717e8af9738SPeter Avalos 		if (desc && file_printf(ms, ", PaX: ") == -1)
7186fca56fbSSascha Wildner 			return -1;
719327e51cbSPeter Avalos 
720e8af9738SPeter Avalos 		for (i = 0; i < __arraycount(pax); i++) {
7216fca56fbSSascha Wildner 			if (((1 << CAST(int, i)) & desc) == 0)
722e8af9738SPeter Avalos 				continue;
723e8af9738SPeter Avalos 			if (file_printf(ms, "%s%s", did++ ? "," : "",
724e8af9738SPeter Avalos 			    pax[i]) == -1)
7256fca56fbSSascha Wildner 				return -1;
726327e51cbSPeter Avalos 		}
72782c5fa3eSPeter Avalos 		return 1;
72882c5fa3eSPeter Avalos 	}
72982c5fa3eSPeter Avalos 	return 0;
730327e51cbSPeter Avalos }
731e8af9738SPeter Avalos 
73282c5fa3eSPeter Avalos private int
do_core_note(struct magic_set * ms,unsigned char * nbuf,uint32_t type,int swap,uint32_t namesz,uint32_t descsz,size_t noff,size_t doff,int * flags,size_t size,int clazz)73382c5fa3eSPeter Avalos do_core_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
73482c5fa3eSPeter Avalos     int swap, uint32_t namesz, uint32_t descsz,
73582c5fa3eSPeter Avalos     size_t noff, size_t doff, int *flags, size_t size, int clazz)
73682c5fa3eSPeter Avalos {
73782c5fa3eSPeter Avalos #ifdef ELFCORE
738c990e5baSDaniel Fojt 	char buf[256];
7396fca56fbSSascha Wildner 	const char *name = RCAST(const char *, &nbuf[noff]);
7406fca56fbSSascha Wildner 
74182c5fa3eSPeter Avalos 	int os_style = -1;
742327e51cbSPeter Avalos 	/*
743327e51cbSPeter Avalos 	 * Sigh.  The 2.0.36 kernel in Debian 2.1, at
744327e51cbSPeter Avalos 	 * least, doesn't correctly implement name
745327e51cbSPeter Avalos 	 * sections, in core dumps, as specified by
746327e51cbSPeter Avalos 	 * the "Program Linking" section of "UNIX(R) System
747327e51cbSPeter Avalos 	 * V Release 4 Programmer's Guide: ANSI C and
748327e51cbSPeter Avalos 	 * Programming Support Tools", because my copy
749327e51cbSPeter Avalos 	 * clearly says "The first 'namesz' bytes in 'name'
750327e51cbSPeter Avalos 	 * contain a *null-terminated* [emphasis mine]
751327e51cbSPeter Avalos 	 * character representation of the entry's owner
752327e51cbSPeter Avalos 	 * or originator", but the 2.0.36 kernel code
753327e51cbSPeter Avalos 	 * doesn't include the terminating null in the
754327e51cbSPeter Avalos 	 * name....
755327e51cbSPeter Avalos 	 */
7566fca56fbSSascha Wildner 	if ((namesz == 4 && strncmp(name, "CORE", 4) == 0) ||
7576fca56fbSSascha Wildner 	    (namesz == 5 && strcmp(name, "CORE") == 0)) {
758327e51cbSPeter Avalos 		os_style = OS_STYLE_SVR4;
759327e51cbSPeter Avalos 	}
760327e51cbSPeter Avalos 
7616fca56fbSSascha Wildner 	if ((namesz == 8 && strcmp(name, "FreeBSD") == 0)) {
762327e51cbSPeter Avalos 		os_style = OS_STYLE_FREEBSD;
763327e51cbSPeter Avalos 	}
764327e51cbSPeter Avalos 
7656fca56fbSSascha Wildner 	if ((namesz >= 11 && strncmp(name, "NetBSD-CORE", 11)
766327e51cbSPeter Avalos 	    == 0)) {
767327e51cbSPeter Avalos 		os_style = OS_STYLE_NETBSD;
768327e51cbSPeter Avalos 	}
769327e51cbSPeter Avalos 
770327e51cbSPeter Avalos 	if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) {
771327e51cbSPeter Avalos 		if (file_printf(ms, ", %s-style", os_style_names[os_style])
772327e51cbSPeter Avalos 		    == -1)
7736fca56fbSSascha Wildner 			return -1;
774327e51cbSPeter Avalos 		*flags |= FLAGS_DID_CORE_STYLE;
775c30bd091SSascha Wildner 		*flags |= os_style;
776327e51cbSPeter Avalos 	}
777327e51cbSPeter Avalos 
778327e51cbSPeter Avalos 	switch (os_style) {
779327e51cbSPeter Avalos 	case OS_STYLE_NETBSD:
78082c5fa3eSPeter Avalos 		if (type == NT_NETBSD_CORE_PROCINFO) {
78182c5fa3eSPeter Avalos 			char sbuf[512];
782c30bd091SSascha Wildner 			struct NetBSD_elfcore_procinfo pi;
783c30bd091SSascha Wildner 			memset(&pi, 0, sizeof(pi));
7846fca56fbSSascha Wildner 			memcpy(&pi, nbuf + doff, MIN(descsz, sizeof(pi)));
785c30bd091SSascha Wildner 
786c30bd091SSascha Wildner 			if (file_printf(ms, ", from '%.31s', pid=%u, uid=%u, "
787c30bd091SSascha Wildner 			    "gid=%u, nlwps=%u, lwp=%u (signal %u/code %u)",
788614728caSSascha Wildner 			    file_printable(ms, sbuf, sizeof(sbuf),
7896fca56fbSSascha Wildner 			    RCAST(char *, pi.cpi_name), sizeof(pi.cpi_name)),
7906fca56fbSSascha Wildner 			    elf_getu32(swap, CAST(uint32_t, pi.cpi_pid)),
791c30bd091SSascha Wildner 			    elf_getu32(swap, pi.cpi_euid),
792c30bd091SSascha Wildner 			    elf_getu32(swap, pi.cpi_egid),
793c30bd091SSascha Wildner 			    elf_getu32(swap, pi.cpi_nlwps),
7946fca56fbSSascha Wildner 			    elf_getu32(swap, CAST(uint32_t, pi.cpi_siglwp)),
795c30bd091SSascha Wildner 			    elf_getu32(swap, pi.cpi_signo),
796c30bd091SSascha Wildner 			    elf_getu32(swap, pi.cpi_sigcode)) == -1)
7976fca56fbSSascha Wildner 				return -1;
798327e51cbSPeter Avalos 
799327e51cbSPeter Avalos 			*flags |= FLAGS_DID_CORE;
80082c5fa3eSPeter Avalos 			return 1;
801327e51cbSPeter Avalos 		}
802327e51cbSPeter Avalos 		break;
803327e51cbSPeter Avalos 
8046fca56fbSSascha Wildner 	case OS_STYLE_FREEBSD:
8056fca56fbSSascha Wildner 		if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
8066fca56fbSSascha Wildner 			size_t argoff, pidoff;
8076fca56fbSSascha Wildner 
8086fca56fbSSascha Wildner 			if (clazz == ELFCLASS32)
8096fca56fbSSascha Wildner 				argoff = 4 + 4 + 17;
8106fca56fbSSascha Wildner 			else
8116fca56fbSSascha Wildner 				argoff = 4 + 4 + 8 + 17;
8126fca56fbSSascha Wildner 			if (file_printf(ms, ", from '%.80s'", nbuf + doff +
8136fca56fbSSascha Wildner 			    argoff) == -1)
8146fca56fbSSascha Wildner 				return -1;
8156fca56fbSSascha Wildner 			pidoff = argoff + 81 + 2;
8166fca56fbSSascha Wildner 			if (doff + pidoff + 4 <= size) {
8176fca56fbSSascha Wildner 				if (file_printf(ms, ", pid=%u",
8186fca56fbSSascha Wildner 				    elf_getu32(swap, *RCAST(uint32_t *, (nbuf +
8196fca56fbSSascha Wildner 				    doff + pidoff)))) == -1)
8206fca56fbSSascha Wildner 					return -1;
8216fca56fbSSascha Wildner 			}
8226fca56fbSSascha Wildner 			*flags |= FLAGS_DID_CORE;
8236fca56fbSSascha Wildner 		}
8246fca56fbSSascha Wildner 		break;
8256fca56fbSSascha Wildner 
826327e51cbSPeter Avalos 	default:
82782c5fa3eSPeter Avalos 		if (type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) {
828327e51cbSPeter Avalos 			size_t i, j;
829327e51cbSPeter Avalos 			unsigned char c;
830327e51cbSPeter Avalos 			/*
831327e51cbSPeter Avalos 			 * Extract the program name.  We assume
832327e51cbSPeter Avalos 			 * it to be 16 characters (that's what it
833327e51cbSPeter Avalos 			 * is in SunOS 5.x and Linux).
834327e51cbSPeter Avalos 			 *
835327e51cbSPeter Avalos 			 * Unfortunately, it's at a different offset
836327e51cbSPeter Avalos 			 * in various OSes, so try multiple offsets.
837327e51cbSPeter Avalos 			 * If the characters aren't all printable,
838327e51cbSPeter Avalos 			 * reject it.
839327e51cbSPeter Avalos 			 */
840327e51cbSPeter Avalos 			for (i = 0; i < NOFFSETS; i++) {
841327e51cbSPeter Avalos 				unsigned char *cname, *cp;
842327e51cbSPeter Avalos 				size_t reloffset = prpsoffsets(i);
843327e51cbSPeter Avalos 				size_t noffset = doff + reloffset;
844a96e001bSPeter Avalos 				size_t k;
845327e51cbSPeter Avalos 				for (j = 0; j < 16; j++, noffset++,
846327e51cbSPeter Avalos 				    reloffset++) {
847327e51cbSPeter Avalos 					/*
848327e51cbSPeter Avalos 					 * Make sure we're not past
849327e51cbSPeter Avalos 					 * the end of the buffer; if
850327e51cbSPeter Avalos 					 * we are, just give up.
851327e51cbSPeter Avalos 					 */
852327e51cbSPeter Avalos 					if (noffset >= size)
853327e51cbSPeter Avalos 						goto tryanother;
854327e51cbSPeter Avalos 
855327e51cbSPeter Avalos 					/*
856327e51cbSPeter Avalos 					 * Make sure we're not past
857327e51cbSPeter Avalos 					 * the end of the contents;
858327e51cbSPeter Avalos 					 * if we are, this obviously
859327e51cbSPeter Avalos 					 * isn't the right offset.
860327e51cbSPeter Avalos 					 */
861327e51cbSPeter Avalos 					if (reloffset >= descsz)
862327e51cbSPeter Avalos 						goto tryanother;
863327e51cbSPeter Avalos 
864327e51cbSPeter Avalos 					c = nbuf[noffset];
865327e51cbSPeter Avalos 					if (c == '\0') {
866327e51cbSPeter Avalos 						/*
867327e51cbSPeter Avalos 						 * A '\0' at the
868327e51cbSPeter Avalos 						 * beginning is
869327e51cbSPeter Avalos 						 * obviously wrong.
870327e51cbSPeter Avalos 						 * Any other '\0'
871327e51cbSPeter Avalos 						 * means we're done.
872327e51cbSPeter Avalos 						 */
873327e51cbSPeter Avalos 						if (j == 0)
874327e51cbSPeter Avalos 							goto tryanother;
875327e51cbSPeter Avalos 						else
876327e51cbSPeter Avalos 							break;
877327e51cbSPeter Avalos 					} else {
878327e51cbSPeter Avalos 						/*
879327e51cbSPeter Avalos 						 * A nonprintable
880327e51cbSPeter Avalos 						 * character is also
881327e51cbSPeter Avalos 						 * wrong.
882327e51cbSPeter Avalos 						 */
883327e51cbSPeter Avalos 						if (!isprint(c) || isquote(c))
884327e51cbSPeter Avalos 							goto tryanother;
885327e51cbSPeter Avalos 					}
886327e51cbSPeter Avalos 				}
887327e51cbSPeter Avalos 				/*
888327e51cbSPeter Avalos 				 * Well, that worked.
889327e51cbSPeter Avalos 				 */
890e4d4ce0cSPeter Avalos 
891e4d4ce0cSPeter Avalos 				/*
892e4d4ce0cSPeter Avalos 				 * Try next offsets, in case this match is
893e4d4ce0cSPeter Avalos 				 * in the middle of a string.
894e4d4ce0cSPeter Avalos 				 */
895e4d4ce0cSPeter Avalos 				for (k = i + 1 ; k < NOFFSETS; k++) {
896e4d4ce0cSPeter Avalos 					size_t no;
897e4d4ce0cSPeter Avalos 					int adjust = 1;
898a96e001bSPeter Avalos 					if (prpsoffsets(k) >= prpsoffsets(i))
899a96e001bSPeter Avalos 						continue;
900*3b9cdfa3SAntonio Huete Jimenez 					/*
901*3b9cdfa3SAntonio Huete Jimenez 					 * pr_fname == pr_psargs - 16 &&
902*3b9cdfa3SAntonio Huete Jimenez 					 * non-nul-terminated fname (qemu)
903*3b9cdfa3SAntonio Huete Jimenez 					 */
904*3b9cdfa3SAntonio Huete Jimenez 					if (prpsoffsets(k) ==
905*3b9cdfa3SAntonio Huete Jimenez 					    prpsoffsets(i) - 16 && j == 16)
906*3b9cdfa3SAntonio Huete Jimenez 						continue;
907e4d4ce0cSPeter Avalos 					for (no = doff + prpsoffsets(k);
908e4d4ce0cSPeter Avalos 					     no < doff + prpsoffsets(i); no++)
909e4d4ce0cSPeter Avalos 						adjust = adjust
910e4d4ce0cSPeter Avalos 						         && isprint(nbuf[no]);
911e4d4ce0cSPeter Avalos 					if (adjust)
912e4d4ce0cSPeter Avalos 						i = k;
913e4d4ce0cSPeter Avalos 				}
914e4d4ce0cSPeter Avalos 
9156fca56fbSSascha Wildner 				cname = CAST(unsigned char *,
9166fca56fbSSascha Wildner 				    &nbuf[doff + prpsoffsets(i)]);
9176fca56fbSSascha Wildner 				for (cp = cname; cp < nbuf + size && *cp
9186fca56fbSSascha Wildner 				    && isprint(*cp); cp++)
919327e51cbSPeter Avalos 					continue;
92079343712SPeter Avalos 				/*
92179343712SPeter Avalos 				 * Linux apparently appends a space at the end
92279343712SPeter Avalos 				 * of the command line: remove it.
92379343712SPeter Avalos 				 */
92479343712SPeter Avalos 				while (cp > cname && isspace(cp[-1]))
925327e51cbSPeter Avalos 					cp--;
926c990e5baSDaniel Fojt 				if (file_printf(ms, ", from '%s'",
927c990e5baSDaniel Fojt 				    file_copystr(buf, sizeof(buf),
928c990e5baSDaniel Fojt 				    CAST(size_t, cp - cname),
929614728caSSascha Wildner 				    RCAST(char *, cname))) == -1)
9306fca56fbSSascha Wildner 					return -1;
931327e51cbSPeter Avalos 				*flags |= FLAGS_DID_CORE;
93282c5fa3eSPeter Avalos 				return 1;
933327e51cbSPeter Avalos 
934327e51cbSPeter Avalos 			tryanother:
935327e51cbSPeter Avalos 				;
936327e51cbSPeter Avalos 			}
937327e51cbSPeter Avalos 		}
938327e51cbSPeter Avalos 		break;
939327e51cbSPeter Avalos 	}
940327e51cbSPeter Avalos #endif
94182c5fa3eSPeter Avalos 	return 0;
94282c5fa3eSPeter Avalos }
94382c5fa3eSPeter Avalos 
944c30bd091SSascha Wildner private off_t
get_offset_from_virtaddr(struct magic_set * ms,int swap,int clazz,int fd,off_t off,int num,off_t fsize,uint64_t virtaddr)945c30bd091SSascha Wildner get_offset_from_virtaddr(struct magic_set *ms, int swap, int clazz, int fd,
946c30bd091SSascha Wildner     off_t off, int num, off_t fsize, uint64_t virtaddr)
947c30bd091SSascha Wildner {
948c30bd091SSascha Wildner 	Elf32_Phdr ph32;
949c30bd091SSascha Wildner 	Elf64_Phdr ph64;
950c30bd091SSascha Wildner 
951c30bd091SSascha Wildner 	/*
952c30bd091SSascha Wildner 	 * Loop through all the program headers and find the header with
953c30bd091SSascha Wildner 	 * virtual address in which the "virtaddr" belongs to.
954c30bd091SSascha Wildner 	 */
955c30bd091SSascha Wildner 	for ( ; num; num--) {
9566fca56fbSSascha Wildner 		if (pread(fd, xph_addr, xph_sizeof, off) <
9576fca56fbSSascha Wildner 		    CAST(ssize_t, xph_sizeof)) {
958970935fdSSascha Wildner 			if (file_printf(ms,
959970935fdSSascha Wildner 			    ", can't read elf program header at %jd",
960970935fdSSascha Wildner 			    (intmax_t)off) == -1)
961c30bd091SSascha Wildner 				return -1;
962970935fdSSascha Wildner 			return 0;
963970935fdSSascha Wildner 
964c30bd091SSascha Wildner 		}
965c30bd091SSascha Wildner 		off += xph_sizeof;
966c30bd091SSascha Wildner 
967c30bd091SSascha Wildner 		if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
968c30bd091SSascha Wildner 			/* Perhaps warn here */
969c30bd091SSascha Wildner 			continue;
970c30bd091SSascha Wildner 		}
971c30bd091SSascha Wildner 
972c30bd091SSascha Wildner 		if (virtaddr >= xph_vaddr && virtaddr < xph_vaddr + xph_filesz)
973c30bd091SSascha Wildner 			return xph_offset + (virtaddr - xph_vaddr);
974c30bd091SSascha Wildner 	}
975c30bd091SSascha Wildner 	return 0;
976c30bd091SSascha Wildner }
977c30bd091SSascha Wildner 
978c30bd091SSascha Wildner private size_t
get_string_on_virtaddr(struct magic_set * ms,int swap,int clazz,int fd,off_t ph_off,int ph_num,off_t fsize,uint64_t virtaddr,char * buf,ssize_t buflen)979c30bd091SSascha Wildner get_string_on_virtaddr(struct magic_set *ms,
980c30bd091SSascha Wildner     int swap, int clazz, int fd, off_t ph_off, int ph_num,
981c30bd091SSascha Wildner     off_t fsize, uint64_t virtaddr, char *buf, ssize_t buflen)
982c30bd091SSascha Wildner {
983c30bd091SSascha Wildner 	char *bptr;
984c30bd091SSascha Wildner 	off_t offset;
985c30bd091SSascha Wildner 
986c30bd091SSascha Wildner 	if (buflen == 0)
987c30bd091SSascha Wildner 		return 0;
988c30bd091SSascha Wildner 
989c30bd091SSascha Wildner 	offset = get_offset_from_virtaddr(ms, swap, clazz, fd, ph_off, ph_num,
990c30bd091SSascha Wildner 	    fsize, virtaddr);
9916fca56fbSSascha Wildner 	if (offset < 0 ||
9926fca56fbSSascha Wildner 	    (buflen = pread(fd, buf, CAST(size_t, buflen), offset)) <= 0) {
993614728caSSascha Wildner 		(void)file_printf(ms, ", can't read elf string at %jd",
994614728caSSascha Wildner 		    (intmax_t)offset);
995c30bd091SSascha Wildner 		return 0;
996c30bd091SSascha Wildner 	}
997c30bd091SSascha Wildner 
998c30bd091SSascha Wildner 	buf[buflen - 1] = '\0';
999c30bd091SSascha Wildner 
1000c30bd091SSascha Wildner 	/* We expect only printable characters, so return if buffer contains
1001c30bd091SSascha Wildner 	 * non-printable character before the '\0' or just '\0'. */
10026fca56fbSSascha Wildner 	for (bptr = buf; *bptr && isprint(CAST(unsigned char, *bptr)); bptr++)
1003c30bd091SSascha Wildner 		continue;
1004c30bd091SSascha Wildner 	if (*bptr != '\0')
1005c30bd091SSascha Wildner 		return 0;
1006c30bd091SSascha Wildner 
1007c30bd091SSascha Wildner 	return bptr - buf;
1008c30bd091SSascha Wildner }
1009c30bd091SSascha Wildner 
1010c30bd091SSascha Wildner 
10116fca56fbSSascha Wildner /*ARGSUSED*/
1012c30bd091SSascha Wildner private int
do_auxv_note(struct magic_set * ms,unsigned char * nbuf,uint32_t type,int swap,uint32_t namesz,uint32_t descsz,size_t noff,size_t doff,int * flags,size_t size,int clazz,int fd,off_t ph_off,int ph_num,off_t fsize)1013c30bd091SSascha Wildner do_auxv_note(struct magic_set *ms, unsigned char *nbuf, uint32_t type,
1014c30bd091SSascha Wildner     int swap, uint32_t namesz __attribute__((__unused__)),
1015c30bd091SSascha Wildner     uint32_t descsz __attribute__((__unused__)),
1016c30bd091SSascha Wildner     size_t noff __attribute__((__unused__)), size_t doff,
1017c30bd091SSascha Wildner     int *flags, size_t size __attribute__((__unused__)), int clazz,
1018c30bd091SSascha Wildner     int fd, off_t ph_off, int ph_num, off_t fsize)
1019c30bd091SSascha Wildner {
1020c30bd091SSascha Wildner #ifdef ELFCORE
1021c30bd091SSascha Wildner 	Aux32Info auxv32;
1022c30bd091SSascha Wildner 	Aux64Info auxv64;
1023c30bd091SSascha Wildner 	size_t elsize = xauxv_sizeof;
1024c30bd091SSascha Wildner 	const char *tag;
1025c30bd091SSascha Wildner 	int is_string;
1026*3b9cdfa3SAntonio Huete Jimenez 	size_t nval, off;
1027c30bd091SSascha Wildner 
1028c30bd091SSascha Wildner 	if ((*flags & (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE)) !=
1029c30bd091SSascha Wildner 	    (FLAGS_IS_CORE|FLAGS_DID_CORE_STYLE))
1030c30bd091SSascha Wildner 		return 0;
1031c30bd091SSascha Wildner 
1032c30bd091SSascha Wildner 	switch (*flags & FLAGS_CORE_STYLE) {
1033c30bd091SSascha Wildner 	case OS_STYLE_SVR4:
1034c30bd091SSascha Wildner 		if (type != NT_AUXV)
1035c30bd091SSascha Wildner 			return 0;
1036c30bd091SSascha Wildner 		break;
1037c30bd091SSascha Wildner #ifdef notyet
1038c30bd091SSascha Wildner 	case OS_STYLE_NETBSD:
1039c30bd091SSascha Wildner 		if (type != NT_NETBSD_CORE_AUXV)
1040c30bd091SSascha Wildner 			return 0;
1041c30bd091SSascha Wildner 		break;
1042c30bd091SSascha Wildner 	case OS_STYLE_FREEBSD:
1043c30bd091SSascha Wildner 		if (type != NT_FREEBSD_PROCSTAT_AUXV)
1044c30bd091SSascha Wildner 			return 0;
1045c30bd091SSascha Wildner 		break;
1046c30bd091SSascha Wildner #endif
1047c30bd091SSascha Wildner 	default:
1048c30bd091SSascha Wildner 		return 0;
1049c30bd091SSascha Wildner 	}
1050c30bd091SSascha Wildner 
1051c30bd091SSascha Wildner 	*flags |= FLAGS_DID_AUXV;
1052c30bd091SSascha Wildner 
1053c30bd091SSascha Wildner 	nval = 0;
1054*3b9cdfa3SAntonio Huete Jimenez 	for (off = 0; off + elsize <= descsz; off += elsize) {
10556fca56fbSSascha Wildner 		memcpy(xauxv_addr, &nbuf[doff + off], xauxv_sizeof);
1056c30bd091SSascha Wildner 		/* Limit processing to 50 vector entries to prevent DoS */
1057c30bd091SSascha Wildner 		if (nval++ >= 50) {
1058c30bd091SSascha Wildner 			file_error(ms, 0, "Too many ELF Auxv elements");
1059c30bd091SSascha Wildner 			return 1;
1060c30bd091SSascha Wildner 		}
1061c30bd091SSascha Wildner 
1062c30bd091SSascha Wildner 		switch(xauxv_type) {
1063c30bd091SSascha Wildner 		case AT_LINUX_EXECFN:
1064c30bd091SSascha Wildner 			is_string = 1;
1065c30bd091SSascha Wildner 			tag = "execfn";
1066c30bd091SSascha Wildner 			break;
1067c30bd091SSascha Wildner 		case AT_LINUX_PLATFORM:
1068c30bd091SSascha Wildner 			is_string = 1;
1069c30bd091SSascha Wildner 			tag = "platform";
1070c30bd091SSascha Wildner 			break;
1071c30bd091SSascha Wildner 		case AT_LINUX_UID:
1072c30bd091SSascha Wildner 			is_string = 0;
1073c30bd091SSascha Wildner 			tag = "real uid";
1074c30bd091SSascha Wildner 			break;
1075c30bd091SSascha Wildner 		case AT_LINUX_GID:
1076c30bd091SSascha Wildner 			is_string = 0;
1077c30bd091SSascha Wildner 			tag = "real gid";
1078c30bd091SSascha Wildner 			break;
1079c30bd091SSascha Wildner 		case AT_LINUX_EUID:
1080c30bd091SSascha Wildner 			is_string = 0;
1081c30bd091SSascha Wildner 			tag = "effective uid";
1082c30bd091SSascha Wildner 			break;
1083c30bd091SSascha Wildner 		case AT_LINUX_EGID:
1084c30bd091SSascha Wildner 			is_string = 0;
1085c30bd091SSascha Wildner 			tag = "effective gid";
1086c30bd091SSascha Wildner 			break;
1087c30bd091SSascha Wildner 		default:
1088c30bd091SSascha Wildner 			is_string = 0;
1089c30bd091SSascha Wildner 			tag = NULL;
1090c30bd091SSascha Wildner 			break;
1091c30bd091SSascha Wildner 		}
1092c30bd091SSascha Wildner 
1093c30bd091SSascha Wildner 		if (tag == NULL)
1094c30bd091SSascha Wildner 			continue;
1095c30bd091SSascha Wildner 
1096c30bd091SSascha Wildner 		if (is_string) {
1097c30bd091SSascha Wildner 			char buf[256];
1098c30bd091SSascha Wildner 			ssize_t buflen;
1099c30bd091SSascha Wildner 			buflen = get_string_on_virtaddr(ms, swap, clazz, fd,
1100c30bd091SSascha Wildner 			    ph_off, ph_num, fsize, xauxv_val, buf, sizeof(buf));
1101c30bd091SSascha Wildner 
1102c30bd091SSascha Wildner 			if (buflen == 0)
1103c30bd091SSascha Wildner 				continue;
1104c30bd091SSascha Wildner 
1105c30bd091SSascha Wildner 			if (file_printf(ms, ", %s: '%s'", tag, buf) == -1)
11066fca56fbSSascha Wildner 				return -1;
1107c30bd091SSascha Wildner 		} else {
11086fca56fbSSascha Wildner 			if (file_printf(ms, ", %s: %d", tag,
11096fca56fbSSascha Wildner 			    CAST(int, xauxv_val)) == -1)
11106fca56fbSSascha Wildner 				return -1;
1111c30bd091SSascha Wildner 		}
1112c30bd091SSascha Wildner 	}
1113c30bd091SSascha Wildner 	return 1;
1114c30bd091SSascha Wildner #else
1115c30bd091SSascha Wildner 	return 0;
1116c30bd091SSascha Wildner #endif
1117c30bd091SSascha Wildner }
1118c30bd091SSascha Wildner 
111982c5fa3eSPeter Avalos private size_t
dodynamic(struct magic_set * ms,void * vbuf,size_t offset,size_t size,int clazz,int swap,int * pie,size_t * need)11206fca56fbSSascha Wildner dodynamic(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
1121970935fdSSascha Wildner     int clazz, int swap, int *pie, size_t *need)
11226fca56fbSSascha Wildner {
11236fca56fbSSascha Wildner 	Elf32_Dyn dh32;
11246fca56fbSSascha Wildner 	Elf64_Dyn dh64;
11256fca56fbSSascha Wildner 	unsigned char *dbuf = CAST(unsigned char *, vbuf);
11266fca56fbSSascha Wildner 
11276fca56fbSSascha Wildner 	if (xdh_sizeof + offset > size) {
11286fca56fbSSascha Wildner 		/*
11296fca56fbSSascha Wildner 		 * We're out of note headers.
11306fca56fbSSascha Wildner 		 */
11316fca56fbSSascha Wildner 		return xdh_sizeof + offset;
11326fca56fbSSascha Wildner 	}
11336fca56fbSSascha Wildner 
11346fca56fbSSascha Wildner 	memcpy(xdh_addr, &dbuf[offset], xdh_sizeof);
11356fca56fbSSascha Wildner 	offset += xdh_sizeof;
11366fca56fbSSascha Wildner 
11376fca56fbSSascha Wildner 	switch (xdh_tag) {
11386fca56fbSSascha Wildner 	case DT_FLAGS_1:
1139970935fdSSascha Wildner 		*pie = 1;
11406fca56fbSSascha Wildner 		if (xdh_val & DF_1_PIE)
11416fca56fbSSascha Wildner 			ms->mode |= 0111;
11426fca56fbSSascha Wildner 		else
11436fca56fbSSascha Wildner 			ms->mode &= ~0111;
11446fca56fbSSascha Wildner 		break;
1145970935fdSSascha Wildner 	case DT_NEEDED:
1146970935fdSSascha Wildner 		(*need)++;
1147970935fdSSascha Wildner 		break;
11486fca56fbSSascha Wildner 	default:
11496fca56fbSSascha Wildner 		break;
11506fca56fbSSascha Wildner 	}
11516fca56fbSSascha Wildner 	return offset;
11526fca56fbSSascha Wildner }
11536fca56fbSSascha Wildner 
11546fca56fbSSascha Wildner 
11556fca56fbSSascha Wildner private size_t
donote(struct magic_set * ms,void * vbuf,size_t offset,size_t size,int clazz,int swap,size_t align,int * flags,uint16_t * notecount,int fd,off_t ph_off,int ph_num,off_t fsize)115682c5fa3eSPeter Avalos donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
1157c30bd091SSascha Wildner     int clazz, int swap, size_t align, int *flags, uint16_t *notecount,
1158c30bd091SSascha Wildner     int fd, off_t ph_off, int ph_num, off_t fsize)
115982c5fa3eSPeter Avalos {
116082c5fa3eSPeter Avalos 	Elf32_Nhdr nh32;
116182c5fa3eSPeter Avalos 	Elf64_Nhdr nh64;
116282c5fa3eSPeter Avalos 	size_t noff, doff;
116382c5fa3eSPeter Avalos 	uint32_t namesz, descsz;
1164c990e5baSDaniel Fojt 	char buf[256];
116582c5fa3eSPeter Avalos 	unsigned char *nbuf = CAST(unsigned char *, vbuf);
116682c5fa3eSPeter Avalos 
116782c5fa3eSPeter Avalos 	if (*notecount == 0)
116882c5fa3eSPeter Avalos 		return 0;
116982c5fa3eSPeter Avalos 	--*notecount;
117082c5fa3eSPeter Avalos 
117182c5fa3eSPeter Avalos 	if (xnh_sizeof + offset > size) {
117282c5fa3eSPeter Avalos 		/*
117382c5fa3eSPeter Avalos 		 * We're out of note headers.
117482c5fa3eSPeter Avalos 		 */
117582c5fa3eSPeter Avalos 		return xnh_sizeof + offset;
117682c5fa3eSPeter Avalos 	}
11776fca56fbSSascha Wildner 	/*XXX: GCC */
11786fca56fbSSascha Wildner 	memset(&nh32, 0, sizeof(nh32));
11796fca56fbSSascha Wildner 	memset(&nh64, 0, sizeof(nh64));
118082c5fa3eSPeter Avalos 
11816fca56fbSSascha Wildner 	memcpy(xnh_addr, &nbuf[offset], xnh_sizeof);
118282c5fa3eSPeter Avalos 	offset += xnh_sizeof;
118382c5fa3eSPeter Avalos 
118482c5fa3eSPeter Avalos 	namesz = xnh_namesz;
118582c5fa3eSPeter Avalos 	descsz = xnh_descsz;
1186c30bd091SSascha Wildner 
118782c5fa3eSPeter Avalos 	if ((namesz == 0) && (descsz == 0)) {
118882c5fa3eSPeter Avalos 		/*
118982c5fa3eSPeter Avalos 		 * We're out of note headers.
119082c5fa3eSPeter Avalos 		 */
119182c5fa3eSPeter Avalos 		return (offset >= size) ? offset : size;
119282c5fa3eSPeter Avalos 	}
119382c5fa3eSPeter Avalos 
119482c5fa3eSPeter Avalos 	if (namesz & 0x80000000) {
1195614728caSSascha Wildner 	    (void)file_printf(ms, ", bad note name size %#lx",
1196614728caSSascha Wildner 		CAST(unsigned long, namesz));
119782c5fa3eSPeter Avalos 	    return 0;
119882c5fa3eSPeter Avalos 	}
119982c5fa3eSPeter Avalos 
120082c5fa3eSPeter Avalos 	if (descsz & 0x80000000) {
1201614728caSSascha Wildner 		(void)file_printf(ms, ", bad note description size %#lx",
1202614728caSSascha Wildner 		    CAST(unsigned long, descsz));
120382c5fa3eSPeter Avalos 		return 0;
120482c5fa3eSPeter Avalos 	}
120582c5fa3eSPeter Avalos 
120682c5fa3eSPeter Avalos 	noff = offset;
120782c5fa3eSPeter Avalos 	doff = ELF_ALIGN(offset + namesz);
120882c5fa3eSPeter Avalos 
120982c5fa3eSPeter Avalos 	if (offset + namesz > size) {
121082c5fa3eSPeter Avalos 		/*
121182c5fa3eSPeter Avalos 		 * We're past the end of the buffer.
121282c5fa3eSPeter Avalos 		 */
121382c5fa3eSPeter Avalos 		return doff;
121482c5fa3eSPeter Avalos 	}
121582c5fa3eSPeter Avalos 
121682c5fa3eSPeter Avalos 	offset = ELF_ALIGN(doff + descsz);
121782c5fa3eSPeter Avalos 	if (doff + descsz > size) {
121882c5fa3eSPeter Avalos 		/*
121982c5fa3eSPeter Avalos 		 * We're past the end of the buffer.
122082c5fa3eSPeter Avalos 		 */
122182c5fa3eSPeter Avalos 		return (offset >= size) ? offset : size;
122282c5fa3eSPeter Avalos 	}
122382c5fa3eSPeter Avalos 
1224c30bd091SSascha Wildner 
122582c5fa3eSPeter Avalos 	if ((*flags & FLAGS_DID_OS_NOTE) == 0) {
122682c5fa3eSPeter Avalos 		if (do_os_note(ms, nbuf, xnh_type, swap,
122782c5fa3eSPeter Avalos 		    namesz, descsz, noff, doff, flags))
1228c30bd091SSascha Wildner 			return offset;
122982c5fa3eSPeter Avalos 	}
123082c5fa3eSPeter Avalos 
123182c5fa3eSPeter Avalos 	if ((*flags & FLAGS_DID_BUILD_ID) == 0) {
123282c5fa3eSPeter Avalos 		if (do_bid_note(ms, nbuf, xnh_type, swap,
123382c5fa3eSPeter Avalos 		    namesz, descsz, noff, doff, flags))
1234c30bd091SSascha Wildner 			return offset;
123582c5fa3eSPeter Avalos 	}
123682c5fa3eSPeter Avalos 
123782c5fa3eSPeter Avalos 	if ((*flags & FLAGS_DID_NETBSD_PAX) == 0) {
123882c5fa3eSPeter Avalos 		if (do_pax_note(ms, nbuf, xnh_type, swap,
123982c5fa3eSPeter Avalos 		    namesz, descsz, noff, doff, flags))
1240c30bd091SSascha Wildner 			return offset;
124182c5fa3eSPeter Avalos 	}
124282c5fa3eSPeter Avalos 
124382c5fa3eSPeter Avalos 	if ((*flags & FLAGS_DID_CORE) == 0) {
124482c5fa3eSPeter Avalos 		if (do_core_note(ms, nbuf, xnh_type, swap,
124582c5fa3eSPeter Avalos 		    namesz, descsz, noff, doff, flags, size, clazz))
1246c30bd091SSascha Wildner 			return offset;
1247c30bd091SSascha Wildner 	}
1248c30bd091SSascha Wildner 
1249c30bd091SSascha Wildner 	if ((*flags & FLAGS_DID_AUXV) == 0) {
1250c30bd091SSascha Wildner 		if (do_auxv_note(ms, nbuf, xnh_type, swap,
1251c30bd091SSascha Wildner 			namesz, descsz, noff, doff, flags, size, clazz,
1252c30bd091SSascha Wildner 			fd, ph_off, ph_num, fsize))
1253c30bd091SSascha Wildner 			return offset;
125482c5fa3eSPeter Avalos 	}
125582c5fa3eSPeter Avalos 
12566fca56fbSSascha Wildner 	if (namesz == 7 && strcmp(RCAST(char *, &nbuf[noff]), "NetBSD") == 0) {
12576fca56fbSSascha Wildner 		int descw, flag;
12586fca56fbSSascha Wildner 		const char *str, *tag;
125982c5fa3eSPeter Avalos 		if (descsz > 100)
126082c5fa3eSPeter Avalos 			descsz = 100;
126182c5fa3eSPeter Avalos 		switch (xnh_type) {
126282c5fa3eSPeter Avalos 	    	case NT_NETBSD_VERSION:
1263c30bd091SSascha Wildner 			return offset;
126482c5fa3eSPeter Avalos 		case NT_NETBSD_MARCH:
12656fca56fbSSascha Wildner 			flag = FLAGS_DID_NETBSD_MARCH;
12666fca56fbSSascha Wildner 			tag = "compiled for";
126782c5fa3eSPeter Avalos 			break;
126882c5fa3eSPeter Avalos 		case NT_NETBSD_CMODEL:
12696fca56fbSSascha Wildner 			flag = FLAGS_DID_NETBSD_CMODEL;
12706fca56fbSSascha Wildner 			tag = "compiler model";
12716fca56fbSSascha Wildner 			break;
12726fca56fbSSascha Wildner 		case NT_NETBSD_EMULATION:
12736fca56fbSSascha Wildner 			flag = FLAGS_DID_NETBSD_EMULATION;
12746fca56fbSSascha Wildner 			tag = "emulation:";
127582c5fa3eSPeter Avalos 			break;
127682c5fa3eSPeter Avalos 		default:
127782c5fa3eSPeter Avalos 			if (*flags & FLAGS_DID_NETBSD_UNKNOWN)
1278c30bd091SSascha Wildner 				return offset;
127982c5fa3eSPeter Avalos 			*flags |= FLAGS_DID_NETBSD_UNKNOWN;
128082c5fa3eSPeter Avalos 			if (file_printf(ms, ", note=%u", xnh_type) == -1)
1281c30bd091SSascha Wildner 				return offset;
12826fca56fbSSascha Wildner 			return offset;
128382c5fa3eSPeter Avalos 		}
12846fca56fbSSascha Wildner 
12856fca56fbSSascha Wildner 		if (*flags & flag)
12866fca56fbSSascha Wildner 			return offset;
12876fca56fbSSascha Wildner 		str = RCAST(const char *, &nbuf[doff]);
12886fca56fbSSascha Wildner 		descw = CAST(int, descsz);
12896fca56fbSSascha Wildner 		*flags |= flag;
1290c990e5baSDaniel Fojt 		file_printf(ms, ", %s: %s", tag,
1291c990e5baSDaniel Fojt 		    file_copystr(buf, sizeof(buf), descw, str));
1292c30bd091SSascha Wildner 		return offset;
129382c5fa3eSPeter Avalos 	}
129482c5fa3eSPeter Avalos 
1295327e51cbSPeter Avalos 	return offset;
1296327e51cbSPeter Avalos }
1297327e51cbSPeter Avalos 
129879343712SPeter Avalos /* SunOS 5.x hardware capability descriptions */
129979343712SPeter Avalos typedef struct cap_desc {
130079343712SPeter Avalos 	uint64_t cd_mask;
130179343712SPeter Avalos 	const char *cd_name;
130279343712SPeter Avalos } cap_desc_t;
130379343712SPeter Avalos 
130479343712SPeter Avalos static const cap_desc_t cap_desc_sparc[] = {
130579343712SPeter Avalos 	{ AV_SPARC_MUL32,		"MUL32" },
130679343712SPeter Avalos 	{ AV_SPARC_DIV32,		"DIV32" },
130779343712SPeter Avalos 	{ AV_SPARC_FSMULD,		"FSMULD" },
130879343712SPeter Avalos 	{ AV_SPARC_V8PLUS,		"V8PLUS" },
130979343712SPeter Avalos 	{ AV_SPARC_POPC,		"POPC" },
131079343712SPeter Avalos 	{ AV_SPARC_VIS,			"VIS" },
131179343712SPeter Avalos 	{ AV_SPARC_VIS2,		"VIS2" },
131279343712SPeter Avalos 	{ AV_SPARC_ASI_BLK_INIT,	"ASI_BLK_INIT" },
131379343712SPeter Avalos 	{ AV_SPARC_FMAF,		"FMAF" },
131479343712SPeter Avalos 	{ AV_SPARC_FJFMAU,		"FJFMAU" },
131579343712SPeter Avalos 	{ AV_SPARC_IMA,			"IMA" },
131679343712SPeter Avalos 	{ 0, NULL }
131779343712SPeter Avalos };
131879343712SPeter Avalos 
131979343712SPeter Avalos static const cap_desc_t cap_desc_386[] = {
132079343712SPeter Avalos 	{ AV_386_FPU,			"FPU" },
132179343712SPeter Avalos 	{ AV_386_TSC,			"TSC" },
132279343712SPeter Avalos 	{ AV_386_CX8,			"CX8" },
132379343712SPeter Avalos 	{ AV_386_SEP,			"SEP" },
132479343712SPeter Avalos 	{ AV_386_AMD_SYSC,		"AMD_SYSC" },
132579343712SPeter Avalos 	{ AV_386_CMOV,			"CMOV" },
132679343712SPeter Avalos 	{ AV_386_MMX,			"MMX" },
132779343712SPeter Avalos 	{ AV_386_AMD_MMX,		"AMD_MMX" },
132879343712SPeter Avalos 	{ AV_386_AMD_3DNow,		"AMD_3DNow" },
132979343712SPeter Avalos 	{ AV_386_AMD_3DNowx,		"AMD_3DNowx" },
133079343712SPeter Avalos 	{ AV_386_FXSR,			"FXSR" },
133179343712SPeter Avalos 	{ AV_386_SSE,			"SSE" },
133279343712SPeter Avalos 	{ AV_386_SSE2,			"SSE2" },
133379343712SPeter Avalos 	{ AV_386_PAUSE,			"PAUSE" },
133479343712SPeter Avalos 	{ AV_386_SSE3,			"SSE3" },
133579343712SPeter Avalos 	{ AV_386_MON,			"MON" },
133679343712SPeter Avalos 	{ AV_386_CX16,			"CX16" },
133779343712SPeter Avalos 	{ AV_386_AHF,			"AHF" },
133879343712SPeter Avalos 	{ AV_386_TSCP,			"TSCP" },
133979343712SPeter Avalos 	{ AV_386_AMD_SSE4A,		"AMD_SSE4A" },
134079343712SPeter Avalos 	{ AV_386_POPCNT,		"POPCNT" },
134179343712SPeter Avalos 	{ AV_386_AMD_LZCNT,		"AMD_LZCNT" },
134279343712SPeter Avalos 	{ AV_386_SSSE3,			"SSSE3" },
134379343712SPeter Avalos 	{ AV_386_SSE4_1,		"SSE4.1" },
134479343712SPeter Avalos 	{ AV_386_SSE4_2,		"SSE4.2" },
134579343712SPeter Avalos 	{ 0, NULL }
134679343712SPeter Avalos };
134779343712SPeter Avalos 
1348327e51cbSPeter Avalos private int
doshn(struct magic_set * ms,int clazz,int swap,int fd,off_t off,int num,size_t size,off_t fsize,int mach,int strtab,int * flags,uint16_t * notecount)134979343712SPeter Avalos doshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num,
135082c5fa3eSPeter Avalos     size_t size, off_t fsize, int mach, int strtab, int *flags,
135182c5fa3eSPeter Avalos     uint16_t *notecount)
1352327e51cbSPeter Avalos {
1353327e51cbSPeter Avalos 	Elf32_Shdr sh32;
1354327e51cbSPeter Avalos 	Elf64_Shdr sh64;
1355c30bd091SSascha Wildner 	int stripped = 1, has_debug_info = 0;
135682c5fa3eSPeter Avalos 	size_t nbadcap = 0;
1357327e51cbSPeter Avalos 	void *nbuf;
1358970935fdSSascha Wildner 	off_t noff, coff, name_off, offs;
1359c30bd091SSascha Wildner 	uint64_t cap_hw1 = 0;	/* SunOS 5.x hardware capabilities */
1360c30bd091SSascha Wildner 	uint64_t cap_sf1 = 0;	/* SunOS 5.x software capabilities */
1361e8af9738SPeter Avalos 	char name[50];
136282c5fa3eSPeter Avalos 	ssize_t namesize;
1363327e51cbSPeter Avalos 
1364c990e5baSDaniel Fojt 	if (ms->flags & MAGIC_MIME)
1365c990e5baSDaniel Fojt 		return 0;
1366c990e5baSDaniel Fojt 
13676fca56fbSSascha Wildner 	if (num == 0) {
13686fca56fbSSascha Wildner 		if (file_printf(ms, ", no section header") == -1)
13696fca56fbSSascha Wildner 			return -1;
13706fca56fbSSascha Wildner 		return 0;
13716fca56fbSSascha Wildner 	}
1372327e51cbSPeter Avalos 	if (size != xsh_sizeof) {
1373327e51cbSPeter Avalos 		if (file_printf(ms, ", corrupted section header size") == -1)
1374327e51cbSPeter Avalos 			return -1;
1375327e51cbSPeter Avalos 		return 0;
1376327e51cbSPeter Avalos 	}
1377327e51cbSPeter Avalos 
1378e8af9738SPeter Avalos 	/* Read offset of name section to be able to read section names later */
1379970935fdSSascha Wildner 	offs = CAST(off_t, (off + size * strtab));
1380970935fdSSascha Wildner 	if (pread(fd, xsh_addr, xsh_sizeof, offs) < CAST(ssize_t, xsh_sizeof)) {
1381970935fdSSascha Wildner 		if (file_printf(ms, ", missing section headers at %jd",
1382970935fdSSascha Wildner 		    (intmax_t)offs) == -1)
1383327e51cbSPeter Avalos 			return -1;
1384c30bd091SSascha Wildner 		return 0;
1385327e51cbSPeter Avalos 	}
1386e8af9738SPeter Avalos 	name_off = xsh_offset;
1387e8af9738SPeter Avalos 
13886fca56fbSSascha Wildner 	if (fsize != SIZE_UNKNOWN && fsize < name_off) {
1389c990e5baSDaniel Fojt 		if (file_printf(ms, ", too large section header offset %jd",
1390c990e5baSDaniel Fojt 		    (intmax_t)name_off) == -1)
13916fca56fbSSascha Wildner 			return -1;
13926fca56fbSSascha Wildner 		return 0;
13936fca56fbSSascha Wildner 	}
13946fca56fbSSascha Wildner 
1395e8af9738SPeter Avalos 	for ( ; num; num--) {
1396e8af9738SPeter Avalos 		/* Read the name of this section. */
1397970935fdSSascha Wildner 		offs = name_off + xsh_name;
1398970935fdSSascha Wildner 		if ((namesize = pread(fd, name, sizeof(name) - 1, offs))
1399970935fdSSascha Wildner 		    == -1) {
1400970935fdSSascha Wildner 			if (file_printf(ms,
1401970935fdSSascha Wildner 			    ", can't read name of elf section at %jd",
1402970935fdSSascha Wildner 			    (intmax_t)offs) == -1)
1403e8af9738SPeter Avalos 				return -1;
1404970935fdSSascha Wildner 			return 0;
1405e8af9738SPeter Avalos 		}
140682c5fa3eSPeter Avalos 		name[namesize] = '\0';
1407c30bd091SSascha Wildner 		if (strcmp(name, ".debug_info") == 0) {
1408c30bd091SSascha Wildner 			has_debug_info = 1;
1409e8af9738SPeter Avalos 			stripped = 0;
1410c30bd091SSascha Wildner 		}
1411e8af9738SPeter Avalos 
14126fca56fbSSascha Wildner 		if (pread(fd, xsh_addr, xsh_sizeof, off) <
14136fca56fbSSascha Wildner 		    CAST(ssize_t, xsh_sizeof)) {
1414970935fdSSascha Wildner 			if (file_printf(ms, ", can't read elf section at %jd",
1415970935fdSSascha Wildner 			    (intmax_t)off) == -1)
1416327e51cbSPeter Avalos 				return -1;
1417970935fdSSascha Wildner 			return 0;
1418327e51cbSPeter Avalos 		}
1419a96e001bSPeter Avalos 		off += size;
1420a96e001bSPeter Avalos 
1421a96e001bSPeter Avalos 		/* Things we can determine before we seek */
1422327e51cbSPeter Avalos 		switch (xsh_type) {
1423327e51cbSPeter Avalos 		case SHT_SYMTAB:
1424327e51cbSPeter Avalos #if 0
1425327e51cbSPeter Avalos 		case SHT_DYNSYM:
1426327e51cbSPeter Avalos #endif
1427327e51cbSPeter Avalos 			stripped = 0;
1428327e51cbSPeter Avalos 			break;
1429a96e001bSPeter Avalos 		default:
143082c5fa3eSPeter Avalos 			if (fsize != SIZE_UNKNOWN && xsh_offset > fsize) {
1431a96e001bSPeter Avalos 				/* Perhaps warn here */
1432a96e001bSPeter Avalos 				continue;
1433327e51cbSPeter Avalos 			}
1434a96e001bSPeter Avalos 			break;
1435a96e001bSPeter Avalos 		}
1436a96e001bSPeter Avalos 
1437c30bd091SSascha Wildner 
1438a96e001bSPeter Avalos 		/* Things we can determine when we seek */
1439a96e001bSPeter Avalos 		switch (xsh_type) {
1440a96e001bSPeter Avalos 		case SHT_NOTE:
14416fca56fbSSascha Wildner 			if (CAST(uintmax_t, (xsh_size + xsh_offset)) >
14426fca56fbSSascha Wildner 			    CAST(uintmax_t, fsize)) {
1443c30bd091SSascha Wildner 				if (file_printf(ms,
1444c30bd091SSascha Wildner 				    ", note offset/size %#" INTMAX_T_FORMAT
1445c30bd091SSascha Wildner 				    "x+%#" INTMAX_T_FORMAT "x exceeds"
1446c30bd091SSascha Wildner 				    " file size %#" INTMAX_T_FORMAT "x",
14476fca56fbSSascha Wildner 				    CAST(uintmax_t, xsh_offset),
14486fca56fbSSascha Wildner 				    CAST(uintmax_t, xsh_size),
14496fca56fbSSascha Wildner 				    CAST(uintmax_t, fsize)) == -1)
1450c30bd091SSascha Wildner 					return -1;
1451c30bd091SSascha Wildner 				return 0;
1452c30bd091SSascha Wildner 			}
1453*3b9cdfa3SAntonio Huete Jimenez 			if (xsh_size > MAX_SHSIZE) {
1454*3b9cdfa3SAntonio Huete Jimenez 				file_error(ms, errno, "Note section size too "
1455*3b9cdfa3SAntonio Huete Jimenez 				    "big (%ju > %u)", (uintmax_t)xsh_size,
1456*3b9cdfa3SAntonio Huete Jimenez 				    MAX_SHSIZE);
1457*3b9cdfa3SAntonio Huete Jimenez 				return -1;
1458*3b9cdfa3SAntonio Huete Jimenez 			}
1459e8af9738SPeter Avalos 			if ((nbuf = malloc(xsh_size)) == NULL) {
1460327e51cbSPeter Avalos 				file_error(ms, errno, "Cannot allocate memory"
1461327e51cbSPeter Avalos 				    " for note");
1462327e51cbSPeter Avalos 				return -1;
1463327e51cbSPeter Avalos 			}
1464970935fdSSascha Wildner 			offs = xsh_offset;
1465970935fdSSascha Wildner 			if (pread(fd, nbuf, xsh_size, offs) <
14666fca56fbSSascha Wildner 			    CAST(ssize_t, xsh_size)) {
1467327e51cbSPeter Avalos 				free(nbuf);
1468970935fdSSascha Wildner 				if (file_printf(ms,
1469970935fdSSascha Wildner 				    ", can't read elf note at %jd",
1470970935fdSSascha Wildner 				    (intmax_t)offs) == -1)
1471327e51cbSPeter Avalos 					return -1;
1472970935fdSSascha Wildner 				return 0;
1473327e51cbSPeter Avalos 			}
1474327e51cbSPeter Avalos 
1475327e51cbSPeter Avalos 			noff = 0;
1476327e51cbSPeter Avalos 			for (;;) {
14776fca56fbSSascha Wildner 				if (noff >= CAST(off_t, xsh_size))
1478327e51cbSPeter Avalos 					break;
14796fca56fbSSascha Wildner 				noff = donote(ms, nbuf, CAST(size_t, noff),
1480c30bd091SSascha Wildner 				    xsh_size, clazz, swap, 4, flags, notecount,
1481c30bd091SSascha Wildner 				    fd, 0, 0, 0);
1482327e51cbSPeter Avalos 				if (noff == 0)
1483327e51cbSPeter Avalos 					break;
1484327e51cbSPeter Avalos 			}
1485327e51cbSPeter Avalos 			free(nbuf);
1486327e51cbSPeter Avalos 			break;
148779343712SPeter Avalos 		case SHT_SUNW_cap:
1488e8af9738SPeter Avalos 			switch (mach) {
1489e8af9738SPeter Avalos 			case EM_SPARC:
1490e8af9738SPeter Avalos 			case EM_SPARCV9:
1491e8af9738SPeter Avalos 			case EM_IA_64:
1492e8af9738SPeter Avalos 			case EM_386:
1493e8af9738SPeter Avalos 			case EM_AMD64:
1494e8af9738SPeter Avalos 				break;
1495e8af9738SPeter Avalos 			default:
1496e8af9738SPeter Avalos 				goto skip;
1497e8af9738SPeter Avalos 			}
1498e8af9738SPeter Avalos 
149982c5fa3eSPeter Avalos 			if (nbadcap > 5)
150082c5fa3eSPeter Avalos 				break;
15016fca56fbSSascha Wildner 			if (lseek(fd, xsh_offset, SEEK_SET)
15026fca56fbSSascha Wildner 			    == CAST(off_t, -1)) {
1503a96e001bSPeter Avalos 				file_badseek(ms);
150479343712SPeter Avalos 				return -1;
150579343712SPeter Avalos 			}
150679343712SPeter Avalos 			coff = 0;
150779343712SPeter Avalos 			for (;;) {
150879343712SPeter Avalos 				Elf32_Cap cap32;
150979343712SPeter Avalos 				Elf64_Cap cap64;
151079343712SPeter Avalos 				char cbuf[/*CONSTCOND*/
15116fca56fbSSascha Wildner 				    MAX(sizeof(cap32), sizeof(cap64))];
15126fca56fbSSascha Wildner 				if ((coff += xcap_sizeof) >
15136fca56fbSSascha Wildner 				    CAST(off_t, xsh_size))
151479343712SPeter Avalos 					break;
15156fca56fbSSascha Wildner 				if (read(fd, cbuf, CAST(size_t, xcap_sizeof)) !=
15166fca56fbSSascha Wildner 				    CAST(ssize_t, xcap_sizeof)) {
151779343712SPeter Avalos 					file_badread(ms);
151879343712SPeter Avalos 					return -1;
151979343712SPeter Avalos 				}
152082c5fa3eSPeter Avalos 				if (cbuf[0] == 'A') {
152182c5fa3eSPeter Avalos #ifdef notyet
152282c5fa3eSPeter Avalos 					char *p = cbuf + 1;
152382c5fa3eSPeter Avalos 					uint32_t len, tag;
152482c5fa3eSPeter Avalos 					memcpy(&len, p, sizeof(len));
152582c5fa3eSPeter Avalos 					p += 4;
152682c5fa3eSPeter Avalos 					len = getu32(swap, len);
152782c5fa3eSPeter Avalos 					if (memcmp("gnu", p, 3) != 0) {
152882c5fa3eSPeter Avalos 					    if (file_printf(ms,
152982c5fa3eSPeter Avalos 						", unknown capability %.3s", p)
153082c5fa3eSPeter Avalos 						== -1)
153182c5fa3eSPeter Avalos 						return -1;
153282c5fa3eSPeter Avalos 					    break;
153382c5fa3eSPeter Avalos 					}
153482c5fa3eSPeter Avalos 					p += strlen(p) + 1;
153582c5fa3eSPeter Avalos 					tag = *p++;
153682c5fa3eSPeter Avalos 					memcpy(&len, p, sizeof(len));
153782c5fa3eSPeter Avalos 					p += 4;
153882c5fa3eSPeter Avalos 					len = getu32(swap, len);
153982c5fa3eSPeter Avalos 					if (tag != 1) {
154082c5fa3eSPeter Avalos 					    if (file_printf(ms, ", unknown gnu"
154182c5fa3eSPeter Avalos 						" capability tag %d", tag)
154282c5fa3eSPeter Avalos 						== -1)
154382c5fa3eSPeter Avalos 						return -1;
154482c5fa3eSPeter Avalos 					    break;
154582c5fa3eSPeter Avalos 					}
154682c5fa3eSPeter Avalos 					// gnu attributes
154782c5fa3eSPeter Avalos #endif
154882c5fa3eSPeter Avalos 					break;
154982c5fa3eSPeter Avalos 				}
15506fca56fbSSascha Wildner 				memcpy(xcap_addr, cbuf, xcap_sizeof);
155179343712SPeter Avalos 				switch (xcap_tag) {
155279343712SPeter Avalos 				case CA_SUNW_NULL:
155379343712SPeter Avalos 					break;
155479343712SPeter Avalos 				case CA_SUNW_HW_1:
155579343712SPeter Avalos 					cap_hw1 |= xcap_val;
155679343712SPeter Avalos 					break;
155779343712SPeter Avalos 				case CA_SUNW_SF_1:
155879343712SPeter Avalos 					cap_sf1 |= xcap_val;
155979343712SPeter Avalos 					break;
156079343712SPeter Avalos 				default:
156179343712SPeter Avalos 					if (file_printf(ms,
156279343712SPeter Avalos 					    ", with unknown capability "
1563c30bd091SSascha Wildner 					    "%#" INT64_T_FORMAT "x = %#"
1564e4d4ce0cSPeter Avalos 					    INT64_T_FORMAT "x",
15656fca56fbSSascha Wildner 					    CAST(unsigned long long, xcap_tag),
15666fca56fbSSascha Wildner 					    CAST(unsigned long long, xcap_val))
15676fca56fbSSascha Wildner 					    == -1)
156879343712SPeter Avalos 						return -1;
156982c5fa3eSPeter Avalos 					if (nbadcap++ > 2)
157082c5fa3eSPeter Avalos 						coff = xsh_size;
157179343712SPeter Avalos 					break;
157279343712SPeter Avalos 				}
157379343712SPeter Avalos 			}
1574e8af9738SPeter Avalos 			/*FALLTHROUGH*/
1575e8af9738SPeter Avalos 		skip:
1576a96e001bSPeter Avalos 		default:
1577a96e001bSPeter Avalos 			break;
1578327e51cbSPeter Avalos 		}
1579327e51cbSPeter Avalos 	}
1580e8af9738SPeter Avalos 
1581c30bd091SSascha Wildner 	if (has_debug_info) {
1582c30bd091SSascha Wildner 		if (file_printf(ms, ", with debug_info") == -1)
1583c30bd091SSascha Wildner 			return -1;
1584c30bd091SSascha Wildner 	}
1585327e51cbSPeter Avalos 	if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1)
1586327e51cbSPeter Avalos 		return -1;
158779343712SPeter Avalos 	if (cap_hw1) {
158879343712SPeter Avalos 		const cap_desc_t *cdp;
158979343712SPeter Avalos 		switch (mach) {
159079343712SPeter Avalos 		case EM_SPARC:
159179343712SPeter Avalos 		case EM_SPARC32PLUS:
159279343712SPeter Avalos 		case EM_SPARCV9:
159379343712SPeter Avalos 			cdp = cap_desc_sparc;
159479343712SPeter Avalos 			break;
159579343712SPeter Avalos 		case EM_386:
159679343712SPeter Avalos 		case EM_IA_64:
159779343712SPeter Avalos 		case EM_AMD64:
159879343712SPeter Avalos 			cdp = cap_desc_386;
159979343712SPeter Avalos 			break;
160079343712SPeter Avalos 		default:
160179343712SPeter Avalos 			cdp = NULL;
160279343712SPeter Avalos 			break;
160379343712SPeter Avalos 		}
160479343712SPeter Avalos 		if (file_printf(ms, ", uses") == -1)
160579343712SPeter Avalos 			return -1;
160679343712SPeter Avalos 		if (cdp) {
160779343712SPeter Avalos 			while (cdp->cd_name) {
160879343712SPeter Avalos 				if (cap_hw1 & cdp->cd_mask) {
160979343712SPeter Avalos 					if (file_printf(ms,
161079343712SPeter Avalos 					    " %s", cdp->cd_name) == -1)
161179343712SPeter Avalos 						return -1;
161279343712SPeter Avalos 					cap_hw1 &= ~cdp->cd_mask;
161379343712SPeter Avalos 				}
161479343712SPeter Avalos 				++cdp;
161579343712SPeter Avalos 			}
161679343712SPeter Avalos 			if (cap_hw1)
161779343712SPeter Avalos 				if (file_printf(ms,
1618c30bd091SSascha Wildner 				    " unknown hardware capability %#"
1619e4d4ce0cSPeter Avalos 				    INT64_T_FORMAT "x",
16206fca56fbSSascha Wildner 				    CAST(unsigned long long, cap_hw1)) == -1)
162179343712SPeter Avalos 					return -1;
162279343712SPeter Avalos 		} else {
162379343712SPeter Avalos 			if (file_printf(ms,
1624c30bd091SSascha Wildner 			    " hardware capability %#" INT64_T_FORMAT "x",
16256fca56fbSSascha Wildner 			    CAST(unsigned long long, cap_hw1)) == -1)
162679343712SPeter Avalos 				return -1;
162779343712SPeter Avalos 		}
162879343712SPeter Avalos 	}
162979343712SPeter Avalos 	if (cap_sf1) {
163079343712SPeter Avalos 		if (cap_sf1 & SF1_SUNW_FPUSED) {
163179343712SPeter Avalos 			if (file_printf(ms,
163279343712SPeter Avalos 			    (cap_sf1 & SF1_SUNW_FPKNWN)
163379343712SPeter Avalos 			    ? ", uses frame pointer"
163479343712SPeter Avalos 			    : ", not known to use frame pointer") == -1)
163579343712SPeter Avalos 				return -1;
163679343712SPeter Avalos 		}
163779343712SPeter Avalos 		cap_sf1 &= ~SF1_SUNW_MASK;
163879343712SPeter Avalos 		if (cap_sf1)
163979343712SPeter Avalos 			if (file_printf(ms,
1640c30bd091SSascha Wildner 			    ", with unknown software capability %#"
1641e4d4ce0cSPeter Avalos 			    INT64_T_FORMAT "x",
16426fca56fbSSascha Wildner 			    CAST(unsigned long long, cap_sf1)) == -1)
164379343712SPeter Avalos 				return -1;
164479343712SPeter Avalos 	}
1645327e51cbSPeter Avalos 	return 0;
1646327e51cbSPeter Avalos }
1647327e51cbSPeter Avalos 
1648327e51cbSPeter Avalos /*
1649970935fdSSascha Wildner  * Look through the program headers of an executable image, to determine
1650970935fdSSascha Wildner  * if it is statically or dynamically linked. If it has a dynamic section,
1651970935fdSSascha Wildner  * it is pie, and does not have an interpreter or needed libraries, we
1652970935fdSSascha Wildner  * call it static pie.
1653327e51cbSPeter Avalos  */
1654327e51cbSPeter Avalos private int
dophn_exec(struct magic_set * ms,int clazz,int swap,int fd,off_t off,int num,size_t size,off_t fsize,int sh_num,int * flags,uint16_t * notecount)165579343712SPeter Avalos dophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off,
165682c5fa3eSPeter Avalos     int num, size_t size, off_t fsize, int sh_num, int *flags,
165782c5fa3eSPeter Avalos     uint16_t *notecount)
1658327e51cbSPeter Avalos {
1659327e51cbSPeter Avalos 	Elf32_Phdr ph32;
1660327e51cbSPeter Avalos 	Elf64_Phdr ph64;
1661970935fdSSascha Wildner 	const char *linking_style;
1662327e51cbSPeter Avalos 	unsigned char nbuf[BUFSIZ];
166382c5fa3eSPeter Avalos 	char ibuf[BUFSIZ];
16646fca56fbSSascha Wildner 	char interp[BUFSIZ];
1665f72f8299SJan Lentfer 	ssize_t bufsize;
1666*3b9cdfa3SAntonio Huete Jimenez 	size_t offset, align, need = 0;
1667970935fdSSascha Wildner 	int pie = 0, dynamic = 0;
1668327e51cbSPeter Avalos 
16696fca56fbSSascha Wildner 	if (num == 0) {
16706fca56fbSSascha Wildner 		if (file_printf(ms, ", no program header") == -1)
16716fca56fbSSascha Wildner 			return -1;
16726fca56fbSSascha Wildner 		return 0;
16736fca56fbSSascha Wildner 	}
1674327e51cbSPeter Avalos 	if (size != xph_sizeof) {
1675327e51cbSPeter Avalos 		if (file_printf(ms, ", corrupted program header size") == -1)
1676327e51cbSPeter Avalos 			return -1;
1677327e51cbSPeter Avalos 		return 0;
1678327e51cbSPeter Avalos 	}
1679327e51cbSPeter Avalos 
16806fca56fbSSascha Wildner 	interp[0] = '\0';
1681a96e001bSPeter Avalos   	for ( ; num; num--) {
16826fca56fbSSascha Wildner 		int doread;
16836fca56fbSSascha Wildner 		if (pread(fd, xph_addr, xph_sizeof, off) <
16846fca56fbSSascha Wildner 		    CAST(ssize_t, xph_sizeof)) {
1685970935fdSSascha Wildner 			if (file_printf(ms,
1686970935fdSSascha Wildner 			    ", can't read elf program headers at %jd",
1687970935fdSSascha Wildner 			    (intmax_t)off) == -1)
1688327e51cbSPeter Avalos 				return -1;
1689970935fdSSascha Wildner 			return 0;
1690327e51cbSPeter Avalos 		}
1691327e51cbSPeter Avalos 
1692a96e001bSPeter Avalos 		off += size;
169382c5fa3eSPeter Avalos 		bufsize = 0;
169482c5fa3eSPeter Avalos 		align = 4;
1695327e51cbSPeter Avalos 
1696a96e001bSPeter Avalos 		/* Things we can determine before we seek */
1697327e51cbSPeter Avalos 		switch (xph_type) {
1698327e51cbSPeter Avalos 		case PT_DYNAMIC:
16996fca56fbSSascha Wildner 			doread = 1;
1700327e51cbSPeter Avalos 			break;
170182c5fa3eSPeter Avalos 		case PT_NOTE:
170282c5fa3eSPeter Avalos 			if (sh_num)	/* Did this through section headers */
170382c5fa3eSPeter Avalos 				continue;
170482c5fa3eSPeter Avalos 			if (((align = xph_align) & 0x80000000UL) != 0 ||
170582c5fa3eSPeter Avalos 			    align < 4) {
170682c5fa3eSPeter Avalos 				if (file_printf(ms,
1707c30bd091SSascha Wildner 				    ", invalid note alignment %#lx",
17086fca56fbSSascha Wildner 				    CAST(unsigned long, align)) == -1)
170982c5fa3eSPeter Avalos 					return -1;
171082c5fa3eSPeter Avalos 				align = 4;
171182c5fa3eSPeter Avalos 			}
171282c5fa3eSPeter Avalos 			/*FALLTHROUGH*/
1713327e51cbSPeter Avalos 		case PT_INTERP:
17146fca56fbSSascha Wildner 			doread = 1;
1715327e51cbSPeter Avalos 			break;
1716a96e001bSPeter Avalos 		default:
17176fca56fbSSascha Wildner 			doread = 0;
171882c5fa3eSPeter Avalos 			if (fsize != SIZE_UNKNOWN && xph_offset > fsize) {
1719a96e001bSPeter Avalos 				/* Maybe warn here? */
1720a96e001bSPeter Avalos 				continue;
1721a96e001bSPeter Avalos 			}
1722a96e001bSPeter Avalos 			break;
1723a96e001bSPeter Avalos 		}
1724a96e001bSPeter Avalos 
17256fca56fbSSascha Wildner 		if (doread) {
1726*3b9cdfa3SAntonio Huete Jimenez 			size_t len = xph_filesz < sizeof(nbuf) ? xph_filesz
17276fca56fbSSascha Wildner 			    : sizeof(nbuf);
1728970935fdSSascha Wildner 			off_t offs = xph_offset;
1729970935fdSSascha Wildner 			bufsize = pread(fd, nbuf, len, offs);
17306fca56fbSSascha Wildner 			if (bufsize == -1) {
1731970935fdSSascha Wildner 				if (file_printf(ms,
1732970935fdSSascha Wildner 				    ", can't read section at %jd",
1733970935fdSSascha Wildner 				    (intmax_t)offs) == -1)
17346fca56fbSSascha Wildner 					return -1;
1735970935fdSSascha Wildner 				return 0;
17366fca56fbSSascha Wildner 			}
1737*3b9cdfa3SAntonio Huete Jimenez 		}
17386fca56fbSSascha Wildner 
1739a96e001bSPeter Avalos 		/* Things we can determine when we seek */
1740a96e001bSPeter Avalos 		switch (xph_type) {
17416fca56fbSSascha Wildner 		case PT_DYNAMIC:
1742970935fdSSascha Wildner 			dynamic = 1;
17436fca56fbSSascha Wildner 			offset = 0;
17446fca56fbSSascha Wildner 			// Let DF_1 determine if we are PIE or not.
17456fca56fbSSascha Wildner 			ms->mode &= ~0111;
17466fca56fbSSascha Wildner 			for (;;) {
17476fca56fbSSascha Wildner 				if (offset >= CAST(size_t, bufsize))
17486fca56fbSSascha Wildner 					break;
17496fca56fbSSascha Wildner 				offset = dodynamic(ms, nbuf, offset,
1750970935fdSSascha Wildner 				    CAST(size_t, bufsize), clazz, swap,
1751970935fdSSascha Wildner 				    &pie, &need);
17526fca56fbSSascha Wildner 				if (offset == 0)
17536fca56fbSSascha Wildner 					break;
17546fca56fbSSascha Wildner 			}
1755c990e5baSDaniel Fojt 			if (ms->flags & MAGIC_MIME)
1756c990e5baSDaniel Fojt 				continue;
17576fca56fbSSascha Wildner 			break;
17586fca56fbSSascha Wildner 
175982c5fa3eSPeter Avalos 		case PT_INTERP:
1760970935fdSSascha Wildner 			need++;
1761c990e5baSDaniel Fojt 			if (ms->flags & MAGIC_MIME)
1762c990e5baSDaniel Fojt 				continue;
176382c5fa3eSPeter Avalos 			if (bufsize && nbuf[0]) {
176482c5fa3eSPeter Avalos 				nbuf[bufsize - 1] = '\0';
17656fca56fbSSascha Wildner 				memcpy(interp, nbuf, CAST(size_t, bufsize));
176682c5fa3eSPeter Avalos 			} else
17676fca56fbSSascha Wildner 				strlcpy(interp, "*empty*", sizeof(interp));
176879343712SPeter Avalos 			break;
176982c5fa3eSPeter Avalos 		case PT_NOTE:
1770c990e5baSDaniel Fojt 			if (ms->flags & MAGIC_MIME)
1771c990e5baSDaniel Fojt 				return 0;
1772327e51cbSPeter Avalos 			/*
1773327e51cbSPeter Avalos 			 * This is a PT_NOTE section; loop through all the notes
1774327e51cbSPeter Avalos 			 * in the section.
1775327e51cbSPeter Avalos 			 */
1776327e51cbSPeter Avalos 			offset = 0;
1777327e51cbSPeter Avalos 			for (;;) {
17786fca56fbSSascha Wildner 				if (offset >= CAST(size_t, bufsize))
1779327e51cbSPeter Avalos 					break;
1780327e51cbSPeter Avalos 				offset = donote(ms, nbuf, offset,
17816fca56fbSSascha Wildner 				    CAST(size_t, bufsize), clazz, swap, align,
1782c30bd091SSascha Wildner 				    flags, notecount, fd, 0, 0, 0);
1783327e51cbSPeter Avalos 				if (offset == 0)
1784327e51cbSPeter Avalos 					break;
1785327e51cbSPeter Avalos 			}
1786327e51cbSPeter Avalos 			break;
1787327e51cbSPeter Avalos 		default:
1788c990e5baSDaniel Fojt 			if (ms->flags & MAGIC_MIME)
1789c990e5baSDaniel Fojt 				continue;
1790327e51cbSPeter Avalos 			break;
1791327e51cbSPeter Avalos 		}
1792327e51cbSPeter Avalos 	}
1793c990e5baSDaniel Fojt 	if (ms->flags & MAGIC_MIME)
1794c990e5baSDaniel Fojt 		return 0;
1795970935fdSSascha Wildner 	if (dynamic) {
1796970935fdSSascha Wildner 		if (pie && need == 0)
1797970935fdSSascha Wildner 			linking_style = "static-pie";
1798970935fdSSascha Wildner 		else
1799970935fdSSascha Wildner 			linking_style = "dynamically";
1800970935fdSSascha Wildner 	} else {
1801970935fdSSascha Wildner 		linking_style = "statically";
1802970935fdSSascha Wildner 	}
1803970935fdSSascha Wildner 	if (file_printf(ms, ", %s linked", linking_style) == -1)
1804327e51cbSPeter Avalos 		return -1;
180582c5fa3eSPeter Avalos 	if (interp[0])
1806614728caSSascha Wildner 		if (file_printf(ms, ", interpreter %s", file_printable(ms,
1807614728caSSascha Wildner 		    ibuf, sizeof(ibuf), interp, sizeof(interp))) == -1)
180882c5fa3eSPeter Avalos 			return -1;
1809327e51cbSPeter Avalos 	return 0;
1810327e51cbSPeter Avalos }
1811327e51cbSPeter Avalos 
1812327e51cbSPeter Avalos 
1813327e51cbSPeter Avalos protected int
file_tryelf(struct magic_set * ms,const struct buffer * b)18146fca56fbSSascha Wildner file_tryelf(struct magic_set *ms, const struct buffer *b)
1815327e51cbSPeter Avalos {
18166fca56fbSSascha Wildner 	int fd = b->fd;
18176fca56fbSSascha Wildner 	const unsigned char *buf = CAST(const unsigned char *, b->fbuf);
18186fca56fbSSascha Wildner 	size_t nbytes = b->flen;
1819327e51cbSPeter Avalos 	union {
1820327e51cbSPeter Avalos 		int32_t l;
1821327e51cbSPeter Avalos 		char c[sizeof(int32_t)];
1822327e51cbSPeter Avalos 	} u;
182379343712SPeter Avalos 	int clazz;
1824327e51cbSPeter Avalos 	int swap;
1825327e51cbSPeter Avalos 	struct stat st;
18266fca56fbSSascha Wildner 	const struct stat *stp;
1827327e51cbSPeter Avalos 	off_t fsize;
1828327e51cbSPeter Avalos 	int flags = 0;
182979343712SPeter Avalos 	Elf32_Ehdr elf32hdr;
183079343712SPeter Avalos 	Elf64_Ehdr elf64hdr;
183182c5fa3eSPeter Avalos 	uint16_t type, phnum, shnum, notecount;
183279343712SPeter Avalos 
1833c990e5baSDaniel Fojt 	if (ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION))
183479343712SPeter Avalos 		return 0;
183579343712SPeter Avalos 	/*
183679343712SPeter Avalos 	 * ELF executables have multiple section headers in arbitrary
183779343712SPeter Avalos 	 * file locations and thus file(1) cannot determine it from easily.
183879343712SPeter Avalos 	 * Instead we traverse thru all section headers until a symbol table
183979343712SPeter Avalos 	 * one is found or else the binary is stripped.
18406fca56fbSSascha Wildner 	 * Return immediately if it's not ELF (so we avoid pipe2file unless
18416fca56fbSSascha Wildner 	 * needed).
184279343712SPeter Avalos 	 */
184379343712SPeter Avalos 	if (buf[EI_MAG0] != ELFMAG0
184479343712SPeter Avalos 	    || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1)
184579343712SPeter Avalos 	    || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
184679343712SPeter Avalos 		return 0;
1847327e51cbSPeter Avalos 
1848327e51cbSPeter Avalos 	/*
1849327e51cbSPeter Avalos 	 * If we cannot seek, it must be a pipe, socket or fifo.
1850327e51cbSPeter Avalos 	 */
18516fca56fbSSascha Wildner 	if((lseek(fd, CAST(off_t, 0), SEEK_SET) == CAST(off_t, -1))
18526fca56fbSSascha Wildner 	    && (errno == ESPIPE))
1853327e51cbSPeter Avalos 		fd = file_pipe2file(ms, fd, buf, nbytes);
1854327e51cbSPeter Avalos 
18556fca56fbSSascha Wildner 	if (fd == -1) {
18566fca56fbSSascha Wildner 		file_badread(ms);
18576fca56fbSSascha Wildner 		return -1;
18586fca56fbSSascha Wildner 	}
18596fca56fbSSascha Wildner 
18606fca56fbSSascha Wildner 	stp = &b->st;
18616fca56fbSSascha Wildner 	/*
18626fca56fbSSascha Wildner 	 * b->st.st_size != 0 if previous fstat() succeeded,
18636fca56fbSSascha Wildner 	 * which is likely, we can avoid extra stat() call.
18646fca56fbSSascha Wildner 	 */
18656fca56fbSSascha Wildner 	if (b->st.st_size == 0) {
18666fca56fbSSascha Wildner 		stp = &st;
1867327e51cbSPeter Avalos 		if (fstat(fd, &st) == -1) {
1868327e51cbSPeter Avalos 			file_badread(ms);
1869327e51cbSPeter Avalos 			return -1;
1870327e51cbSPeter Avalos 		}
18716fca56fbSSascha Wildner 	}
18726fca56fbSSascha Wildner 	if (S_ISREG(stp->st_mode) || stp->st_size != 0)
18736fca56fbSSascha Wildner 		fsize = stp->st_size;
187482c5fa3eSPeter Avalos 	else
187582c5fa3eSPeter Avalos 		fsize = SIZE_UNKNOWN;
1876327e51cbSPeter Avalos 
187779343712SPeter Avalos 	clazz = buf[EI_CLASS];
1878327e51cbSPeter Avalos 
187979343712SPeter Avalos 	switch (clazz) {
188079343712SPeter Avalos 	case ELFCLASS32:
188179343712SPeter Avalos #undef elf_getu
188279343712SPeter Avalos #define elf_getu(a, b)	elf_getu32(a, b)
188379343712SPeter Avalos #undef elfhdr
188479343712SPeter Avalos #define elfhdr elf32hdr
188579343712SPeter Avalos #include "elfclass.h"
188679343712SPeter Avalos 	case ELFCLASS64:
188779343712SPeter Avalos #undef elf_getu
188879343712SPeter Avalos #define elf_getu(a, b)	elf_getu64(a, b)
188979343712SPeter Avalos #undef elfhdr
189079343712SPeter Avalos #define elfhdr elf64hdr
189179343712SPeter Avalos #include "elfclass.h"
1892327e51cbSPeter Avalos 	default:
189379343712SPeter Avalos 	    if (file_printf(ms, ", unknown class %d", clazz) == -1)
189479343712SPeter Avalos 		    return -1;
1895327e51cbSPeter Avalos 	    break;
1896327e51cbSPeter Avalos 	}
1897327e51cbSPeter Avalos 	return 0;
1898327e51cbSPeter Avalos }
1899327e51cbSPeter Avalos #endif
1900