File: | src/usr.bin/nm/nm.c |
Warning: | line 709, column 9 2nd function call argument is an uninitialized value |
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 | } |