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