2 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 /* $OpenBSD: nm.c,v 1.4 1997/01/15 23:42:59 millert Exp $ */
24 /* $NetBSD: nm.c,v 1.7 1996/01/14 23:04:03 pk Exp $ */
27 * Copyright (c) 1989, 1993
28 * The Regents of the University of California. All rights reserved.
30 * This code is derived from software contributed to Berkeley by
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * The NeXT Computer, Inc. nm(1) program that handles fat files, archives and
63 * Mach-O objects files (no BSD a.out files). A few lines of code were taken
64 * and adapted from the BSD release.
66 * When processing multiple files which are archives the BSD version of nm
67 * would only print the archive member name (without the -o option) of the
68 * object files before printing the symbols. This version of nm will print the
69 * archive name with the member name in ()'s in this case which makes it clear
70 * which symbols belong to which arguments in the case that multiple arguments
71 * are archives and have members of the same name.
73 * To allow the "-arch <arch_flag>" command line argument the processing of
74 * command line arguments was changed to allow the options to be specified
75 * in more than one group of arguments with each group preceded by a '-'. This
76 * change in behavior would only be noticed if a command line of the form
77 * "nm -n -Q" was used where the BSD version would open a file of the name
78 * "-Q" to process. To do this with this version of nm the new command line
79 * argument "-" would be used to treat all remaining arguments as file names.
80 * So the equivalent command would be "nm -n - -Q". This should not be a
81 * problem as the BSD would treat the command "nm -Q" by saying "-Q" is an
82 * invalid argument which was slightly inconsistant.
84 #include <mach/mach.h> /* first so to get rid of a precomp warning */
89 #include <mach-o/loader.h>
90 #include <mach-o/nlist.h>
91 #include <mach-o/stab.h>
92 #include "stuff/bool.h"
93 #include "stuff/ofile.h"
94 #include "stuff/errors.h"
95 #include "stuff/allocate.h"
96 #include "stuff/guess_short_name.h"
98 #include "stuff/lto.h"
99 #endif /* LTO_SUPPORT */
101 /* used by error routines as the name of the program */
102 char *progname
= NULL
;
104 /* flags set from the command line arguments */
107 enum bool a
; /* print all symbol table entries including stabs */
108 enum bool g
; /* print only global symbols */
109 enum bool n
; /* sort numericly rather than alphabetically */
110 enum bool o
; /* prepend file or archive element name to each line */
111 enum bool p
; /* don't sort; print in symbol table order */
112 enum bool r
; /* sort in reverse direction */
113 enum bool u
; /* print only undefined symbols */
114 enum bool U
; /* only undefined symbols */
115 enum bool m
; /* print symbol in Mach-O symbol format */
116 enum bool x
; /* print the symbol table entry in hex and the name */
117 enum bool j
; /* just print the symbol name (no value or type) */
118 enum bool s
; /* print only symbol in the following section */
119 char *segname
, /* segment name for -s */
120 *sectname
; /* section name for -s */
121 enum bool l
; /* print a .section_start symbol if none exists (-s) */
122 enum bool f
; /* print a dynamic shared library flat */
123 enum bool v
; /* sort and print by value diffences ,used with -n -s */
124 enum bool b
; /* print only stabs for the following include */
125 char *bincl_name
; /* the begin include name for -b */
126 enum bool i
; /* start searching for begin include at -iN index */
127 uint32_t index
; /* the index to start searching at */
128 enum bool A
; /* pathname or library name of an object on each line */
129 enum bool P
; /* portable output format */
130 char *format
; /* the -t format */
132 /* These need to be static because of the qsort compare function */
133 static struct cmd_flags cmd_flags
= { 0 };
134 static char *strings
= NULL
;
135 static uint32_t strsize
= 0;
136 static enum bool compare_lto
= FALSE
;
138 /* flags set by processing a specific object file */
139 struct process_flags
{
140 uint32_t nsect
; /* The nsect, address and size for the */
141 uint64_t sect_addr
, /* section specified by the -s flag */
143 enum bool sect_start_symbol
;/* For processing the -l flag, set if a */
144 /* symbol with the start address of the */
145 /* section is found */
146 uint32_t nsects
; /* For printing the symbol types, the number */
147 struct section
**sections
; /* of sections and an array of section ptrs */
148 struct section_64
**sections64
;
149 unsigned char text_nsect
, /* For printing symbols types, T, D, and B */
150 data_nsect
, /* for text, data and bss symbols */
152 uint32_t nlibs
; /* For printing the twolevel namespace */
153 char **lib_names
; /* references types, the number of libraries */
154 /* an array of pointers to library names */
165 struct symbol symbol
;
178 struct cmd_flags
*cmd_flags
);
179 #endif /* LTO_SUPPORT */
180 static void print_header(
183 struct cmd_flags
*cmd_flags
);
184 static struct symbol
*select_symbols(
186 struct symtab_command
*st
,
187 struct dysymtab_command
*dyst
,
188 struct cmd_flags
*cmd_flags
,
189 struct process_flags
*process_flags
,
191 static void make_symbol_32(
192 struct symbol
*symbol
,
194 static void make_symbol_64(
195 struct symbol
*symbol
,
196 struct nlist_64
*nl
);
197 static enum bool select_symbol(
198 struct symbol
*symbol
,
199 struct cmd_flags
*cmd_flags
,
200 struct process_flags
*process_flags
);
201 static void print_mach_symbols(
203 struct symbol
*symbols
,
207 struct cmd_flags
*cmd_flags
,
208 struct process_flags
*process_flags
,
210 static void print_symbols(
212 struct symbol
*symbols
,
216 struct cmd_flags
*cmd_flags
,
217 struct process_flags
*process_flags
,
219 struct value_diff
*value_diffs
);
221 unsigned char n_type
);
225 static int value_diff_compare(
226 struct value_diff
*p1
,
227 struct value_diff
*p2
);
229 /* apple_version is created by the libstuff/Makefile */
230 extern char apple_version
[];
231 char *version
= apple_version
;
241 struct arch_flag
*arch_flags
;
242 uint32_t narch_flags
;
252 cmd_flags
.nfiles
= 0;
265 cmd_flags
.segname
= NULL
;
266 cmd_flags
.sectname
= NULL
;
269 cmd_flags
.bincl_name
= NULL
;
272 cmd_flags
.format
= "%llx";
274 files
= allocate(sizeof(char *) * argc
);
275 for(i
= 1; i
< argc
; i
++){
276 if(argv
[i
][0] == '-'){
277 if(argv
[i
][1] == '\0' ||
278 (argv
[i
][1] == '-' && argv
[i
][2] == '\0')){
280 for( ; i
< argc
; i
++)
281 files
[cmd_flags
.nfiles
++] = argv
[i
];
284 if(strcmp(argv
[i
], "-arch") == 0){
286 error("missing argument(s) to %s option", argv
[i
]);
289 if(strcmp("all", argv
[i
+1]) == 0){
293 arch_flags
= reallocate(arch_flags
,
294 (narch_flags
+ 1) * sizeof(struct arch_flag
));
295 if(get_arch_from_flag(argv
[i
+1],
296 arch_flags
+ narch_flags
) == 0){
297 error("unknown architecture specification flag: "
298 "%s %s", argv
[i
], argv
[i
+1]);
306 else if(strcmp(argv
[i
], "-t") == 0){
308 error("missing argument to %s option", argv
[i
]);
311 if(argv
[i
+1][1] != '\0'){
312 error("invalid argument to option: %s %s",
316 switch(argv
[i
+1][0]){
318 cmd_flags
.format
= "%lld";
321 cmd_flags
.format
= "%llo";
324 cmd_flags
.format
= "%llx";
327 error("invalid argument to option: %s %s",
334 for(j
= 1; argv
[i
][j
] != '\0'; j
++){
355 if(cmd_flags
.U
== TRUE
){
356 error("can't specifiy both -u and -U");
362 if(cmd_flags
.u
== TRUE
){
363 error("can't specifiy both -U and -u");
378 if(cmd_flags
.s
== TRUE
){
379 error("more than one -s option specified");
385 if(cmd_flags
.b
== TRUE
){
386 error("more than one -b option specified");
392 if(cmd_flags
.i
== TRUE
){
393 error("more than one -i option specified");
397 while(isdigit(argv
[i
][j
+1])){
398 cmd_flags
.index
= cmd_flags
.index
* 10 +
399 (argv
[i
][j
+1] - '0');
418 error("invalid argument -%c", argv
[i
][j
]);
422 if(cmd_flags
.s
== TRUE
&& cmd_flags
.segname
== NULL
){
424 error("missing arguments to -s");
427 cmd_flags
.segname
= argv
[i
+1];
428 cmd_flags
.sectname
= argv
[i
+2];
431 if(cmd_flags
.b
== TRUE
&& cmd_flags
.bincl_name
== NULL
){
433 error("missing arguments to -b");
436 cmd_flags
.bincl_name
= argv
[i
+1];
442 files
[cmd_flags
.nfiles
++] = argv
[i
];
445 for(j
= 0; j
< cmd_flags
.nfiles
; j
++)
446 ofile_process(files
[j
], arch_flags
, narch_flags
, all_archs
, TRUE
,
447 cmd_flags
.f
, TRUE
, nm
, &cmd_flags
);
448 if(cmd_flags
.nfiles
== 0)
449 ofile_process("a.out", arch_flags
, narch_flags
, all_archs
, TRUE
,
450 cmd_flags
.f
, TRUE
, nm
, &cmd_flags
);
453 return(EXIT_SUCCESS
);
455 return(EXIT_FAILURE
);
459 * usage() prints the current usage message and exits indicating failure.
466 fprintf(stderr
, "Usage: %s [-agnopruUmxjlfAP[s segname sectname] [-] "
467 "[-t format] [[-arch <arch_flag>] ...] [file ...]\n", progname
);
472 * nm() is the routine that gets called by ofile_process() to process single
482 uint32_t ncmds
, mh_flags
;
483 struct cmd_flags
*cmd_flags
;
484 struct process_flags process_flags
;
486 struct load_command
*lc
;
487 struct symtab_command
*st
;
488 struct dysymtab_command
*dyst
;
489 struct segment_command
*sg
;
490 struct segment_command_64
*sg64
;
492 struct section_64
*s64
;
493 struct dylib_command
*dl
;
495 struct symbol
*symbols
;
497 struct value_diff
*value_diffs
;
499 char *short_name
, *has_suffix
;
500 enum bool is_framework
;
502 cmd_flags
= (struct cmd_flags
*)cookie
;
504 process_flags
.nsect
= -1;
505 process_flags
.sect_addr
= 0;
506 process_flags
.sect_size
= 0;
507 process_flags
.sect_start_symbol
= FALSE
;
508 process_flags
.nsects
= 0;
509 process_flags
.sections
= NULL
;
510 process_flags
.text_nsect
= NO_SECT
;
511 process_flags
.data_nsect
= NO_SECT
;
512 process_flags
.bss_nsect
= NO_SECT
;
513 process_flags
.nlibs
= 0;
514 process_flags
.lib_names
= NULL
;
516 if(ofile
->mh
== NULL
&& ofile
->mh64
== NULL
){
518 if(ofile
->lto
!= NULL
)
519 nm_lto(ofile
, arch_name
, cmd_flags
);
520 #endif /* LTO_SUPPORT */
525 lc
= ofile
->load_commands
;
526 if(ofile
->mh
!= NULL
){
527 ncmds
= ofile
->mh
->ncmds
;
528 mh_flags
= ofile
->mh
->flags
;
531 ncmds
= ofile
->mh64
->ncmds
;
532 mh_flags
= ofile
->mh64
->flags
;
534 for(i
= 0; i
< ncmds
; i
++){
535 if(st
== NULL
&& lc
->cmd
== LC_SYMTAB
){
536 st
= (struct symtab_command
*)lc
;
538 else if(dyst
== NULL
&& lc
->cmd
== LC_DYSYMTAB
){
539 dyst
= (struct dysymtab_command
*)lc
;
541 else if(lc
->cmd
== LC_SEGMENT
){
542 sg
= (struct segment_command
*)lc
;
543 process_flags
.nsects
+= sg
->nsects
;
545 else if(lc
->cmd
== LC_SEGMENT_64
){
546 sg64
= (struct segment_command_64
*)lc
;
547 process_flags
.nsects
+= sg64
->nsects
;
549 else if((mh_flags
& MH_TWOLEVEL
) == MH_TWOLEVEL
&&
550 (lc
->cmd
== LC_LOAD_DYLIB
||
551 lc
->cmd
== LC_LOAD_WEAK_DYLIB
||
552 lc
->cmd
== LC_LAZY_LOAD_DYLIB
||
553 lc
->cmd
== LC_REEXPORT_DYLIB
||
554 lc
->cmd
== LC_LOAD_UPWARD_DYLIB
)){
555 process_flags
.nlibs
++;
557 lc
= (struct load_command
*)((char *)lc
+ lc
->cmdsize
);
559 if(st
== NULL
|| st
->nsyms
== 0){
560 warning("no name list");
563 if(process_flags
.nsects
> 0){
564 if(ofile
->mh
!= NULL
){
565 process_flags
.sections
= (struct section
**)
566 malloc(sizeof(struct section
*) *
567 process_flags
.nsects
);
568 process_flags
.sections64
= NULL
;
571 process_flags
.sections64
= (struct section_64
**)
572 malloc(sizeof(struct section_64
*) *
573 process_flags
.nsects
);
574 process_flags
.sections
= NULL
;
577 lc
= ofile
->load_commands
;
578 for (i
= 0; i
< ncmds
; i
++){
579 if(lc
->cmd
== LC_SEGMENT
){
580 sg
= (struct segment_command
*)lc
;
581 s
= (struct section
*)
582 ((char *)sg
+ sizeof(struct segment_command
));
583 for(j
= 0; j
< sg
->nsects
; j
++){
584 if(strcmp((s
+ j
)->sectname
, SECT_TEXT
) == 0 &&
585 strcmp((s
+ j
)->segname
, SEG_TEXT
) == 0)
586 process_flags
.text_nsect
= k
+ 1;
587 else if(strcmp((s
+ j
)->sectname
, SECT_DATA
) == 0 &&
588 strcmp((s
+ j
)->segname
, SEG_DATA
) == 0)
589 process_flags
.data_nsect
= k
+ 1;
590 else if(strcmp((s
+ j
)->sectname
, SECT_BSS
) == 0 &&
591 strcmp((s
+ j
)->segname
, SEG_DATA
) == 0)
592 process_flags
.bss_nsect
= k
+ 1;
593 if(cmd_flags
->segname
!= NULL
){
594 if(strncmp((s
+ j
)->sectname
, cmd_flags
->sectname
,
595 sizeof(s
->sectname
)) == 0 &&
596 strncmp((s
+ j
)->segname
, cmd_flags
->segname
,
597 sizeof(s
->segname
)) == 0){
598 process_flags
.nsect
= k
+ 1;
599 process_flags
.sect_addr
= (s
+ j
)->addr
;
600 process_flags
.sect_size
= (s
+ j
)->size
;
603 process_flags
.sections
[k
++] = s
+ j
;
606 else if(lc
->cmd
== LC_SEGMENT_64
){
607 sg64
= (struct segment_command_64
*)lc
;
608 s64
= (struct section_64
*)
609 ((char *)sg64
+ sizeof(struct segment_command_64
));
610 for(j
= 0; j
< sg64
->nsects
; j
++){
611 if(strcmp((s64
+ j
)->sectname
, SECT_TEXT
) == 0 &&
612 strcmp((s64
+ j
)->segname
, SEG_TEXT
) == 0)
613 process_flags
.text_nsect
= k
+ 1;
614 else if(strcmp((s64
+ j
)->sectname
, SECT_DATA
) == 0 &&
615 strcmp((s64
+ j
)->segname
, SEG_DATA
) == 0)
616 process_flags
.data_nsect
= k
+ 1;
617 else if(strcmp((s64
+ j
)->sectname
, SECT_BSS
) == 0 &&
618 strcmp((s64
+ j
)->segname
, SEG_DATA
) == 0)
619 process_flags
.bss_nsect
= k
+ 1;
620 if(cmd_flags
->segname
!= NULL
){
621 if(strncmp((s64
+ j
)->sectname
, cmd_flags
->sectname
,
622 sizeof(s64
->sectname
)) == 0 &&
623 strncmp((s64
+ j
)->segname
, cmd_flags
->segname
,
624 sizeof(s64
->segname
)) == 0){
625 process_flags
.nsect
= k
+ 1;
626 process_flags
.sect_addr
= (s64
+ j
)->addr
;
627 process_flags
.sect_size
= (s64
+ j
)->size
;
630 process_flags
.sections64
[k
++] = s64
+ j
;
633 lc
= (struct load_command
*)
634 ((char *)lc
+ lc
->cmdsize
);
637 if((mh_flags
& MH_TWOLEVEL
) == MH_TWOLEVEL
&&
638 process_flags
.nlibs
> 0){
639 process_flags
.lib_names
= (char **)
640 malloc(sizeof(char *) * process_flags
.nlibs
);
642 lc
= ofile
->load_commands
;
643 for (i
= 0; i
< ncmds
; i
++){
644 if(lc
->cmd
== LC_LOAD_DYLIB
||
645 lc
->cmd
== LC_LOAD_WEAK_DYLIB
||
646 lc
->cmd
== LC_LAZY_LOAD_DYLIB
||
647 lc
->cmd
== LC_REEXPORT_DYLIB
||
648 lc
->cmd
== LC_LOAD_UPWARD_DYLIB
){
649 dl
= (struct dylib_command
*)lc
;
650 process_flags
.lib_names
[j
] =
651 (char *)dl
+ dl
->dylib
.name
.offset
;
652 short_name
= guess_short_name(process_flags
.lib_names
[j
],
653 &is_framework
, &has_suffix
);
654 if(short_name
!= NULL
)
655 process_flags
.lib_names
[j
] = short_name
;
658 lc
= (struct load_command
*)
659 ((char *)lc
+ lc
->cmdsize
);
663 /* select symbols to print */
664 symbols
= select_symbols(ofile
, st
, dyst
, cmd_flags
, &process_flags
,
667 /* set names in the symbols to be printed */
668 strings
= ofile
->object_addr
+ st
->stroff
;
669 strsize
= st
->strsize
;
671 if(cmd_flags
->x
== FALSE
){
672 for(i
= 0; i
< nsymbols
; i
++){
673 if(symbols
[i
].nl
.n_un
.n_strx
== 0)
674 symbols
[i
].name
= "";
675 else if((int)symbols
[i
].nl
.n_un
.n_strx
< 0 ||
676 (uint32_t)symbols
[i
].nl
.n_un
.n_strx
> st
->strsize
)
677 symbols
[i
].name
= "bad string index";
679 symbols
[i
].name
= symbols
[i
].nl
.n_un
.n_strx
+ strings
;
681 if((symbols
[i
].nl
.n_type
& N_STAB
) == 0 &&
682 (symbols
[i
].nl
.n_type
& N_TYPE
) == N_INDR
){
683 if(symbols
[i
].nl
.n_value
== 0)
684 symbols
[i
].indr_name
= "";
685 else if(symbols
[i
].nl
.n_value
> st
->strsize
)
686 symbols
[i
].indr_name
= "bad string index";
688 symbols
[i
].indr_name
= strings
+ symbols
[i
].nl
.n_value
;
691 if(cmd_flags
->l
== TRUE
&&
692 (int32_t)process_flags
.nsect
!= -1 &&
693 process_flags
.sect_start_symbol
== FALSE
&&
694 process_flags
.sect_size
!= 0){
695 symbols
= reallocate(symbols
,
696 (nsymbols
+ 1) * sizeof(struct symbol
));
697 symbols
[nsymbols
].name
= ".section_start";
698 symbols
[nsymbols
].nl
.n_type
= N_SECT
;
699 symbols
[nsymbols
].nl
.n_sect
= process_flags
.nsect
;
700 symbols
[nsymbols
].nl
.n_value
= process_flags
.sect_addr
;
705 /* print header if needed */
706 print_header(ofile
, arch_name
, cmd_flags
);
708 /* sort the symbols if needed */
709 if(cmd_flags
->p
== FALSE
&& cmd_flags
->b
== FALSE
)
710 qsort(symbols
, nsymbols
, sizeof(struct symbol
),
711 (int (*)(const void *, const void *))compare
);
714 if(cmd_flags
->v
== TRUE
&& cmd_flags
->n
== TRUE
&&
715 cmd_flags
->r
== FALSE
&& cmd_flags
->s
== TRUE
&&
717 value_diffs
= allocate(sizeof(struct value_diff
) * nsymbols
);
718 for(i
= 0; i
< nsymbols
- 1; i
++){
719 value_diffs
[i
].symbol
= symbols
[i
];
720 value_diffs
[i
].size
= symbols
[i
+1].nl
.n_value
-
721 symbols
[i
].nl
.n_value
;
723 value_diffs
[i
].symbol
= symbols
[i
];
724 value_diffs
[i
].size
=
725 process_flags
.sect_addr
+ process_flags
.sect_size
-
726 symbols
[i
].nl
.n_value
;
727 qsort(value_diffs
, nsymbols
, sizeof(struct value_diff
),
728 (int (*)(const void *, const void *))value_diff_compare
);
729 for(i
= 0; i
< nsymbols
; i
++)
730 symbols
[i
] = value_diffs
[i
].symbol
;
733 /* now print the symbols as specified by the flags */
734 if(cmd_flags
->m
== TRUE
)
735 print_mach_symbols(ofile
, symbols
, nsymbols
, strings
, st
->strsize
,
736 cmd_flags
, &process_flags
, arch_name
);
738 print_symbols(ofile
, symbols
, nsymbols
, strings
, st
->strsize
,
739 cmd_flags
, &process_flags
, arch_name
, value_diffs
);
742 if(process_flags
.sections
!= NULL
){
743 if(process_flags
.sections
!= NULL
){
744 free(process_flags
.sections
);
745 process_flags
.sections
= NULL
;
747 if(process_flags
.sections64
!= NULL
){
748 free(process_flags
.sections64
);
749 process_flags
.sections64
= NULL
;
756 * In translating the information in an lto bitcode file to something that looks
757 * like what would be in a Mach-O file for use by print_mach_symbols() we use
758 * these sections for the CODE, DATA and RODATA defined symbols.
760 static struct section lto_code_section
= { "CODE", "LTO" };
761 static struct section lto_data_section
= { "DATA", "LTO" };
762 static struct section lto_rodata_section
= { "RODATA", "LTO" };
763 static struct section
*lto_sections
[3] = {
768 static struct section_64 lto_code_section64
= { "CODE", "LTO" };
769 static struct section_64 lto_data_section64
= { "DATA", "LTO" };
770 static struct section_64 lto_rodata_section64
= { "RODATA", "LTO" };
771 static struct section_64
*lto_sections64
[3] = {
774 <o_rodata_section64
778 * nm_lto() is called by nm() to process an lto bitcode file.
785 struct cmd_flags
*cmd_flags
)
787 uint32_t nsyms
, nsymbols
, i
;
788 struct symbol symbol
, *symbols
;
789 struct process_flags process_flags
;
791 process_flags
.nsect
= -1;
792 if(cmd_flags
->segname
!= NULL
&&
793 strcmp(cmd_flags
->segname
, "LTO") == 0){
794 if(strcmp(cmd_flags
->sectname
, "CODE") == 0)
795 process_flags
.nsect
= 1;
796 else if(strcmp(cmd_flags
->sectname
, "DATA") == 0)
797 process_flags
.nsect
= 2;
798 else if(strcmp(cmd_flags
->sectname
, "RODATA") == 0)
799 process_flags
.nsect
= 3;
801 process_flags
.sect_addr
= 0;
802 process_flags
.sect_size
= 0;
803 process_flags
.sect_start_symbol
= FALSE
;
804 process_flags
.nsects
= 3;
805 if((ofile
->lto_cputype
& CPU_ARCH_ABI64
) != CPU_ARCH_ABI64
){
806 process_flags
.sections
= lto_sections
;
807 process_flags
.sections64
= NULL
;
810 process_flags
.sections64
= lto_sections64
;
811 process_flags
.sections
= NULL
;
813 process_flags
.text_nsect
= 1;
814 process_flags
.data_nsect
= 2;
815 process_flags
.bss_nsect
= NO_SECT
;
816 process_flags
.nlibs
= 0;
817 process_flags
.lib_names
= NULL
;
819 nsyms
= lto_get_nsyms(ofile
->lto
);
820 symbols
= allocate(sizeof(struct symbol
) * nsyms
);
823 for(i
= 0; i
< nsyms
; i
++){
824 symbol
.name
= lto_symbol_name(ofile
->lto
, i
);
825 symbol
.indr_name
= NULL
;
826 lto_get_nlist_64(&(symbol
.nl
), ofile
->lto
, i
);
827 if(select_symbol(&symbol
, cmd_flags
, &process_flags
))
828 symbols
[nsymbols
++] = symbol
;
831 print_header(ofile
, arch_name
, cmd_flags
);
833 /* reset these as the can be used by compare() with -x */
838 /* sort the symbols if needed */
839 if(cmd_flags
->p
== FALSE
)
840 qsort(symbols
, nsymbols
, sizeof(struct symbol
),
841 (int (*)(const void *, const void *))compare
);
843 /* now print the symbols as specified by the flags */
844 if(cmd_flags
->m
== TRUE
)
845 print_mach_symbols(ofile
, symbols
, nsymbols
, NULL
, 0,
846 cmd_flags
, &process_flags
, arch_name
);
848 print_symbols(ofile
, symbols
, nsymbols
, NULL
, 0,
849 cmd_flags
, &process_flags
, arch_name
, NULL
);
853 #endif /* LTO_SUPPORT */
855 /* print header if needed */
861 struct cmd_flags
*cmd_flags
)
863 if((ofile
->member_ar_hdr
!= NULL
||
864 ofile
->dylib_module_name
!= NULL
||
865 cmd_flags
->nfiles
> 1 ||
866 arch_name
!= NULL
) &&
867 (cmd_flags
->o
== FALSE
&& cmd_flags
->A
== FALSE
)){
868 if(ofile
->dylib_module_name
!= NULL
){
869 printf("\n%s(%s)", ofile
->file_name
, ofile
->dylib_module_name
);
871 else if(ofile
->member_ar_hdr
!= NULL
){
872 printf("\n%s(%.*s)", ofile
->file_name
,
873 (int)ofile
->member_name_size
, ofile
->member_name
);
876 printf("\n%s", ofile
->file_name
);
877 if(arch_name
!= NULL
)
878 printf(" (for architecture %s):\n", arch_name
);
885 * select_symbols returns an allocated array of symbol structs as the symbols
886 * that are to be printed based on the flags. The number of symbols in the
887 * array returned in returned indirectly through nsymbols.
893 struct symtab_command
*st
,
894 struct dysymtab_command
*dyst
,
895 struct cmd_flags
*cmd_flags
,
896 struct process_flags
*process_flags
,
899 uint32_t i
, flags
, nest
;
900 struct nlist
*all_symbols
;
901 struct nlist_64
*all_symbols64
;
902 struct symbol
*selected_symbols
, symbol
;
903 struct dylib_module m
;
904 struct dylib_module_64 m64
;
905 struct dylib_reference
*refs
;
907 uint32_t irefsym
, nrefsym
, nextdefsym
, iextdefsym
, nlocalsym
, ilocalsym
;
909 if(ofile
->mh
!= NULL
){
910 all_symbols
= (struct nlist
*)(ofile
->object_addr
+ st
->symoff
);
911 all_symbols64
= NULL
;
915 all_symbols64
= (struct nlist_64
*)(ofile
->object_addr
+st
->symoff
);
917 selected_symbols
= allocate(sizeof(struct symbol
) * st
->nsyms
);
920 if(ofile
->object_byte_sex
!= get_host_byte_sex()){
921 if(ofile
->mh
!= NULL
)
922 swap_nlist(all_symbols
, st
->nsyms
, get_host_byte_sex());
924 swap_nlist_64(all_symbols64
, st
->nsyms
, get_host_byte_sex());
927 if(ofile
->dylib_module
!= NULL
){
928 if(ofile
->mh
!= NULL
){
929 m
= *ofile
->dylib_module
;
930 if(ofile
->object_byte_sex
!= get_host_byte_sex())
931 swap_dylib_module(&m
, 1, get_host_byte_sex());
934 nextdefsym
= m
.nextdefsym
;
935 iextdefsym
= m
.iextdefsym
;
936 nlocalsym
= m
.nlocalsym
;
937 ilocalsym
= m
.ilocalsym
;
940 m64
= *ofile
->dylib_module64
;
941 if(ofile
->object_byte_sex
!= get_host_byte_sex())
942 swap_dylib_module_64(&m64
, 1, get_host_byte_sex());
943 irefsym
= m64
.irefsym
;
944 nrefsym
= m64
.nrefsym
;
945 nextdefsym
= m64
.nextdefsym
;
946 iextdefsym
= m64
.iextdefsym
;
947 nlocalsym
= m64
.nlocalsym
;
948 ilocalsym
= m64
.ilocalsym
;
950 refs
= (struct dylib_reference
*)(ofile
->object_addr
+
952 if(ofile
->object_byte_sex
!= get_host_byte_sex()){
953 swap_dylib_reference(refs
+ irefsym
, nrefsym
,
954 get_host_byte_sex());
956 for(i
= 0; i
< nrefsym
; i
++){
957 flags
= refs
[i
+ irefsym
].flags
;
958 if(flags
== REFERENCE_FLAG_UNDEFINED_NON_LAZY
||
959 flags
== REFERENCE_FLAG_UNDEFINED_LAZY
||
960 flags
== REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY
||
961 flags
== REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY
){
962 if(ofile
->mh
!= NULL
)
963 make_symbol_32(&symbol
,
964 all_symbols
+ refs
[i
+ irefsym
].isym
);
966 make_symbol_64(&symbol
,
967 all_symbols64
+ refs
[i
+ irefsym
].isym
);
968 if(flags
== REFERENCE_FLAG_UNDEFINED_NON_LAZY
||
969 flags
== REFERENCE_FLAG_UNDEFINED_LAZY
||
970 cmd_flags
->m
== TRUE
)
971 symbol
.nl
.n_type
= N_UNDF
| N_EXT
;
973 symbol
.nl
.n_type
= N_UNDF
;
974 symbol
.nl
.n_desc
= (symbol
.nl
.n_desc
&~ REFERENCE_TYPE
) |
976 symbol
.nl
.n_value
= 0;
977 if(select_symbol(&symbol
, cmd_flags
, process_flags
))
978 selected_symbols
[(*nsymbols
)++] = symbol
;
981 for(i
= 0; i
< nextdefsym
&& iextdefsym
+ i
< st
->nsyms
; i
++){
982 if(ofile
->mh
!= NULL
)
983 make_symbol_32(&symbol
, all_symbols
+ iextdefsym
+ i
);
985 make_symbol_64(&symbol
, all_symbols64
+ iextdefsym
+ i
);
986 if(select_symbol(&symbol
, cmd_flags
, process_flags
))
987 selected_symbols
[(*nsymbols
)++] = symbol
;
989 for(i
= 0; i
< nlocalsym
&& ilocalsym
+ i
< st
->nsyms
; i
++){
990 if(ofile
->mh
!= NULL
)
991 make_symbol_32(&symbol
, all_symbols
+ ilocalsym
+ i
);
993 make_symbol_64(&symbol
, all_symbols64
+ ilocalsym
+ i
);
994 if(select_symbol(&symbol
, cmd_flags
, process_flags
))
995 selected_symbols
[(*nsymbols
)++] = symbol
;
998 else if(cmd_flags
->b
== TRUE
){
1000 strings
= ofile
->object_addr
+ st
->stroff
;
1001 if(cmd_flags
->i
== TRUE
)
1002 i
= cmd_flags
->index
;
1005 for( ; i
< st
->nsyms
; i
++){
1006 if(ofile
->mh
!= NULL
)
1007 make_symbol_32(&symbol
, all_symbols
+ i
);
1009 make_symbol_64(&symbol
, all_symbols64
+ i
);
1010 if(symbol
.nl
.n_type
== N_BINCL
&&
1011 symbol
.nl
.n_un
.n_strx
!= 0 &&
1012 (uint32_t)symbol
.nl
.n_un
.n_strx
< st
->strsize
&&
1013 strcmp(cmd_flags
->bincl_name
,
1014 strings
+ symbol
.nl
.n_un
.n_strx
) == 0){
1015 selected_symbols
[(*nsymbols
)++] = symbol
;
1018 for(i
= i
+ 1 ; i
< st
->nsyms
; i
++){
1019 if(ofile
->mh
!= NULL
)
1020 make_symbol_32(&symbol
, all_symbols
+ i
);
1022 make_symbol_64(&symbol
, all_symbols64
+ i
);
1023 if(symbol
.nl
.n_type
== N_BINCL
)
1025 else if(symbol
.nl
.n_type
== N_EINCL
){
1027 selected_symbols
[(*nsymbols
)++] = symbol
;
1033 selected_symbols
[(*nsymbols
)++] = symbol
;
1041 for(i
= 0; i
< st
->nsyms
; i
++){
1042 if(ofile
->mh
!= NULL
)
1043 make_symbol_32(&symbol
, all_symbols
+ i
);
1045 make_symbol_64(&symbol
, all_symbols64
+ i
);
1046 if(select_symbol(&symbol
, cmd_flags
, process_flags
))
1047 selected_symbols
[(*nsymbols
)++] = symbol
;
1050 if(ofile
->object_byte_sex
!= get_host_byte_sex()){
1051 if(ofile
->mh
!= NULL
)
1052 swap_nlist(all_symbols
, st
->nsyms
, ofile
->object_byte_sex
);
1054 swap_nlist_64(all_symbols64
, st
->nsyms
, ofile
->object_byte_sex
);
1057 * Could reallocate selected symbols to the exact size but it is more
1058 * of a time waste than a memory savings.
1060 return(selected_symbols
);
1066 struct symbol
*symbol
,
1069 symbol
->nl
.n_un
.n_strx
= nl
->n_un
.n_strx
;
1070 symbol
->nl
.n_type
= nl
->n_type
;
1071 symbol
->nl
.n_sect
= nl
->n_sect
;
1072 symbol
->nl
.n_desc
= nl
->n_desc
;
1073 symbol
->nl
.n_value
= nl
->n_value
;
1079 struct symbol
*symbol
,
1080 struct nlist_64
*nl
)
1086 * select_symbol() returns TRUE or FALSE if the specified symbol is to be
1087 * printed based on the flags.
1092 struct symbol
*symbol
,
1093 struct cmd_flags
*cmd_flags
,
1094 struct process_flags
*process_flags
)
1096 if(cmd_flags
->u
== TRUE
){
1097 if((symbol
->nl
.n_type
== (N_UNDF
| N_EXT
) &&
1098 symbol
->nl
.n_value
== 0) ||
1099 symbol
->nl
.n_type
== (N_PBUD
| N_EXT
))
1104 if(cmd_flags
->U
== TRUE
){
1105 if((symbol
->nl
.n_type
== (N_UNDF
| N_EXT
) &&
1106 symbol
->nl
.n_value
== 0) ||
1107 symbol
->nl
.n_type
== (N_PBUD
| N_EXT
))
1112 if(cmd_flags
->g
== TRUE
&& (symbol
->nl
.n_type
& N_EXT
) == 0)
1114 if(cmd_flags
->s
== TRUE
){
1115 if(((symbol
->nl
.n_type
& N_TYPE
) == N_SECT
) &&
1116 (symbol
->nl
.n_sect
== process_flags
->nsect
)){
1118 symbol
->nl
.n_value
== process_flags
->sect_addr
){
1119 process_flags
->sect_start_symbol
= TRUE
;
1125 if((symbol
->nl
.n_type
& N_STAB
) &&
1126 (cmd_flags
->a
== FALSE
|| cmd_flags
->g
== TRUE
||
1127 cmd_flags
->u
== TRUE
))
1133 * print_mach_symbols() is called when the -m flag is specified and prints
1134 * symbols in the extended Mach-O style format.
1139 struct ofile
*ofile
,
1140 struct symbol
*symbols
,
1144 struct cmd_flags
*cmd_flags
,
1145 struct process_flags
*process_flags
,
1148 uint32_t i
, library_ordinal
;
1149 char *ta_xfmt
, *i_xfmt
, *dashes
, *spaces
;
1153 if(ofile
->mh
!= NULL
||
1154 (ofile
->lto
!= NULL
&&
1155 (ofile
->lto_cputype
& CPU_ARCH_ABI64
) != CPU_ARCH_ABI64
)){
1158 if(ofile
->mh
!= NULL
)
1159 mh_flags
= ofile
->mh
->flags
;
1161 dashes
= "--------";
1164 ta_xfmt
= "%016llx";
1166 if(ofile
->mh64
!= NULL
)
1167 mh_flags
= ofile
->mh64
->flags
;
1169 dashes
= "----------------";
1171 for(i
= 0; i
< nsymbols
; i
++){
1172 if(cmd_flags
->x
== TRUE
){
1173 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1174 printf(" %02x %02x %04x ",
1175 (unsigned int)(symbols
[i
].nl
.n_type
& 0xff),
1176 (unsigned int)(symbols
[i
].nl
.n_sect
& 0xff),
1177 (unsigned int)(symbols
[i
].nl
.n_desc
& 0xffff));
1178 if(symbols
[i
].nl
.n_un
.n_strx
== 0){
1179 printf(i_xfmt
, symbols
[i
].nl
.n_un
.n_strx
);
1180 if(ofile
->lto
!= NULL
)
1181 printf(" %s", symbols
[i
].name
);
1185 else if((uint32_t)symbols
[i
].nl
.n_un
.n_strx
> strsize
){
1186 printf(i_xfmt
, symbols
[i
].nl
.n_un
.n_strx
);
1187 printf(" (bad string index)");
1190 printf(i_xfmt
, symbols
[i
].nl
.n_un
.n_strx
);
1191 printf(" %s", symbols
[i
].nl
.n_un
.n_strx
+ strings
);
1193 if((symbols
[i
].nl
.n_type
& N_STAB
) == 0 &&
1194 (symbols
[i
].nl
.n_type
& N_TYPE
) == N_INDR
){
1195 if(symbols
[i
].nl
.n_value
== 0){
1196 printf(" (indirect for ");
1197 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1198 printf(" (null))\n");
1200 else if(symbols
[i
].nl
.n_value
> strsize
){
1201 printf(" (indirect for ");
1202 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1203 printf(" (bad string index))\n");
1206 printf(" (indirect for ");
1207 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1208 printf(" %s)\n", symbols
[i
].indr_name
);
1216 if(symbols
[i
].nl
.n_type
& N_STAB
){
1217 if(cmd_flags
->o
== TRUE
|| cmd_flags
->A
== TRUE
){
1218 if(arch_name
!= NULL
)
1219 printf("(for architecture %s):", arch_name
);
1220 if(ofile
->dylib_module_name
!= NULL
){
1221 printf("%s:%s: ", ofile
->file_name
,
1222 ofile
->dylib_module_name
);
1224 else if(ofile
->member_ar_hdr
!= NULL
){
1225 printf("%s:%.*s: ", ofile
->file_name
,
1226 (int)ofile
->member_name_size
,
1227 ofile
->member_name
);
1230 printf("%s: ", ofile
->file_name
);
1232 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1233 printf(" - %02x %04x %5.5s %s\n",
1234 (unsigned int)symbols
[i
].nl
.n_sect
& 0xff,
1235 (unsigned int)symbols
[i
].nl
.n_desc
& 0xffff,
1236 stab(symbols
[i
].nl
.n_type
), symbols
[i
].name
);
1240 if(cmd_flags
->o
== TRUE
|| cmd_flags
->A
== TRUE
){
1241 if(arch_name
!= NULL
)
1242 printf("(for architecture %s):", arch_name
);
1243 if(ofile
->dylib_module_name
!= NULL
){
1244 printf("%s:%s: ", ofile
->file_name
,
1245 ofile
->dylib_module_name
);
1247 else if(ofile
->member_ar_hdr
!= NULL
){
1248 printf("%s:%.*s: ", ofile
->file_name
,
1249 (int)ofile
->member_name_size
,
1250 ofile
->member_name
);
1253 printf("%s: ", ofile
->file_name
);
1256 if(((symbols
[i
].nl
.n_type
& N_TYPE
) == N_UNDF
&&
1257 symbols
[i
].nl
.n_value
== 0) ||
1258 (symbols
[i
].nl
.n_type
& N_TYPE
) == N_INDR
)
1259 printf("%s", spaces
);
1262 printf("%s", dashes
);
1264 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1267 switch(symbols
[i
].nl
.n_type
& N_TYPE
){
1270 if((symbols
[i
].nl
.n_type
& N_TYPE
) == N_UNDF
&&
1271 symbols
[i
].nl
.n_value
!= 0){
1272 printf(" (common) ");
1273 if(GET_COMM_ALIGN(symbols
[i
].nl
.n_desc
) != 0)
1274 printf("(alignment 2^%d) ",
1275 GET_COMM_ALIGN(symbols
[i
].nl
.n_desc
));
1278 if((symbols
[i
].nl
.n_type
& N_TYPE
) == N_PBUD
)
1279 printf(" (prebound ");
1282 if((symbols
[i
].nl
.n_desc
& REFERENCE_TYPE
) ==
1283 REFERENCE_FLAG_UNDEFINED_LAZY
)
1284 printf("undefined [lazy bound]) ");
1285 else if((symbols
[i
].nl
.n_desc
& REFERENCE_TYPE
) ==
1286 REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY
)
1287 printf("undefined [private lazy bound]) ");
1288 else if((symbols
[i
].nl
.n_desc
& REFERENCE_TYPE
) ==
1289 REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY
)
1290 printf("undefined [private]) ");
1292 printf("undefined) ");
1296 printf(" (absolute) ");
1300 printf(" (indirect) ");
1303 if(symbols
[i
].nl
.n_sect
>= 1 &&
1304 symbols
[i
].nl
.n_sect
<= process_flags
->nsects
){
1305 if(ofile
->mh
!= NULL
||
1306 (ofile
->lto
!= NULL
&&
1307 (ofile
->lto_cputype
& CPU_ARCH_ABI64
) !=
1309 printf(" (%.16s,%.16s) ",
1310 process_flags
->sections
[
1311 symbols
[i
].nl
.n_sect
-1]->segname
,
1312 process_flags
->sections
[
1313 symbols
[i
].nl
.n_sect
-1]->sectname
);
1316 printf(" (%.16s,%.16s) ",
1317 process_flags
->sections64
[
1318 symbols
[i
].nl
.n_sect
-1]->segname
,
1319 process_flags
->sections64
[
1320 symbols
[i
].nl
.n_sect
-1]->sectname
);
1331 if(symbols
[i
].nl
.n_type
& N_EXT
){
1332 if(symbols
[i
].nl
.n_desc
& REFERENCED_DYNAMICALLY
)
1333 printf("[referenced dynamically] ");
1334 if(symbols
[i
].nl
.n_type
& N_PEXT
){
1335 if((symbols
[i
].nl
.n_desc
& N_WEAK_DEF
) == N_WEAK_DEF
)
1336 printf("weak private external ");
1338 printf("private external ");
1341 if((symbols
[i
].nl
.n_desc
& N_WEAK_REF
) == N_WEAK_REF
||
1342 (symbols
[i
].nl
.n_desc
& N_WEAK_DEF
) == N_WEAK_DEF
){
1343 if((symbols
[i
].nl
.n_desc
& (N_WEAK_REF
| N_WEAK_DEF
)) ==
1344 (N_WEAK_REF
| N_WEAK_DEF
))
1345 printf("weak external automatically hidden ");
1347 printf("weak external ");
1350 printf("external ");
1354 if(symbols
[i
].nl
.n_type
& N_PEXT
)
1355 printf("non-external (was a private external) ");
1357 printf("non-external ");
1360 if(ofile
->mh_filetype
== MH_OBJECT
&&
1361 (symbols
[i
].nl
.n_desc
& N_NO_DEAD_STRIP
) == N_NO_DEAD_STRIP
)
1362 printf("[no dead strip] ");
1364 if(ofile
->mh_filetype
== MH_OBJECT
&&
1365 ((symbols
[i
].nl
.n_type
& N_TYPE
) != N_UNDF
) &&
1366 (symbols
[i
].nl
.n_desc
& N_SYMBOL_RESOLVER
) == N_SYMBOL_RESOLVER
)
1367 printf("[symbol resolver] ");
1369 if((symbols
[i
].nl
.n_desc
& N_ARM_THUMB_DEF
) == N_ARM_THUMB_DEF
)
1372 if((symbols
[i
].nl
.n_type
& N_TYPE
) == N_INDR
)
1373 printf("%s (for %s)", symbols
[i
].name
, symbols
[i
].indr_name
);
1375 printf("%s", symbols
[i
].name
);
1377 if((mh_flags
& MH_TWOLEVEL
) == MH_TWOLEVEL
&&
1378 (((symbols
[i
].nl
.n_type
& N_TYPE
) == N_UNDF
&&
1379 symbols
[i
].nl
.n_value
== 0) ||
1380 (symbols
[i
].nl
.n_type
& N_TYPE
) == N_PBUD
)){
1381 library_ordinal
= GET_LIBRARY_ORDINAL(symbols
[i
].nl
.n_desc
);
1382 if(library_ordinal
!= 0){
1383 if(library_ordinal
== EXECUTABLE_ORDINAL
)
1384 printf(" (from executable)");
1385 else if(process_flags
->nlibs
!= DYNAMIC_LOOKUP_ORDINAL
&&
1386 library_ordinal
== DYNAMIC_LOOKUP_ORDINAL
)
1387 printf(" (dynamically looked up)");
1388 else if(library_ordinal
-1 >= process_flags
->nlibs
)
1389 printf(" (from bad library ordinal %u)",
1392 printf(" (from %s)", process_flags
->lib_names
[
1393 library_ordinal
-1]);
1401 * print_symbols() is called with the -m flag is not specified and prints
1402 * symbols in the standard BSD format.
1407 struct ofile
*ofile
,
1408 struct symbol
*symbols
,
1412 struct cmd_flags
*cmd_flags
,
1413 struct process_flags
*process_flags
,
1415 struct value_diff
*value_diffs
)
1419 char *ta_xfmt
, *i_xfmt
, *spaces
, *dashes
, *p
;
1421 if(ofile
->mh
!= NULL
||
1422 (ofile
->lto
!= NULL
&&
1423 (ofile
->lto_cputype
& CPU_ARCH_ABI64
) != CPU_ARCH_ABI64
)){
1427 dashes
= "--------";
1430 ta_xfmt
= "%016llx";
1433 dashes
= "----------------";
1436 for(i
= 0; i
< nsymbols
; i
++){
1437 if(cmd_flags
->x
== TRUE
){
1438 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1439 printf(" %02x %02x %04x ",
1440 (unsigned int)(symbols
[i
].nl
.n_type
& 0xff),
1441 (unsigned int)(symbols
[i
].nl
.n_sect
& 0xff),
1442 (unsigned int)(symbols
[i
].nl
.n_desc
& 0xffff));
1443 if(symbols
[i
].nl
.n_un
.n_strx
== 0){
1444 printf(i_xfmt
, symbols
[i
].nl
.n_un
.n_strx
);
1445 if(ofile
->lto
!= NULL
)
1446 printf(" %s", symbols
[i
].name
);
1450 else if((uint32_t)symbols
[i
].nl
.n_un
.n_strx
> strsize
){
1451 printf(i_xfmt
, symbols
[i
].nl
.n_un
.n_strx
);
1452 printf(" (bad string index)");
1455 printf(i_xfmt
, symbols
[i
].nl
.n_un
.n_strx
);
1456 printf(" %s", symbols
[i
].nl
.n_un
.n_strx
+ strings
);
1458 if((symbols
[i
].nl
.n_type
& N_STAB
) == 0 &&
1459 (symbols
[i
].nl
.n_type
& N_TYPE
) == N_INDR
){
1460 if(symbols
[i
].nl
.n_value
== 0){
1461 printf(" (indirect for ");
1462 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1463 printf(" (null))\n");
1465 else if(symbols
[i
].nl
.n_value
> strsize
){
1466 printf(" (indirect for ");
1467 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1468 printf(" (bad string index))\n");
1471 printf(" (indirect for ");
1472 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1473 printf(" %s)\n", symbols
[i
].indr_name
);
1480 if(cmd_flags
->P
== TRUE
){
1481 if(cmd_flags
->A
== TRUE
){
1482 if(arch_name
!= NULL
)
1483 printf("(for architecture %s): ", arch_name
);
1484 if(ofile
->dylib_module_name
!= NULL
){
1485 printf("%s[%s]: ", ofile
->file_name
,
1486 ofile
->dylib_module_name
);
1488 else if(ofile
->member_ar_hdr
!= NULL
){
1489 printf("%s[%.*s]: ", ofile
->file_name
,
1490 (int)ofile
->member_name_size
,
1491 ofile
->member_name
);
1494 printf("%s: ", ofile
->file_name
);
1496 printf("%s ", symbols
[i
].name
);
1499 c
= symbols
[i
].nl
.n_type
;
1506 if(symbols
[i
].nl
.n_value
!= 0)
1516 if(symbols
[i
].nl
.n_sect
==
1517 process_flags
->text_nsect
)
1519 else if(symbols
[i
].nl
.n_sect
==
1520 process_flags
->data_nsect
)
1522 else if(symbols
[i
].nl
.n_sect
==
1523 process_flags
->bss_nsect
)
1536 if((symbols
[i
].nl
.n_type
& N_EXT
) && c
!= '?')
1539 printf(cmd_flags
->format
, symbols
[i
].nl
.n_value
);
1540 printf(" 0\n"); /* the 0 is the size for conformance */
1543 c
= symbols
[i
].nl
.n_type
;
1545 if(cmd_flags
->o
== TRUE
|| cmd_flags
->A
== TRUE
){
1546 if(arch_name
!= NULL
)
1547 printf("(for architecture %s):", arch_name
);
1548 if(ofile
->dylib_module_name
!= NULL
){
1549 printf("%s:%s: ", ofile
->file_name
,
1550 ofile
->dylib_module_name
);
1552 else if(ofile
->member_ar_hdr
!= NULL
){
1553 printf("%s:%.*s: ", ofile
->file_name
,
1554 (int)ofile
->member_name_size
,
1555 ofile
->member_name
);
1558 printf("%s: ", ofile
->file_name
);
1560 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1561 printf(" - %02x %04x %5.5s ",
1562 (unsigned int)symbols
[i
].nl
.n_sect
& 0xff,
1563 (unsigned int)symbols
[i
].nl
.n_desc
& 0xffff,
1564 stab(symbols
[i
].nl
.n_type
));
1565 if(cmd_flags
->b
== TRUE
){
1566 for(p
= symbols
[i
].name
; *p
!= '\0'; p
++){
1570 while(isdigit((unsigned char)*p
))
1574 if(*p
== '.' && p
[1] != '\0' && p
[1] == '_'){
1575 p
++; /* one for the '.' */
1576 p
++; /* and one for the '_' */
1577 while(isdigit((unsigned char)*p
))
1585 printf("%s\n", symbols
[i
].name
);
1592 if(symbols
[i
].nl
.n_value
!= 0)
1602 if(symbols
[i
].nl
.n_sect
== process_flags
->text_nsect
)
1604 else if(symbols
[i
].nl
.n_sect
== process_flags
->data_nsect
)
1606 else if(symbols
[i
].nl
.n_sect
== process_flags
->bss_nsect
)
1618 if(cmd_flags
->u
== TRUE
&& c
!= 'u')
1620 if(cmd_flags
->o
== TRUE
|| cmd_flags
->A
== TRUE
){
1621 if(arch_name
!= NULL
)
1622 printf("(for architecture %s):", arch_name
);
1623 if(ofile
->dylib_module_name
!= NULL
){
1624 printf("%s:%s: ", ofile
->file_name
,
1625 ofile
->dylib_module_name
);
1627 else if(ofile
->member_ar_hdr
!= NULL
){
1628 printf("%s:%.*s: ", ofile
->file_name
,
1629 (int)ofile
->member_name_size
,
1630 ofile
->member_name
);
1633 printf("%s: ", ofile
->file_name
);
1635 if((symbols
[i
].nl
.n_type
& N_EXT
) && c
!= '?')
1637 if(cmd_flags
->u
== FALSE
&& cmd_flags
->j
== FALSE
){
1638 if(c
== 'u' || c
== 'U' || c
== 'i' || c
== 'I')
1639 printf("%s", spaces
);
1641 if(cmd_flags
->v
&& value_diffs
!= NULL
){
1642 printf(ta_xfmt
, value_diffs
[i
].size
);
1646 printf("%s", dashes
);
1648 printf(ta_xfmt
, symbols
[i
].nl
.n_value
);
1652 if(cmd_flags
->j
== FALSE
&&
1653 (symbols
[i
].nl
.n_type
& N_TYPE
) == N_INDR
)
1654 printf("%s (indirect for %s)\n", symbols
[i
].name
,
1655 symbols
[i
].indr_name
);
1657 printf("%s\n", symbols
[i
].name
);
1662 unsigned char n_type
;
1665 static const struct stabnames stabnames
[] = {
1667 { N_FNAME
, "FNAME" },
1669 { N_STSYM
, "STSYM" },
1670 { N_LCSYM
, "LCSYM" },
1671 { N_BNSYM
, "BNSYM" },
1674 { N_SLINE
, "SLINE" },
1675 { N_ENSYM
, "ENSYM" },
1680 { N_BINCL
, "BINCL" },
1682 { N_PARAMS
,"PARAM" },
1683 { N_VERSION
,"VERS" },
1684 { N_OLEVEL
,"OLEV" },
1686 { N_EINCL
, "EINCL" },
1687 { N_ENTRY
, "ENTRY" },
1688 { N_LBRAC
, "LBRAC" },
1690 { N_RBRAC
, "RBRAC" },
1691 { N_BCOMM
, "BCOMM" },
1692 { N_ECOMM
, "ECOMM" },
1693 { N_ECOML
, "ECOML" },
1700 * stab() returns the name of the specified stab n_type.
1705 unsigned char n_type
)
1707 const struct stabnames
*p
;
1708 static char prbuf
[32];
1710 for(p
= stabnames
; p
->name
; p
++)
1711 if(p
->n_type
== n_type
)
1713 sprintf(prbuf
, "%02x", (unsigned int)n_type
);
1718 * compare is the function used by qsort if any sorting of symbols is to be
1730 if(cmd_flags
.n
== TRUE
){
1731 if(p1
->nl
.n_value
> p2
->nl
.n_value
)
1732 return(cmd_flags
.r
== FALSE
? 1 : -1);
1733 else if(p1
->nl
.n_value
< p2
->nl
.n_value
)
1734 return(cmd_flags
.r
== FALSE
? -1 : 1);
1736 * If p1->nl.n_value == p2->nl.n_value fall through
1741 if(cmd_flags
.x
== TRUE
&& compare_lto
== FALSE
){
1742 if((uint32_t)p1
->nl
.n_un
.n_strx
> strsize
||
1743 (uint32_t)p2
->nl
.n_un
.n_strx
> strsize
){
1744 if((uint32_t)p1
->nl
.n_un
.n_strx
> strsize
)
1746 else if((uint32_t)p2
->nl
.n_un
.n_strx
> strsize
)
1750 r
= strcmp(p1
->nl
.n_un
.n_strx
+ strings
,
1751 p2
->nl
.n_un
.n_strx
+ strings
);
1754 r
= strcmp(p1
->name
, p2
->name
);
1756 if(cmd_flags
.r
== TRUE
)
1765 struct value_diff
*p1
,
1766 struct value_diff
*p2
)
1768 if(p1
->size
< p2
->size
)
1770 else if(p1
->size
> p2
->size
)
1772 /* if p1->size == p2->size */