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