/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * dispsyms: Display Symbols * * This program demonstrates the use of the libelf interface to * read an ELF file. dispsyms will open an ELF file using * elf_begin(ELF_C_READ) and examine search the ELF file * for a symbol table (SHT_SYMTAB, SHT_DYNSYM, or SHT_SUNW_LDYNSYM). * It will display the contents of any symbol tables it finds. * * Note: This program also understands about the use * of 'Extended ELF Section indexes' and will * decode a corresponding SHT_SYMTAB_SHNDX * section if required. */ #include #include #include #include #include #include #include static const char *symbind[STB_NUM] = { /* STB_LOCL */ "LOCL", /* STB_GLOBAL */ "GLOB", /* STB_WEAK */ "WEAK" }; static const char *symtype[STT_NUM] = { /* STT_NOTYPE */ "NOTY", /* STT_OBJECT */ "OBJT", /* STT_FUNC */ "FUNC", /* STT_SECTION */ "SECT", /* STT_FILE */ "FILE", /* STT_COMMON */ "COMM", /* STT_TLS */ "TLS" }; #if STT_NUM != (STT_TLS + 1) #error "STT_NUM has grown. Update symtype[]." #endif #define INTSTRLEN 32 static void print_symtab(Elf *elf, const char *file) { Elf_Scn *scn; GElf_Shdr shdr; GElf_Ehdr ehdr; size_t shstrndx; if (gelf_getehdr(elf, &ehdr) == 0) { (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", file, elf_errmsg(0)); return; } if (elf_getshdrstrndx(elf, &shstrndx) == -1) { (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", file, elf_errmsg(0)); return; } scn = 0; while ((scn = elf_nextscn(elf, scn)) != 0) { uint_t symcnt; uint_t ndx; uint_t nosymshndx; Elf_Data *symdata; Elf_Data *shndxdata; if (gelf_getshdr(scn, &shdr) == 0) { (void) fprintf(stderr, "%s: elf_getshdr() failed: %s\n", file, elf_errmsg(0)); return; } if ((shdr.sh_type != SHT_SYMTAB) && (shdr.sh_type != SHT_DYNSYM) && (shdr.sh_type != SHT_SUNW_LDYNSYM)) continue; /* * Get the data associated with the Symbol * section. */ if ((symdata = elf_getdata(scn, 0)) == 0) { (void) fprintf(stderr, "%s: elf_getdata() failed: %s\n", file, elf_errmsg(0)); return; } /* * Print symbol table title and header for symbol display */ (void) printf("\nSymTab: %s:%s\n", file, elf_strptr(elf, shstrndx, shdr.sh_name)); (void) printf(" index value size type " "bind oth shndx name\n"); /* * We now iterate over the full symbol table printing * the symbols as we go. */ shndxdata = 0; nosymshndx = 0; symcnt = shdr.sh_size / shdr.sh_entsize; for (ndx = 0; ndx < symcnt; ndx++) { GElf_Sym sym; Elf32_Word shndx; uint_t type; uint_t bind; uint_t specshndx; char bindbuf[INTSTRLEN]; char typebuf[INTSTRLEN]; char shndxbuf[INTSTRLEN]; const char *bindstr; const char *typestr; const char *shndxstr; /* * Get a symbol entry */ if (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL) { (void) fprintf(stderr, "%s: gelf_getsymshndx() failed: %s\n", file, elf_errmsg(0)); return; } /* * Check to see if this symbol's st_shndx * is using the 'Extended SHNDX table' for * a SYMTAB. * * If it is - and we havn't searched before, * go find the associated SHT_SYMTAB_SHNDX * section. */ if ((sym.st_shndx == SHN_XINDEX) && (shndxdata == 0) && (nosymshndx == 0)) { Elf_Scn *_scn; GElf_Shdr _shdr; GElf_Word symscnndx; _scn = 0; specshndx = 0; symscnndx = elf_ndxscn(scn); while ((_scn = elf_nextscn(elf, _scn)) != 0) { if (gelf_getshdr(_scn, &_shdr) == 0) break; /* * We've found the Symtab SHNDX table * if it's of type SHT_SYMTAB_SHNDX * and it's shdr.sh_link points to the * section index for the current symbol * table. */ if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) && (_shdr.sh_link == symscnndx)) { if ((shndxdata = elf_getdata(_scn, 0)) != 0) break; } } /* * Get a symbol entry */ if (shndxdata && (gelf_getsymshndx(symdata, shndxdata, ndx, &sym, &shndx) == NULL)) { (void) fprintf(stderr, "%s: gelf_getsymshndx() " "failed: %s\n", file, elf_errmsg(0)); return; } /* * No Symtab SHNDX table was found. We could * give a fatal error here - instead we'll * just mark that fact and display as much of * the symbol table as we can. Any symbol * displayed with a XINDX section index has * a bogus value. */ if (shndxdata == 0) nosymshndx = 1; } /* * Decode the type & binding information */ type = GELF_ST_TYPE(sym.st_info); bind = GELF_ST_BIND(sym.st_info); if (type < STT_NUM) typestr = symtype[type]; else { (void) snprintf(typebuf, INTSTRLEN, "%d", type); typestr = typebuf; } if (bind < STB_NUM) bindstr = symbind[bind]; else { (void) snprintf(bindbuf, INTSTRLEN, "%d", bind); bindstr = bindbuf; } specshndx = 0; if (sym.st_shndx < SHN_LORESERVE) shndx = sym.st_shndx; else if ((sym.st_shndx != SHN_XINDEX) || (shndxdata == NULL)) { shndx = sym.st_shndx; specshndx = 1; } if (shndx == SHN_UNDEF) { shndxstr = (const char *)"UNDEF"; } else if (specshndx) { if (shndx == SHN_ABS) shndxstr = (const char *)"ABS"; else if (shndx == SHN_COMMON) shndxstr = (const char *)"COMM"; else if (shndx == SHN_XINDEX) shndxstr = (const char *)"XIND"; else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } } else { (void) snprintf(shndxbuf, INTSTRLEN, "%ld", shndx); shndxstr = shndxbuf; } /* * Display the symbol entry. */ (void) printf("[%3d] 0x%08llx 0x%08llx %-4s " "%-6s %2d %5s %s\n", ndx, sym.st_value, sym.st_size, typestr, bindstr, sym.st_other, shndxstr, elf_strptr(elf, shdr.sh_link, sym.st_name)); } } } static void process_elf(Elf *elf, char *file, int fd, int member) { Elf_Cmd cmd; Elf *_elf; switch (elf_kind(elf)) { case ELF_K_ELF: /* * This is an ELF file, now attempt to find it's * .comment section and to display it. */ print_symtab(elf, file); break; case ELF_K_AR: /* * Archives contain multiple ELF files, which can each * in turn be examined with libelf. * * The below loop will iterate over each member of the * archive and recursivly call process_elf() for processing. */ cmd = ELF_C_READ; while ((_elf = elf_begin(fd, cmd, elf)) != 0) { Elf_Arhdr *arhdr; char buffer[1024]; arhdr = elf_getarhdr(_elf); /* * Build up file names based off of * 'archivename(membername)'. */ (void) snprintf(buffer, 1024, "%s(%s)", file, arhdr->ar_name); /* * recursivly process the ELF members. */ process_elf(_elf, buffer, fd, 1); cmd = elf_next(_elf); (void) elf_end(_elf); } break; default: if (!member) (void) fprintf(stderr, "%s: unexpected elf_kind(): 0x%x\n", file, elf_kind(elf)); return; } } int main(int argc, char **argv) { int i; if (argc < 2) { (void) printf("usage: %s elf_file ...\n", argv[0]); return (1); } /* * Initialize the elf library, must be called before elf_begin() * can be called. */ if (elf_version(EV_CURRENT) == EV_NONE) { (void) fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); return (1); } for (i = 1; i < argc; i++) { int fd; Elf *elf; char *elf_fname; elf_fname = argv[i]; if ((fd = open(elf_fname, O_RDONLY)) == -1) { perror("open"); continue; } /* * Attempt to open an Elf descriptor Read-Only * for each file. */ if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { (void) fprintf(stderr, "elf_begin() failed: %s\n", elf_errmsg(0)); (void) close(fd); continue; } /* * Process each elf descriptor. */ process_elf(elf, elf_fname, fd, 0); (void) elf_end(elf); (void) close(fd); } return (0); }