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