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