GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: nm.c,v 1.52 2017/09/12 08:32:44 mpi 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_abi.h> |
||
40 |
#include <ar.h> |
||
41 |
#include <ranlib.h> |
||
42 |
#include <unistd.h> |
||
43 |
#include <err.h> |
||
44 |
#include <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/ " |
||
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) & N_EXT) |
||
96 |
#define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB)) |
||
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" |
||
107 |
const struct option longopts_nm[] = { |
||
108 |
{ "debug-syms", no_argument, 0, 'a' }, |
||
109 |
{ "demangle", no_argument, 0, 'C' }, |
||
110 |
{ "dynamic", no_argument, 0, 'D' }, |
||
111 |
{ "extern-only", no_argument, 0, 'g' }, |
||
112 |
/* { "line-numbers", no_argument, 0, 'l' }, */ |
||
113 |
{ "no-sort", no_argument, 0, 'p' }, |
||
114 |
{ "numeric-sort", no_argument, 0, 'n' }, |
||
115 |
{ "print-armap", no_argument, 0, 's' }, |
||
116 |
{ "print-file-name", no_argument, 0, 'o' }, |
||
117 |
{ "reverse-sort", no_argument, 0, 'r' }, |
||
118 |
/* { "size-sort", no_argument, &szval, 1 }, */ |
||
119 |
{ "undefined-only", no_argument, 0, 'u' }, |
||
120 |
{ "help", no_argument, 0, '?' }, |
||
121 |
{ NULL } |
||
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 |
✗✓ | 376 |
if (pledge("stdio rpath proc exec flock cpath wpath", NULL) == -1) |
139 |
err(1, "pledge"); |
||
140 |
|||
141 |
optstr = OPTSTRING_NM; |
||
142 |
lopts = longopts_nm; |
||
143 |
✗✓ | 188 |
if (!strcmp(__progname, "size")) { |
144 |
if (pledge("stdio rpath flock cpath wpath", NULL) == -1) |
||
145 |
err(1, "pledge"); |
||
146 |
|||
147 |
issize = 1; |
||
148 |
optstr = "tw"; |
||
149 |
lopts = NULL; |
||
150 |
} |
||
151 |
|||
152 |
✓✓ | 556 |
while ((ch = getopt_long(argc, argv, optstr, lopts, NULL)) != -1) { |
153 |
✓✗✓✗ ✗✓✗✗ ✗✓✗✗ ✗✗✗✗ ✗✗ |
736 |
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 |
5 |
demangle = 1; |
|
162 |
5 |
break; |
|
163 |
case 'D': |
||
164 |
dynamic_only = 1; |
||
165 |
break; |
||
166 |
case 'e': |
||
167 |
show_extensions = 1; |
||
168 |
break; |
||
169 |
case 'g': |
||
170 |
180 |
print_only_external_symbols = 1; |
|
171 |
180 |
break; |
|
172 |
case 'n': |
||
173 |
case 'v': |
||
174 |
sfunc = value; |
||
175 |
break; |
||
176 |
case 'A': |
||
177 |
case 'o': |
||
178 |
183 |
print_file_each_line = 1; |
|
179 |
183 |
break; |
|
180 |
case 'p': |
||
181 |
sfunc = NULL; |
||
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 |
✗✓ | 188 |
if (posix_output) |
216 |
(void)snprintf(posix_fmtstr, sizeof posix_fmtstr, "%%%c %%%c", |
||
217 |
posix_radix, posix_radix); |
||
218 |
✓✓ | 188 |
if (demangle) |
219 |
5 |
pipe2cppfilt(); |
|
220 |
|||
221 |
✗✓ | 188 |
if (pledge("stdio rpath flock cpath wpath", NULL) == -1) |
222 |
err(1, "pledge"); |
||
223 |
|||
224 |
188 |
argv += optind; |
|
225 |
188 |
argc -= optind; |
|
226 |
|||
227 |
✗✓ | 188 |
if (rev && sfunc == fname) |
228 |
sfunc = rname; |
||
229 |
|||
230 |
eval = 0; |
||
231 |
✓✗ | 188 |
if (*argv) |
232 |
do { |
||
233 |
14035 |
eval |= process_file(argc, *argv); |
|
234 |
✓✓ | 14035 |
} while (*++argv); |
235 |
else |
||
236 |
eval |= process_file(1, "a.out"); |
||
237 |
|||
238 |
✗✓ | 188 |
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 |
28070 |
union hdr exec_head; |
|
254 |
FILE *fp; |
||
255 |
int retval; |
||
256 |
size_t bytes; |
||
257 |
14035 |
char magic[SARMAG]; |
|
258 |
|||
259 |
✗✓ | 14035 |
if (!(fp = fopen(fname, "r"))) { |
260 |
warn("cannot read %s", fname); |
||
261 |
return(1); |
||
262 |
} |
||
263 |
|||
264 |
✓✓ | 14035 |
if (!issize && count > 1) |
265 |
14027 |
(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 |
14035 |
bzero(&exec_head, sizeof(exec_head)); |
|
272 |
14035 |
bytes = fread((char *)&exec_head, 1, sizeof(exec_head), fp); |
|
273 |
✗✓ | 14035 |
if (bytes < sizeof(exec_head)) { |
274 |
if (bytes < sizeof(exec_head.elf32) || IS_ELF(exec_head.elf32)) { |
||
275 |
warnx("%s: bad format", fname); |
||
276 |
(void)fclose(fp); |
||
277 |
return(1); |
||
278 |
} |
||
279 |
} |
||
280 |
14035 |
rewind(fp); |
|
281 |
|||
282 |
/* this could be an archive */ |
||
283 |
✓✓✓✗ ✓✗✗✓ |
56131 |
if (!IS_ELF(exec_head.elf32)) { |
284 |
✓✗✗✓ |
6 |
if (fread(magic, sizeof(magic), (size_t)1, fp) != 1 || |
285 |
3 |
strncmp(magic, ARMAG, SARMAG)) { |
|
286 |
warnx("%s: not object file or archive", fname); |
||
287 |
(void)fclose(fp); |
||
288 |
return(1); |
||
289 |
} |
||
290 |
3 |
retval = show_archive(count, fname, fp); |
|
291 |
3 |
} else |
|
292 |
14032 |
retval = show_file(count, 1, fname, fp, 0, &exec_head); |
|
293 |
14035 |
(void)fclose(fp); |
|
294 |
14035 |
return(retval); |
|
295 |
14035 |
} |
|
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 |
228 |
char *p = *name + strlen(*name); |
|
307 |
long i; |
||
308 |
|||
309 |
✗✓✗✗ |
114 |
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) |
||
317 |
err(1, NULL); |
||
318 |
*namelen = len; |
||
319 |
p += (long)*name; |
||
320 |
} |
||
321 |
strlcpy(p, &nametab[i], len); |
||
322 |
p += len - 1; |
||
323 |
} else |
||
324 |
#ifdef AR_EFMT1 |
||
325 |
/* |
||
326 |
* BSD 4.4 extended AR format: #1/<namelen>, with name as the |
||
327 |
* first <namelen> bytes of the file |
||
328 |
*/ |
||
329 |
✗✓✗✗ |
114 |
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) |
||
338 |
err(1, NULL); |
||
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 |
✓✓ | 3876 |
for (i = 0; i < sizeof(arh->ar_name); ++i) |
351 |
✓✗✓✓ |
3648 |
if (arh->ar_name[i] && arh->ar_name[i] != ' ') |
352 |
1167 |
*p++ = arh->ar_name[i]; |
|
353 |
114 |
*p = '\0'; |
|
354 |
✓✗ | 114 |
if (p[-1] == '/') |
355 |
114 |
*--p = '\0'; |
|
356 |
|||
357 |
114 |
return (0); |
|
358 |
114 |
} |
|
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); |
||
377 |
if (symtab == MAP_FAILED) |
||
378 |
return (1); |
||
379 |
|||
380 |
namelen = sizeof(ar_head.ar_name); |
||
381 |
if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) { |
||
382 |
warn("%s: malloc", name); |
||
383 |
MUNMAP(symtab, len); |
||
384 |
} |
||
385 |
|||
386 |
printf("\nArchive index:\n"); |
||
387 |
num = betoh32(*symtab); |
||
388 |
strtab = (char *)(symtab + num + 1); |
||
389 |
for (ps = symtab + 1; num--; ps++, strtab += strlen(strtab) + 1) { |
||
390 |
if (fseeko(fp, betoh32(*ps), SEEK_SET)) { |
||
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, 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_SET); |
||
413 |
|||
414 |
free(p); |
||
415 |
MUNMAP(symtab, len); |
||
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); |
||
434 |
if (symdef == MAP_FAILED) |
||
435 |
return (1); |
||
436 |
if (usemmap) |
||
437 |
(void)madvise(symdef, len, MADV_SEQUENTIAL); |
||
438 |
|||
439 |
namelen = sizeof(ar_head.ar_name); |
||
440 |
if ((p = malloc(sizeof(ar_head.ar_name))) == NULL) { |
||
441 |
warn("%s: malloc", name); |
||
442 |
MUNMAP(symdef, len); |
||
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_SET)) { |
||
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, 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); |
||
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 |
6 |
struct ar_hdr ar_head; |
|
488 |
3 |
union hdr exec_head; |
|
489 |
int i, rval; |
||
490 |
off_t last_ar_off, foff, symtaboff; |
||
491 |
3 |
char *name; |
|
492 |
3 |
int baselen, namelen; |
|
493 |
u_long mmbrlen, symtablen; |
||
494 |
|||
495 |
3 |
baselen = strlen(fname) + 3; |
|
496 |
✗✓ | 3 |
if (posix_output) |
497 |
baselen += 2; |
||
498 |
3 |
namelen = sizeof(ar_head.ar_name); |
|
499 |
✗✓ | 3 |
if ((name = malloc(baselen + namelen)) == NULL) |
500 |
err(1, NULL); |
||
501 |
|||
502 |
rval = 0; |
||
503 |
3 |
nametab = NULL; |
|
504 |
symtaboff = 0; |
||
505 |
symtablen = 0; |
||
506 |
|||
507 |
/* while there are more entries in the archive */ |
||
508 |
✓✓ | 123 |
while (fread(&ar_head, sizeof(ar_head), 1, fp) == 1) { |
509 |
/* bad archive entry - stop processing this archive */ |
||
510 |
✗✓ | 117 |
if (memcmp(ar_head.ar_fmag, ARFMAG, 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 |
117 |
last_ar_off = ftello(fp); |
|
518 |
117 |
mmbrlen = atol(ar_head.ar_size); |
|
519 |
|||
520 |
✗✓ | 234 |
if (strncmp(ar_head.ar_name, RANLIBMAG, |
521 |
117 |
sizeof(RANLIBMAG) - 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 |
✓✓ | 234 |
} else if (strncmp(ar_head.ar_name, SYMTABMAG, |
529 |
117 |
sizeof(SYMTABMAG) - 1) == 0) { |
|
530 |
/* if nametab hasn't been seen yet -- doit later */ |
||
531 |
✓✗ | 3 |
if (!nametab) { |
532 |
symtablen = mmbrlen; |
||
533 |
symtaboff = last_ar_off; |
||
534 |
3 |
goto skip; |
|
535 |
} |
||
536 |
|||
537 |
/* load the Sys5 long names table */ |
||
538 |
✗✓ | 228 |
} else if (strncmp(ar_head.ar_name, STRTABMAG, |
539 |
114 |
sizeof(STRTABMAG) - 1) == 0) { |
|
540 |
char *p; |
||
541 |
|||
542 |
if ((nametab = malloc(mmbrlen)) == NULL) { |
||
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, |
||
563 |
sizeof(ar_head.ar_name)) == 0) { |
||
564 |
/* IRIX6-compatible archive map */ |
||
565 |
goto skip; |
||
566 |
} |
||
567 |
#endif |
||
568 |
|||
569 |
✗✓ | 114 |
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 |
114 |
*name = '\0'; |
|
585 |
✗✓ | 114 |
if (posix_output) |
586 |
snprintf(name, baselen - 1, "%s[", fname); |
||
587 |
✗✓ | 114 |
else if (count > 1) |
588 |
snprintf(name, baselen - 1, "%s:", fname); |
||
589 |
|||
590 |
✗✓ | 114 |
if (mmbr_name(&ar_head, &name, baselen, &namelen, fp)) { |
591 |
rval = 1; |
||
592 |
break; |
||
593 |
} |
||
594 |
|||
595 |
✗✓ | 114 |
if (posix_output) |
596 |
strlcat(name, "]", baselen + namelen); |
||
597 |
|||
598 |
114 |
foff = ftello(fp); |
|
599 |
|||
600 |
/* get and check current object's header */ |
||
601 |
✗✓ | 228 |
if (fread((char *)&exec_head, sizeof(exec_head), |
602 |
114 |
(size_t)1, fp) != 1) { |
|
603 |
warnx("%s: premature EOF", fname); |
||
604 |
rval = 1; |
||
605 |
break; |
||
606 |
} |
||
607 |
|||
608 |
114 |
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) |
||
614 |
✓✗ | 117 |
skip: if (fseeko(fp, last_ar_off + even(mmbrlen), SEEK_SET)) { |
615 |
warn("%s", fname); |
||
616 |
rval = 1; |
||
617 |
break; |
||
618 |
} |
||
619 |
} |
||
620 |
3 |
free(nametab); |
|
621 |
3 |
nametab = NULL; |
|
622 |
3 |
free(name); |
|
623 |
3 |
return(rval); |
|
624 |
3 |
} |
|
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 |
28292 |
u_long text, data, bss, total; |
|
638 |
14146 |
struct xnlist *np, *names, **snames; |
|
639 |
14146 |
int i, nrawnames, nnames; |
|
640 |
14146 |
size_t stabsize; |
|
641 |
|||
642 |
✓✗✓✗ ✓✗✓✗ ✗✗ |
56584 |
if (IS_ELF(head->elf32) && |
643 |
✗✓ | 14146 |
head->elf32.e_ident[EI_CLASS] == ELFCLASS32 && |
644 |
head->elf32.e_ident[EI_VERSION] == ELF_TARG_VER) { |
||
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 |
✗✗✓✗ ✓✗✓✗ ✓✗✓✗ |
70730 |
} else if (IS_ELF(head->elf64) && |
659 |
✓✗ | 14146 |
head->elf64.e_ident[EI_CLASS] == ELFCLASS64 && |
660 |
14146 |
head->elf64.e_ident[EI_VERSION] == ELF_TARG_VER) { |
|
661 |
void *shdr; |
||
662 |
|||
663 |
✗✓ | 14146 |
if (!(shdr = elf64_load_shdrs(name, fp, foff, &head->elf64))) |
664 |
return (1); |
||
665 |
|||
666 |
✗✓ | 42438 |
i = issize? |
667 |
elf64_size(&head->elf64, shdr, &text, &data, &bss) : |
||
668 |
14146 |
elf64_symload(name, fp, foff, &head->elf64, shdr, |
|
669 |
&names, &snames, &stabsize, &nrawnames); |
||
670 |
14146 |
free(shdr); |
|
671 |
✗✓ | 14146 |
if (i) |
672 |
return (i); |
||
673 |
✓✗ | 14146 |
} else { |
674 |
if (warn_fmt) |
||
675 |
warnx("%s: bad format", name); |
||
676 |
return (1); |
||
677 |
} |
||
678 |
|||
679 |
✗✓ | 14146 |
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 |
✗✓ | 14146 |
if (sfunc == NULL && usemmap) |
708 |
(void)madvise(stab, stabsize, MADV_SEQUENTIAL); |
||
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 |
✓✓ | 1277930 |
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 |
✓✗ | 624819 |
if (np->nl.n_un.n_strx) |
727 |
624819 |
np->nl.n_un.n_name = stab + np->nl.n_un.n_strx; |
|
728 |
else |
||
729 |
np->nl.n_un.n_name = ""; |
||
730 |
✓✓✓✓ |
1233725 |
if (print_only_external_symbols && !IS_EXTERNAL(np->nl.n_type)) |
731 |
continue; |
||
732 |
✗✓✗✗ |
298347 |
if (print_only_undefined_symbols && |
733 |
SYMBOL_TYPE(np->nl.n_type) != N_UNDF) |
||
734 |
continue; |
||
735 |
|||
736 |
298347 |
snames[nnames++] = np; |
|
737 |
298347 |
} |
|
738 |
|||
739 |
/* sort the symbol table if applicable */ |
||
740 |
✓✗ | 14146 |
if (sfunc) |
741 |
14146 |
qsort(snames, (size_t)nnames, sizeof(*snames), sfunc); |
|
742 |
|||
743 |
✓✓ | 14146 |
if (count > 1) |
744 |
14141 |
(void)printf("\n%s:\n", name); |
|
745 |
|||
746 |
/* print out symbols */ |
||
747 |
✓✓ | 624986 |
for (i = 0; i < nnames; i++) |
748 |
298347 |
print_symbol(name, snames[i]); |
|
749 |
|||
750 |
14146 |
free(snames); |
|
751 |
14146 |
free(names); |
|
752 |
✓✗ | 42438 |
MUNMAP(stab, stabsize); |
753 |
14146 |
return(0); |
|
754 |
14146 |
} |
|
755 |
|||
756 |
char * |
||
757 |
symname(struct xnlist *sym) |
||
758 |
{ |
||
759 |
596694 |
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 |
✓✓ | 596694 |
if (print_file_each_line) { |
770 |
✗✓ | 298217 |
if (posix_output) |
771 |
(void)printf("%s: ", name); |
||
772 |
else |
||
773 |
298217 |
(void)printf("%s:", name); |
|
774 |
} |
||
775 |
|||
776 |
✗✓ | 298347 |
if (posix_output) { |
777 |
(void)printf("%s %c ", symname(sym), typeletter(sym)); |
||
778 |
if (SYMBOL_TYPE(sym->nl.n_type) != N_UNDF) |
||
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 |
✓✗ | 298347 |
if (!print_only_undefined_symbols) { |
788 |
/* print symbol's value */ |
||
789 |
✓✓ | 298347 |
if (SYMBOL_TYPE(sym->nl.n_type) == N_UNDF) |
790 |
198536 |
(void)printf(" "); |
|
791 |
else |
||
792 |
99811 |
(void)printf("%08lx", sym->nl.n_value); |
|
793 |
|||
794 |
/* print type information */ |
||
795 |
✗✓ | 596694 |
if (show_extensions) |
796 |
298347 |
(void)printf(" %c ", typeletter(sym)); |
|
797 |
else |
||
798 |
298347 |
(void)printf(" %c ", typeletter(sym)); |
|
799 |
} |
||
800 |
|||
801 |
298347 |
(void)puts(symname(sym)); |
|
802 |
} |
||
803 |
298347 |
} |
|
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 |
596694 |
int ext = IS_EXTERNAL(np->nl.n_type); |
|
815 |
|||
816 |
✓✓ | 298347 |
if (np->nl.n_other) |
817 |
15083 |
return np->nl.n_other; |
|
818 |
|||
819 |
✗✓✓✓ ✓✓✗✓ ✗ |
283264 |
switch(SYMBOL_TYPE(np->nl.n_type)) { |
820 |
case N_ABS: |
||
821 |
return(ext? 'A' : 'a'); |
||
822 |
case N_BSS: |
||
823 |
2989 |
return(ext? 'B' : 'b'); |
|
824 |
case N_COMM: |
||
825 |
1400 |
return(ext? 'C' : 'c'); |
|
826 |
case N_DATA: |
||
827 |
7707 |
return(ext? 'D' : 'd'); |
|
828 |
case N_FN: |
||
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 |
13567 |
return(ext? 'F' : 'W'); |
|
834 |
case N_TEXT: |
||
835 |
59077 |
return(ext? 'T' : 't'); |
|
836 |
case N_SIZE: |
||
837 |
return(ext? 'S' : 's'); |
||
838 |
case N_UNDF: |
||
839 |
198524 |
return(ext? 'U' : 'u'); |
|
840 |
} |
||
841 |
return('?'); |
||
842 |
298347 |
} |
|
843 |
|||
844 |
int |
||
845 |
fname(const void *a0, const void *b0) |
||
846 |
{ |
||
847 |
2793912 |
struct xnlist * const *a = a0, * const *b = b0; |
|
848 |
|||
849 |
1396956 |
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) == N_UNDF) |
||
866 |
if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF) |
||
867 |
return(0); |
||
868 |
else |
||
869 |
return(-1); |
||
870 |
else if (SYMBOL_TYPE((*b)->nl.n_type) == N_UNDF) |
||
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" |
||
884 |
|||
885 |
void |
||
886 |
pipe2cppfilt(void) |
||
887 |
{ |
||
888 |
10 |
int pip[2]; |
|
889 |
5 |
char *argv[2]; |
|
890 |
|||
891 |
5 |
argv[0] = "c++filt"; |
|
892 |
5 |
argv[1] = NULL; |
|
893 |
|||
894 |
✗✓ | 5 |
if (pipe(pip) == -1) |
895 |
err(1, "pipe"); |
||
896 |
✗✗✓ | 5 |
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, argv, NULL); |
||
904 |
err(1, "execve"); |
||
905 |
case 0: |
||
906 |
5 |
dup2(pip[1], 1); |
|
907 |
5 |
close(pip[1]); |
|
908 |
5 |
close(pip[0]); |
|
909 |
} |
||
910 |
5 |
} |
|
911 |
|||
912 |
void |
||
913 |
usage(void) |
||
914 |
{ |
||
915 |
extern char *__progname; |
||
916 |
|||
917 |
if (issize) |
||
918 |
fprintf(stderr, "usage: %s [-tw] [file ...]\n", __progname); |
||
919 |
else |
||
920 |
fprintf(stderr, "usage: %s [-AaCDegnoPprsuw] [-t d|o|x] [file ...]\n", |
||
921 |
__progname); |
||
922 |
exit(1); |
||
923 |
} |
Generated by: GCOVR (Version 3.3) |