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