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