Annotation of src/usr.bin/file/readelf.c, Revision 1.2
1.2 ! mickey 1: /* $OpenBSD: readelf.c,v 1.1 1997/02/09 23:58:33 millert Exp $ */
1.1 millert 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)
1.2 ! mickey 34: err(1, "lseek failed");
1.1 millert 35:
36: for ( ; num; num--) {
37: if (read(fd, buf, size) == -1)
1.2 ! mickey 38: err(1, "read failed");
1.1 millert 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)
1.2 ! mickey 64: err(1, "lseek failed");
1.1 millert 65:
66: for ( ; num; num--) {
67: if (read(fd, buf, size) == -1)
1.2 ! mickey 68: err(1, "read failed");
1.1 millert 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)
1.2 ! mickey 125: err(1, "lseek failed");
1.1 millert 126: if (read(fd, buf, size) == -1)
1.2 ! mickey 127: err(1, "read failed");
1.1 millert 128: off += size;
129: if (ph->p_type != PT_NOTE)
130: continue;
131: if (lseek(fd, ph->p_offset, SEEK_SET) == -1)
1.2 ! mickey 132: err(1, "lseek failed");
1.1 millert 133: bufsize = read(fd, nbuf, BUFSIZ);
134: if (bufsize == -1)
1.2 ! mickey 135: err(1, "read failed");
1.1 millert 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