| File: | src/usr.bin/nm/nm.c |
| Warning: | line 720, column 10 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: nm.c,v 1.54 2019/03/03 16:07:39 schwarze Exp $ */ | |||
| 2 | /* $NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 1989, 1993 | |||
| 6 | * The Regents of the University of California. All rights reserved. | |||
| 7 | * | |||
| 8 | * This code is derived from software contributed to Berkeley by | |||
| 9 | * Hans Huebner. | |||
| 10 | * | |||
| 11 | * Redistribution and use in source and binary forms, with or without | |||
| 12 | * modification, are permitted provided that the following conditions | |||
| 13 | * are met: | |||
| 14 | * 1. Redistributions of source code must retain the above copyright | |||
| 15 | * notice, this list of conditions and the following disclaimer. | |||
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 17 | * notice, this list of conditions and the following disclaimer in the | |||
| 18 | * documentation and/or other materials provided with the distribution. | |||
| 19 | * 3. Neither the name of the University nor the names of its contributors | |||
| 20 | * may be used to endorse or promote products derived from this software | |||
| 21 | * without specific prior written permission. | |||
| 22 | * | |||
| 23 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 27 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 28 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 29 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 30 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 31 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 32 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 33 | * SUCH DAMAGE. | |||
| 34 | */ | |||
| 35 | ||||
| 36 | #include <sys/types.h> | |||
| 37 | #include <sys/mman.h> | |||
| 38 | #include <a.out.h> | |||
| 39 | #include <elf.h> | |||
| 40 | #include <ar.h> | |||
| 41 | #include <ranlib.h> | |||
| 42 | #include <unistd.h> | |||
| 43 | #include <err.h> | |||
| 44 | #include <errno(*__errno()).h> | |||
| 45 | #include <ctype.h> | |||
| 46 | #include <link.h> | |||
| 47 | ||||
| 48 | #include <stdio.h> | |||
| 49 | #include <stdlib.h> | |||
| 50 | #include <string.h> | |||
| 51 | #include <getopt.h> | |||
| 52 | #include "util.h" | |||
| 53 | #include "elfuncs.h" | |||
| 54 | ||||
| 55 | #define SYMTABMAG"/ " "/ " | |||
| 56 | #define STRTABMAG"//" "//" | |||
| 57 | #define SYM64MAG"/SYM64/ " "/SYM64/ " | |||
| 58 | ||||
| 59 | union hdr { | |||
| 60 | Elf32_Ehdr elf32; | |||
| 61 | Elf64_Ehdr elf64; | |||
| 62 | }; | |||
| 63 | ||||
| 64 | int armap; | |||
| 65 | int demangle; | |||
| 66 | int non_object_warning; | |||
| 67 | int print_only_external_symbols; | |||
| 68 | int print_only_undefined_symbols; | |||
| 69 | int print_all_symbols; | |||
| 70 | int print_file_each_line; | |||
| 71 | int show_extensions; | |||
| 72 | int issize; | |||
| 73 | char posix_fmtstr[6]; | |||
| 74 | int posix_output; | |||
| 75 | char posix_radix = 'x'; | |||
| 76 | int usemmap = 1; | |||
| 77 | int dynamic_only; | |||
| 78 | ||||
| 79 | /* size vars */ | |||
| 80 | unsigned long total_text, total_data, total_bss, total_total; | |||
| 81 | int non_object_warning, print_totals; | |||
| 82 | ||||
| 83 | int rev; | |||
| 84 | int fname(const void *, const void *); | |||
| 85 | int rname(const void *, const void *); | |||
| 86 | int value(const void *, const void *); | |||
| 87 | char *otherstring(struct xnlist *); | |||
| 88 | int (*sfunc)(const void *, const void *) = fname; | |||
| 89 | char typeletter(struct xnlist *); | |||
| 90 | int mmbr_name(struct ar_hdr *, char **, int, int *, FILE *); | |||
| 91 | int show_symtab(off_t, u_long, const char *, FILE *); | |||
| 92 | int show_symdef(off_t, u_long, const char *, FILE *); | |||
| 93 | ||||
| 94 | /* some macros for symbol type (nlist.n_type) handling */ | |||
| 95 | #define IS_EXTERNAL(x)((x) & 0x01) ((x) & N_EXT0x01) | |||
| 96 | #define SYMBOL_TYPE(x)((x) & (0x1e | 0x0e0)) ((x) & (N_TYPE0x1e | N_STAB0x0e0)) | |||
| 97 | ||||
| 98 | void pipe2cppfilt(void); | |||
| 99 | void usage(void); | |||
| 100 | char *symname(struct xnlist *); | |||
| 101 | int process_file(int, const char *); | |||
| 102 | int show_archive(int, const char *, FILE *); | |||
| 103 | int show_file(int, int, const char *, FILE *fp, off_t, union hdr *); | |||
| 104 | void print_symbol(const char *, struct xnlist *); | |||
| 105 | ||||
| 106 | #define OPTSTRING_NM"aABCDegnopPrst:uvw" "aABCDegnopPrst:uvw" | |||
| 107 | const struct option longopts_nm[] = { | |||
| 108 | { "debug-syms", no_argument0, 0, 'a' }, | |||
| 109 | { "demangle", no_argument0, 0, 'C' }, | |||
| 110 | { "dynamic", no_argument0, 0, 'D' }, | |||
| 111 | { "extern-only", no_argument0, 0, 'g' }, | |||
| 112 | /* { "line-numbers", no_argument, 0, 'l' }, */ | |||
| 113 | { "no-sort", no_argument0, 0, 'p' }, | |||
| 114 | { "numeric-sort", no_argument0, 0, 'n' }, | |||
| 115 | { "print-armap", no_argument0, 0, 's' }, | |||
| 116 | { "print-file-name", no_argument0, 0, 'o' }, | |||
| 117 | { "reverse-sort", no_argument0, 0, 'r' }, | |||
| 118 | /* { "size-sort", no_argument, &szval, 1 }, */ | |||
| 119 | { "undefined-only", no_argument0, 0, 'u' }, | |||
| 120 | { "help", no_argument0, 0, '?' }, | |||
| 121 | { NULL((void *)0) } | |||
| 122 | }; | |||
| 123 | ||||
| 124 | /* | |||
| 125 | * main() | |||
| 126 | * parse command line, execute process_file() for each file | |||
| 127 | * specified on the command line. | |||
| 128 | */ | |||
| 129 | int | |||
| 130 | main(int argc, char *argv[]) | |||
| 131 | { | |||
| 132 | extern char *__progname; | |||
| 133 | extern int optind; | |||
| 134 | const char *optstr; | |||
| 135 | const struct option *lopts; | |||
| 136 | int ch, eval; | |||
| 137 | ||||
| 138 | if (pledge("stdio rpath proc exec", NULL((void *)0)) == -1) | |||
| ||||
| 139 | err(1, "pledge"); | |||
| 140 | ||||
| 141 | optstr = OPTSTRING_NM"aABCDegnopPrst:uvw"; | |||
| 142 | lopts = longopts_nm; | |||
| 143 | if (!strcmp(__progname, "size")) { | |||
| 144 | if (pledge("stdio rpath", NULL((void *)0)) == -1) | |||
| 145 | err(1, "pledge"); | |||
| 146 | ||||
| 147 | issize = 1; | |||
| 148 | optstr = "tw"; | |||
| 149 | lopts = NULL((void *)0); | |||
| 150 | } | |||
| 151 | ||||
| 152 | while ((ch = getopt_long(argc, argv, optstr, lopts, NULL((void *)0))) != -1) { | |||
| 153 | switch (ch) { | |||
| 154 | case 'a': | |||
| 155 | print_all_symbols = 1; | |||
| 156 | break; | |||
| 157 | case 'B': | |||
| 158 | /* no-op, compat with gnu-nm */ | |||
| 159 | break; | |||
| 160 | case 'C': | |||
| 161 | demangle = 1; | |||
| 162 | break; | |||
| 163 | case 'D': | |||
| 164 | dynamic_only = 1; | |||
| 165 | break; | |||
| 166 | case 'e': | |||
| 167 | show_extensions = 1; | |||
| 168 | break; | |||
| 169 | case 'g': | |||
| 170 | print_only_external_symbols = 1; | |||
| 171 | break; | |||
| 172 | case 'n': | |||
| 173 | case 'v': | |||
| 174 | sfunc = value; | |||
| 175 | break; | |||
| 176 | case 'A': | |||
| 177 | case 'o': | |||
| 178 | print_file_each_line = 1; | |||
| 179 | break; | |||
| 180 | case 'p': | |||
| 181 | sfunc = NULL((void *)0); | |||
| 182 | break; | |||
| 183 | case 'P': | |||
| 184 | posix_output = 1; | |||
| 185 | break; | |||
| 186 | case 'r': | |||
| 187 | rev = 1; | |||
| 188 | break; | |||
| 189 | case 's': | |||
| 190 | armap = 1; | |||
| 191 | break; | |||
| 192 | case 'u': | |||
| 193 | print_only_undefined_symbols = 1; | |||
| 194 | break; | |||
| 195 | case 'w': | |||
| 196 | non_object_warning = 1; | |||
| 197 | break; | |||
| 198 | case 't': | |||
| 199 | if (issize) { | |||
| 200 | print_totals = 1; | |||
| 201 | } else { | |||
| 202 | posix_radix = *optarg; | |||
| 203 | if (strlen(optarg) != 1 || | |||
| 204 | (posix_radix != 'd' && posix_radix != 'o' && | |||
| 205 | posix_radix != 'x')) | |||
| 206 | usage(); | |||
| 207 | } | |||
| 208 | break; | |||
| 209 | case '?': | |||
| 210 | default: | |||
| 211 | usage(); | |||
| 212 | } | |||
| 213 | } | |||
| 214 | ||||
| 215 | if (posix_output) | |||
| 216 | (void)snprintf(posix_fmtstr, sizeof posix_fmtstr, "%%%c %%%c", | |||
| 217 | posix_radix, posix_radix); | |||
| 218 | if (demangle) | |||
| 219 | pipe2cppfilt(); | |||
| 220 | ||||
| 221 | if (pledge("stdio rpath", NULL((void *)0)) == -1) | |||
| 222 | err(1, "pledge"); | |||
| 223 | ||||
| 224 | argv += optind; | |||
| 225 | argc -= optind; | |||
| 226 | ||||
| 227 | if (rev && sfunc == fname) | |||
| 228 | sfunc = rname; | |||
| 229 | ||||
| 230 | eval = 0; | |||
| 231 | if (*argv) | |||
| 232 | do { | |||
| 233 | eval |= process_file(argc, *argv); | |||
| 234 | } while (*++argv); | |||
| 235 | else | |||
| 236 | eval |= process_file(1, "a.out"); | |||
| 237 | ||||
| 238 | if (issize && print_totals) | |||
| 239 | printf("\n%lu\t%lu\t%lu\t%lu\t%lx\tTOTAL\n", | |||
| 240 | total_text, total_data, total_bss, | |||
| 241 | total_total, total_total); | |||
| 242 | exit(eval); | |||
| 243 | } | |||
| 244 | ||||
| 245 | /* | |||
| 246 | * process_file() | |||
| 247 | * show symbols in the file given as an argument. Accepts archive and | |||
| 248 | * object files as input. | |||
| 249 | */ | |||
| 250 | int | |||
| 251 | process_file(int count, const char *fname) | |||
| 252 | { | |||
| 253 | union hdr exec_head; | |||
| 254 | FILE *fp; | |||
| 255 | int retval; | |||
| 256 | size_t bytes; | |||
| 257 | char magic[SARMAG8]; | |||
| 258 | ||||
| 259 | if (!(fp = fopen(fname, "r"))) { | |||
| 260 | warn("cannot read %s", fname); | |||
| 261 | return(1); | |||
| 262 | } | |||
| 263 | ||||
| 264 | if (!issize && count > 1) | |||
| 265 | (void)printf("\n%s:\n", fname); | |||
| 266 | ||||
| 267 | /* | |||
| 268 | * first check whether this is an object file - read a object | |||
| 269 | * header, and skip back to the beginning | |||
| 270 | */ | |||
| 271 | bzero(&exec_head, sizeof(exec_head)); | |||
| 272 | bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp); | |||
| 273 | if (bytes < sizeof(exec_head)) { | |||
| 274 | if (bytes < sizeof(exec_head.elf32) || IS_ELF(exec_head.elf32)((exec_head.elf32).e_ident[0] == 0x7f && (exec_head.elf32 ).e_ident[1] == 'E' && (exec_head.elf32).e_ident[2] == 'L' && (exec_head.elf32).e_ident[3] == 'F')) { | |||
| 275 | warnx("%s: bad format", fname); | |||
| 276 | (void)fclose(fp); | |||
| 277 | return(1); | |||
| 278 | } | |||
| 279 | } | |||
| 280 | rewind(fp); | |||
| 281 | ||||
| 282 | /* this could be an archive */ | |||
| 283 | if (!IS_ELF(exec_head.elf32)((exec_head.elf32).e_ident[0] == 0x7f && (exec_head.elf32 ).e_ident[1] == 'E' && (exec_head.elf32).e_ident[2] == 'L' && (exec_head.elf32).e_ident[3] == 'F')) { | |||
| 284 | if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || | |||
| 285 | strncmp(magic, ARMAG"!<arch>\n", SARMAG8)) { | |||
| 286 | warnx("%s: not object file or archive", fname); | |||
| 287 | (void)fclose(fp); | |||
| 288 | return(1); | |||
| 289 | } | |||
| 290 | retval = show_archive(count, fname, fp); | |||
| 291 | } else | |||
| 292 | retval = show_file(count, 1, fname, fp, 0, &exec_head); | |||
| 293 | (void)fclose(fp); | |||
| 294 | return(retval); | |||
| 295 | } | |||
| 296 | ||||
| 297 | char *nametab; | |||
| 298 | ||||
| 299 | /* | |||
| 300 | * | |||
| 301 | * given the archive member header -- produce member name | |||
| 302 | */ | |||
| 303 | int | |||
| 304 | mmbr_name(struct ar_hdr *arh, char **name, int baselen, int *namelen, FILE *fp) | |||
| 305 | { | |||
| 306 | char *p = *name + strlen(*name); | |||
| 307 | long i; | |||
| 308 | ||||
| 309 | if (nametab && arh->ar_name[0] == '/') { | |||
| 310 | int len; | |||
| 311 | ||||
| 312 | i = atol(&arh->ar_name[1]); | |||
| 313 | len = strlen(&nametab[i]) + 1; | |||
| 314 | if (len > *namelen) { | |||
| 315 | p -= (long)*name; | |||
| 316 | if ((*name = realloc(*name, baselen+len)) == NULL((void *)0)) | |||
| 317 | err(1, NULL((void *)0)); | |||
| 318 | *namelen = len; | |||
| 319 | p += (long)*name; | |||
| 320 | } | |||
| 321 | strlcpy(p, &nametab[i], len); | |||
| 322 | p += len - 1; | |||
| 323 | } else | |||
| 324 | #ifdef AR_EFMT1"#1/" | |||
| 325 | /* | |||
| 326 | * BSD 4.4 extended AR format: #1/<namelen>, with name as the | |||
| 327 | * first <namelen> bytes of the file | |||
| 328 | */ | |||
| 329 | if ((arh->ar_name[0] == '#') && | |||
| 330 | (arh->ar_name[1] == '1') && | |||
| 331 | (arh->ar_name[2] == '/') && | |||
| 332 | (isdigit((unsigned char)arh->ar_name[3]))) { | |||
| 333 | int len = atoi(&arh->ar_name[3]); | |||
| 334 | ||||
| 335 | if (len > *namelen) { | |||
| 336 | p -= (long)*name; | |||
| 337 | if ((*name = realloc(*name, baselen+len)) == NULL((void *)0)) | |||
| 338 | err(1, NULL((void *)0)); | |||
| 339 | *namelen = len; | |||
| 340 | p += (long)*name; | |||
| 341 | } | |||
| 342 | if (fread(p, len, 1, fp) != 1) { | |||
| 343 | warnx("%s: premature EOF", *name); | |||
| 344 | free(*name); | |||
| 345 | return(1); | |||
| 346 | } | |||
| 347 | p += len; | |||
| 348 | } else | |||
| 349 | #endif | |||
| 350 | for (i = 0; i < sizeof(arh->ar_name); ++i) | |||
| 351 | if (arh->ar_name[i] && arh->ar_name[i] != ' ') | |||
| 352 | *p++ = arh->ar_name[i]; | |||
| 353 | *p = '\0'; | |||
| 354 | if (p[-1] == '/') | |||
| 355 | *--p = '\0'; | |||
| 356 | ||||
| 357 | return (0); | |||
| 358 | } | |||
| 359 | ||||
| 360 | /* | |||
| 361 | * show_symtab() | |||
| 362 | * show archive ranlib index (fs5) | |||
| 363 | */ | |||
| 364 | int | |||
| 365 | show_symtab(off_t off, u_long len, const char *name, FILE *fp) | |||
| 366 | { | |||
| 367 | struct ar_hdr ar_head; | |||
| 368 | int *symtab, *ps; | |||
| 369 | char *strtab, *p; | |||
| 370 | int num, rval = 0; | |||
| 371 | int namelen; | |||
| 372 | off_t restore; | |||
| 373 | ||||
| 374 | restore = ftello(fp); | |||
| 375 | ||||
| 376 | MMAP(symtab, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off)do { if ((symtab = mmap(((void *)0), len, 0x01, 0x0002|0, (!__isthreaded ? ((fp)->_file) : (fileno)(fp)), off)) == ((void *)-1)) { usemmap = 0; if ((*__errno()) != 22) warn("mmap"); else if ( (symtab = malloc(len)) == ((void *)0)) { symtab = ((void *)-1 ); warn("malloc"); } else if (pread((!__isthreaded ? ((fp)-> _file) : (fileno)(fp)), symtab, len, off) != len) { free(symtab ); symtab = ((void *)-1); warn("pread"); } } } while (0); | |||
| 377 | if (symtab == MAP_FAILED((void *)-1)) | |||
| 378 | return (1); | |||
| 379 | ||||
| 380 | namelen = sizeof(ar_head.ar_name); | |||
| 381 | if ((p = malloc(sizeof(ar_head.ar_name))) == NULL((void *)0)) { | |||
| 382 | warn("%s: malloc", name); | |||
| 383 | MUNMAP(symtab, len)do { if (usemmap) munmap(symtab, len); else free(symtab); symtab = ((void *)0); } while (0); | |||
| 384 | return (1); | |||
| 385 | } | |||
| 386 | ||||
| 387 | printf("\nArchive index:\n"); | |||
| 388 | num = betoh32(*symtab)(__uint32_t)(__builtin_constant_p(*symtab) ? (__uint32_t)(((__uint32_t )(*symtab) & 0xff) << 24 | ((__uint32_t)(*symtab) & 0xff00) << 8 | ((__uint32_t)(*symtab) & 0xff0000) >> 8 | ((__uint32_t)(*symtab) & 0xff000000) >> 24) : __swap32md (*symtab)); | |||
| 389 | strtab = (char *)(symtab + num + 1); | |||
| 390 | for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) { | |||
| 391 | if (fseeko(fp, betoh32(*ps)(__uint32_t)(__builtin_constant_p(*ps) ? (__uint32_t)(((__uint32_t )(*ps) & 0xff) << 24 | ((__uint32_t)(*ps) & 0xff00 ) << 8 | ((__uint32_t)(*ps) & 0xff0000) >> 8 | ((__uint32_t)(*ps) & 0xff000000) >> 24) : __swap32md (*ps)), SEEK_SET0)) { | |||
| 392 | warn("%s: fseeko", name); | |||
| 393 | rval = 1; | |||
| 394 | break; | |||
| 395 | } | |||
| 396 | ||||
| 397 | if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || | |||
| 398 | memcmp(ar_head.ar_fmag, ARFMAG"`\n", sizeof(ar_head.ar_fmag))) { | |||
| 399 | warnx("%s: member fseeko", name); | |||
| 400 | rval = 1; | |||
| 401 | break; | |||
| 402 | } | |||
| 403 | ||||
| 404 | *p = '\0'; | |||
| 405 | if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { | |||
| 406 | rval = 1; | |||
| 407 | break; | |||
| 408 | } | |||
| 409 | ||||
| 410 | printf("%s in %s\n", strtab, p); | |||
| 411 | } | |||
| 412 | ||||
| 413 | fseeko(fp, restore, SEEK_SET0); | |||
| 414 | ||||
| 415 | free(p); | |||
| 416 | MUNMAP(symtab, len)do { if (usemmap) munmap(symtab, len); else free(symtab); symtab = ((void *)0); } while (0); | |||
| 417 | return (rval); | |||
| 418 | } | |||
| 419 | ||||
| 420 | /* | |||
| 421 | * show_symdef() | |||
| 422 | * show archive ranlib index (gob) | |||
| 423 | */ | |||
| 424 | int | |||
| 425 | show_symdef(off_t off, u_long len, const char *name, FILE *fp) | |||
| 426 | { | |||
| 427 | struct ranlib *prn, *eprn; | |||
| 428 | struct ar_hdr ar_head; | |||
| 429 | char *symdef; | |||
| 430 | char *strtab, *p; | |||
| 431 | u_long size; | |||
| 432 | int namelen, rval = 0; | |||
| 433 | ||||
| 434 | MMAP(symdef, len, PROT_READ, MAP_PRIVATE|MAP_FILE, fileno(fp), off)do { if ((symdef = mmap(((void *)0), len, 0x01, 0x0002|0, (!__isthreaded ? ((fp)->_file) : (fileno)(fp)), off)) == ((void *)-1)) { usemmap = 0; if ((*__errno()) != 22) warn("mmap"); else if ( (symdef = malloc(len)) == ((void *)0)) { symdef = ((void *)-1 ); warn("malloc"); } else if (pread((!__isthreaded ? ((fp)-> _file) : (fileno)(fp)), symdef, len, off) != len) { free(symdef ); symdef = ((void *)-1); warn("pread"); } } } while (0); | |||
| 435 | if (symdef == MAP_FAILED((void *)-1)) | |||
| 436 | return (1); | |||
| 437 | if (usemmap) | |||
| 438 | (void)madvise(symdef, len, MADV_SEQUENTIAL2); | |||
| 439 | ||||
| 440 | namelen = sizeof(ar_head.ar_name); | |||
| 441 | if ((p = malloc(sizeof(ar_head.ar_name))) == NULL((void *)0)) { | |||
| 442 | warn("%s: malloc", name); | |||
| 443 | MUNMAP(symdef, len)do { if (usemmap) munmap(symdef, len); else free(symdef); symdef = ((void *)0); } while (0); | |||
| 444 | return (1); | |||
| 445 | } | |||
| 446 | ||||
| 447 | size = *(u_long *)symdef; | |||
| 448 | prn = (struct ranlib *)(symdef + sizeof(u_long)); | |||
| 449 | eprn = prn + size / sizeof(*prn); | |||
| 450 | strtab = symdef + sizeof(u_long) + size + sizeof(u_long); | |||
| 451 | ||||
| 452 | printf("\nArchive index:\n"); | |||
| 453 | for (; prn < eprn; prn++) { | |||
| 454 | if (fseeko(fp, prn->ran_off, SEEK_SET0)) { | |||
| 455 | warn("%s: fseeko", name); | |||
| 456 | rval = 1; | |||
| 457 | break; | |||
| 458 | } | |||
| 459 | ||||
| 460 | if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || | |||
| 461 | memcmp(ar_head.ar_fmag, ARFMAG"`\n", sizeof(ar_head.ar_fmag))) { | |||
| 462 | warnx("%s: member fseeko", name); | |||
| 463 | rval = 1; | |||
| 464 | break; | |||
| 465 | } | |||
| 466 | ||||
| 467 | *p = '\0'; | |||
| 468 | if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { | |||
| 469 | rval = 1; | |||
| 470 | break; | |||
| 471 | } | |||
| 472 | ||||
| 473 | printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p); | |||
| 474 | } | |||
| 475 | ||||
| 476 | free(p); | |||
| 477 | MUNMAP(symdef, len)do { if (usemmap) munmap(symdef, len); else free(symdef); symdef = ((void *)0); } while (0); | |||
| 478 | return (rval); | |||
| 479 | } | |||
| 480 | ||||
| 481 | /* | |||
| 482 | * show_archive() | |||
| 483 | * show symbols in the given archive file | |||
| 484 | */ | |||
| 485 | int | |||
| 486 | show_archive(int count, const char *fname, FILE *fp) | |||
| 487 | { | |||
| 488 | struct ar_hdr ar_head; | |||
| 489 | union hdr exec_head; | |||
| 490 | int i, rval; | |||
| 491 | off_t last_ar_off, foff, symtaboff; | |||
| 492 | char *name; | |||
| 493 | int baselen, namelen; | |||
| 494 | u_long mmbrlen, symtablen; | |||
| 495 | ||||
| 496 | baselen = strlen(fname) + 3; | |||
| 497 | if (posix_output) | |||
| 498 | baselen += 2; | |||
| 499 | namelen = sizeof(ar_head.ar_name); | |||
| 500 | if ((name = malloc(baselen + namelen)) == NULL((void *)0)) | |||
| 501 | err(1, NULL((void *)0)); | |||
| 502 | ||||
| 503 | rval = 0; | |||
| 504 | nametab = NULL((void *)0); | |||
| 505 | symtaboff = 0; | |||
| 506 | symtablen = 0; | |||
| 507 | ||||
| 508 | /* while there are more entries in the archive */ | |||
| 509 | while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) { | |||
| 510 | /* bad archive entry - stop processing this archive */ | |||
| 511 | if (memcmp(ar_head.ar_fmag, ARFMAG"`\n", sizeof(ar_head.ar_fmag))) { | |||
| 512 | warnx("%s: bad format archive header", fname); | |||
| 513 | rval = 1; | |||
| 514 | break; | |||
| 515 | } | |||
| 516 | ||||
| 517 | /* remember start position of current archive object */ | |||
| 518 | last_ar_off = ftello(fp); | |||
| 519 | mmbrlen = atol(ar_head.ar_size); | |||
| 520 | ||||
| 521 | if (strncmp(ar_head.ar_name, RANLIBMAG"__.SYMDEF", | |||
| 522 | sizeof(RANLIBMAG"__.SYMDEF") - 1) == 0) { | |||
| 523 | if (!issize && armap && | |||
| 524 | show_symdef(last_ar_off, mmbrlen, fname, fp)) { | |||
| 525 | rval = 1; | |||
| 526 | break; | |||
| 527 | } | |||
| 528 | goto skip; | |||
| 529 | } else if (strncmp(ar_head.ar_name, SYMTABMAG"/ ", | |||
| 530 | sizeof(SYMTABMAG"/ ") - 1) == 0) { | |||
| 531 | /* if nametab hasn't been seen yet -- doit later */ | |||
| 532 | if (!nametab) { | |||
| 533 | symtablen = mmbrlen; | |||
| 534 | symtaboff = last_ar_off; | |||
| 535 | goto skip; | |||
| 536 | } | |||
| 537 | ||||
| 538 | /* load the Sys5 long names table */ | |||
| 539 | } else if (strncmp(ar_head.ar_name, STRTABMAG"//", | |||
| 540 | sizeof(STRTABMAG"//") - 1) == 0) { | |||
| 541 | char *p; | |||
| 542 | ||||
| 543 | if ((nametab = malloc(mmbrlen)) == NULL((void *)0)) { | |||
| 544 | warn("%s: nametab", fname); | |||
| 545 | rval = 1; | |||
| 546 | break; | |||
| 547 | } | |||
| 548 | ||||
| 549 | if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) { | |||
| 550 | warnx("%s: premature EOF", fname); | |||
| 551 | rval = 1; | |||
| 552 | break; | |||
| 553 | } | |||
| 554 | ||||
| 555 | for (p = nametab, i = mmbrlen; i--; p++) | |||
| 556 | if (*p == '\n') | |||
| 557 | *p = '\0'; | |||
| 558 | ||||
| 559 | if (issize || !armap || !symtablen || !symtaboff) | |||
| 560 | goto skip; | |||
| 561 | } | |||
| 562 | #ifdef __mips64 | |||
| 563 | else if (memcmp(ar_head.ar_name, SYM64MAG"/SYM64/ ", | |||
| 564 | sizeof(ar_head.ar_name)) == 0) { | |||
| 565 | /* IRIX6-compatible archive map */ | |||
| 566 | goto skip; | |||
| 567 | } | |||
| 568 | #endif | |||
| 569 | ||||
| 570 | if (!issize && armap && symtablen && symtaboff) { | |||
| 571 | if (show_symtab(symtaboff, symtablen, fname, fp)) { | |||
| 572 | rval = 1; | |||
| 573 | break; | |||
| 574 | } else { | |||
| 575 | symtaboff = 0; | |||
| 576 | symtablen = 0; | |||
| 577 | } | |||
| 578 | } | |||
| 579 | ||||
| 580 | /* | |||
| 581 | * construct a name of the form "archive.a:obj.o:" for the | |||
| 582 | * current archive entry if the object name is to be printed | |||
| 583 | * on each output line | |||
| 584 | */ | |||
| 585 | *name = '\0'; | |||
| 586 | if (posix_output) | |||
| 587 | snprintf(name, baselen - 1, "%s[", fname); | |||
| 588 | else if (count > 1) | |||
| 589 | snprintf(name, baselen - 1, "%s:", fname); | |||
| 590 | ||||
| 591 | if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) { | |||
| 592 | rval = 1; | |||
| 593 | break; | |||
| 594 | } | |||
| 595 | ||||
| 596 | if (posix_output) | |||
| 597 | strlcat(name, "]", baselen + namelen); | |||
| 598 | ||||
| 599 | foff = ftello(fp); | |||
| 600 | ||||
| 601 | /* get and check current object's header */ | |||
| 602 | if (fread((char *)&exec_head, sizeof(exec_head), | |||
| 603 | (size_t)1, fp) != 1) { | |||
| 604 | warnx("%s: premature EOF", fname); | |||
| 605 | rval = 1; | |||
| 606 | break; | |||
| 607 | } | |||
| 608 | ||||
| 609 | rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head); | |||
| 610 | /* | |||
| 611 | * skip to next archive object - it starts at the next | |||
| 612 | * even byte boundary | |||
| 613 | */ | |||
| 614 | #define even(x)(((x) + 1) & ~1) (((x) + 1) & ~1) | |||
| 615 | skip: if (fseeko(fp, last_ar_off + even(mmbrlen)(((mmbrlen) + 1) & ~1), SEEK_SET0)) { | |||
| 616 | warn("%s", fname); | |||
| 617 | rval = 1; | |||
| 618 | break; | |||
| 619 | } | |||
| 620 | } | |||
| 621 | free(nametab); | |||
| 622 | nametab = NULL((void *)0); | |||
| 623 | free(name); | |||
| 624 | return(rval); | |||
| 625 | } | |||
| 626 | ||||
| 627 | char *stab; | |||
| 628 | ||||
| 629 | /* | |||
| 630 | * show_file() | |||
| 631 | * show symbols from the object file pointed to by fp. The current | |||
| 632 | * file pointer for fp is expected to be at the beginning of an object | |||
| 633 | * file header. | |||
| 634 | */ | |||
| 635 | int | |||
| 636 | show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head) | |||
| 637 | { | |||
| 638 | u_long text, data, bss, total; | |||
| 639 | struct xnlist *np, *names, **snames; | |||
| 640 | int i, nrawnames, nnames; | |||
| 641 | size_t stabsize; | |||
| 642 | ||||
| 643 | if (IS_ELF(head->elf32)((head->elf32).e_ident[0] == 0x7f && (head->elf32 ).e_ident[1] == 'E' && (head->elf32).e_ident[2] == 'L' && (head->elf32).e_ident[3] == 'F') && | |||
| 644 | head->elf32.e_ident[EI_CLASS4] == ELFCLASS321 && | |||
| 645 | head->elf32.e_ident[EI_VERSION6] == ELF_TARG_VER1) { | |||
| 646 | void *shdr; | |||
| 647 | ||||
| 648 | if (!(shdr = elf32_load_shdrs(name, fp, foff, &head->elf32))) | |||
| 649 | return (1); | |||
| 650 | ||||
| 651 | i = issize? | |||
| 652 | elf32_size(&head->elf32, shdr, &text, &data, &bss) : | |||
| 653 | elf32_symload(name, fp, foff, &head->elf32, shdr, | |||
| 654 | &names, &snames, &stabsize, &nrawnames); | |||
| 655 | free(shdr); | |||
| 656 | if (i) | |||
| 657 | return (i); | |||
| 658 | ||||
| 659 | } else if (IS_ELF(head->elf64)((head->elf64).e_ident[0] == 0x7f && (head->elf64 ).e_ident[1] == 'E' && (head->elf64).e_ident[2] == 'L' && (head->elf64).e_ident[3] == 'F') && | |||
| 660 | head->elf64.e_ident[EI_CLASS4] == ELFCLASS642 && | |||
| 661 | head->elf64.e_ident[EI_VERSION6] == ELF_TARG_VER1) { | |||
| 662 | void *shdr; | |||
| 663 | ||||
| 664 | if (!(shdr = elf64_load_shdrs(name, fp, foff, &head->elf64))) | |||
| 665 | return (1); | |||
| 666 | ||||
| 667 | i = issize? | |||
| 668 | elf64_size(&head->elf64, shdr, &text, &data, &bss) : | |||
| 669 | elf64_symload(name, fp, foff, &head->elf64, shdr, | |||
| 670 | &names, &snames, &stabsize, &nrawnames); | |||
| 671 | free(shdr); | |||
| 672 | if (i) | |||
| 673 | return (i); | |||
| 674 | } else { | |||
| 675 | if (warn_fmt) | |||
| 676 | warnx("%s: bad format", name); | |||
| 677 | return (1); | |||
| 678 | } | |||
| 679 | ||||
| 680 | if (issize) { | |||
| 681 | static int first = 1; | |||
| 682 | ||||
| 683 | if (first) { | |||
| 684 | first = 0; | |||
| 685 | printf("text\tdata\tbss\tdec\thex\n"); | |||
| 686 | } | |||
| 687 | ||||
| 688 | total = text + data + bss; | |||
| 689 | printf("%lu\t%lu\t%lu\t%lu\t%lx", | |||
| 690 | text, data, bss, total, total); | |||
| 691 | if (count > 1) | |||
| 692 | (void)printf("\t%s", name); | |||
| 693 | ||||
| 694 | total_text += text; | |||
| 695 | total_data += data; | |||
| 696 | total_bss += bss; | |||
| 697 | total_total += total; | |||
| 698 | ||||
| 699 | printf("\n"); | |||
| 700 | return (0); | |||
| 701 | } | |||
| 702 | /* else we are nm */ | |||
| 703 | ||||
| 704 | /* | |||
| 705 | * it seems that string table is sequential | |||
| 706 | * relative to the symbol table order | |||
| 707 | */ | |||
| 708 | if (sfunc == NULL((void *)0) && usemmap) | |||
| 709 | (void)madvise(stab, stabsize, MADV_SEQUENTIAL2); | |||
| 710 | ||||
| 711 | /* | |||
| 712 | * fix up the symbol table and filter out unwanted entries | |||
| 713 | * | |||
| 714 | * common symbols are characterized by a n_type of N_UNDF and a | |||
| 715 | * non-zero n_value -- change n_type to N_COMM for all such | |||
| 716 | * symbols to make life easier later. | |||
| 717 | * | |||
| 718 | * filter out all entries which we don't want to print anyway | |||
| 719 | */ | |||
| 720 | for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { | |||
| ||||
| 721 | /* | |||
| 722 | * make n_un.n_name a character pointer by adding the string | |||
| 723 | * table's base to n_un.n_strx | |||
| 724 | * | |||
| 725 | * don't mess with zero offsets | |||
| 726 | */ | |||
| 727 | if (np->nl.n_un.n_strx) | |||
| 728 | np->nl.n_un.n_name = stab + np->nl.n_un.n_strx; | |||
| 729 | else | |||
| 730 | np->nl.n_un.n_name = ""; | |||
| 731 | if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type)((np->nl.n_type) & 0x01)) | |||
| 732 | continue; | |||
| 733 | if (print_only_undefined_symbols && | |||
| 734 | SYMBOL_TYPE(np->nl.n_type)((np->nl.n_type) & (0x1e | 0x0e0)) != N_UNDF0x00) | |||
| 735 | continue; | |||
| 736 | ||||
| 737 | snames[nnames++] = np; | |||
| 738 | } | |||
| 739 | ||||
| 740 | /* sort the symbol table if applicable */ | |||
| 741 | if (sfunc) | |||
| 742 | qsort(snames, (size_t)nnames, sizeof(*snames), sfunc); | |||
| 743 | ||||
| 744 | if (count > 1) | |||
| 745 | (void)printf("\n%s:\n", name); | |||
| 746 | ||||
| 747 | /* print out symbols */ | |||
| 748 | for (i = 0; i < nnames; i++) | |||
| 749 | print_symbol(name, snames[i]); | |||
| 750 | ||||
| 751 | free(snames); | |||
| 752 | free(names); | |||
| 753 | MUNMAP(stab, stabsize)do { if (usemmap) munmap(stab, stabsize); else free(stab); stab = ((void *)0); } while (0); | |||
| 754 | return(0); | |||
| 755 | } | |||
| 756 | ||||
| 757 | char * | |||
| 758 | symname(struct xnlist *sym) | |||
| 759 | { | |||
| 760 | return sym->nl.n_un.n_name; | |||
| 761 | } | |||
| 762 | ||||
| 763 | /* | |||
| 764 | * print_symbol() | |||
| 765 | * show one symbol | |||
| 766 | */ | |||
| 767 | void | |||
| 768 | print_symbol(const char *name, struct xnlist *sym) | |||
| 769 | { | |||
| 770 | if (print_file_each_line) { | |||
| 771 | if (posix_output) | |||
| 772 | (void)printf("%s: ", name); | |||
| 773 | else | |||
| 774 | (void)printf("%s:", name); | |||
| 775 | } | |||
| 776 | ||||
| 777 | if (posix_output) { | |||
| 778 | (void)printf("%s %c ", symname(sym), typeletter(sym)); | |||
| 779 | if (SYMBOL_TYPE(sym->nl.n_type)((sym->nl.n_type) & (0x1e | 0x0e0)) != N_UNDF0x00) | |||
| 780 | (void)printf(posix_fmtstr, sym->nl.n_value, | |||
| 781 | sym->n_size); | |||
| 782 | (void)printf("\n"); | |||
| 783 | } else { | |||
| 784 | /* | |||
| 785 | * handle undefined-only format especially (no space is | |||
| 786 | * left for symbol values, no type field is printed) | |||
| 787 | */ | |||
| 788 | if (!print_only_undefined_symbols) { | |||
| 789 | /* print symbol's value */ | |||
| 790 | if (SYMBOL_TYPE(sym->nl.n_type)((sym->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
| 791 | (void)printf(" "); | |||
| 792 | else | |||
| 793 | (void)printf("%08lx", sym->nl.n_value); | |||
| 794 | ||||
| 795 | /* print type information */ | |||
| 796 | if (show_extensions) | |||
| 797 | (void)printf(" %c ", typeletter(sym)); | |||
| 798 | else | |||
| 799 | (void)printf(" %c ", typeletter(sym)); | |||
| 800 | } | |||
| 801 | ||||
| 802 | (void)puts(symname(sym)); | |||
| 803 | } | |||
| 804 | } | |||
| 805 | ||||
| 806 | /* | |||
| 807 | * typeletter() | |||
| 808 | * return a description letter for the given basic type code of an | |||
| 809 | * symbol table entry. The return value will be upper case for | |||
| 810 | * external, lower case for internal symbols. | |||
| 811 | */ | |||
| 812 | char | |||
| 813 | typeletter(struct xnlist *np) | |||
| 814 | { | |||
| 815 | int ext = IS_EXTERNAL(np->nl.n_type)((np->nl.n_type) & 0x01); | |||
| 816 | ||||
| 817 | if (np->nl.n_other) | |||
| 818 | return np->nl.n_other; | |||
| 819 | ||||
| 820 | switch(SYMBOL_TYPE(np->nl.n_type)((np->nl.n_type) & (0x1e | 0x0e0))) { | |||
| 821 | case N_ABS0x02: | |||
| 822 | return(ext? 'A' : 'a'); | |||
| 823 | case N_BSS0x08: | |||
| 824 | return(ext? 'B' : 'b'); | |||
| 825 | case N_COMM0x12: | |||
| 826 | return(ext? 'C' : 'c'); | |||
| 827 | case N_DATA0x06: | |||
| 828 | return(ext? 'D' : 'd'); | |||
| 829 | case N_FN0x1e: | |||
| 830 | /* NOTE: N_FN == N_WARNING, | |||
| 831 | * in this case, the N_EXT bit is to considered as | |||
| 832 | * part of the symbol's type itself. | |||
| 833 | */ | |||
| 834 | return(ext? 'F' : 'W'); | |||
| 835 | case N_TEXT0x04: | |||
| 836 | return(ext? 'T' : 't'); | |||
| 837 | case N_SIZE0x0c: | |||
| 838 | return(ext? 'S' : 's'); | |||
| 839 | case N_UNDF0x00: | |||
| 840 | return(ext? 'U' : 'u'); | |||
| 841 | } | |||
| 842 | return('?'); | |||
| 843 | } | |||
| 844 | ||||
| 845 | int | |||
| 846 | fname(const void *a0, const void *b0) | |||
| 847 | { | |||
| 848 | struct xnlist * const *a = a0, * const *b = b0; | |||
| 849 | ||||
| 850 | return(strcmp((*a)->nl.n_un.n_name, (*b)->nl.n_un.n_name)); | |||
| 851 | } | |||
| 852 | ||||
| 853 | int | |||
| 854 | rname(const void *a0, const void *b0) | |||
| 855 | { | |||
| 856 | struct xnlist * const *a = a0, * const *b = b0; | |||
| 857 | ||||
| 858 | return(strcmp((*b)->nl.n_un.n_name, (*a)->nl.n_un.n_name)); | |||
| 859 | } | |||
| 860 | ||||
| 861 | int | |||
| 862 | value(const void *a0, const void *b0) | |||
| 863 | { | |||
| 864 | struct xnlist * const *a = a0, * const *b = b0; | |||
| 865 | ||||
| 866 | if (SYMBOL_TYPE((*a)->nl.n_type)(((*a)->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
| 867 | if (SYMBOL_TYPE((*b)->nl.n_type)(((*b)->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
| 868 | return(0); | |||
| 869 | else | |||
| 870 | return(-1); | |||
| 871 | else if (SYMBOL_TYPE((*b)->nl.n_type)(((*b)->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
| 872 | return(1); | |||
| 873 | if (rev) { | |||
| 874 | if ((*a)->nl.n_value == (*b)->nl.n_value) | |||
| 875 | return(rname(a0, b0)); | |||
| 876 | return((*b)->nl.n_value > (*a)->nl.n_value ? 1 : -1); | |||
| 877 | } else { | |||
| 878 | if ((*a)->nl.n_value == (*b)->nl.n_value) | |||
| 879 | return(fname(a0, b0)); | |||
| 880 | return((*a)->nl.n_value > (*b)->nl.n_value ? 1 : -1); | |||
| 881 | } | |||
| 882 | } | |||
| 883 | ||||
| 884 | #define CPPFILT"/usr/bin/c++filt" "/usr/bin/c++filt" | |||
| 885 | ||||
| 886 | void | |||
| 887 | pipe2cppfilt(void) | |||
| 888 | { | |||
| 889 | int pip[2]; | |||
| 890 | char *argv[2]; | |||
| 891 | ||||
| 892 | argv[0] = "c++filt"; | |||
| 893 | argv[1] = NULL((void *)0); | |||
| 894 | ||||
| 895 | if (pipe(pip) == -1) | |||
| 896 | err(1, "pipe"); | |||
| 897 | switch(fork()) { | |||
| 898 | case -1: | |||
| 899 | err(1, "fork"); | |||
| 900 | default: | |||
| 901 | dup2(pip[0], 0); | |||
| 902 | close(pip[0]); | |||
| 903 | close(pip[1]); | |||
| 904 | execve(CPPFILT"/usr/bin/c++filt", argv, NULL((void *)0)); | |||
| 905 | err(1, "execve"); | |||
| 906 | case 0: | |||
| 907 | dup2(pip[1], 1); | |||
| 908 | close(pip[1]); | |||
| 909 | close(pip[0]); | |||
| 910 | } | |||
| 911 | } | |||
| 912 | ||||
| 913 | void | |||
| 914 | usage(void) | |||
| 915 | { | |||
| 916 | extern char *__progname; | |||
| 917 | ||||
| 918 | if (issize) | |||
| 919 | fprintf(stderr(&__sF[2]), "usage: %s [-tw] [file ...]\n", __progname); | |||
| 920 | else | |||
| 921 | fprintf(stderr(&__sF[2]), "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n", | |||
| 922 | __progname); | |||
| 923 | exit(1); | |||
| 924 | } |