2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * @(#) Copyright (c) 1989, 1993 The Regents of the University of California. All rights reserved.
37 * @(#)nm.c 8.1 (Berkeley) 6/6/93
38 * $FreeBSD: src/usr.bin/nm/nm.c,v 1.13.2.1 2001/03/04 08:54:10 kris Exp $
39 * $DragonFly: src/usr.bin/nm/nm.c,v 1.3 2003/10/04 22:36:50 hmp Exp $
42 #include <sys/types.h>
55 int ignore_bad_archive_entries
= 1;
56 int print_only_external_symbols
;
57 int print_only_undefined_symbols
;
58 int print_all_symbols
;
59 int print_file_each_line
;
60 int print_weak_symbols
;
64 int fname(), rname(), value();
65 int (*sfunc
)() = fname
;
67 /* some macros for symbol type (nlist.n_type) handling */
68 #define IS_DEBUGGER_SYMBOL(x) ((x) & N_STAB)
69 #define IS_EXTERNAL(x) ((x) & N_EXT)
70 #define SYMBOL_TYPE(x) ((x) & (N_TYPE | N_STAB))
71 #define SYMBOL_BIND(x) (((x) >> 4) & 0xf)
74 static void usage( void );
75 int process_file( char * );
76 int show_archive( char *, FILE * );
77 int show_objfile( char *, FILE * );
78 void print_symbol( char *, struct nlist
* );
79 char typeletter(u_char
);
83 * parse command line, execute process_file() for each file
84 * specified on the command line.
87 main(int argc
, char **argv
)
91 while ((ch
= getopt(argc
, argv
, "agnoprtuwW")) != -1) {
94 print_all_symbols
= 1;
97 print_only_external_symbols
= 1;
103 print_file_each_line
= 1;
115 print_only_undefined_symbols
= 1;
118 ignore_bad_archive_entries
= 0;
121 print_weak_symbols
= 1;
128 fcount
= argc
- optind
;
131 if (rev
&& sfunc
== fname
)
135 errors
= process_file("a.out");
139 errors
|= process_file(*argv
);
147 * show symbols in the file given as an argument. Accepts archive and
148 * object files as input.
151 process_file(char *fname
)
153 struct exec exec_head
;
158 if (!(fp
= fopen(fname
, "r"))) {
159 warnx("cannot read %s", fname
);
163 if (fcount
> 1 && !table
)
164 (void)printf("\n%s:\n", fname
);
167 * first check whether this is an object file - read a object
168 * header, and skip back to the beginning
170 if (fread((char *)&exec_head
, sizeof(exec_head
), (size_t)1, fp
) != 1) {
171 warnx("%s: bad format", fname
);
177 /* this could be an archive */
178 if (N_BADMAG(exec_head
)) {
179 if (fread(magic
, sizeof(magic
), (size_t)1, fp
) != 1 ||
180 strncmp(magic
, ARMAG
, SARMAG
)) {
181 warnx("%s: not object file or archive", fname
);
185 retval
= show_archive(fname
, fp
);
187 retval
= show_objfile(fname
, fp
);
192 /* scat: concatenate strings, returning new concatenation point
193 * and permitting overlap.
195 static char *scat(char *dest
, char *src
)
198 int l1
= strlen(dest
), l2
= strlen(src
);
200 memmove(dest
+ l1
, src
, l2
);
201 end
= dest
+ l1
+ l2
;
209 * show symbols in the given archive file
212 show_archive(char *fname
, FILE *fp
)
214 struct ar_hdr ar_head
;
215 struct exec exec_head
;
218 char *p
, *name
, *ar_name
;
219 int extra
= strlen(fname
) + 3;
221 name
= emalloc(MAXNAMLEN
+ extra
);
222 ar_name
= name
+ extra
;
226 /* while there are more entries in the archive */
227 while (fread((char *)&ar_head
, sizeof(ar_head
), (size_t)1, fp
) == 1) {
228 /* bad archive entry - stop processing this archive */
229 if (strncmp(ar_head
.ar_fmag
, ARFMAG
, sizeof(ar_head
.ar_fmag
))) {
230 warnx("%s: bad format archive header", fname
);
235 /* remember start position of current archive object */
236 last_ar_off
= ftell(fp
);
238 /* skip ranlib entries */
239 if (!bcmp(ar_head
.ar_name
, RANLIBMAG
, sizeof(RANLIBMAG
) - 1))
242 /* handle long names. If one is present, read it in at the
243 * end of the "name" buffer.
245 if (!bcmp(ar_head
.ar_name
, AR_EFMT1
, sizeof(AR_EFMT1
) - 1))
247 size_t len
= atoi(ar_head
.ar_name
+ sizeof(AR_EFMT1
) - 1);
249 if (len
<= 0 || len
> MAXNAMLEN
)
251 warnx("illegal length for format 1 long name");
254 if (fread(ar_name
, 1, len
, fp
) != len
)
256 warnx("EOF reading format 1 long name");
265 for (i
= 0; i
< sizeof(ar_head
.ar_name
) && p
[i
] && p
[i
] != ' '; i
++)
271 * construct a name of the form "archive.a:obj.o:" for the
272 * current archive entry if the object name is to be printed
273 * on each output line
277 if (print_file_each_line
&& !table
)
282 p
= scat(p
, ar_name
);
284 /* get and check current object's header */
285 if (fread((char *)&exec_head
, sizeof(exec_head
), (size_t)1, fp
) != 1) {
286 warnx("%s: premature EOF", name
);
291 if (N_BADMAG(exec_head
)) {
292 if (!ignore_bad_archive_entries
) {
293 warnx("%s: bad format", name
);
297 (void)fseek(fp
, -(long)sizeof(exec_head
),
299 if (!print_file_each_line
&& !table
)
300 (void)printf("\n%s:\n", name
);
301 rval
|= show_objfile(name
, fp
);
305 * skip to next archive object - it starts at the next
308 #define even(x) (((x) + 1) & ~1)
309 skip
: if (fseek(fp
, last_ar_off
+ even(atol(ar_head
.ar_size
)),
322 * show symbols from the object file pointed to by fp. The current
323 * file pointer for fp is expected to be at the beginning of an a.out
327 show_objfile(char *objname
, FILE *fp
)
329 register struct nlist
*names
, *np
;
330 register int i
, nnames
, nrawnames
;
335 /* read a.out header */
336 if (fread((char *)&head
, sizeof(head
), (size_t)1, fp
) != 1) {
337 warnx("%s: cannot read header", objname
);
342 * skip back to the header - the N_-macros return values relative
343 * to the beginning of the a.out header
345 if (fseek(fp
, -(long)sizeof(head
), SEEK_CUR
)) {
350 /* stop if this is no valid object file */
351 if (N_BADMAG(head
)) {
352 warnx("%s: bad format", objname
);
356 /* stop if the object file contains no symbol table */
358 warnx("%s: no name list", objname
);
362 if (fseek(fp
, (long)N_SYMOFF(head
), SEEK_CUR
)) {
367 /* get memory for the symbol table */
368 names
= emalloc((size_t)head
.a_syms
);
369 nrawnames
= head
.a_syms
/ sizeof(*names
);
370 if (fread((char *)names
, (size_t)head
.a_syms
, (size_t)1, fp
) != 1) {
371 warnx("%s: cannot read symbol table", objname
);
372 (void)free((char *)names
);
377 * Following the symbol table comes the string table. The first
378 * 4-byte-integer gives the total size of the string table
379 * _including_ the size specification itself.
381 if (fread((char *)&stabsize
, sizeof(stabsize
), (size_t)1, fp
) != 1) {
382 warnx("%s: cannot read stab size", objname
);
383 (void)free((char *)names
);
386 stab
= emalloc((size_t)stabsize
);
389 * read the string table offset by 4 - all indices into the string
390 * table include the size specification.
392 stabsize
-= 4; /* we already have the size */
393 if (fread(stab
+ 4, (size_t)stabsize
, (size_t)1, fp
) != 1) {
394 warnx("%s: stab truncated..", objname
);
395 (void)free((char *)names
);
401 * fix up the symbol table and filter out unwanted entries
403 * common symbols are characterized by a n_type of N_UNDF and a
404 * non-zero n_value -- change n_type to N_COMM for all such
405 * symbols to make life easier later.
407 * filter out all entries which we don't want to print anyway
409 for (np
= names
, i
= nnames
= 0; i
< nrawnames
; np
++, i
++) {
410 if (SYMBOL_TYPE(np
->n_type
) == N_UNDF
&& np
->n_value
)
411 np
->n_type
= N_COMM
| (np
->n_type
& N_EXT
);
412 if (!print_all_symbols
&& IS_DEBUGGER_SYMBOL(np
->n_type
))
414 if (print_only_external_symbols
&& !IS_EXTERNAL(np
->n_type
))
416 if (print_only_undefined_symbols
&&
417 SYMBOL_TYPE(np
->n_type
) != N_UNDF
)
421 * make n_un.n_name a character pointer by adding the string
422 * table's base to n_un.n_strx
424 * don't mess with zero offsets
427 np
->n_un
.n_name
= stab
+ np
->n_un
.n_strx
;
429 np
->n_un
.n_name
= "";
430 names
[nnames
++] = *np
;
433 /* sort the symbol table if applicable */
435 qsort((char *)names
, (size_t)nnames
, sizeof(*names
), sfunc
);
437 /* print out symbols */
438 for (np
= names
, i
= 0; i
< nnames
; np
++, i
++)
439 print_symbol(objname
, np
);
441 (void)free((char *)names
);
451 print_symbol(char *objname
, register struct nlist
*sym
)
456 printf("%s|", objname
);
457 if (SYMBOL_TYPE(sym
->n_type
) != N_UNDF
)
458 (void)printf("%08lx", (u_long
)sym
->n_value
);
460 if (IS_DEBUGGER_SYMBOL(sym
->n_type
))
461 (void)printf("-|%02x %04x %5s|", sym
->n_other
,
462 sym
->n_desc
&0xffff, typestring(sym
->n_type
));
464 putchar(typeletter(sym
->n_type
));
465 if (print_weak_symbols
&& SYMBOL_BIND(sym
->n_other
)== 2)
470 /* print the symbol's name */
471 (void)printf("%s\n",sym
->n_un
.n_name
);
474 if (print_file_each_line
)
475 (void)printf("%s:", objname
);
478 * handle undefined-only format separately (no space is
479 * left for symbol values, no type field is printed)
481 if (print_only_undefined_symbols
) {
482 (void)puts(sym
->n_un
.n_name
);
486 /* print symbol's value */
487 if (SYMBOL_TYPE(sym
->n_type
) == N_UNDF
)
490 (void)printf("%08lx", (u_long
)sym
->n_value
);
492 /* print type information */
493 if (IS_DEBUGGER_SYMBOL(sym
->n_type
))
494 (void)printf(" - %02x %04x %5s ", sym
->n_other
,
495 sym
->n_desc
&0xffff, typestring(sym
->n_type
));
498 putchar(typeletter(sym
->n_type
));
499 if (print_weak_symbols
) {
500 if (SYMBOL_BIND(sym
->n_other
) == 2)
508 /* print the symbol's name */
509 (void)puts(sym
->n_un
.n_name
);
514 * return the a description string for an STAB entry
517 typestring(register u_char type
)
566 * return a description letter for the given basic type code of an
567 * symbol table entry. The return value will be upper case for
568 * external, lower case for internal symbols.
571 typeletter(u_char type
)
573 switch(SYMBOL_TYPE(type
)) {
575 return(IS_EXTERNAL(type
) ? 'A' : 'a');
577 return(IS_EXTERNAL(type
) ? 'B' : 'b');
579 return(IS_EXTERNAL(type
) ? 'C' : 'c');
581 return(IS_EXTERNAL(type
) ? 'D' : 'd');
583 /* This one is overloaded. EXT = Filename, INT = warn refs */
584 return(IS_EXTERNAL(type
) ? 'F' : 'w');
586 return(IS_EXTERNAL(type
) ? 'I' : 'i');
588 return(IS_EXTERNAL(type
) ? 'T' : 't');
590 return(IS_EXTERNAL(type
) ? 'U' : 'u');
596 fname(void *a0
, void *b0
)
598 struct nlist
*a
= a0
, *b
= b0
;
600 return(strcmp(a
->n_un
.n_name
, b
->n_un
.n_name
));
604 rname(void *a0
, void *b0
)
606 struct nlist
*a
= a0
, *b
= b0
;
608 return(strcmp(b
->n_un
.n_name
, a
->n_un
.n_name
));
612 value(void *a0
, void *b0
)
614 register struct nlist
*a
= a0
, *b
= b0
;
616 if (SYMBOL_TYPE(a
->n_type
) == N_UNDF
)
617 if (SYMBOL_TYPE(b
->n_type
) == N_UNDF
)
621 else if (SYMBOL_TYPE(b
->n_type
) == N_UNDF
)
624 if (a
->n_value
== b
->n_value
)
625 return(rname(a0
, b0
));
626 return(b
->n_value
> a
->n_value
? 1 : -1);
628 if (a
->n_value
== b
->n_value
)
629 return(fname(a0
, b0
));
630 return(a
->n_value
> b
->n_value
? 1 : -1);
640 if ( (p
= malloc(size
)) )
648 (void)fprintf(stderr
, "usage: nm [-agnoprtuwW] [file ...]\n");