File: | src/usr.bin/nm/nm.c |
Warning: | line 719, column 10 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: nm.c,v 1.55 2022/12/04 23:50:49 cheloha 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 | default: | |||
210 | usage(); | |||
211 | } | |||
212 | } | |||
213 | ||||
214 | if (posix_output) | |||
215 | (void)snprintf(posix_fmtstr, sizeof posix_fmtstr, "%%%c %%%c", | |||
216 | posix_radix, posix_radix); | |||
217 | if (demangle) | |||
218 | pipe2cppfilt(); | |||
219 | ||||
220 | if (pledge("stdio rpath", NULL((void *)0)) == -1) | |||
221 | err(1, "pledge"); | |||
222 | ||||
223 | argv += optind; | |||
224 | argc -= optind; | |||
225 | ||||
226 | if (rev && sfunc == fname) | |||
227 | sfunc = rname; | |||
228 | ||||
229 | eval = 0; | |||
230 | if (*argv) | |||
231 | do { | |||
232 | eval |= process_file(argc, *argv); | |||
233 | } while (*++argv); | |||
234 | else | |||
235 | eval |= process_file(1, "a.out"); | |||
236 | ||||
237 | if (issize && print_totals) | |||
238 | printf("\n%lu\t%lu\t%lu\t%lu\t%lx\tTOTAL\n", | |||
239 | total_text, total_data, total_bss, | |||
240 | total_total, total_total); | |||
241 | exit(eval); | |||
242 | } | |||
243 | ||||
244 | /* | |||
245 | * process_file() | |||
246 | * show symbols in the file given as an argument. Accepts archive and | |||
247 | * object files as input. | |||
248 | */ | |||
249 | int | |||
250 | process_file(int count, const char *fname) | |||
251 | { | |||
252 | union hdr exec_head; | |||
253 | FILE *fp; | |||
254 | int retval; | |||
255 | size_t bytes; | |||
256 | char magic[SARMAG8]; | |||
257 | ||||
258 | if (!(fp = fopen(fname, "r"))) { | |||
259 | warn("cannot read %s", fname); | |||
260 | return(1); | |||
261 | } | |||
262 | ||||
263 | if (!issize && count > 1) | |||
264 | (void)printf("\n%s:\n", fname); | |||
265 | ||||
266 | /* | |||
267 | * first check whether this is an object file - read a object | |||
268 | * header, and skip back to the beginning | |||
269 | */ | |||
270 | bzero(&exec_head, sizeof(exec_head)); | |||
271 | bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp); | |||
272 | if (bytes < sizeof(exec_head)) { | |||
273 | 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')) { | |||
274 | warnx("%s: bad format", fname); | |||
275 | (void)fclose(fp); | |||
276 | return(1); | |||
277 | } | |||
278 | } | |||
279 | rewind(fp); | |||
280 | ||||
281 | /* this could be an archive */ | |||
282 | 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')) { | |||
283 | if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || | |||
284 | strncmp(magic, ARMAG"!<arch>\n", SARMAG8)) { | |||
285 | warnx("%s: not object file or archive", fname); | |||
286 | (void)fclose(fp); | |||
287 | return(1); | |||
288 | } | |||
289 | retval = show_archive(count, fname, fp); | |||
290 | } else | |||
291 | retval = show_file(count, 1, fname, fp, 0, &exec_head); | |||
292 | (void)fclose(fp); | |||
293 | return(retval); | |||
294 | } | |||
295 | ||||
296 | char *nametab; | |||
297 | ||||
298 | /* | |||
299 | * | |||
300 | * given the archive member header -- produce member name | |||
301 | */ | |||
302 | int | |||
303 | mmbr_name(struct ar_hdr *arh, char **name, int baselen, int *namelen, FILE *fp) | |||
304 | { | |||
305 | char *p = *name + strlen(*name); | |||
306 | long i; | |||
307 | ||||
308 | if (nametab && arh->ar_name[0] == '/') { | |||
309 | int len; | |||
310 | ||||
311 | i = atol(&arh->ar_name[1]); | |||
312 | len = strlen(&nametab[i]) + 1; | |||
313 | if (len > *namelen) { | |||
314 | p -= (long)*name; | |||
315 | if ((*name = realloc(*name, baselen+len)) == NULL((void *)0)) | |||
316 | err(1, NULL((void *)0)); | |||
317 | *namelen = len; | |||
318 | p += (long)*name; | |||
319 | } | |||
320 | strlcpy(p, &nametab[i], len); | |||
321 | p += len - 1; | |||
322 | } else | |||
323 | #ifdef AR_EFMT1"#1/" | |||
324 | /* | |||
325 | * BSD 4.4 extended AR format: #1/<namelen>, with name as the | |||
326 | * first <namelen> bytes of the file | |||
327 | */ | |||
328 | if ((arh->ar_name[0] == '#') && | |||
329 | (arh->ar_name[1] == '1') && | |||
330 | (arh->ar_name[2] == '/') && | |||
331 | (isdigit((unsigned char)arh->ar_name[3]))) { | |||
332 | int len = atoi(&arh->ar_name[3]); | |||
333 | ||||
334 | if (len > *namelen) { | |||
335 | p -= (long)*name; | |||
336 | if ((*name = realloc(*name, baselen+len)) == NULL((void *)0)) | |||
337 | err(1, NULL((void *)0)); | |||
338 | *namelen = len; | |||
339 | p += (long)*name; | |||
340 | } | |||
341 | if (fread(p, len, 1, fp) != 1) { | |||
342 | warnx("%s: premature EOF", *name); | |||
343 | free(*name); | |||
344 | return(1); | |||
345 | } | |||
346 | p += len; | |||
347 | } else | |||
348 | #endif | |||
349 | for (i = 0; i < sizeof(arh->ar_name); ++i) | |||
350 | if (arh->ar_name[i] && arh->ar_name[i] != ' ') | |||
351 | *p++ = arh->ar_name[i]; | |||
352 | *p = '\0'; | |||
353 | if (p[-1] == '/') | |||
354 | *--p = '\0'; | |||
355 | ||||
356 | return (0); | |||
357 | } | |||
358 | ||||
359 | /* | |||
360 | * show_symtab() | |||
361 | * show archive ranlib index (fs5) | |||
362 | */ | |||
363 | int | |||
364 | show_symtab(off_t off, u_long len, const char *name, FILE *fp) | |||
365 | { | |||
366 | struct ar_hdr ar_head; | |||
367 | int *symtab, *ps; | |||
368 | char *strtab, *p; | |||
369 | int num, rval = 0; | |||
370 | int namelen; | |||
371 | off_t restore; | |||
372 | ||||
373 | restore = ftello(fp); | |||
374 | ||||
375 | 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); | |||
376 | if (symtab == MAP_FAILED((void *)-1)) | |||
377 | return (1); | |||
378 | ||||
379 | namelen = sizeof(ar_head.ar_name); | |||
380 | if ((p = malloc(sizeof(ar_head.ar_name))) == NULL((void *)0)) { | |||
381 | warn("%s: malloc", name); | |||
382 | MUNMAP(symtab, len)do { if (usemmap) munmap(symtab, len); else free(symtab); symtab = ((void *)0); } while (0); | |||
383 | return (1); | |||
384 | } | |||
385 | ||||
386 | printf("\nArchive index:\n"); | |||
387 | 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)); | |||
388 | strtab = (char *)(symtab + num + 1); | |||
389 | for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) { | |||
390 | 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)) { | |||
391 | warn("%s: fseeko", name); | |||
392 | rval = 1; | |||
393 | break; | |||
394 | } | |||
395 | ||||
396 | if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || | |||
397 | memcmp(ar_head.ar_fmag, ARFMAG"`\n", sizeof(ar_head.ar_fmag))) { | |||
398 | warnx("%s: member fseeko", name); | |||
399 | rval = 1; | |||
400 | break; | |||
401 | } | |||
402 | ||||
403 | *p = '\0'; | |||
404 | if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { | |||
405 | rval = 1; | |||
406 | break; | |||
407 | } | |||
408 | ||||
409 | printf("%s in %s\n", strtab, p); | |||
410 | } | |||
411 | ||||
412 | fseeko(fp, restore, SEEK_SET0); | |||
413 | ||||
414 | free(p); | |||
415 | MUNMAP(symtab, len)do { if (usemmap) munmap(symtab, len); else free(symtab); symtab = ((void *)0); } while (0); | |||
416 | return (rval); | |||
417 | } | |||
418 | ||||
419 | /* | |||
420 | * show_symdef() | |||
421 | * show archive ranlib index (gob) | |||
422 | */ | |||
423 | int | |||
424 | show_symdef(off_t off, u_long len, const char *name, FILE *fp) | |||
425 | { | |||
426 | struct ranlib *prn, *eprn; | |||
427 | struct ar_hdr ar_head; | |||
428 | char *symdef; | |||
429 | char *strtab, *p; | |||
430 | u_long size; | |||
431 | int namelen, rval = 0; | |||
432 | ||||
433 | 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); | |||
434 | if (symdef == MAP_FAILED((void *)-1)) | |||
435 | return (1); | |||
436 | if (usemmap) | |||
437 | (void)madvise(symdef, len, MADV_SEQUENTIAL2); | |||
438 | ||||
439 | namelen = sizeof(ar_head.ar_name); | |||
440 | if ((p = malloc(sizeof(ar_head.ar_name))) == NULL((void *)0)) { | |||
441 | warn("%s: malloc", name); | |||
442 | MUNMAP(symdef, len)do { if (usemmap) munmap(symdef, len); else free(symdef); symdef = ((void *)0); } while (0); | |||
443 | return (1); | |||
444 | } | |||
445 | ||||
446 | size = *(u_long *)symdef; | |||
447 | prn = (struct ranlib *)(symdef + sizeof(u_long)); | |||
448 | eprn = prn + size / sizeof(*prn); | |||
449 | strtab = symdef + sizeof(u_long) + size + sizeof(u_long); | |||
450 | ||||
451 | printf("\nArchive index:\n"); | |||
452 | for (; prn < eprn; prn++) { | |||
453 | if (fseeko(fp, prn->ran_off, SEEK_SET0)) { | |||
454 | warn("%s: fseeko", name); | |||
455 | rval = 1; | |||
456 | break; | |||
457 | } | |||
458 | ||||
459 | if (fread(&ar_head, sizeof(ar_head), 1, fp) != 1 || | |||
460 | memcmp(ar_head.ar_fmag, ARFMAG"`\n", sizeof(ar_head.ar_fmag))) { | |||
461 | warnx("%s: member fseeko", name); | |||
462 | rval = 1; | |||
463 | break; | |||
464 | } | |||
465 | ||||
466 | *p = '\0'; | |||
467 | if (mmbr_name(&ar_head, &p, 0, &namelen, fp)) { | |||
468 | rval = 1; | |||
469 | break; | |||
470 | } | |||
471 | ||||
472 | printf("%s in %s\n", strtab + prn->ran_un.ran_strx, p); | |||
473 | } | |||
474 | ||||
475 | free(p); | |||
476 | MUNMAP(symdef, len)do { if (usemmap) munmap(symdef, len); else free(symdef); symdef = ((void *)0); } while (0); | |||
477 | return (rval); | |||
478 | } | |||
479 | ||||
480 | /* | |||
481 | * show_archive() | |||
482 | * show symbols in the given archive file | |||
483 | */ | |||
484 | int | |||
485 | show_archive(int count, const char *fname, FILE *fp) | |||
486 | { | |||
487 | struct ar_hdr ar_head; | |||
488 | union hdr exec_head; | |||
489 | int i, rval; | |||
490 | off_t last_ar_off, foff, symtaboff; | |||
491 | char *name; | |||
492 | int baselen, namelen; | |||
493 | u_long mmbrlen, symtablen; | |||
494 | ||||
495 | baselen = strlen(fname) + 3; | |||
496 | if (posix_output) | |||
497 | baselen += 2; | |||
498 | namelen = sizeof(ar_head.ar_name); | |||
499 | if ((name = malloc(baselen + namelen)) == NULL((void *)0)) | |||
500 | err(1, NULL((void *)0)); | |||
501 | ||||
502 | rval = 0; | |||
503 | nametab = NULL((void *)0); | |||
504 | symtaboff = 0; | |||
505 | symtablen = 0; | |||
506 | ||||
507 | /* while there are more entries in the archive */ | |||
508 | while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) { | |||
509 | /* bad archive entry - stop processing this archive */ | |||
510 | if (memcmp(ar_head.ar_fmag, ARFMAG"`\n", sizeof(ar_head.ar_fmag))) { | |||
511 | warnx("%s: bad format archive header", fname); | |||
512 | rval = 1; | |||
513 | break; | |||
514 | } | |||
515 | ||||
516 | /* remember start position of current archive object */ | |||
517 | last_ar_off = ftello(fp); | |||
518 | mmbrlen = atol(ar_head.ar_size); | |||
519 | ||||
520 | if (strncmp(ar_head.ar_name, RANLIBMAG"__.SYMDEF", | |||
521 | sizeof(RANLIBMAG"__.SYMDEF") - 1) == 0) { | |||
522 | if (!issize && armap && | |||
523 | show_symdef(last_ar_off, mmbrlen, fname, fp)) { | |||
524 | rval = 1; | |||
525 | break; | |||
526 | } | |||
527 | goto skip; | |||
528 | } else if (strncmp(ar_head.ar_name, SYMTABMAG"/ ", | |||
529 | sizeof(SYMTABMAG"/ ") - 1) == 0) { | |||
530 | /* if nametab hasn't been seen yet -- doit later */ | |||
531 | if (!nametab) { | |||
532 | symtablen = mmbrlen; | |||
533 | symtaboff = last_ar_off; | |||
534 | goto skip; | |||
535 | } | |||
536 | ||||
537 | /* load the Sys5 long names table */ | |||
538 | } else if (strncmp(ar_head.ar_name, STRTABMAG"//", | |||
539 | sizeof(STRTABMAG"//") - 1) == 0) { | |||
540 | char *p; | |||
541 | ||||
542 | if ((nametab = malloc(mmbrlen)) == NULL((void *)0)) { | |||
543 | warn("%s: nametab", fname); | |||
544 | rval = 1; | |||
545 | break; | |||
546 | } | |||
547 | ||||
548 | if (fread(nametab, mmbrlen, (size_t)1, fp) != 1) { | |||
549 | warnx("%s: premature EOF", fname); | |||
550 | rval = 1; | |||
551 | break; | |||
552 | } | |||
553 | ||||
554 | for (p = nametab, i = mmbrlen; i--; p++) | |||
555 | if (*p == '\n') | |||
556 | *p = '\0'; | |||
557 | ||||
558 | if (issize || !armap || !symtablen || !symtaboff) | |||
559 | goto skip; | |||
560 | } | |||
561 | #ifdef __mips64 | |||
562 | else if (memcmp(ar_head.ar_name, SYM64MAG"/SYM64/ ", | |||
563 | sizeof(ar_head.ar_name)) == 0) { | |||
564 | /* IRIX6-compatible archive map */ | |||
565 | goto skip; | |||
566 | } | |||
567 | #endif | |||
568 | ||||
569 | if (!issize && armap && symtablen && symtaboff) { | |||
570 | if (show_symtab(symtaboff, symtablen, fname, fp)) { | |||
571 | rval = 1; | |||
572 | break; | |||
573 | } else { | |||
574 | symtaboff = 0; | |||
575 | symtablen = 0; | |||
576 | } | |||
577 | } | |||
578 | ||||
579 | /* | |||
580 | * construct a name of the form "archive.a:obj.o:" for the | |||
581 | * current archive entry if the object name is to be printed | |||
582 | * on each output line | |||
583 | */ | |||
584 | *name = '\0'; | |||
585 | if (posix_output) | |||
586 | snprintf(name, baselen - 1, "%s[", fname); | |||
587 | else if (count > 1) | |||
588 | snprintf(name, baselen - 1, "%s:", fname); | |||
589 | ||||
590 | if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) { | |||
591 | rval = 1; | |||
592 | break; | |||
593 | } | |||
594 | ||||
595 | if (posix_output) | |||
596 | strlcat(name, "]", baselen + namelen); | |||
597 | ||||
598 | foff = ftello(fp); | |||
599 | ||||
600 | /* get and check current object's header */ | |||
601 | if (fread((char *)&exec_head, sizeof(exec_head), | |||
602 | (size_t)1, fp) != 1) { | |||
603 | warnx("%s: premature EOF", fname); | |||
604 | rval = 1; | |||
605 | break; | |||
606 | } | |||
607 | ||||
608 | rval |= show_file(2, non_object_warning, name, fp, foff, &exec_head); | |||
609 | /* | |||
610 | * skip to next archive object - it starts at the next | |||
611 | * even byte boundary | |||
612 | */ | |||
613 | #define even(x)(((x) + 1) & ~1) (((x) + 1) & ~1) | |||
614 | skip: if (fseeko(fp, last_ar_off + even(mmbrlen)(((mmbrlen) + 1) & ~1), SEEK_SET0)) { | |||
615 | warn("%s", fname); | |||
616 | rval = 1; | |||
617 | break; | |||
618 | } | |||
619 | } | |||
620 | free(nametab); | |||
621 | nametab = NULL((void *)0); | |||
622 | free(name); | |||
623 | return(rval); | |||
624 | } | |||
625 | ||||
626 | char *stab; | |||
627 | ||||
628 | /* | |||
629 | * show_file() | |||
630 | * show symbols from the object file pointed to by fp. The current | |||
631 | * file pointer for fp is expected to be at the beginning of an object | |||
632 | * file header. | |||
633 | */ | |||
634 | int | |||
635 | show_file(int count, int warn_fmt, const char *name, FILE *fp, off_t foff, union hdr *head) | |||
636 | { | |||
637 | u_long text, data, bss, total; | |||
638 | struct xnlist *np, *names, **snames; | |||
639 | int i, nrawnames, nnames; | |||
640 | size_t stabsize; | |||
641 | ||||
642 | 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') && | |||
643 | head->elf32.e_ident[EI_CLASS4] == ELFCLASS321 && | |||
644 | head->elf32.e_ident[EI_VERSION6] == ELF_TARG_VER1) { | |||
645 | void *shdr; | |||
646 | ||||
647 | if (!(shdr = elf32_load_shdrs(name, fp, foff, &head->elf32))) | |||
648 | return (1); | |||
649 | ||||
650 | i = issize? | |||
651 | elf32_size(&head->elf32, shdr, &text, &data, &bss) : | |||
652 | elf32_symload(name, fp, foff, &head->elf32, shdr, | |||
653 | &names, &snames, &stabsize, &nrawnames); | |||
654 | free(shdr); | |||
655 | if (i) | |||
656 | return (i); | |||
657 | ||||
658 | } 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') && | |||
659 | head->elf64.e_ident[EI_CLASS4] == ELFCLASS642 && | |||
660 | head->elf64.e_ident[EI_VERSION6] == ELF_TARG_VER1) { | |||
661 | void *shdr; | |||
662 | ||||
663 | if (!(shdr = elf64_load_shdrs(name, fp, foff, &head->elf64))) | |||
664 | return (1); | |||
665 | ||||
666 | i = issize? | |||
667 | elf64_size(&head->elf64, shdr, &text, &data, &bss) : | |||
668 | elf64_symload(name, fp, foff, &head->elf64, shdr, | |||
669 | &names, &snames, &stabsize, &nrawnames); | |||
670 | free(shdr); | |||
671 | if (i) | |||
672 | return (i); | |||
673 | } else { | |||
674 | if (warn_fmt) | |||
675 | warnx("%s: bad format", name); | |||
676 | return (1); | |||
677 | } | |||
678 | ||||
679 | if (issize) { | |||
680 | static int first = 1; | |||
681 | ||||
682 | if (first) { | |||
683 | first = 0; | |||
684 | printf("text\tdata\tbss\tdec\thex\n"); | |||
685 | } | |||
686 | ||||
687 | total = text + data + bss; | |||
688 | printf("%lu\t%lu\t%lu\t%lu\t%lx", | |||
689 | text, data, bss, total, total); | |||
690 | if (count > 1) | |||
691 | (void)printf("\t%s", name); | |||
692 | ||||
693 | total_text += text; | |||
694 | total_data += data; | |||
695 | total_bss += bss; | |||
696 | total_total += total; | |||
697 | ||||
698 | printf("\n"); | |||
699 | return (0); | |||
700 | } | |||
701 | /* else we are nm */ | |||
702 | ||||
703 | /* | |||
704 | * it seems that string table is sequential | |||
705 | * relative to the symbol table order | |||
706 | */ | |||
707 | if (sfunc == NULL((void *)0) && usemmap) | |||
708 | (void)madvise(stab, stabsize, MADV_SEQUENTIAL2); | |||
709 | ||||
710 | /* | |||
711 | * fix up the symbol table and filter out unwanted entries | |||
712 | * | |||
713 | * common symbols are characterized by a n_type of N_UNDF and a | |||
714 | * non-zero n_value -- change n_type to N_COMM for all such | |||
715 | * symbols to make life easier later. | |||
716 | * | |||
717 | * filter out all entries which we don't want to print anyway | |||
718 | */ | |||
719 | for (np = names, i = nnames = 0; i < nrawnames; np++, i++) { | |||
| ||||
720 | /* | |||
721 | * make n_un.n_name a character pointer by adding the string | |||
722 | * table's base to n_un.n_strx | |||
723 | * | |||
724 | * don't mess with zero offsets | |||
725 | */ | |||
726 | if (np->nl.n_un.n_strx) | |||
727 | np->nl.n_un.n_name = stab + np->nl.n_un.n_strx; | |||
728 | else | |||
729 | np->nl.n_un.n_name = ""; | |||
730 | if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type)((np->nl.n_type) & 0x01)) | |||
731 | continue; | |||
732 | if (print_only_undefined_symbols && | |||
733 | SYMBOL_TYPE(np->nl.n_type)((np->nl.n_type) & (0x1e | 0x0e0)) != N_UNDF0x00) | |||
734 | continue; | |||
735 | ||||
736 | snames[nnames++] = np; | |||
737 | } | |||
738 | ||||
739 | /* sort the symbol table if applicable */ | |||
740 | if (sfunc) | |||
741 | qsort(snames, (size_t)nnames, sizeof(*snames), sfunc); | |||
742 | ||||
743 | if (count > 1) | |||
744 | (void)printf("\n%s:\n", name); | |||
745 | ||||
746 | /* print out symbols */ | |||
747 | for (i = 0; i < nnames; i++) | |||
748 | print_symbol(name, snames[i]); | |||
749 | ||||
750 | free(snames); | |||
751 | free(names); | |||
752 | MUNMAP(stab, stabsize)do { if (usemmap) munmap(stab, stabsize); else free(stab); stab = ((void *)0); } while (0); | |||
753 | return(0); | |||
754 | } | |||
755 | ||||
756 | char * | |||
757 | symname(struct xnlist *sym) | |||
758 | { | |||
759 | return sym->nl.n_un.n_name; | |||
760 | } | |||
761 | ||||
762 | /* | |||
763 | * print_symbol() | |||
764 | * show one symbol | |||
765 | */ | |||
766 | void | |||
767 | print_symbol(const char *name, struct xnlist *sym) | |||
768 | { | |||
769 | if (print_file_each_line) { | |||
770 | if (posix_output) | |||
771 | (void)printf("%s: ", name); | |||
772 | else | |||
773 | (void)printf("%s:", name); | |||
774 | } | |||
775 | ||||
776 | if (posix_output) { | |||
777 | (void)printf("%s %c ", symname(sym), typeletter(sym)); | |||
778 | if (SYMBOL_TYPE(sym->nl.n_type)((sym->nl.n_type) & (0x1e | 0x0e0)) != N_UNDF0x00) | |||
779 | (void)printf(posix_fmtstr, sym->nl.n_value, | |||
780 | sym->n_size); | |||
781 | (void)printf("\n"); | |||
782 | } else { | |||
783 | /* | |||
784 | * handle undefined-only format especially (no space is | |||
785 | * left for symbol values, no type field is printed) | |||
786 | */ | |||
787 | if (!print_only_undefined_symbols) { | |||
788 | /* print symbol's value */ | |||
789 | if (SYMBOL_TYPE(sym->nl.n_type)((sym->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
790 | (void)printf(" "); | |||
791 | else | |||
792 | (void)printf("%08lx", sym->nl.n_value); | |||
793 | ||||
794 | /* print type information */ | |||
795 | if (show_extensions) | |||
796 | (void)printf(" %c ", typeletter(sym)); | |||
797 | else | |||
798 | (void)printf(" %c ", typeletter(sym)); | |||
799 | } | |||
800 | ||||
801 | (void)puts(symname(sym)); | |||
802 | } | |||
803 | } | |||
804 | ||||
805 | /* | |||
806 | * typeletter() | |||
807 | * return a description letter for the given basic type code of an | |||
808 | * symbol table entry. The return value will be upper case for | |||
809 | * external, lower case for internal symbols. | |||
810 | */ | |||
811 | char | |||
812 | typeletter(struct xnlist *np) | |||
813 | { | |||
814 | int ext = IS_EXTERNAL(np->nl.n_type)((np->nl.n_type) & 0x01); | |||
815 | ||||
816 | if (np->nl.n_other) | |||
817 | return np->nl.n_other; | |||
818 | ||||
819 | switch(SYMBOL_TYPE(np->nl.n_type)((np->nl.n_type) & (0x1e | 0x0e0))) { | |||
820 | case N_ABS0x02: | |||
821 | return(ext? 'A' : 'a'); | |||
822 | case N_BSS0x08: | |||
823 | return(ext? 'B' : 'b'); | |||
824 | case N_COMM0x12: | |||
825 | return(ext? 'C' : 'c'); | |||
826 | case N_DATA0x06: | |||
827 | return(ext? 'D' : 'd'); | |||
828 | case N_FN0x1e: | |||
829 | /* NOTE: N_FN == N_WARNING, | |||
830 | * in this case, the N_EXT bit is to considered as | |||
831 | * part of the symbol's type itself. | |||
832 | */ | |||
833 | return(ext? 'F' : 'W'); | |||
834 | case N_TEXT0x04: | |||
835 | return(ext? 'T' : 't'); | |||
836 | case N_SIZE0x0c: | |||
837 | return(ext? 'S' : 's'); | |||
838 | case N_UNDF0x00: | |||
839 | return(ext? 'U' : 'u'); | |||
840 | } | |||
841 | return('?'); | |||
842 | } | |||
843 | ||||
844 | int | |||
845 | fname(const void *a0, const void *b0) | |||
846 | { | |||
847 | struct xnlist * const *a = a0, * const *b = b0; | |||
848 | ||||
849 | return(strcmp((*a)->nl.n_un.n_name, (*b)->nl.n_un.n_name)); | |||
850 | } | |||
851 | ||||
852 | int | |||
853 | rname(const void *a0, const void *b0) | |||
854 | { | |||
855 | struct xnlist * const *a = a0, * const *b = b0; | |||
856 | ||||
857 | return(strcmp((*b)->nl.n_un.n_name, (*a)->nl.n_un.n_name)); | |||
858 | } | |||
859 | ||||
860 | int | |||
861 | value(const void *a0, const void *b0) | |||
862 | { | |||
863 | struct xnlist * const *a = a0, * const *b = b0; | |||
864 | ||||
865 | if (SYMBOL_TYPE((*a)->nl.n_type)(((*a)->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
866 | if (SYMBOL_TYPE((*b)->nl.n_type)(((*b)->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
867 | return(0); | |||
868 | else | |||
869 | return(-1); | |||
870 | else if (SYMBOL_TYPE((*b)->nl.n_type)(((*b)->nl.n_type) & (0x1e | 0x0e0)) == N_UNDF0x00) | |||
871 | return(1); | |||
872 | if (rev) { | |||
873 | if ((*a)->nl.n_value == (*b)->nl.n_value) | |||
874 | return(rname(a0, b0)); | |||
875 | return((*b)->nl.n_value > (*a)->nl.n_value ? 1 : -1); | |||
876 | } else { | |||
877 | if ((*a)->nl.n_value == (*b)->nl.n_value) | |||
878 | return(fname(a0, b0)); | |||
879 | return((*a)->nl.n_value > (*b)->nl.n_value ? 1 : -1); | |||
880 | } | |||
881 | } | |||
882 | ||||
883 | #define CPPFILT"/usr/bin/c++filt" "/usr/bin/c++filt" | |||
884 | ||||
885 | void | |||
886 | pipe2cppfilt(void) | |||
887 | { | |||
888 | int pip[2]; | |||
889 | char *argv[2]; | |||
890 | ||||
891 | argv[0] = "c++filt"; | |||
892 | argv[1] = NULL((void *)0); | |||
893 | ||||
894 | if (pipe(pip) == -1) | |||
895 | err(1, "pipe"); | |||
896 | switch(fork()) { | |||
897 | case -1: | |||
898 | err(1, "fork"); | |||
899 | default: | |||
900 | dup2(pip[0], 0); | |||
901 | close(pip[0]); | |||
902 | close(pip[1]); | |||
903 | execve(CPPFILT"/usr/bin/c++filt", argv, NULL((void *)0)); | |||
904 | err(1, "execve"); | |||
905 | case 0: | |||
906 | dup2(pip[1], 1); | |||
907 | close(pip[1]); | |||
908 | close(pip[0]); | |||
909 | } | |||
910 | } | |||
911 | ||||
912 | void | |||
913 | usage(void) | |||
914 | { | |||
915 | extern char *__progname; | |||
916 | ||||
917 | if (issize) | |||
918 | fprintf(stderr(&__sF[2]), "usage: %s [-tw] [file ...]\n", __progname); | |||
919 | else | |||
920 | fprintf(stderr(&__sF[2]), "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n", | |||
921 | __progname); | |||
922 | exit(1); | |||
923 | } |