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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * dispsyms: Display Symbols 30 * 31 * This program demonstrates the use of the libelf interface to 32 * read an ELF file. dispsyms will open an ELF file using 33 * elf_begin(ELF_C_READ) and examine search the ELF file 34 * for either a SHT_SYMTAB or SHT_DYNSYM symbol table. 35 * If it finds either - it will display the contents of 36 * the symbol tables it finds. 37 * 38 * Note: This program also understands about the use 39 * of 'Extended ELF Section indexes' and will 40 * decode a corresponding SHT_SYMTAB_SHNDX 41 * section if required. 42 */ 43 44 45 #include <stdio.h> 46 #include <libelf.h> 47 #include <gelf.h> 48 #include <fcntl.h> 49 #include <unistd.h> 50 #include <stdlib.h> 51 #include <string.h> 52 53 static const char *symbind[STB_NUM] = { 54 /* STB_LOCL */ "LOCL", 55 /* STB_GLOBAL */ "GLOB", 56 /* STB_WEAK */ "WEAK" 57 }; 58 59 static const char *symtype[STT_NUM] = { 60 /* STT_NOTYPE */ "NOTY", 61 /* STT_OBJECT */ "OBJT", 62 /* STT_FUNC */ "FUNC", 63 /* STT_SECTION */ "SECT", 64 /* STT_FILE */ "FILE", 65 /* STT_COMMON */ "COMM", 66 /* STT_TLS */ "TLS" 67 }; 68 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 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