xref: /titanic_52/usr/src/ucblib/libucb/port/gen/nlist.c (revision 5bbb4db2c3f208d12bf0fd11769728f9e5ba66a2)
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
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
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 *
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
348  end_elf_job(int fd)
349  {
350  	(void) close(fd);
351  	return (-1);
352  }
353  
354  #if COFF_NLIST_SUPPORTED
355  static int
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
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
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
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