readelf.c revision 226048
1133359Sobrien/* 2133359Sobrien * Copyright (c) Christos Zoulas 2003. 3133359Sobrien * All Rights Reserved. 4133359Sobrien * 5133359Sobrien * Redistribution and use in source and binary forms, with or without 6133359Sobrien * modification, are permitted provided that the following conditions 7133359Sobrien * are met: 8133359Sobrien * 1. Redistributions of source code must retain the above copyright 9133359Sobrien * notice immediately at the beginning of the file, without modification, 10133359Sobrien * this list of conditions, and the following disclaimer. 11133359Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12133359Sobrien * notice, this list of conditions and the following disclaimer in the 13133359Sobrien * documentation and/or other materials provided with the distribution. 14133359Sobrien * 15133359Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16133359Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17133359Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18133359Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 19133359Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20133359Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21133359Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22133359Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23133359Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24133359Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25133359Sobrien * SUCH DAMAGE. 26133359Sobrien */ 2768349Sobrien#include "file.h" 2868349Sobrien 29191736Sobrien#ifndef lint 30226048SobrienFILE_RCSID("@(#)$File: readelf.c,v 1.90 2011/08/23 08:01:12 christos Exp $") 31191736Sobrien#endif 32191736Sobrien 3368349Sobrien#ifdef BUILTIN_ELF 3468349Sobrien#include <string.h> 3568349Sobrien#include <ctype.h> 3668349Sobrien#include <stdlib.h> 3768349Sobrien#ifdef HAVE_UNISTD_H 3868349Sobrien#include <unistd.h> 3968349Sobrien#endif 4068349Sobrien 4168349Sobrien#include "readelf.h" 42186690Sobrien#include "magic.h" 4368349Sobrien 4468349Sobrien#ifdef ELFCORE 45169942Sobrienprivate int dophn_core(struct magic_set *, int, int, int, off_t, int, size_t, 46169942Sobrien off_t, int *); 4768349Sobrien#endif 48169942Sobrienprivate int dophn_exec(struct magic_set *, int, int, int, off_t, int, size_t, 49186690Sobrien off_t, int *, int); 50226048Sobrienprivate int doshn(struct magic_set *, int, int, int, off_t, int, size_t, 51226048Sobrien off_t, int *, int); 52186690Sobrienprivate size_t donote(struct magic_set *, void *, size_t, size_t, int, 53159764Sobrien int, size_t, int *); 5468349Sobrien 55133359Sobrien#define ELF_ALIGN(a) ((((a) + align - 1) / align) * align) 5668349Sobrien 57159764Sobrien#define isquote(c) (strchr("'\"`", (c)) != NULL) 58159764Sobrien 59133359Sobrienprivate uint16_t getu16(int, uint16_t); 60133359Sobrienprivate uint32_t getu32(int, uint32_t); 61133359Sobrienprivate uint64_t getu64(int, uint64_t); 62133359Sobrien 63133359Sobrienprivate uint16_t 64103373Sobriengetu16(int swap, uint16_t value) 6568349Sobrien{ 6668349Sobrien union { 6768349Sobrien uint16_t ui; 6868349Sobrien char c[2]; 6968349Sobrien } retval, tmpval; 7068349Sobrien 7168349Sobrien if (swap) { 7268349Sobrien tmpval.ui = value; 7368349Sobrien 7468349Sobrien retval.c[0] = tmpval.c[1]; 7568349Sobrien retval.c[1] = tmpval.c[0]; 7668349Sobrien 7768349Sobrien return retval.ui; 7868349Sobrien } else 7968349Sobrien return value; 8068349Sobrien} 8168349Sobrien 82133359Sobrienprivate uint32_t 83103373Sobriengetu32(int swap, uint32_t value) 8468349Sobrien{ 8568349Sobrien union { 8668349Sobrien uint32_t ui; 8768349Sobrien char c[4]; 8868349Sobrien } retval, tmpval; 8968349Sobrien 9068349Sobrien if (swap) { 9168349Sobrien tmpval.ui = value; 9268349Sobrien 9368349Sobrien retval.c[0] = tmpval.c[3]; 9468349Sobrien retval.c[1] = tmpval.c[2]; 9568349Sobrien retval.c[2] = tmpval.c[1]; 9668349Sobrien retval.c[3] = tmpval.c[0]; 9768349Sobrien 9868349Sobrien return retval.ui; 9968349Sobrien } else 10068349Sobrien return value; 10168349Sobrien} 10268349Sobrien 103133359Sobrienprivate uint64_t 104103373Sobriengetu64(int swap, uint64_t value) 10568349Sobrien{ 10668349Sobrien union { 10768349Sobrien uint64_t ui; 10868349Sobrien char c[8]; 10968349Sobrien } retval, tmpval; 11068349Sobrien 11168349Sobrien if (swap) { 11268349Sobrien tmpval.ui = value; 11368349Sobrien 11468349Sobrien retval.c[0] = tmpval.c[7]; 11568349Sobrien retval.c[1] = tmpval.c[6]; 11668349Sobrien retval.c[2] = tmpval.c[5]; 11768349Sobrien retval.c[3] = tmpval.c[4]; 11868349Sobrien retval.c[4] = tmpval.c[3]; 11968349Sobrien retval.c[5] = tmpval.c[2]; 12068349Sobrien retval.c[6] = tmpval.c[1]; 12168349Sobrien retval.c[7] = tmpval.c[0]; 12268349Sobrien 12368349Sobrien return retval.ui; 12468349Sobrien } else 12568349Sobrien return value; 12668349Sobrien} 12768349Sobrien 128186690Sobrien#define elf_getu16(swap, value) getu16(swap, value) 129186690Sobrien#define elf_getu32(swap, value) getu32(swap, value) 130159764Sobrien#ifdef USE_ARRAY_FOR_64BIT_TYPES 131159764Sobrien# define elf_getu64(swap, array) \ 132186690Sobrien ((swap ? ((uint64_t)elf_getu32(swap, array[0])) << 32 : elf_getu32(swap, array[0])) + \ 133186690Sobrien (swap ? elf_getu32(swap, array[1]) : ((uint64_t)elf_getu32(swap, array[1]) << 32))) 134159764Sobrien#else 135159764Sobrien# define elf_getu64(swap, value) getu64(swap, value) 136159764Sobrien#endif 137159764Sobrien 138186690Sobrien#define xsh_addr (clazz == ELFCLASS32 \ 139186690Sobrien ? (void *) &sh32 \ 14068349Sobrien : (void *) &sh64) 141186690Sobrien#define xsh_sizeof (clazz == ELFCLASS32 \ 142186690Sobrien ? sizeof sh32 \ 143111658Sobrien : sizeof sh64) 144186690Sobrien#define xsh_size (clazz == ELFCLASS32 \ 145186690Sobrien ? elf_getu32(swap, sh32.sh_size) \ 146186690Sobrien : elf_getu64(swap, sh64.sh_size)) 147226048Sobrien#define xsh_offset (off_t)(clazz == ELFCLASS32 \ 148186690Sobrien ? elf_getu32(swap, sh32.sh_offset) \ 149186690Sobrien : elf_getu64(swap, sh64.sh_offset)) 150186690Sobrien#define xsh_type (clazz == ELFCLASS32 \ 151186690Sobrien ? elf_getu32(swap, sh32.sh_type) \ 152186690Sobrien : elf_getu32(swap, sh64.sh_type)) 153186690Sobrien#define xph_addr (clazz == ELFCLASS32 \ 154186690Sobrien ? (void *) &ph32 \ 15568349Sobrien : (void *) &ph64) 156186690Sobrien#define xph_sizeof (clazz == ELFCLASS32 \ 157186690Sobrien ? sizeof ph32 \ 158111658Sobrien : sizeof ph64) 159186690Sobrien#define xph_type (clazz == ELFCLASS32 \ 160186690Sobrien ? elf_getu32(swap, ph32.p_type) \ 161186690Sobrien : elf_getu32(swap, ph64.p_type)) 162186690Sobrien#define xph_offset (off_t)(clazz == ELFCLASS32 \ 163186690Sobrien ? elf_getu32(swap, ph32.p_offset) \ 164186690Sobrien : elf_getu64(swap, ph64.p_offset)) 165186690Sobrien#define xph_align (size_t)((clazz == ELFCLASS32 \ 166186690Sobrien ? (off_t) (ph32.p_align ? \ 167186690Sobrien elf_getu32(swap, ph32.p_align) : 4) \ 168186690Sobrien : (off_t) (ph64.p_align ? \ 169186690Sobrien elf_getu64(swap, ph64.p_align) : 4))) 170186690Sobrien#define xph_filesz (size_t)((clazz == ELFCLASS32 \ 171186690Sobrien ? elf_getu32(swap, ph32.p_filesz) \ 172186690Sobrien : elf_getu64(swap, ph64.p_filesz))) 173186690Sobrien#define xnh_addr (clazz == ELFCLASS32 \ 174186690Sobrien ? (void *) &nh32 \ 175159764Sobrien : (void *) &nh64) 176186690Sobrien#define xph_memsz (size_t)((clazz == ELFCLASS32 \ 177186690Sobrien ? elf_getu32(swap, ph32.p_memsz) \ 178186690Sobrien : elf_getu64(swap, ph64.p_memsz))) 179186690Sobrien#define xnh_sizeof (clazz == ELFCLASS32 \ 180186690Sobrien ? sizeof nh32 \ 181133359Sobrien : sizeof nh64) 182186690Sobrien#define xnh_type (clazz == ELFCLASS32 \ 183186690Sobrien ? elf_getu32(swap, nh32.n_type) \ 184186690Sobrien : elf_getu32(swap, nh64.n_type)) 185186690Sobrien#define xnh_namesz (clazz == ELFCLASS32 \ 186186690Sobrien ? elf_getu32(swap, nh32.n_namesz) \ 187186690Sobrien : elf_getu32(swap, nh64.n_namesz)) 188186690Sobrien#define xnh_descsz (clazz == ELFCLASS32 \ 189186690Sobrien ? elf_getu32(swap, nh32.n_descsz) \ 190186690Sobrien : elf_getu32(swap, nh64.n_descsz)) 191186690Sobrien#define prpsoffsets(i) (clazz == ELFCLASS32 \ 192186690Sobrien ? prpsoffsets32[i] \ 19368349Sobrien : prpsoffsets64[i]) 194186690Sobrien#define xcap_addr (clazz == ELFCLASS32 \ 195186690Sobrien ? (void *) &cap32 \ 196186690Sobrien : (void *) &cap64) 197186690Sobrien#define xcap_sizeof (clazz == ELFCLASS32 \ 198186690Sobrien ? sizeof cap32 \ 199186690Sobrien : sizeof cap64) 200186690Sobrien#define xcap_tag (clazz == ELFCLASS32 \ 201186690Sobrien ? elf_getu32(swap, cap32.c_tag) \ 202186690Sobrien : elf_getu64(swap, cap64.c_tag)) 203186690Sobrien#define xcap_val (clazz == ELFCLASS32 \ 204186690Sobrien ? elf_getu32(swap, cap32.c_un.c_val) \ 205186690Sobrien : elf_getu64(swap, cap64.c_un.c_val)) 20668349Sobrien 20768349Sobrien#ifdef ELFCORE 208186690Sobrien/* 209186690Sobrien * Try larger offsets first to avoid false matches 210186690Sobrien * from earlier data that happen to look like strings. 211186690Sobrien */ 212186690Sobrienstatic const size_t prpsoffsets32[] = { 213186690Sobrien#ifdef USE_NT_PSINFO 214186690Sobrien 104, /* SunOS 5.x (command line) */ 215186690Sobrien 88, /* SunOS 5.x (short name) */ 216186690Sobrien#endif /* USE_NT_PSINFO */ 217186690Sobrien 218186690Sobrien 100, /* SunOS 5.x (command line) */ 219186690Sobrien 84, /* SunOS 5.x (short name) */ 220186690Sobrien 221186690Sobrien 44, /* Linux (command line) */ 222186690Sobrien 28, /* Linux 2.0.36 (short name) */ 223186690Sobrien 22468349Sobrien 8, /* FreeBSD */ 22568349Sobrien}; 22668349Sobrien 227186690Sobrienstatic const size_t prpsoffsets64[] = { 228186690Sobrien#ifdef USE_NT_PSINFO 229186690Sobrien 152, /* SunOS 5.x (command line) */ 230186690Sobrien 136, /* SunOS 5.x (short name) */ 231186690Sobrien#endif /* USE_NT_PSINFO */ 232186690Sobrien 233186690Sobrien 136, /* SunOS 5.x, 64-bit (command line) */ 234186690Sobrien 120, /* SunOS 5.x, 64-bit (short name) */ 235186690Sobrien 236186690Sobrien 56, /* Linux (command line) */ 237186690Sobrien 40, /* Linux (tested on core from 2.4.x, short name) */ 238186690Sobrien 239159764Sobrien 16, /* FreeBSD, 64-bit */ 24068349Sobrien}; 24168349Sobrien 24268349Sobrien#define NOFFSETS32 (sizeof prpsoffsets32 / sizeof prpsoffsets32[0]) 24368349Sobrien#define NOFFSETS64 (sizeof prpsoffsets64 / sizeof prpsoffsets64[0]) 24468349Sobrien 245186690Sobrien#define NOFFSETS (clazz == ELFCLASS32 ? NOFFSETS32 : NOFFSETS64) 24668349Sobrien 24768349Sobrien/* 24868349Sobrien * Look through the program headers of an executable image, searching 24968349Sobrien * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE" or 25068349Sobrien * "FreeBSD"; if one is found, try looking in various places in its 25168349Sobrien * contents for a 16-character string containing only printable 25268349Sobrien * characters - if found, that string should be the name of the program 25368349Sobrien * that dropped core. Note: right after that 16-character string is, 25468349Sobrien * at least in SunOS 5.x (and possibly other SVR4-flavored systems) and 25568349Sobrien * Linux, a longer string (80 characters, in 5.x, probably other 25668349Sobrien * SVR4-flavored systems, and Linux) containing the start of the 25768349Sobrien * command line for that program. 25868349Sobrien * 259186690Sobrien * SunOS 5.x core files contain two PT_NOTE sections, with the types 260186690Sobrien * NT_PRPSINFO (old) and NT_PSINFO (new). These structs contain the 261186690Sobrien * same info about the command name and command line, so it probably 262186690Sobrien * isn't worthwhile to look for NT_PSINFO, but the offsets are provided 263186690Sobrien * above (see USE_NT_PSINFO), in case we ever decide to do so. The 264186690Sobrien * NT_PRPSINFO and NT_PSINFO sections are always in order and adjacent; 265186690Sobrien * the SunOS 5.x file command relies on this (and prefers the latter). 266186690Sobrien * 26768349Sobrien * The signal number probably appears in a section of type NT_PRSTATUS, 26868349Sobrien * but that's also rather OS-dependent, in ways that are harder to 26968349Sobrien * dissect with heuristics, so I'm not bothering with the signal number. 27068349Sobrien * (I suppose the signal number could be of interest in situations where 27168349Sobrien * you don't have the binary of the program that dropped core; if you 27268349Sobrien * *do* have that binary, the debugger will probably tell you what 27368349Sobrien * signal it was.) 27468349Sobrien */ 275103373Sobrien 276103373Sobrien#define OS_STYLE_SVR4 0 277103373Sobrien#define OS_STYLE_FREEBSD 1 278103373Sobrien#define OS_STYLE_NETBSD 2 279103373Sobrien 280186690Sobrienprivate const char os_style_names[][8] = { 281103373Sobrien "SVR4", 282103373Sobrien "FreeBSD", 283103373Sobrien "NetBSD", 284103373Sobrien}; 285103373Sobrien 286226048Sobrien#define FLAGS_DID_CORE 0x01 287226048Sobrien#define FLAGS_DID_NOTE 0x02 288226048Sobrien#define FLAGS_DID_BUILD_ID 0x04 289226048Sobrien#define FLAGS_DID_CORE_STYLE 0x08 290226048Sobrien#define FLAGS_IS_CORE 0x10 291159764Sobrien 292133359Sobrienprivate int 293186690Sobriendophn_core(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 294169942Sobrien int num, size_t size, off_t fsize, int *flags) 29568349Sobrien{ 29668349Sobrien Elf32_Phdr ph32; 29768349Sobrien Elf64_Phdr ph64; 298133359Sobrien size_t offset; 299133359Sobrien unsigned char nbuf[BUFSIZ]; 300133359Sobrien ssize_t bufsize; 30168349Sobrien 302159764Sobrien if (size != xph_sizeof) { 303133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 304133359Sobrien return -1; 305133359Sobrien return 0; 306133359Sobrien } 307159764Sobrien 30868349Sobrien /* 30968349Sobrien * Loop through all the program headers. 31068349Sobrien */ 31168349Sobrien for ( ; num; num--) { 312226048Sobrien if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 313133359Sobrien file_badseek(ms); 314133359Sobrien return -1; 315133359Sobrien } 316159764Sobrien if (read(fd, xph_addr, xph_sizeof) == -1) { 317133359Sobrien file_badread(ms); 318133359Sobrien return -1; 319133359Sobrien } 320226048Sobrien off += size; 321226048Sobrien 322169942Sobrien if (xph_offset > fsize) { 323226048Sobrien /* Perhaps warn here */ 324169942Sobrien continue; 325169942Sobrien } 326169942Sobrien 327159764Sobrien if (xph_type != PT_NOTE) 32868349Sobrien continue; 32968349Sobrien 33068349Sobrien /* 33168349Sobrien * This is a PT_NOTE section; loop through all the notes 33268349Sobrien * in the section. 33368349Sobrien */ 334169962Sobrien if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { 335133359Sobrien file_badseek(ms); 336133359Sobrien return -1; 337133359Sobrien } 338139368Sobrien bufsize = read(fd, nbuf, 339159764Sobrien ((xph_filesz < sizeof(nbuf)) ? xph_filesz : sizeof(nbuf))); 340133359Sobrien if (bufsize == -1) { 341133359Sobrien file_badread(ms); 342133359Sobrien return -1; 343133359Sobrien } 34468349Sobrien offset = 0; 34568349Sobrien for (;;) { 346133359Sobrien if (offset >= (size_t)bufsize) 34768349Sobrien break; 348133359Sobrien offset = donote(ms, nbuf, offset, (size_t)bufsize, 349186690Sobrien clazz, swap, 4, flags); 350133359Sobrien if (offset == 0) 351133359Sobrien break; 35268349Sobrien 353133359Sobrien } 354133359Sobrien } 355133359Sobrien return 0; 356133359Sobrien} 357133359Sobrien#endif 358133359Sobrien 359133359Sobrienprivate size_t 360186690Sobriendonote(struct magic_set *ms, void *vbuf, size_t offset, size_t size, 361186690Sobrien int clazz, int swap, size_t align, int *flags) 362133359Sobrien{ 363133359Sobrien Elf32_Nhdr nh32; 364133359Sobrien Elf64_Nhdr nh64; 365133359Sobrien size_t noff, doff; 366133359Sobrien#ifdef ELFCORE 367133359Sobrien int os_style = -1; 368133359Sobrien#endif 369133359Sobrien uint32_t namesz, descsz; 370186690Sobrien unsigned char *nbuf = CAST(unsigned char *, vbuf); 371133359Sobrien 372159764Sobrien (void)memcpy(xnh_addr, &nbuf[offset], xnh_sizeof); 373159764Sobrien offset += xnh_sizeof; 374133359Sobrien 375159764Sobrien namesz = xnh_namesz; 376159764Sobrien descsz = xnh_descsz; 377133359Sobrien if ((namesz == 0) && (descsz == 0)) { 378133359Sobrien /* 379133359Sobrien * We're out of note headers. 380133359Sobrien */ 381169942Sobrien return (offset >= size) ? offset : size; 382133359Sobrien } 383133359Sobrien 384133359Sobrien if (namesz & 0x80000000) { 385133359Sobrien (void)file_printf(ms, ", bad note name size 0x%lx", 386133359Sobrien (unsigned long)namesz); 387133359Sobrien return offset; 388133359Sobrien } 389133359Sobrien 390133359Sobrien if (descsz & 0x80000000) { 391133359Sobrien (void)file_printf(ms, ", bad note description size 0x%lx", 392133359Sobrien (unsigned long)descsz); 393133359Sobrien return offset; 394133359Sobrien } 395133359Sobrien 396133359Sobrien 397133359Sobrien noff = offset; 398133359Sobrien doff = ELF_ALIGN(offset + namesz); 399133359Sobrien 400133359Sobrien if (offset + namesz > size) { 401133359Sobrien /* 402133359Sobrien * We're past the end of the buffer. 403133359Sobrien */ 404133359Sobrien return doff; 405133359Sobrien } 406133359Sobrien 407133359Sobrien offset = ELF_ALIGN(doff + descsz); 408139368Sobrien if (doff + descsz > size) { 409169942Sobrien /* 410169942Sobrien * We're past the end of the buffer. 411169942Sobrien */ 412169942Sobrien return (offset >= size) ? offset : size; 413133359Sobrien } 414133359Sobrien 415226048Sobrien if ((*flags & (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) == 416226048Sobrien (FLAGS_DID_NOTE|FLAGS_DID_BUILD_ID)) 417169942Sobrien goto core; 418169942Sobrien 419133359Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 420159764Sobrien xnh_type == NT_GNU_VERSION && descsz == 16) { 421133359Sobrien uint32_t desc[4]; 422133359Sobrien (void)memcpy(desc, &nbuf[doff], sizeof(desc)); 423133359Sobrien 424133359Sobrien if (file_printf(ms, ", for GNU/") == -1) 425133359Sobrien return size; 426186690Sobrien switch (elf_getu32(swap, desc[0])) { 427133359Sobrien case GNU_OS_LINUX: 428133359Sobrien if (file_printf(ms, "Linux") == -1) 429133359Sobrien return size; 430133359Sobrien break; 431133359Sobrien case GNU_OS_HURD: 432133359Sobrien if (file_printf(ms, "Hurd") == -1) 433133359Sobrien return size; 434133359Sobrien break; 435133359Sobrien case GNU_OS_SOLARIS: 436133359Sobrien if (file_printf(ms, "Solaris") == -1) 437133359Sobrien return size; 438133359Sobrien break; 439186690Sobrien case GNU_OS_KFREEBSD: 440186690Sobrien if (file_printf(ms, "kFreeBSD") == -1) 441186690Sobrien return size; 442186690Sobrien break; 443186690Sobrien case GNU_OS_KNETBSD: 444186690Sobrien if (file_printf(ms, "kNetBSD") == -1) 445186690Sobrien return size; 446186690Sobrien break; 447133359Sobrien default: 448133359Sobrien if (file_printf(ms, "<unknown>") == -1) 449133359Sobrien return size; 450133359Sobrien } 451186690Sobrien if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]), 452186690Sobrien elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1) 453133359Sobrien return size; 454169942Sobrien *flags |= FLAGS_DID_NOTE; 455133359Sobrien return size; 456133359Sobrien } 457133359Sobrien 458226048Sobrien if (namesz == 4 && strcmp((char *)&nbuf[noff], "GNU") == 0 && 459226048Sobrien xnh_type == NT_GNU_BUILD_ID && (descsz == 16 || descsz == 20)) { 460226048Sobrien uint32_t desc[5], i; 461226048Sobrien if (file_printf(ms, ", BuildID[%s]=0x", descsz == 16 ? "md5/uuid" : 462226048Sobrien "sha1") == -1) 463226048Sobrien return size; 464226048Sobrien (void)memcpy(desc, &nbuf[doff], descsz); 465226048Sobrien for (i = 0; i < descsz >> 2; i++) 466226048Sobrien if (file_printf(ms, "%.8x", desc[i]) == -1) 467226048Sobrien return size; 468226048Sobrien *flags |= FLAGS_DID_BUILD_ID; 469226048Sobrien } 470226048Sobrien 471133359Sobrien if (namesz == 7 && strcmp((char *)&nbuf[noff], "NetBSD") == 0 && 472159764Sobrien xnh_type == NT_NETBSD_VERSION && descsz == 4) { 473133359Sobrien uint32_t desc; 474133359Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 475186690Sobrien desc = elf_getu32(swap, desc); 476133359Sobrien 477133359Sobrien if (file_printf(ms, ", for NetBSD") == -1) 478133359Sobrien return size; 479133359Sobrien /* 480133359Sobrien * The version number used to be stuck as 199905, and was thus 481133359Sobrien * basically content-free. Newer versions of NetBSD have fixed 482133359Sobrien * this and now use the encoding of __NetBSD_Version__: 483133359Sobrien * 484133359Sobrien * MMmmrrpp00 485133359Sobrien * 486133359Sobrien * M = major version 487133359Sobrien * m = minor version 488133359Sobrien * r = release ["",A-Z,Z[A-Z] but numeric] 489133359Sobrien * p = patchlevel 490133359Sobrien */ 491133359Sobrien if (desc > 100000000U) { 492169942Sobrien uint32_t ver_patch = (desc / 100) % 100; 493169942Sobrien uint32_t ver_rel = (desc / 10000) % 100; 494169942Sobrien uint32_t ver_min = (desc / 1000000) % 100; 495169942Sobrien uint32_t ver_maj = desc / 100000000; 496133359Sobrien 497133359Sobrien if (file_printf(ms, " %u.%u", ver_maj, ver_min) == -1) 498133359Sobrien return size; 499133359Sobrien if (ver_rel == 0 && ver_patch != 0) { 500133359Sobrien if (file_printf(ms, ".%u", ver_patch) == -1) 501133359Sobrien return size; 502133359Sobrien } else if (ver_rel != 0) { 503133359Sobrien while (ver_rel > 26) { 504169942Sobrien if (file_printf(ms, "Z") == -1) 505169942Sobrien return size; 506133359Sobrien ver_rel -= 26; 507133359Sobrien } 508169942Sobrien if (file_printf(ms, "%c", 'A' + ver_rel - 1) 509169942Sobrien == -1) 510169942Sobrien return size; 51168349Sobrien } 512133359Sobrien } 513169942Sobrien *flags |= FLAGS_DID_NOTE; 514133359Sobrien return size; 515133359Sobrien } 51668349Sobrien 517133359Sobrien if (namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0 && 518159764Sobrien xnh_type == NT_FREEBSD_VERSION && descsz == 4) { 519133359Sobrien uint32_t desc; 520133359Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 521186690Sobrien desc = elf_getu32(swap, desc); 522133359Sobrien if (file_printf(ms, ", for FreeBSD") == -1) 523133359Sobrien return size; 52468349Sobrien 525133359Sobrien /* 526133359Sobrien * Contents is __FreeBSD_version, whose relation to OS 527139368Sobrien * versions is defined by a huge table in the Porter's 528139368Sobrien * Handbook. This is the general scheme: 529139368Sobrien * 530139368Sobrien * Releases: 531139368Sobrien * Mmp000 (before 4.10) 532139368Sobrien * Mmi0p0 (before 5.0) 533139368Sobrien * Mmm0p0 534139368Sobrien * 535139368Sobrien * Development branches: 536139368Sobrien * Mmpxxx (before 4.6) 537139368Sobrien * Mmp1xx (before 4.10) 538139368Sobrien * Mmi1xx (before 5.0) 539139368Sobrien * M000xx (pre-M.0) 540139368Sobrien * Mmm1xx 541139368Sobrien * 542139368Sobrien * M = major version 543139368Sobrien * m = minor version 544139368Sobrien * i = minor version increment (491000 -> 4.10) 545139368Sobrien * p = patchlevel 546139368Sobrien * x = revision 547139368Sobrien * 548139368Sobrien * The first release of FreeBSD to use ELF by default 549139368Sobrien * was version 3.0. 550133359Sobrien */ 551139368Sobrien if (desc == 460002) { 552139368Sobrien if (file_printf(ms, " 4.6.2") == -1) 553139368Sobrien return size; 554139368Sobrien } else if (desc < 460100) { 555139368Sobrien if (file_printf(ms, " %d.%d", desc / 100000, 556139368Sobrien desc / 10000 % 10) == -1) 557139368Sobrien return size; 558139368Sobrien if (desc / 1000 % 10 > 0) 559139368Sobrien if (file_printf(ms, ".%d", desc / 1000 % 10) 560139368Sobrien == -1) 561133359Sobrien return size; 562139368Sobrien if ((desc % 1000 > 0) || (desc % 100000 == 0)) 563139368Sobrien if (file_printf(ms, " (%d)", desc) == -1) 564133359Sobrien return size; 565139368Sobrien } else if (desc < 500000) { 566139368Sobrien if (file_printf(ms, " %d.%d", desc / 100000, 567139368Sobrien desc / 10000 % 10 + desc / 1000 % 10) == -1) 568139368Sobrien return size; 569139368Sobrien if (desc / 100 % 10 > 0) { 570139368Sobrien if (file_printf(ms, " (%d)", desc) == -1) 571139368Sobrien return size; 572139368Sobrien } else if (desc / 10 % 10 > 0) { 573139368Sobrien if (file_printf(ms, ".%d", desc / 10 % 10) 574139368Sobrien == -1) 575139368Sobrien return size; 576103373Sobrien } 577133359Sobrien } else { 578133359Sobrien if (file_printf(ms, " %d.%d", desc / 100000, 579133359Sobrien desc / 1000 % 100) == -1) 580133359Sobrien return size; 581139368Sobrien if ((desc / 100 % 10 > 0) || 582139368Sobrien (desc % 100000 / 100 == 0)) { 583139368Sobrien if (file_printf(ms, " (%d)", desc) == -1) 584133359Sobrien return size; 585139368Sobrien } else if (desc / 10 % 10 > 0) { 586139368Sobrien if (file_printf(ms, ".%d", desc / 10 % 10) 587139368Sobrien == -1) 588133359Sobrien return size; 589133359Sobrien } 590133359Sobrien } 591169942Sobrien *flags |= FLAGS_DID_NOTE; 592133359Sobrien return size; 593133359Sobrien } 594103373Sobrien 595133359Sobrien if (namesz == 8 && strcmp((char *)&nbuf[noff], "OpenBSD") == 0 && 596159764Sobrien xnh_type == NT_OPENBSD_VERSION && descsz == 4) { 597133359Sobrien if (file_printf(ms, ", for OpenBSD") == -1) 598133359Sobrien return size; 599133359Sobrien /* Content of note is always 0 */ 600169942Sobrien *flags |= FLAGS_DID_NOTE; 601133359Sobrien return size; 602133359Sobrien } 603103373Sobrien 604159764Sobrien if (namesz == 10 && strcmp((char *)&nbuf[noff], "DragonFly") == 0 && 605159764Sobrien xnh_type == NT_DRAGONFLY_VERSION && descsz == 4) { 606159764Sobrien uint32_t desc; 607159764Sobrien if (file_printf(ms, ", for DragonFly") == -1) 608159764Sobrien return size; 609159764Sobrien (void)memcpy(&desc, &nbuf[doff], sizeof(desc)); 610186690Sobrien desc = elf_getu32(swap, desc); 611159764Sobrien if (file_printf(ms, " %d.%d.%d", desc / 100000, 612159764Sobrien desc / 10000 % 10, desc % 10000) == -1) 613159764Sobrien return size; 614169942Sobrien *flags |= FLAGS_DID_NOTE; 615159764Sobrien return size; 616159764Sobrien } 617159764Sobrien 618169942Sobriencore: 619133359Sobrien /* 620133359Sobrien * Sigh. The 2.0.36 kernel in Debian 2.1, at 621133359Sobrien * least, doesn't correctly implement name 622133359Sobrien * sections, in core dumps, as specified by 623133359Sobrien * the "Program Linking" section of "UNIX(R) System 624133359Sobrien * V Release 4 Programmer's Guide: ANSI C and 625133359Sobrien * Programming Support Tools", because my copy 626133359Sobrien * clearly says "The first 'namesz' bytes in 'name' 627133359Sobrien * contain a *null-terminated* [emphasis mine] 628133359Sobrien * character representation of the entry's owner 629133359Sobrien * or originator", but the 2.0.36 kernel code 630133359Sobrien * doesn't include the terminating null in the 631133359Sobrien * name.... 632133359Sobrien */ 633133359Sobrien if ((namesz == 4 && strncmp((char *)&nbuf[noff], "CORE", 4) == 0) || 634133359Sobrien (namesz == 5 && strcmp((char *)&nbuf[noff], "CORE") == 0)) { 635133359Sobrien os_style = OS_STYLE_SVR4; 636133359Sobrien } 637133359Sobrien 638133359Sobrien if ((namesz == 8 && strcmp((char *)&nbuf[noff], "FreeBSD") == 0)) { 639133359Sobrien os_style = OS_STYLE_FREEBSD; 640133359Sobrien } 641133359Sobrien 642133359Sobrien if ((namesz >= 11 && strncmp((char *)&nbuf[noff], "NetBSD-CORE", 11) 643133359Sobrien == 0)) { 644133359Sobrien os_style = OS_STYLE_NETBSD; 645133359Sobrien } 646133359Sobrien 647133359Sobrien#ifdef ELFCORE 648169942Sobrien if ((*flags & FLAGS_DID_CORE) != 0) 649169942Sobrien return size; 650169942Sobrien 651175296Sobrien if (os_style != -1 && (*flags & FLAGS_DID_CORE_STYLE) == 0) { 652169942Sobrien if (file_printf(ms, ", %s-style", os_style_names[os_style]) 653169942Sobrien == -1) 654169942Sobrien return size; 655175296Sobrien *flags |= FLAGS_DID_CORE_STYLE; 656159764Sobrien } 657133359Sobrien 658159764Sobrien switch (os_style) { 659159764Sobrien case OS_STYLE_NETBSD: 660159764Sobrien if (xnh_type == NT_NETBSD_CORE_PROCINFO) { 661159764Sobrien uint32_t signo; 662159764Sobrien /* 663159764Sobrien * Extract the program name. It is at 664159764Sobrien * offset 0x7c, and is up to 32-bytes, 665159764Sobrien * including the terminating NUL. 666159764Sobrien */ 667159764Sobrien if (file_printf(ms, ", from '%.31s'", 668159764Sobrien &nbuf[doff + 0x7c]) == -1) 669159764Sobrien return size; 670159764Sobrien 671159764Sobrien /* 672159764Sobrien * Extract the signal number. It is at 673159764Sobrien * offset 0x08. 674159764Sobrien */ 675159764Sobrien (void)memcpy(&signo, &nbuf[doff + 0x08], 676159764Sobrien sizeof(signo)); 677159764Sobrien if (file_printf(ms, " (signal %u)", 678186690Sobrien elf_getu32(swap, signo)) == -1) 679159764Sobrien return size; 680175296Sobrien *flags |= FLAGS_DID_CORE; 681133359Sobrien return size; 682159764Sobrien } 683159764Sobrien break; 684133359Sobrien 685159764Sobrien default: 686226048Sobrien if (xnh_type == NT_PRPSINFO && *flags & FLAGS_IS_CORE) { 687159764Sobrien size_t i, j; 688159764Sobrien unsigned char c; 689159764Sobrien /* 690159764Sobrien * Extract the program name. We assume 691159764Sobrien * it to be 16 characters (that's what it 692159764Sobrien * is in SunOS 5.x and Linux). 693159764Sobrien * 694159764Sobrien * Unfortunately, it's at a different offset 695175296Sobrien * in various OSes, so try multiple offsets. 696159764Sobrien * If the characters aren't all printable, 697159764Sobrien * reject it. 698159764Sobrien */ 699159764Sobrien for (i = 0; i < NOFFSETS; i++) { 700175296Sobrien unsigned char *cname, *cp; 701159764Sobrien size_t reloffset = prpsoffsets(i); 702159764Sobrien size_t noffset = doff + reloffset; 703226048Sobrien size_t k; 704159764Sobrien for (j = 0; j < 16; j++, noffset++, 705159764Sobrien reloffset++) { 70668349Sobrien /* 707159764Sobrien * Make sure we're not past 708159764Sobrien * the end of the buffer; if 709159764Sobrien * we are, just give up. 71068349Sobrien */ 711159764Sobrien if (noffset >= size) 712133359Sobrien goto tryanother; 713159764Sobrien 714133359Sobrien /* 715159764Sobrien * Make sure we're not past 716159764Sobrien * the end of the contents; 717159764Sobrien * if we are, this obviously 718159764Sobrien * isn't the right offset. 719133359Sobrien */ 720159764Sobrien if (reloffset >= descsz) 721133359Sobrien goto tryanother; 722159764Sobrien 723159764Sobrien c = nbuf[noffset]; 724159764Sobrien if (c == '\0') { 725159764Sobrien /* 726159764Sobrien * A '\0' at the 727159764Sobrien * beginning is 728159764Sobrien * obviously wrong. 729159764Sobrien * Any other '\0' 730159764Sobrien * means we're done. 731159764Sobrien */ 732159764Sobrien if (j == 0) 733159764Sobrien goto tryanother; 734159764Sobrien else 735159764Sobrien break; 736159764Sobrien } else { 737159764Sobrien /* 738159764Sobrien * A nonprintable 739159764Sobrien * character is also 740159764Sobrien * wrong. 741159764Sobrien */ 742159764Sobrien if (!isprint(c) || isquote(c)) 743159764Sobrien goto tryanother; 744159764Sobrien } 74568349Sobrien } 746159764Sobrien /* 747159764Sobrien * Well, that worked. 748159764Sobrien */ 749226048Sobrien 750226048Sobrien /* 751226048Sobrien * Try next offsets, in case this match is 752226048Sobrien * in the middle of a string. 753226048Sobrien */ 754226048Sobrien for (k = i + 1 ; k < NOFFSETS ; k++) { 755226048Sobrien size_t no; 756226048Sobrien int adjust = 1; 757226048Sobrien if (prpsoffsets(k) >= prpsoffsets(i)) 758226048Sobrien continue; 759226048Sobrien for (no = doff + prpsoffsets(k); 760226048Sobrien no < doff + prpsoffsets(i); no++) 761226048Sobrien adjust = adjust 762226048Sobrien && isprint(nbuf[no]); 763226048Sobrien if (adjust) 764226048Sobrien i = k; 765226048Sobrien } 766226048Sobrien 767175296Sobrien cname = (unsigned char *) 768175296Sobrien &nbuf[doff + prpsoffsets(i)]; 769175296Sobrien for (cp = cname; *cp && isprint(*cp); cp++) 770175296Sobrien continue; 771186690Sobrien /* 772186690Sobrien * Linux apparently appends a space at the end 773186690Sobrien * of the command line: remove it. 774186690Sobrien */ 775186690Sobrien while (cp > cname && isspace(cp[-1])) 776175296Sobrien cp--; 777175296Sobrien if (file_printf(ms, ", from '%.*s'", 778175296Sobrien (int)(cp - cname), cname) == -1) 779159764Sobrien return size; 780175296Sobrien *flags |= FLAGS_DID_CORE; 781133359Sobrien return size; 782133359Sobrien 783159764Sobrien tryanother: 784159764Sobrien ; 785159764Sobrien } 78668349Sobrien } 787159764Sobrien break; 78868349Sobrien } 789133359Sobrien#endif 790133359Sobrien return offset; 79168349Sobrien} 79268349Sobrien 793186690Sobrien/* SunOS 5.x hardware capability descriptions */ 794186690Sobrientypedef struct cap_desc { 795186690Sobrien uint64_t cd_mask; 796186690Sobrien const char *cd_name; 797186690Sobrien} cap_desc_t; 798186690Sobrien 799186690Sobrienstatic const cap_desc_t cap_desc_sparc[] = { 800186690Sobrien { AV_SPARC_MUL32, "MUL32" }, 801186690Sobrien { AV_SPARC_DIV32, "DIV32" }, 802186690Sobrien { AV_SPARC_FSMULD, "FSMULD" }, 803186690Sobrien { AV_SPARC_V8PLUS, "V8PLUS" }, 804186690Sobrien { AV_SPARC_POPC, "POPC" }, 805186690Sobrien { AV_SPARC_VIS, "VIS" }, 806186690Sobrien { AV_SPARC_VIS2, "VIS2" }, 807186690Sobrien { AV_SPARC_ASI_BLK_INIT, "ASI_BLK_INIT" }, 808186690Sobrien { AV_SPARC_FMAF, "FMAF" }, 809186690Sobrien { AV_SPARC_FJFMAU, "FJFMAU" }, 810186690Sobrien { AV_SPARC_IMA, "IMA" }, 811186690Sobrien { 0, NULL } 812186690Sobrien}; 813186690Sobrien 814186690Sobrienstatic const cap_desc_t cap_desc_386[] = { 815186690Sobrien { AV_386_FPU, "FPU" }, 816186690Sobrien { AV_386_TSC, "TSC" }, 817186690Sobrien { AV_386_CX8, "CX8" }, 818186690Sobrien { AV_386_SEP, "SEP" }, 819186690Sobrien { AV_386_AMD_SYSC, "AMD_SYSC" }, 820186690Sobrien { AV_386_CMOV, "CMOV" }, 821186690Sobrien { AV_386_MMX, "MMX" }, 822186690Sobrien { AV_386_AMD_MMX, "AMD_MMX" }, 823186690Sobrien { AV_386_AMD_3DNow, "AMD_3DNow" }, 824186690Sobrien { AV_386_AMD_3DNowx, "AMD_3DNowx" }, 825186690Sobrien { AV_386_FXSR, "FXSR" }, 826186690Sobrien { AV_386_SSE, "SSE" }, 827186690Sobrien { AV_386_SSE2, "SSE2" }, 828186690Sobrien { AV_386_PAUSE, "PAUSE" }, 829186690Sobrien { AV_386_SSE3, "SSE3" }, 830186690Sobrien { AV_386_MON, "MON" }, 831186690Sobrien { AV_386_CX16, "CX16" }, 832186690Sobrien { AV_386_AHF, "AHF" }, 833186690Sobrien { AV_386_TSCP, "TSCP" }, 834186690Sobrien { AV_386_AMD_SSE4A, "AMD_SSE4A" }, 835186690Sobrien { AV_386_POPCNT, "POPCNT" }, 836186690Sobrien { AV_386_AMD_LZCNT, "AMD_LZCNT" }, 837186690Sobrien { AV_386_SSSE3, "SSSE3" }, 838186690Sobrien { AV_386_SSE4_1, "SSE4.1" }, 839186690Sobrien { AV_386_SSE4_2, "SSE4.2" }, 840186690Sobrien { 0, NULL } 841186690Sobrien}; 842186690Sobrien 843133359Sobrienprivate int 844186690Sobriendoshn(struct magic_set *ms, int clazz, int swap, int fd, off_t off, int num, 845226048Sobrien size_t size, off_t fsize, int *flags, int mach) 84668349Sobrien{ 847133359Sobrien Elf32_Shdr sh32; 848133359Sobrien Elf64_Shdr sh64; 849159764Sobrien int stripped = 1; 850159764Sobrien void *nbuf; 851226048Sobrien off_t noff, coff; 852186690Sobrien uint64_t cap_hw1 = 0; /* SunOS 5.x hardware capabilites */ 853186690Sobrien uint64_t cap_sf1 = 0; /* SunOS 5.x software capabilites */ 854133359Sobrien 855159764Sobrien if (size != xsh_sizeof) { 856133359Sobrien if (file_printf(ms, ", corrupted section header size") == -1) 857133359Sobrien return -1; 858133359Sobrien return 0; 859133359Sobrien } 860133359Sobrien 861133359Sobrien for ( ; num; num--) { 862226048Sobrien if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 863226048Sobrien file_badseek(ms); 864226048Sobrien return -1; 865226048Sobrien } 866159764Sobrien if (read(fd, xsh_addr, xsh_sizeof) == -1) { 867133359Sobrien file_badread(ms); 868133359Sobrien return -1; 869133359Sobrien } 870226048Sobrien off += size; 871226048Sobrien 872226048Sobrien /* Things we can determine before we seek */ 873159764Sobrien switch (xsh_type) { 874159764Sobrien case SHT_SYMTAB: 875159764Sobrien#if 0 876159764Sobrien case SHT_DYNSYM: 877159764Sobrien#endif 878159764Sobrien stripped = 0; 879159764Sobrien break; 880226048Sobrien default: 881226048Sobrien if (xsh_offset > fsize) { 882226048Sobrien /* Perhaps warn here */ 883226048Sobrien continue; 884226048Sobrien } 885226048Sobrien break; 886226048Sobrien } 887226048Sobrien 888226048Sobrien /* Things we can determine when we seek */ 889226048Sobrien switch (xsh_type) { 890159764Sobrien case SHT_NOTE: 891159764Sobrien if ((nbuf = malloc((size_t)xsh_size)) == NULL) { 892159764Sobrien file_error(ms, errno, "Cannot allocate memory" 893159764Sobrien " for note"); 894159764Sobrien return -1; 895159764Sobrien } 896159764Sobrien if ((noff = lseek(fd, (off_t)xsh_offset, SEEK_SET)) == 897159764Sobrien (off_t)-1) { 898159764Sobrien file_badread(ms); 899159764Sobrien free(nbuf); 900159764Sobrien return -1; 901159764Sobrien } 902159764Sobrien if (read(fd, nbuf, (size_t)xsh_size) != 903159764Sobrien (ssize_t)xsh_size) { 904159764Sobrien free(nbuf); 905159764Sobrien file_badread(ms); 906159764Sobrien return -1; 907159764Sobrien } 908159764Sobrien 909159764Sobrien noff = 0; 910159764Sobrien for (;;) { 911191736Sobrien if (noff >= (off_t)xsh_size) 912159764Sobrien break; 913159764Sobrien noff = donote(ms, nbuf, (size_t)noff, 914186690Sobrien (size_t)xsh_size, clazz, swap, 4, 915169942Sobrien flags); 916159764Sobrien if (noff == 0) 917159764Sobrien break; 918159764Sobrien } 919159764Sobrien free(nbuf); 920159764Sobrien break; 921186690Sobrien case SHT_SUNW_cap: 922186690Sobrien if (lseek(fd, (off_t)xsh_offset, SEEK_SET) == 923186690Sobrien (off_t)-1) { 924226048Sobrien file_badseek(ms); 925186690Sobrien return -1; 926186690Sobrien } 927186690Sobrien coff = 0; 928186690Sobrien for (;;) { 929186690Sobrien Elf32_Cap cap32; 930186690Sobrien Elf64_Cap cap64; 931191736Sobrien char cbuf[/*CONSTCOND*/ 932191736Sobrien MAX(sizeof cap32, sizeof cap64)]; 933226048Sobrien if ((coff += xcap_sizeof) > (off_t)xsh_size) 934186690Sobrien break; 935186690Sobrien if (read(fd, cbuf, (size_t)xcap_sizeof) != 936186690Sobrien (ssize_t)xcap_sizeof) { 937186690Sobrien file_badread(ms); 938186690Sobrien return -1; 939186690Sobrien } 940186690Sobrien (void)memcpy(xcap_addr, cbuf, xcap_sizeof); 941186690Sobrien switch (xcap_tag) { 942186690Sobrien case CA_SUNW_NULL: 943186690Sobrien break; 944186690Sobrien case CA_SUNW_HW_1: 945186690Sobrien cap_hw1 |= xcap_val; 946186690Sobrien break; 947186690Sobrien case CA_SUNW_SF_1: 948186690Sobrien cap_sf1 |= xcap_val; 949186690Sobrien break; 950186690Sobrien default: 951186690Sobrien if (file_printf(ms, 952186690Sobrien ", with unknown capability " 953226048Sobrien "0x%" INT64_T_FORMAT "x = 0x%" 954226048Sobrien INT64_T_FORMAT "x", 955191736Sobrien (unsigned long long)xcap_tag, 956191736Sobrien (unsigned long long)xcap_val) == -1) 957186690Sobrien return -1; 958186690Sobrien break; 959186690Sobrien } 960186690Sobrien } 961186690Sobrien break; 962226048Sobrien 963226048Sobrien default: 964226048Sobrien break; 965133359Sobrien } 966133359Sobrien } 967159764Sobrien if (file_printf(ms, ", %sstripped", stripped ? "" : "not ") == -1) 968133359Sobrien return -1; 969186690Sobrien if (cap_hw1) { 970186690Sobrien const cap_desc_t *cdp; 971186690Sobrien switch (mach) { 972186690Sobrien case EM_SPARC: 973186690Sobrien case EM_SPARC32PLUS: 974186690Sobrien case EM_SPARCV9: 975186690Sobrien cdp = cap_desc_sparc; 976186690Sobrien break; 977186690Sobrien case EM_386: 978186690Sobrien case EM_IA_64: 979186690Sobrien case EM_AMD64: 980186690Sobrien cdp = cap_desc_386; 981186690Sobrien break; 982186690Sobrien default: 983186690Sobrien cdp = NULL; 984186690Sobrien break; 985186690Sobrien } 986186690Sobrien if (file_printf(ms, ", uses") == -1) 987186690Sobrien return -1; 988186690Sobrien if (cdp) { 989186690Sobrien while (cdp->cd_name) { 990186690Sobrien if (cap_hw1 & cdp->cd_mask) { 991186690Sobrien if (file_printf(ms, 992186690Sobrien " %s", cdp->cd_name) == -1) 993186690Sobrien return -1; 994186690Sobrien cap_hw1 &= ~cdp->cd_mask; 995186690Sobrien } 996186690Sobrien ++cdp; 997186690Sobrien } 998186690Sobrien if (cap_hw1) 999186690Sobrien if (file_printf(ms, 1000226048Sobrien " unknown hardware capability 0x%" 1001226048Sobrien INT64_T_FORMAT "x", 1002191736Sobrien (unsigned long long)cap_hw1) == -1) 1003186690Sobrien return -1; 1004186690Sobrien } else { 1005186690Sobrien if (file_printf(ms, 1006226048Sobrien " hardware capability 0x%" INT64_T_FORMAT "x", 1007191736Sobrien (unsigned long long)cap_hw1) == -1) 1008186690Sobrien return -1; 1009186690Sobrien } 1010186690Sobrien } 1011186690Sobrien if (cap_sf1) { 1012186690Sobrien if (cap_sf1 & SF1_SUNW_FPUSED) { 1013186690Sobrien if (file_printf(ms, 1014186690Sobrien (cap_sf1 & SF1_SUNW_FPKNWN) 1015186690Sobrien ? ", uses frame pointer" 1016186690Sobrien : ", not known to use frame pointer") == -1) 1017186690Sobrien return -1; 1018186690Sobrien } 1019186690Sobrien cap_sf1 &= ~SF1_SUNW_MASK; 1020186690Sobrien if (cap_sf1) 1021186690Sobrien if (file_printf(ms, 1022226048Sobrien ", with unknown software capability 0x%" 1023226048Sobrien INT64_T_FORMAT "x", 1024191736Sobrien (unsigned long long)cap_sf1) == -1) 1025186690Sobrien return -1; 1026186690Sobrien } 1027133359Sobrien return 0; 1028133359Sobrien} 1029133359Sobrien 1030133359Sobrien/* 1031133359Sobrien * Look through the program headers of an executable image, searching 1032133359Sobrien * for a PT_INTERP section; if one is found, it's dynamically linked, 1033133359Sobrien * otherwise it's statically linked. 1034133359Sobrien */ 1035133359Sobrienprivate int 1036186690Sobriendophn_exec(struct magic_set *ms, int clazz, int swap, int fd, off_t off, 1037186690Sobrien int num, size_t size, off_t fsize, int *flags, int sh_num) 1038133359Sobrien{ 1039133359Sobrien Elf32_Phdr ph32; 1040133359Sobrien Elf64_Phdr ph64; 1041133359Sobrien const char *linking_style = "statically"; 1042133359Sobrien const char *shared_libraries = ""; 1043133359Sobrien unsigned char nbuf[BUFSIZ]; 1044226048Sobrien ssize_t bufsize; 1045133359Sobrien size_t offset, align; 1046169942Sobrien 1047159764Sobrien if (size != xph_sizeof) { 1048133359Sobrien if (file_printf(ms, ", corrupted program header size") == -1) 1049186690Sobrien return -1; 1050133359Sobrien return 0; 1051133359Sobrien } 1052169942Sobrien 1053133359Sobrien for ( ; num; num--) { 1054226048Sobrien if (lseek(fd, off, SEEK_SET) == (off_t)-1) { 1055226048Sobrien file_badseek(ms); 1056133359Sobrien return -1; 1057133359Sobrien } 1058169942Sobrien 1059226048Sobrien if (read(fd, xph_addr, xph_sizeof) == -1) { 1060226048Sobrien file_badread(ms); 1061133359Sobrien return -1; 1062133359Sobrien } 1063133359Sobrien 1064226048Sobrien off += size; 1065169942Sobrien 1066226048Sobrien /* Things we can determine before we seek */ 1067159764Sobrien switch (xph_type) { 1068133359Sobrien case PT_DYNAMIC: 1069133359Sobrien linking_style = "dynamically"; 1070133359Sobrien break; 1071133359Sobrien case PT_INTERP: 1072133359Sobrien shared_libraries = " (uses shared libs)"; 1073133359Sobrien break; 1074226048Sobrien default: 1075226048Sobrien if (xph_offset > fsize) { 1076226048Sobrien /* Maybe warn here? */ 1077226048Sobrien continue; 1078226048Sobrien } 1079226048Sobrien break; 1080226048Sobrien } 1081226048Sobrien 1082226048Sobrien /* Things we can determine when we seek */ 1083226048Sobrien switch (xph_type) { 1084133359Sobrien case PT_NOTE: 1085226048Sobrien if ((align = xph_align) & 0x80000000UL) { 1086133359Sobrien if (file_printf(ms, 1087133359Sobrien ", invalid note alignment 0x%lx", 1088133359Sobrien (unsigned long)align) == -1) 1089133359Sobrien return -1; 1090133359Sobrien align = 4; 1091133359Sobrien } 1092186690Sobrien if (sh_num) 1093186690Sobrien break; 1094133359Sobrien /* 1095133359Sobrien * This is a PT_NOTE section; loop through all the notes 1096133359Sobrien * in the section. 1097133359Sobrien */ 1098226048Sobrien if (lseek(fd, xph_offset, SEEK_SET) == (off_t)-1) { 1099133359Sobrien file_badseek(ms); 1100133359Sobrien return -1; 1101133359Sobrien } 1102159764Sobrien bufsize = read(fd, nbuf, ((xph_filesz < sizeof(nbuf)) ? 1103159764Sobrien xph_filesz : sizeof(nbuf))); 1104133359Sobrien if (bufsize == -1) { 1105133359Sobrien file_badread(ms); 1106133359Sobrien return -1; 1107133359Sobrien } 1108133359Sobrien offset = 0; 1109133359Sobrien for (;;) { 1110133359Sobrien if (offset >= (size_t)bufsize) 1111133359Sobrien break; 1112133359Sobrien offset = donote(ms, nbuf, offset, 1113186690Sobrien (size_t)bufsize, clazz, swap, align, 1114169942Sobrien flags); 1115133359Sobrien if (offset == 0) 1116133359Sobrien break; 1117133359Sobrien } 1118133359Sobrien break; 1119175296Sobrien default: 1120175296Sobrien break; 1121133359Sobrien } 1122133359Sobrien } 1123133359Sobrien if (file_printf(ms, ", %s linked%s", linking_style, shared_libraries) 1124133359Sobrien == -1) 1125133359Sobrien return -1; 1126133359Sobrien return 0; 1127133359Sobrien} 1128133359Sobrien 1129133359Sobrien 1130133359Sobrienprotected int 1131133359Sobrienfile_tryelf(struct magic_set *ms, int fd, const unsigned char *buf, 1132133359Sobrien size_t nbytes) 1133133359Sobrien{ 113468349Sobrien union { 1135103373Sobrien int32_t l; 1136103373Sobrien char c[sizeof (int32_t)]; 113768349Sobrien } u; 1138186690Sobrien int clazz; 113968349Sobrien int swap; 1140169942Sobrien struct stat st; 1141169942Sobrien off_t fsize; 1142169942Sobrien int flags = 0; 1143186690Sobrien Elf32_Ehdr elf32hdr; 1144186690Sobrien Elf64_Ehdr elf64hdr; 1145186690Sobrien uint16_t type; 114668349Sobrien 1147191736Sobrien if (ms->flags & (MAGIC_MIME|MAGIC_APPLE)) 1148186690Sobrien return 0; 114968349Sobrien /* 115068349Sobrien * ELF executables have multiple section headers in arbitrary 115168349Sobrien * file locations and thus file(1) cannot determine it from easily. 115268349Sobrien * Instead we traverse thru all section headers until a symbol table 115368349Sobrien * one is found or else the binary is stripped. 1154186690Sobrien * Return immediately if it's not ELF (so we avoid pipe2file unless needed). 115568349Sobrien */ 115668349Sobrien if (buf[EI_MAG0] != ELFMAG0 115768349Sobrien || (buf[EI_MAG1] != ELFMAG1 && buf[EI_MAG1] != OLFMAG1) 115868349Sobrien || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3) 1159186690Sobrien return 0; 116068349Sobrien 1161186690Sobrien /* 1162186690Sobrien * If we cannot seek, it must be a pipe, socket or fifo. 1163186690Sobrien */ 1164186690Sobrien if((lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) && (errno == ESPIPE)) 1165186690Sobrien fd = file_pipe2file(ms, fd, buf, nbytes); 116668349Sobrien 1167186690Sobrien if (fstat(fd, &st) == -1) { 1168186690Sobrien file_badread(ms); 1169186690Sobrien return -1; 117068349Sobrien } 1171186690Sobrien fsize = st.st_size; 117268349Sobrien 1173186690Sobrien clazz = buf[EI_CLASS]; 117468349Sobrien 1175186690Sobrien switch (clazz) { 1176186690Sobrien case ELFCLASS32: 1177186690Sobrien#undef elf_getu 1178186690Sobrien#define elf_getu(a, b) elf_getu32(a, b) 1179186690Sobrien#undef elfhdr 1180186690Sobrien#define elfhdr elf32hdr 1181186690Sobrien#include "elfclass.h" 1182186690Sobrien case ELFCLASS64: 1183186690Sobrien#undef elf_getu 1184186690Sobrien#define elf_getu(a, b) elf_getu64(a, b) 1185186690Sobrien#undef elfhdr 1186186690Sobrien#define elfhdr elf64hdr 1187186690Sobrien#include "elfclass.h" 1188186690Sobrien default: 1189186690Sobrien if (file_printf(ms, ", unknown class %d", clazz) == -1) 1190186690Sobrien return -1; 1191186690Sobrien break; 119268349Sobrien } 1193133359Sobrien return 0; 119468349Sobrien} 119568349Sobrien#endif 1196