1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1988 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 /*LINTLIBRARY*/
40
41 #include <sys/types.h>
42 #include "libelf.h"
43 #include <stdlib.h>
44 #include <unistd.h>
45 #include <sys/fcntl.h>
46 #include <nlist.h>
47 #include <sys/file.h>
48 #include <string.h>
49
50 #if COFF_NLIST_SUPPORTED
51 #include "aouthdr.h"
52 #include "filehdr.h"
53 #include "scnhdr.h"
54 #include "reloc.h"
55 #endif /* COFF_NLIST_SUPPORTED */
56
57 #include "linenum.h"
58 #include "syms.h"
59
60 #undef BADMAG
61 #define BADMAG(x) (!ISCOFF(x))
62
63 #ifndef FLEXNAMES
64 #define FLEXNAMES 1
65 #endif
66 #undef n_name /* this patch causes problems here */
67
68 #define SPACE 100 /* number of symbols read at a time */
69 #define ISELF (strncmp(magic_buf, ELFMAG, SELFMAG) == 0)
70
71 #if COFF_NLIST_SUPPORTED
72 static char sym_buf[SPACE * SYMESZ];
73 static int num_in_buf = 0;
74 static char *next_entry = (char *)0;
75 #endif /* COFF_NLIST_SUPPORTED */
76
77 static unsigned encode; /* data encoding if an ELF file */
78 static unsigned fvers; /* object file version if an ELF file */
79
80 /* forward declarations */
81 static int _elf_nlist(int, struct nlist *);
82 static int end_elf_job(int);
83 static Elf_Data *elf_read(int, long, size_t, size_t, Elf_Type);
84
85 #if COFF_NLIST_SUPPORTED
86 static int _coff_nlist(int, struct nlist *);
87 static void sym_close(int);
88 static int sym_read(int, struct syment *, int);
89 static int fill_sym_buf(int, int);
90 #endif /* COFF_NLIST_SUPPORTED */
91
92 int
nlist(const char * name,struct nlist * list)93 nlist(const char *name, struct nlist *list)
94 {
95 struct nlist *p;
96 char magic_buf[EI_NIDENT+1];
97 int fd;
98
99 for (p = list; p->n_name && p->n_name[0]; p++) { /* n_name can be ptr */
100 p->n_type = 0;
101 p->n_value = 0L;
102 p->n_scnum = 0;
103 p->n_sclass = 0;
104 p->n_numaux = 0;
105 }
106
107 if ((fd = open(name, 0)) < 0)
108 return (-1);
109 if (read(fd, magic_buf, (size_t)EI_NIDENT) == -1) {
110 (void) close(fd);
111 return (-1);
112 }
113 magic_buf[EI_NIDENT] = '\0';
114 if (lseek(fd, 0L, 0) == -1L) { /* rewind to beginning of object file */
115 (void) close(fd);
116 return (-1);
117 }
118
119 if (ISELF) {
120 /*
121 * right now can only handle 32-bit architectures
122 * XX64 work to come? ELFCLASS64?
123 */
124 if (magic_buf[EI_CLASS] != ELFCLASS32) {
125 (void) close(fd);
126 return (-1);
127 }
128 encode = (unsigned)magic_buf[EI_DATA];
129 fvers = (unsigned)magic_buf[EI_VERSION];
130 return (_elf_nlist(fd, list));
131 }
132 else
133 #if COFF_NLIST_SUPPORTED
134 return (_coff_nlist(fd, list));
135 #else /* COFF_NLIST_SUPPORTED */
136 return (-1);
137 #endif /* COFF_NLIST_SUPPORTED */
138 }
139
140 static int
_elf_nlist(int fd,struct nlist * list)141 _elf_nlist(int fd, struct nlist *list)
142 {
143 Elf_Data *symdata; /* buffer points to symbol table */
144 Elf_Data *strdata; /* buffer points to string table */
145 Elf_Data *secdata; /* buffer points to section table */
146 Elf32_Shdr *symhdr; /* section table entry for symtab */
147 Elf32_Shdr *strhdr; /* section table entry for strtab */
148 Elf32_Sym *sym; /* buffer storing one symbol information */
149 Elf32_Sym *sym_end; /* end of symbol table */
150 Elf32_Ehdr *ehdr; /* file header */
151 Elf_Data *edata; /* data buffer for ehdr */
152 int i;
153 int nreq;
154 struct nlist *inl;
155
156 if (elf_version(EV_CURRENT) == EV_NONE)
157 return (end_elf_job(fd));
158
159 /* count the number of symbols requested */
160 for (inl = list, nreq = 0; inl->n_name && inl->n_name[0]; ++inl, nreq++)
161 ;
162
163 /* read file header and section header table */
164 if ((edata = elf_read(fd, 0L, elf32_fsize(ELF_T_EHDR, 1, fvers),
165 sizeof (Elf32_Ehdr), ELF_T_EHDR)) == 0)
166 return (end_elf_job(fd));
167
168 ehdr = (Elf32_Ehdr *)edata->d_buf;
169
170 if (ehdr->e_shoff == 0) {
171 free(edata->d_buf);
172 free(edata);
173 return (end_elf_job(fd));
174 }
175
176 if ((secdata = elf_read(fd, (long)ehdr->e_shoff,
177 (size_t)(ehdr->e_shentsize * ehdr->e_shnum),
178 (size_t)(ehdr->e_shnum * sizeof (Elf32_Ehdr)),
179 ELF_T_SHDR)) == 0) {
180 free(edata->d_buf);
181 free(edata);
182 return (end_elf_job(fd));
183 }
184
185 /* find symbol table section */
186 symhdr = (Elf32_Shdr *)secdata->d_buf;
187 for (i = 0; i < (Elf32_Word)ehdr->e_shnum; i++, symhdr++)
188 if (symhdr->sh_type == SHT_SYMTAB)
189 break;
190
191 if ((symhdr->sh_type != SHT_SYMTAB) ||
192 (symhdr->sh_link >= ehdr->e_shnum)) {
193 free(secdata->d_buf);
194 free(secdata);
195 free(edata->d_buf);
196 free(edata);
197 return (end_elf_job(fd));
198 }
199
200 if ((symdata = elf_read(fd, (long)symhdr->sh_offset,
201 (size_t)symhdr->sh_size,
202 (size_t)((symhdr->sh_size / symhdr->sh_entsize) *
203 sizeof (Elf32_Sym)), ELF_T_SYM)) == 0) {
204 free(secdata->d_buf);
205 free(secdata);
206 free(edata->d_buf);
207 free(edata);
208 return (end_elf_job(fd));
209 }
210
211 /* read string table */
212 strhdr = (Elf32_Shdr *)secdata->d_buf;
213 strhdr = strhdr + symhdr->sh_link;
214
215 if (strhdr->sh_type != SHT_STRTAB) {
216 free(symdata->d_buf);
217 free(symdata);
218 free(secdata->d_buf);
219 free(secdata);
220 free(edata->d_buf);
221 free(edata);
222 return (end_elf_job(fd));
223 }
224
225 if ((strdata = elf_read(fd, strhdr->sh_offset, strhdr->sh_size,
226 strhdr->sh_size, ELF_T_BYTE)) == 0) {
227 free(symdata->d_buf);
228 free(symdata);
229 free(secdata->d_buf);
230 free(secdata);
231 free(edata->d_buf);
232 free(edata);
233 return (end_elf_job(fd));
234 }
235
236 ((char *)strdata->d_buf)[0] = '\0';
237 ((char *)strdata->d_buf)[strhdr->sh_size-1] = '\0';
238
239 sym = (Elf32_Sym *) (symdata->d_buf);
240 sym_end = sym + symdata->d_size / sizeof (Elf32_Sym);
241 for (; sym < sym_end; ++sym) {
242 struct nlist *p;
243 char *name;
244 if (sym->st_name > strhdr->sh_size) {
245 free(strdata->d_buf);
246 free(strdata);
247 free(symdata->d_buf);
248 free(symdata);
249 free(secdata->d_buf);
250 free(secdata);
251 free(edata->d_buf);
252 free(edata);
253 return (end_elf_job(fd));
254 }
255 name = (char *)strdata->d_buf + sym->st_name;
256 if (name == 0)
257 continue;
258 for (p = list; p->n_name && p->n_name[0]; ++p) {
259 if (strcmp(p->n_name, name)) {
260 continue;
261 }
262 p->n_value = sym->st_value;
263 p->n_type = ELF32_ST_TYPE(sym->st_info);
264 p->n_scnum = sym->st_shndx;
265 nreq--;
266 break;
267 }
268 }
269 /*
270 * Currently there is only one symbol table section
271 * in an object file, but this restriction may be
272 * relaxed in the future.
273 */
274 (void) close(fd);
275 free(secdata->d_buf);
276 free(strdata->d_buf);
277 free(symdata->d_buf);
278 free(edata->d_buf);
279 free(secdata);
280 free(strdata);
281 free(symdata);
282 free(edata);
283 return (nreq);
284 }
285
286 /*
287 * allocate memory of size memsize and read size bytes
288 * starting at offset from fd - the file data are
289 * translated in place using the low-level libelf
290 * translation routines
291 */
292
293 static Elf_Data *
elf_read(int fd,long offset,size_t size,size_t memsize,Elf_Type dtype)294 elf_read(int fd, long offset, size_t size, size_t memsize, Elf_Type dtype)
295 {
296 Elf_Data *dsrc, *ddst;
297 Elf_Data srcdata;
298 size_t maxsize;
299 char *p;
300
301 dsrc = &srcdata;
302
303 if (size == 0)
304 return (0);
305
306 if ((maxsize = memsize) < size)
307 maxsize = size;
308
309
310 if ((ddst = (Elf_Data *)malloc(sizeof (Elf_Data))) == 0)
311 return (0);
312
313 if ((p = malloc(maxsize)) == 0) {
314 free(ddst);
315 return (0);
316 }
317
318 if (lseek(fd, offset, 0L) == -1) {
319 free(ddst);
320 free(p);
321 return (0);
322 }
323
324 if (read(fd, p, size) != size) {
325 free(ddst);
326 free(p);
327 return (0);
328 }
329
330 dsrc->d_buf = p;
331 dsrc->d_type = dtype;
332 dsrc->d_size = size;
333 dsrc->d_version = fvers;
334 ddst->d_buf = p;
335 ddst->d_size = memsize;
336 ddst->d_version = EV_CURRENT;
337
338 if (elf32_xlatetom(ddst, dsrc, encode) != ddst) {
339 free(ddst);
340 free(p);
341 return (0);
342 }
343
344 return (ddst);
345 }
346
347 static int
end_elf_job(int fd)348 end_elf_job(int fd)
349 {
350 (void) close(fd);
351 return (-1);
352 }
353
354 #if COFF_NLIST_SUPPORTED
355 static int
_coff_nlist(int fd,struct nlist * list)356 _coff_nlist(int fd, struct nlist *list)
357 {
358 struct filehdr buf;
359 struct syment sym;
360 long n;
361 int bufsiz = FILHSZ;
362 #if FLEXNAMES
363 char *strtab = (char *)0;
364 long strtablen;
365 #endif
366 struct nlist *p, *inl;
367 struct syment *q;
368 long sa;
369 int nreq;
370
371 if (read(fd, (char *)&buf, bufsiz) == -1) {
372 (void) close(fd);
373 return (-1);
374 }
375
376 if (BADMAG(buf.f_magic)) {
377 (void) close(fd);
378 return (-1);
379 }
380 sa = buf.f_symptr; /* direct pointer to sym tab */
381 if (lseek(fd, (long)sa, 0) == -1L) {
382 (void) close(fd);
383 return (-1);
384 }
385 q = &sym;
386 n = buf.f_nsyms; /* num. of sym tab entries */
387
388 /* count the number of symbols requested */
389 for (inl = list, nreq = 0; inl->n_name && inl->n_name[0]; ++inl, nreq++)
390 ;
391
392 while (n) {
393 if (sym_read(fd, &sym, SYMESZ) == -1) {
394 sym_close(fd);
395 return (-1);
396 }
397 n -= (q->n_numaux + 1L);
398 for (p = list; p->n_name && p->n_name[0]; ++p) {
399 if (p->n_value != 0L && p->n_sclass == C_EXT)
400 continue;
401 /*
402 * For 6.0, the name in an object file is
403 * either stored in the eight long character
404 * array, or in a string table at the end
405 * of the object file. If the name is in the
406 * string table, the eight characters are
407 * thought of as a pair of longs, (n_zeroes
408 * and n_offset) the first of which is zero
409 * and the second is the offset of the name
410 * in the string table.
411 */
412 #if FLEXNAMES
413 if (q->n_zeroes == 0L) /* in string table */
414 {
415 if (strtab == (char *)0) /* need it */
416 {
417 long home = lseek(fd, 0L, 1);
418 if (home == -1L) {
419 sym_close(fd);
420 return (-1);
421 }
422 if (lseek(fd, buf.f_symptr +
423 buf.f_nsyms * SYMESZ, 0) == -1 ||
424 read(fd, (char *)&strtablen,
425 sizeof (long)) != sizeof (long) ||
426 (strtab = (char *)malloc(
427 (unsigned)strtablen)) ==
428 (char *)0 ||
429 read(fd, strtab + sizeof (long),
430 strtablen - sizeof (long)) !=
431 strtablen - sizeof (long) ||
432 strtab[strtablen - 1] != '\0' ||
433 lseek(fd, home, 0) == -1) {
434 (void) lseek(fd, home, 0);
435 sym_close(fd);
436 if (strtab != (char *)0)
437 free(strtab);
438 return (-1);
439 }
440 }
441 if (q->n_offset < sizeof (long) ||
442 q->n_offset >= strtablen) {
443 sym_close(fd);
444 if (strtab != (char *)0)
445 free(strtab);
446 return (-1);
447 }
448 if (strcmp(&strtab[q->n_offset],
449 p->n_name)) {
450 continue;
451 }
452 }
453 else
454 #endif /* FLEXNAMES */
455 {
456 if (strncmp(q->_n._n_name,
457 p->n_name, SYMNMLEN)) {
458 continue;
459 }
460 }
461
462 p->n_value = q->n_value;
463 p->n_type = q->n_type;
464 p->n_scnum = q->n_scnum;
465 p->n_sclass = q->n_sclass;
466 nreq--;
467 break;
468 }
469 }
470 #if FLEXNAMES
471 sym_close(fd);
472 if (strtab != (char *)0)
473 free(strtab);
474 #endif
475 return (nreq);
476 }
477
478 static void
sym_close(int fd)479 sym_close(int fd)
480 {
481 num_in_buf = 0;
482 next_entry = (char *)0;
483
484 (void) close(fd);
485 }
486
487 /* buffered read of symbol table */
488 static int
sym_read(int fd,struct syment * sym,int size)489 sym_read(int fd, struct syment *sym, int size)
490 {
491 long where = 0L;
492
493 if ((where = lseek(fd, 0L, 1)) == -1L) {
494 sym_close(fd);
495 return (-1);
496 }
497
498 if (!num_in_buf) {
499 if (fill_sym_buf(fd, size) == -1)
500 return (-1);
501 }
502 (void) memcpy((char *)sym, next_entry, size);
503 num_in_buf--;
504
505 if (sym->n_numaux && !num_in_buf) {
506 if (fill_sym_buf(fd, size) == -1)
507 return (-1);
508 }
509 if ((lseek(fd, where + SYMESZ + (AUXESZ * sym->n_numaux), 0)) == -1L) {
510 sym_close(fd);
511 return (-1);
512 }
513 size += AUXESZ * sym->n_numaux;
514 num_in_buf--;
515
516 next_entry += size;
517 return (0);
518 }
519
520 static int
fill_sym_buf(int fd,int size)521 fill_sym_buf(int fd, int size)
522 {
523 if ((num_in_buf = read(fd, sym_buf, size * SPACE)) == -1)
524 return (-1);
525 num_in_buf /= size;
526 next_entry = &(sym_buf[0]);
527 return (0);
528 }
529 #endif /* COFF_NLIST_SUPPORTED */
530