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