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 /* 23 * Copyright 2007 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 * Dump an elf file. 30 */ 31 #include <sys/param.h> 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <libelf.h> 35 #include <link.h> 36 #include <stdarg.h> 37 #include <unistd.h> 38 #include <libgen.h> 39 #include <libintl.h> 40 #include <locale.h> 41 #include <errno.h> 42 #include <strings.h> 43 #include <debug.h> 44 #include <conv.h> 45 #include <msg.h> 46 #include <_elfdump.h> 47 48 const Cache cache_init = {NULL, NULL, NULL, NULL, 0}; 49 50 const char * 51 _elfdump_msg(Msg mid) 52 { 53 return (gettext(MSG_ORIG(mid))); 54 } 55 56 /* 57 * Determine whether a symbol name should be demangled. 58 */ 59 const char * 60 demangle(const char *name, uint_t flags) 61 { 62 if (flags & FLG_DEMANGLE) 63 return (Elf_demangle_name(name)); 64 else 65 return ((char *)name); 66 } 67 68 /* 69 * Define our own standard error routine. 70 */ 71 void 72 failure(const char *file, const char *func) 73 { 74 (void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE), 75 file, func, elf_errmsg(elf_errno())); 76 } 77 78 /* 79 * The full usage message 80 */ 81 static void 82 detail_usage() 83 { 84 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1)); 85 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2)); 86 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3)); 87 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4)); 88 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5)); 89 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6)); 90 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7)); 91 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8)); 92 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9)); 93 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1)); 94 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10)); 95 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11)); 96 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12)); 97 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13)); 98 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14)); 99 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15)); 100 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16)); 101 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17)); 102 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18)); 103 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19)); 104 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20)); 105 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21)); 106 } 107 108 static void 109 decide(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd) 110 { 111 if (gelf_getclass(elf) == ELFCLASS64) 112 regular64(file, elf, flags, Nname, wfd); 113 else 114 regular32(file, elf, flags, Nname, wfd); 115 } 116 117 static void 118 archive(const char *file, int fd, Elf *elf, uint_t flags, char *Nname, 119 int wfd) 120 { 121 Elf_Cmd cmd = ELF_C_READ; 122 Elf_Arhdr *arhdr; 123 Elf *_elf = 0; 124 size_t ptr; 125 Elf_Arsym *arsym = 0; 126 127 /* 128 * Determine if the archive symbol table itself is required. 129 */ 130 if ((flags & FLG_SYMBOLS) && ((Nname == NULL) || 131 (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) { 132 /* 133 * Get the archive symbol table. 134 */ 135 if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) { 136 /* 137 * The arsym could be 0 even though there was no error. 138 * Print the error message only when there was 139 * real error from elf_getarsym(). 140 */ 141 failure(file, MSG_ORIG(MSG_ELF_GETARSYM)); 142 return; 143 } 144 } 145 146 /* 147 * Print the archive symbol table only when the archive symbol 148 * table exists and it was requested to print. 149 */ 150 if (arsym) { 151 size_t cnt; 152 char index[MAXNDXSIZE]; 153 size_t offset = 0, _offset = 0; 154 155 /* 156 * Print out all the symbol entries. 157 */ 158 dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB)); 159 dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS)); 160 161 for (cnt = 0; cnt < ptr; cnt++, arsym++) { 162 /* 163 * For each object obtain an elf descriptor so that we 164 * can establish the members name. Note, we have had 165 * archives where the archive header has not been 166 * obtainable so be lenient with errors. 167 */ 168 if ((offset == 0) || ((arsym->as_off != 0) && 169 (arsym->as_off != _offset))) { 170 171 if (_elf) 172 (void) elf_end(_elf); 173 174 if (elf_rand(elf, arsym->as_off) != 175 arsym->as_off) { 176 failure(file, MSG_ORIG(MSG_ELF_RAND)); 177 arhdr = 0; 178 } else if ((_elf = elf_begin(fd, 179 ELF_C_READ, elf)) == 0) { 180 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 181 arhdr = 0; 182 } else if ((arhdr = elf_getarhdr(_elf)) == 0) { 183 failure(file, 184 MSG_ORIG(MSG_ELF_GETARHDR)); 185 arhdr = 0; 186 } 187 188 _offset = arsym->as_off; 189 if (offset == 0) 190 offset = _offset; 191 } 192 193 (void) snprintf(index, MAXNDXSIZE, 194 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt)); 195 if (arsym->as_off) 196 dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index, 197 /* LINTED */ 198 (int)arsym->as_off, arhdr ? arhdr->ar_name : 199 MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ? 200 demangle(arsym->as_name, flags) : 201 MSG_INTL(MSG_STR_NULL))); 202 else 203 dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index, 204 /* LINTED */ 205 (int)arsym->as_off); 206 } 207 208 if (_elf) 209 (void) elf_end(_elf); 210 211 /* 212 * If we only need the archive symbol table return. 213 */ 214 if ((flags & FLG_SYMBOLS) && Nname && 215 (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0)) 216 return; 217 218 /* 219 * Reset elf descriptor in preparation for processing each 220 * member. 221 */ 222 if (offset) 223 (void) elf_rand(elf, offset); 224 } 225 226 /* 227 * Process each object within the archive. 228 */ 229 while ((_elf = elf_begin(fd, cmd, elf)) != NULL) { 230 char name[MAXPATHLEN]; 231 232 if ((arhdr = elf_getarhdr(_elf)) == NULL) { 233 failure(file, MSG_ORIG(MSG_ELF_GETARHDR)); 234 return; 235 } 236 if (*arhdr->ar_name != '/') { 237 (void) snprintf(name, MAXPATHLEN, 238 MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name); 239 dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name); 240 241 switch (elf_kind(_elf)) { 242 case ELF_K_AR: 243 archive(name, fd, _elf, flags, Nname, wfd); 244 break; 245 case ELF_K_ELF: 246 decide(name, _elf, flags, Nname, wfd); 247 break; 248 default: 249 (void) fprintf(stderr, 250 MSG_INTL(MSG_ERR_BADFILE), name); 251 break; 252 } 253 } 254 255 cmd = elf_next(_elf); 256 (void) elf_end(_elf); 257 } 258 } 259 260 int 261 main(int argc, char **argv, char **envp) 262 { 263 Elf *elf; 264 int var, fd, wfd = 0; 265 char *Nname = NULL, *wname = 0; 266 uint_t flags = 0; 267 268 /* 269 * If we're on a 64-bit kernel, try to exec a full 64-bit version of 270 * the binary. If successful, conv_check_native() won't return. 271 */ 272 (void) conv_check_native(argv, envp); 273 274 /* 275 * Establish locale. 276 */ 277 (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 278 (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 279 280 (void) setvbuf(stdout, NULL, _IOLBF, 0); 281 (void) setvbuf(stderr, NULL, _IOLBF, 0); 282 283 opterr = 0; 284 while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 285 switch (var) { 286 case 'C': 287 flags |= FLG_DEMANGLE; 288 break; 289 case 'c': 290 flags |= FLG_SHDR; 291 break; 292 case 'd': 293 flags |= FLG_DYNAMIC; 294 break; 295 case 'e': 296 flags |= FLG_EHDR; 297 break; 298 case 'G': 299 flags |= FLG_GOT; 300 break; 301 case 'g': 302 flags |= FLG_GROUP; 303 break; 304 case 'H': 305 flags |= FLG_CAP; 306 break; 307 case 'h': 308 flags |= FLG_HASH; 309 break; 310 case 'i': 311 flags |= FLG_INTERP; 312 break; 313 case 'k': 314 flags |= FLG_CHECKSUM; 315 break; 316 case 'l': 317 flags |= FLG_LONGNAME; 318 break; 319 case 'm': 320 flags |= FLG_MOVE; 321 break; 322 case 'N': 323 Nname = optarg; 324 break; 325 case 'n': 326 flags |= FLG_NOTE; 327 break; 328 case 'p': 329 flags |= FLG_PHDR; 330 break; 331 case 'r': 332 flags |= FLG_RELOC; 333 break; 334 case 'S': 335 flags |= FLG_SORT; 336 break; 337 case 's': 338 flags |= FLG_SYMBOLS; 339 break; 340 case 'u': 341 flags |= FLG_UNWIND; 342 break; 343 case 'v': 344 flags |= FLG_VERSIONS; 345 break; 346 case 'w': 347 wname = optarg; 348 break; 349 case 'y': 350 flags |= FLG_SYMINFO; 351 break; 352 case '?': 353 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 354 basename(argv[0])); 355 detail_usage(); 356 return (1); 357 default: 358 break; 359 } 360 } 361 362 /* 363 * Validate any arguments. 364 */ 365 if ((flags & ~(FLG_DEMANGLE | FLG_LONGNAME)) == 0) { 366 if (!wname && !Nname) { 367 flags |= FLG_EVERYTHING; 368 } else if (!wname || !Nname) { 369 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 370 basename(argv[0])); 371 return (1); 372 } 373 } 374 375 if ((var = argc - optind) == 0) { 376 (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 377 basename(argv[0])); 378 return (1); 379 } 380 381 /* 382 * If the -l/-C option is specified, set up the liblddbg.so. 383 */ 384 if (flags & FLG_LONGNAME) 385 dbg_desc->d_extra |= DBG_E_LONG; 386 if (flags & FLG_DEMANGLE) 387 dbg_desc->d_extra |= DBG_E_DEMANGLE; 388 389 /* 390 * If the -w option has indicated an output file open it. It's 391 * arguable whether this option has much use when multiple files are 392 * being processed. 393 */ 394 if (wname) { 395 if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC), 396 0666)) < 0) { 397 int err = errno; 398 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 399 wname, strerror(err)); 400 wfd = 0; 401 } 402 } 403 404 /* 405 * Open the input file and initialize the elf interface. 406 */ 407 for (; optind < argc; optind++) { 408 const char *file = argv[optind]; 409 410 if ((fd = open(argv[optind], O_RDONLY)) == -1) { 411 int err = errno; 412 (void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN), 413 file, strerror(err)); 414 continue; 415 } 416 (void) elf_version(EV_CURRENT); 417 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 418 failure(file, MSG_ORIG(MSG_ELF_BEGIN)); 419 (void) close(fd); 420 continue; 421 } 422 423 if (var > 1) 424 dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file); 425 426 switch (elf_kind(elf)) { 427 case ELF_K_AR: 428 archive(file, fd, elf, flags, Nname, wfd); 429 break; 430 case ELF_K_ELF: 431 decide(file, elf, flags, Nname, wfd); 432 break; 433 default: 434 (void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file); 435 break; 436 } 437 438 (void) close(fd); 439 (void) elf_end(elf); 440 } 441 442 if (wfd) 443 (void) close(wfd); 444 return (0); 445 } 446