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 (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 /* 26 * dispsyms: Display Symbols 27 * 28 * This program demonstrates the use of the libelf interface to 29 * read an ELF file. dispsyms will open an ELF file using 30 * elf_begin(ELF_C_READ) and examine search the ELF file 31 * for a symbol table (SHT_SYMTAB, SHT_DYNSYM, or SHT_SUNW_LDYNSYM). 32 * It will display the contents of any symbol tables it finds. 33 * 34 * Note: This program also understands about the use 35 * of 'Extended ELF Section indexes' and will 36 * decode a corresponding SHT_SYMTAB_SHNDX 37 * section if required. 38 */ 39 #include <stdio.h> 40 #include <libelf.h> 41 #include <gelf.h> 42 #include <fcntl.h> 43 #include <unistd.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 static const char *symbind[STB_NUM] = { 48 /* STB_LOCL */ "LOCL", 49 /* STB_GLOBAL */ "GLOB", 50 /* STB_WEAK */ "WEAK" 51 }; 52 53 static const char *symtype[STT_NUM] = { 54 /* STT_NOTYPE */ "NOTY", 55 /* STT_OBJECT */ "OBJT", 56 /* STT_FUNC */ "FUNC", 57 /* STT_SECTION */ "SECT", 58 /* STT_FILE */ "FILE", 59 /* STT_COMMON */ "COMM", 60 /* STT_TLS */ "TLS" 61 }; 62 #if STT_NUM != (STT_TLS + 1) 63 #error "STT_NUM has grown. Update symtype[]." 64 #endif 65 66 #define INTSTRLEN 32 67 68 69 static void 70 print_symtab(Elf *elf, const char *file) 71 { 72 Elf_Scn *scn = NULL; 73 GElf_Shdr shdr; 74 GElf_Ehdr ehdr; 75 size_t shstrndx; 76 77 78 if (gelf_getehdr(elf, &ehdr) == NULL) { 79 (void) fprintf(stderr, "%s: elf_getehdr() failed: %s\n", 80 file, elf_errmsg(0)); 81 return; 82 } 83 84 if (elf_getshdrstrndx(elf, &shstrndx) == -1) { 85 (void) fprintf(stderr, "%s: elf_getshdrstrndx() failed: %s\n", 86 file, elf_errmsg(0)); 87 return; 88 } 89 90 while ((scn = elf_nextscn(elf, scn)) != NULL) { 91 uint_t symcnt, ndx, nosymshndx; 92 Elf_Data *symdata, *shndxdata; 93 94 if (gelf_getshdr(scn, &shdr) == NULL) { 95 (void) fprintf(stderr, 96 "%s: elf_getshdr() failed: %s\n", 97 file, elf_errmsg(0)); 98 return; 99 } 100 if ((shdr.sh_type != SHT_SYMTAB) && 101 (shdr.sh_type != SHT_DYNSYM) && 102 (shdr.sh_type != SHT_SUNW_LDYNSYM)) 103 continue; 104 105 /* 106 * Get the data associated with the Symbol 107 * section. 108 */ 109 if ((symdata = elf_getdata(scn, NULL)) == NULL) { 110 (void) fprintf(stderr, 111 "%s: elf_getdata() failed: %s\n", 112 file, elf_errmsg(0)); 113 return; 114 } 115 116 /* 117 * Print symbol table title and header for symbol display 118 */ 119 (void) printf("\nSymTab: %s:%s\n", file, 120 elf_strptr(elf, shstrndx, shdr.sh_name)); 121 (void) printf(" index value size type " 122 "bind oth shndx name\n"); 123 124 /* 125 * We now iterate over the full symbol table printing 126 * the symbols as we go. 127 */ 128 shndxdata = 0; 129 nosymshndx = 0; 130 symcnt = shdr.sh_size / shdr.sh_entsize; 131 for (ndx = 0; ndx < symcnt; ndx++) { 132 GElf_Sym sym; 133 Elf32_Word shndx; 134 uint_t type, bind, specshndx; 135 char bindbuf[INTSTRLEN]; 136 char typebuf[INTSTRLEN]; 137 char shndxbuf[INTSTRLEN]; 138 const char *bindstr, *typestr, *shndxstr; 139 140 /* 141 * Get a symbol entry 142 */ 143 if (gelf_getsymshndx(symdata, shndxdata, ndx, 144 &sym, &shndx) == NULL) { 145 (void) fprintf(stderr, 146 "%s: gelf_getsymshndx() failed: %s\n", 147 file, elf_errmsg(0)); 148 return; 149 } 150 /* 151 * Check to see if this symbol's st_shndx is using 152 * the 'Extended SHNDX table' for a SYMTAB. 153 * 154 * If it is - and we haven't searched before, go 155 * find the associated SHT_SYMTAB_SHNDX section. 156 */ 157 if ((sym.st_shndx == SHN_XINDEX) && 158 (shndxdata == 0) && (nosymshndx == 0)) { 159 Elf_Scn *_scn = NULL; 160 GElf_Shdr _shdr; 161 GElf_Word symscnndx; 162 163 specshndx = 0; 164 symscnndx = elf_ndxscn(scn); 165 166 while ((_scn = 167 elf_nextscn(elf, _scn)) != NULL) { 168 if (gelf_getshdr(_scn, &_shdr) == NULL) 169 break; 170 171 /* 172 * We've found the Symtab SHNDX table 173 * if it's of type SHT_SYMTAB_SHNDX 174 * and it's shdr.sh_link points to the 175 * section index for the current symbol 176 * table. 177 */ 178 if ((_shdr.sh_type == 179 SHT_SYMTAB_SHNDX) && 180 (_shdr.sh_link == symscnndx) && 181 ((shndxdata = elf_getdata(_scn, 182 NULL)) != NULL)) 183 break; 184 } 185 /* 186 * Get a symbol entry 187 */ 188 if (shndxdata && 189 (gelf_getsymshndx(symdata, shndxdata, ndx, 190 &sym, &shndx) == NULL)) { 191 (void) fprintf(stderr, 192 "%s: gelf_getsymshndx() " 193 "failed: %s\n", 194 file, elf_errmsg(0)); 195 return; 196 } 197 /* 198 * No Symtab SHNDX table was found. We could 199 * give a fatal error here - instead we'll 200 * just mark that fact and display as much of 201 * the symbol table as we can. Any symbol 202 * displayed with a XINDX section index has 203 * a bogus value. 204 */ 205 if (shndxdata == 0) 206 nosymshndx = 1; 207 } 208 209 /* 210 * Decode the type & binding information 211 */ 212 type = GELF_ST_TYPE(sym.st_info); 213 bind = GELF_ST_BIND(sym.st_info); 214 215 if (type < STT_NUM) 216 typestr = symtype[type]; 217 else { 218 (void) snprintf(typebuf, INTSTRLEN, 219 "%d", type); 220 typestr = typebuf; 221 } 222 223 if (bind < STB_NUM) 224 bindstr = symbind[bind]; 225 else { 226 (void) snprintf(bindbuf, INTSTRLEN, 227 "%d", bind); 228 bindstr = bindbuf; 229 } 230 231 232 specshndx = 0; 233 if (sym.st_shndx < SHN_LORESERVE) 234 shndx = sym.st_shndx; 235 else if ((sym.st_shndx != SHN_XINDEX) || 236 (shndxdata == NULL)) { 237 shndx = sym.st_shndx; 238 specshndx = 1; 239 } 240 241 if (shndx == SHN_UNDEF) { 242 shndxstr = (const char *)"UNDEF"; 243 244 } else if (specshndx) { 245 if (shndx == SHN_ABS) 246 shndxstr = (const char *)"ABS"; 247 else if (shndx == SHN_COMMON) 248 shndxstr = (const char *)"COMM"; 249 else if (shndx == SHN_XINDEX) 250 shndxstr = (const char *)"XIND"; 251 else { 252 (void) snprintf(shndxbuf, INTSTRLEN, 253 "%ld", shndx); 254 shndxstr = shndxbuf; 255 } 256 } else { 257 (void) snprintf(shndxbuf, INTSTRLEN, 258 "%ld", shndx); 259 shndxstr = shndxbuf; 260 } 261 262 /* 263 * Display the symbol entry. 264 */ 265 (void) printf("[%3d] 0x%08llx 0x%08llx %-4s " 266 "%-6s %2d %5s %s\n", 267 ndx, sym.st_value, sym.st_size, 268 typestr, bindstr, sym.st_other, shndxstr, 269 elf_strptr(elf, shdr.sh_link, sym.st_name)); 270 } 271 } 272 } 273 274 275 static void 276 process_elf(Elf *elf, char *file, int fd, int member) 277 { 278 Elf_Cmd cmd; 279 Elf *_elf; 280 281 switch (elf_kind(elf)) { 282 case ELF_K_ELF: 283 /* 284 * This is an ELF file, now attempt to find it's 285 * .comment section and to display it. 286 */ 287 print_symtab(elf, file); 288 break; 289 case ELF_K_AR: 290 /* 291 * Archives contain multiple ELF files, which can each 292 * in turn be examined with libelf. 293 * 294 * The below loop will iterate over each member of the 295 * archive and recursively call process_elf(). 296 */ 297 cmd = ELF_C_READ; 298 while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 299 Elf_Arhdr *arhdr; 300 char buffer[1024]; 301 302 arhdr = elf_getarhdr(_elf); 303 304 /* 305 * Build up file names based off of 306 * 'archivename(membername)'. 307 */ 308 (void) snprintf(buffer, 1024, "%s(%s)", 309 file, arhdr->ar_name); 310 311 /* 312 * Recursively process the ELF members. 313 */ 314 process_elf(_elf, buffer, fd, 1); 315 cmd = elf_next(_elf); 316 (void) elf_end(_elf); 317 } 318 break; 319 default: 320 if (!member) 321 (void) fprintf(stderr, 322 "%s: unexpected elf_kind(): 0x%x\n", 323 file, elf_kind(elf)); 324 return; 325 } 326 } 327 328 int 329 main(int argc, char **argv) 330 { 331 int i; 332 333 if (argc < 2) { 334 (void) printf("usage: %s elf_file ...\n", argv[0]); 335 return (1); 336 } 337 338 /* 339 * Initialize the elf library, must be called before elf_begin() 340 * can be called. 341 */ 342 if (elf_version(EV_CURRENT) == EV_NONE) { 343 (void) fprintf(stderr, 344 "elf_version() failed: %s\n", elf_errmsg(0)); 345 return (1); 346 } 347 348 for (i = 1; i < argc; i++) { 349 int fd; 350 Elf *elf; 351 char *elf_fname; 352 353 elf_fname = argv[i]; 354 if ((fd = open(elf_fname, O_RDONLY)) == -1) { 355 perror("open"); 356 continue; 357 } 358 359 /* 360 * Attempt to open an Elf descriptor Read-Only 361 * for each file. 362 */ 363 if ((elf = elf_begin(fd, ELF_C_READ, 0)) == NULL) { 364 (void) fprintf(stderr, "elf_begin() failed: %s\n", 365 elf_errmsg(0)); 366 (void) close(fd); 367 continue; 368 } 369 370 /* 371 * Process each elf descriptor. 372 */ 373 process_elf(elf, elf_fname, fd, 0); 374 (void) elf_end(elf); 375 (void) close(fd); 376 } 377 378 return (0); 379 } 380