Annotation of src/usr.bin/file/readelf.c, Revision 1.1
1.1 ! millert 1: /* $OpenBSD: file.c,v 1.4 1997/01/15 23:42:26 millert Exp $ */
! 2:
! 3: #ifdef BUILTIN_ELF
! 4: #include <sys/types.h>
! 5: #include <string.h>
! 6: #include <stdio.h>
! 7: #include <ctype.h>
! 8: #include <stdlib.h>
! 9: #include <unistd.h>
! 10: #include <errno.h>
! 11:
! 12: #include "readelf.h"
! 13: #include "file.h"
! 14:
! 15: static void
! 16: doshn(fd, off, num, size, buf)
! 17: int fd;
! 18: off_t off;
! 19: int num;
! 20: size_t size;
! 21: char *buf;
! 22: {
! 23: /*
! 24: * This works for both 32-bit and 64-bit ELF formats,
! 25: * because it looks only at the "sh_type" field, which is
! 26: * always 32 bits, and is preceded only by the "sh_name"
! 27: * field which is also always 32 bits, and because it uses
! 28: * the shdr size from the ELF header rather than using
! 29: * the size of an "Elf32_Shdr".
! 30: */
! 31: Elf32_Shdr *sh = (Elf32_Shdr *) buf;
! 32:
! 33: if (lseek(fd, off, SEEK_SET) == -1)
! 34: error("lseek failed (%s).\n", strerror(errno));
! 35:
! 36: for ( ; num; num--) {
! 37: if (read(fd, buf, size) == -1)
! 38: error("read failed (%s).\n", strerror(errno));
! 39: if (sh->sh_type == SHT_SYMTAB) {
! 40: (void) printf (", not stripped");
! 41: return;
! 42: }
! 43: }
! 44: (void) printf (", stripped");
! 45: }
! 46:
! 47: /*
! 48: * Look through the program headers of an executable image, searching
! 49: * for a PT_INTERP section; if one is found, it's dynamically linked,
! 50: * otherwise it's statically linked.
! 51: */
! 52: static void
! 53: dophn_exec(fd, off, num, size, buf)
! 54: int fd;
! 55: off_t off;
! 56: int num;
! 57: size_t size;
! 58: char *buf;
! 59: {
! 60: /* I am not sure if this works for 64 bit elf formats */
! 61: Elf32_Phdr *ph = (Elf32_Phdr *) buf;
! 62:
! 63: if (lseek(fd, off, SEEK_SET) == -1)
! 64: error("lseek failed (%s).\n", strerror(errno));
! 65:
! 66: for ( ; num; num--) {
! 67: if (read(fd, buf, size) == -1)
! 68: error("read failed (%s).\n", strerror(errno));
! 69: if (ph->p_type == PT_INTERP) {
! 70: /*
! 71: * Has an interpreter - must be a dynamically-linked
! 72: * executable.
! 73: */
! 74: printf(", dynamically linked");
! 75: return;
! 76: }
! 77: }
! 78: printf(", statically linked");
! 79: }
! 80:
! 81: size_t prpsoffsets[] = {
! 82: 100, /* SunOS 5.x */
! 83: 32, /* Linux */
! 84: };
! 85:
! 86: #define NOFFSETS (sizeof prpsoffsets / sizeof prpsoffsets[0])
! 87:
! 88: /*
! 89: * Look through the program headers of an executable image, searching
! 90: * for a PT_NOTE section of type NT_PRPSINFO, with a name "CORE"; if one
! 91: * is found, try looking in various places in its contents for a 16-character
! 92: * string containing only printable characters - if found, that string
! 93: * should be the name of the program that dropped core.
! 94: * Note: right after that 16-character string is, at least in SunOS 5.x
! 95: * (and possibly other SVR4-flavored systems) and Linux, a longer string
! 96: * (80 characters, in 5.x, probably other SVR4-flavored systems, and Linux)
! 97: * containing the start of the command line for that program.
! 98: */
! 99: static void
! 100: dophn_core(fd, off, num, size, buf)
! 101: int fd;
! 102: off_t off;
! 103: int num;
! 104: size_t size;
! 105: char *buf;
! 106: {
! 107: /*
! 108: * This doesn't work for 64-bit ELF, as the "p_offset" field is
! 109: * 64 bits in 64-bit ELF.
! 110: */
! 111: /*
! 112: * This doesn't work for 64-bit ELF, as the "p_offset" field is
! 113: * 64 bits in 64-bit ELF.
! 114: */
! 115: Elf32_Phdr *ph = (Elf32_Phdr *) buf;
! 116: Elf32_Nhdr *nh;
! 117: size_t offset, noffset, reloffset;
! 118: unsigned char c;
! 119: int i, j;
! 120: char nbuf[BUFSIZ];
! 121: int bufsize;
! 122:
! 123: for ( ; num; num--) {
! 124: if (lseek(fd, off, SEEK_SET) == -1)
! 125: error("lseek failed (%s).\n", strerror(errno));
! 126: if (read(fd, buf, size) == -1)
! 127: error("read failed (%s).\n", strerror(errno));
! 128: off += size;
! 129: if (ph->p_type != PT_NOTE)
! 130: continue;
! 131: if (lseek(fd, ph->p_offset, SEEK_SET) == -1)
! 132: error("lseek failed (%s).\n", strerror(errno));
! 133: bufsize = read(fd, nbuf, BUFSIZ);
! 134: if (bufsize == -1)
! 135: error("read failed (%s).\n", strerror(errno));
! 136: offset = 0;
! 137: for (;;) {
! 138: if (offset >= bufsize)
! 139: break;
! 140: nh = (Elf32_Nhdr *)&nbuf[offset];
! 141: offset += sizeof *nh;
! 142:
! 143: /*
! 144: * If this note isn't an NT_PRPSINFO note, it's
! 145: * not what we're looking for.
! 146: */
! 147: if (nh->n_type != NT_PRPSINFO) {
! 148: offset += nh->n_namesz;
! 149: offset = ((offset + 3)/4)*4;
! 150: offset += nh->n_descsz;
! 151: offset = ((offset + 3)/4)*4;
! 152: continue;
! 153: }
! 154:
! 155: /*
! 156: * Make sure this note has the name "CORE".
! 157: */
! 158: if (offset + nh->n_namesz >= bufsize) {
! 159: /*
! 160: * We're past the end of the buffer.
! 161: */
! 162: break;
! 163: }
! 164: if (nh->n_namesz != 5
! 165: || strcmp(&nbuf[offset], "CORE") != 0)
! 166: continue;
! 167: offset += nh->n_namesz;
! 168: offset = ((offset + 3)/4)*4;
! 169:
! 170: /*
! 171: * Extract the program name. We assume it to be
! 172: * 16 characters (that's what it is in SunOS 5.x
! 173: * and Linux).
! 174: *
! 175: * Unfortunately, it's at a different offset in
! 176: * SunOS 5.x and Linux, so try multiple offsets.
! 177: * If the characters aren't all printable, reject
! 178: * it.
! 179: */
! 180: for (i = 0; i < NOFFSETS; i++) {
! 181: reloffset = prpsoffsets[i];
! 182: noffset = offset + reloffset;
! 183: for (j = 0; j < 16;
! 184: j++, noffset++, reloffset++) {
! 185: /*
! 186: * Make sure we're not past the end
! 187: * of the buffer; if we are, just
! 188: * give up.
! 189: */
! 190: if (noffset >= bufsize)
! 191: return;
! 192:
! 193: /*
! 194: * Make sure we're not past the
! 195: * end of the contents; if we
! 196: * are, this obviously isn't
! 197: * the right offset.
! 198: */
! 199: if (reloffset >= nh->n_descsz)
! 200: goto tryanother;
! 201:
! 202: c = nbuf[noffset];
! 203: if (c != '\0' && !isprint(c))
! 204: goto tryanother;
! 205: }
! 206:
! 207: /*
! 208: * Well, that worked.
! 209: */
! 210: printf(", from '%.16s'",
! 211: &nbuf[offset + prpsoffsets[i]]);
! 212: return;
! 213:
! 214: tryanother:
! 215: ;
! 216: }
! 217: offset += nh->n_descsz;
! 218: offset = ((offset + 3)/4)*4;
! 219: }
! 220: }
! 221: }
! 222:
! 223: void
! 224: tryelf(fd, buf, nbytes)
! 225: int fd;
! 226: char *buf;
! 227: int nbytes;
! 228: {
! 229: union {
! 230: int32 l;
! 231: char c[sizeof (int32)];
! 232: } u;
! 233:
! 234: /*
! 235: * ELF executables have multiple section headers in arbitrary
! 236: * file locations and thus file(1) cannot determine it from easily.
! 237: * Instead we traverse thru all section headers until a symbol table
! 238: * one is found or else the binary is stripped.
! 239: */
! 240: if (buf[EI_MAG0] != ELFMAG0 || buf[EI_MAG1] != ELFMAG1
! 241: || buf[EI_MAG2] != ELFMAG2 || buf[EI_MAG3] != ELFMAG3)
! 242: return;
! 243:
! 244:
! 245: if (buf[4] == ELFCLASS32) {
! 246: Elf32_Ehdr elfhdr;
! 247: if (nbytes <= sizeof (Elf32_Ehdr))
! 248: return;
! 249:
! 250:
! 251: u.l = 1;
! 252: (void) memcpy(&elfhdr, buf, sizeof elfhdr);
! 253: /*
! 254: * If the system byteorder does not equal the
! 255: * object byteorder then don't test.
! 256: * XXX - we could conceivably fix up the "dophn_XXX()" and
! 257: * "doshn()" routines to extract stuff in the right
! 258: * byte order....
! 259: */
! 260: if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) {
! 261: if (elfhdr.e_type == ET_CORE)
! 262: dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum,
! 263: elfhdr.e_phentsize, buf);
! 264: else {
! 265: if (elfhdr.e_type == ET_EXEC) {
! 266: dophn_exec(fd, elfhdr.e_phoff,
! 267: elfhdr.e_phnum,
! 268: elfhdr.e_phentsize, buf);
! 269: }
! 270: doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum,
! 271: elfhdr.e_shentsize, buf);
! 272: }
! 273: }
! 274: return;
! 275: }
! 276:
! 277: if (buf[4] == ELFCLASS64) {
! 278: Elf64_Ehdr elfhdr;
! 279: if (nbytes <= sizeof (Elf64_Ehdr))
! 280: return;
! 281:
! 282:
! 283: u.l = 1;
! 284: (void) memcpy(&elfhdr, buf, sizeof elfhdr);
! 285:
! 286: /*
! 287: * If the system byteorder does not equal the
! 288: * object byteorder then don't test.
! 289: * XXX - we could conceivably fix up the "dophn_XXX()" and
! 290: * "doshn()" routines to extract stuff in the right
! 291: * byte order....
! 292: */
! 293: if ((u.c[sizeof(long) - 1] + 1) == elfhdr.e_ident[5]) {
! 294: #ifdef notyet
! 295: if (elfhdr.e_type == ET_CORE)
! 296: dophn_core(fd, elfhdr.e_phoff, elfhdr.e_phnum,
! 297: elfhdr.e_phentsize, buf);
! 298: else
! 299: #endif
! 300: {
! 301: #ifdef notyet
! 302: if (elfhdr.e_type == ET_EXEC) {
! 303: dophn_exec(fd, elfhdr.e_phoff,
! 304: elfhdr.e_phnum,
! 305: elfhdr.e_phentsize, buf);
! 306: }
! 307: #endif
! 308: doshn(fd, elfhdr.e_shoff, elfhdr.e_shnum,
! 309: elfhdr.e_shentsize, buf);
! 310: }
! 311: }
! 312: return;
! 313: }
! 314: }
! 315: #endif