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