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