nm: Add nm.c source and support for building the nm tool
[striptease.git] / nm.c
blobf35543769629433aa520d23ac6387ee805fd680e
1 /*
2 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
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
31 * Hans Huebner.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
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
59 * SUCH DAMAGE.
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 */
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88 #include <ctype.h>
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"
97 #ifdef LTO_SUPPORT
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 */
105 struct cmd_flags {
106 uint32_t nfiles;
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 */
142 sect_size;
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 */
151 bss_nsect;
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 */
157 struct symbol {
158 char *name;
159 char *indr_name;
160 struct nlist_64 nl;
163 struct value_diff {
164 uint64_t size;
165 struct symbol symbol;
168 static void usage(
169 void);
170 static void nm(
171 struct ofile *ofile,
172 char *arch_name,
173 void *cookie);
174 #ifdef LTO_SUPPORT
175 static void nm_lto(
176 struct ofile *ofile,
177 char *arch_name,
178 struct cmd_flags *cmd_flags);
179 #endif /* LTO_SUPPORT */
180 static void print_header(
181 struct ofile *ofile,
182 char *arch_name,
183 struct cmd_flags *cmd_flags);
184 static struct symbol *select_symbols(
185 struct ofile *ofile,
186 struct symtab_command *st,
187 struct dysymtab_command *dyst,
188 struct cmd_flags *cmd_flags,
189 struct process_flags *process_flags,
190 uint32_t *nsymbols);
191 static void make_symbol_32(
192 struct symbol *symbol,
193 struct nlist *nl);
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(
202 struct ofile *ofile,
203 struct symbol *symbols,
204 uint32_t nsymbols,
205 char *strings,
206 uint32_t strsize,
207 struct cmd_flags *cmd_flags,
208 struct process_flags *process_flags,
209 char *arch_name);
210 static void print_symbols(
211 struct ofile *ofile,
212 struct symbol *symbols,
213 uint32_t nsymbols,
214 char *strings,
215 uint32_t strsize,
216 struct cmd_flags *cmd_flags,
217 struct process_flags *process_flags,
218 char *arch_name,
219 struct value_diff *value_diffs);
220 static char * stab(
221 unsigned char n_type);
222 static int compare(
223 struct symbol *p1,
224 struct symbol *p2);
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;
234 main(
235 int argc,
236 char **argv,
237 char **envp)
239 int i;
240 uint32_t j;
241 struct arch_flag *arch_flags;
242 uint32_t narch_flags;
243 enum bool all_archs;
244 char **files;
246 progname = argv[0];
248 arch_flags = NULL;
249 narch_flags = 0;
250 all_archs = FALSE;
252 cmd_flags.nfiles = 0;
253 cmd_flags.a = FALSE;
254 cmd_flags.g = FALSE;
255 cmd_flags.n = FALSE;
256 cmd_flags.o = FALSE;
257 cmd_flags.p = FALSE;
258 cmd_flags.r = FALSE;
259 cmd_flags.u = FALSE;
260 cmd_flags.U = FALSE;
261 cmd_flags.m = FALSE;
262 cmd_flags.x = FALSE;
263 cmd_flags.j = FALSE;
264 cmd_flags.s = FALSE;
265 cmd_flags.segname = NULL;
266 cmd_flags.sectname = NULL;
267 cmd_flags.l = FALSE;
268 cmd_flags.f = FALSE;
269 cmd_flags.bincl_name = NULL;
270 cmd_flags.A = FALSE;
271 cmd_flags.P = FALSE;
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')){
279 i++;
280 for( ; i < argc; i++)
281 files[cmd_flags.nfiles++] = argv[i];
282 break;
284 if(strcmp(argv[i], "-arch") == 0){
285 if(i + 1 == argc){
286 error("missing argument(s) to %s option", argv[i]);
287 usage();
289 if(strcmp("all", argv[i+1]) == 0){
290 all_archs = TRUE;
292 else{
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]);
299 arch_usage();
300 usage();
302 narch_flags++;
304 i++;
306 else if(strcmp(argv[i], "-t") == 0){
307 if(i + 1 == argc){
308 error("missing argument to %s option", argv[i]);
309 usage();
311 if(argv[i+1][1] != '\0'){
312 error("invalid argument to option: %s %s",
313 argv[i], argv[i+1]);
314 usage();
316 switch(argv[i+1][0]){
317 case 'd':
318 cmd_flags.format = "%lld";
319 break;
320 case 'o':
321 cmd_flags.format = "%llo";
322 break;
323 case 'x':
324 cmd_flags.format = "%llx";
325 break;
326 default:
327 error("invalid argument to option: %s %s",
328 argv[i], argv[i+1]);
329 usage();
331 i++;
333 else{
334 for(j = 1; argv[i][j] != '\0'; j++){
335 switch(argv[i][j]){
336 case 'a':
337 cmd_flags.a = TRUE;
338 break;
339 case 'g':
340 cmd_flags.g = TRUE;
341 break;
342 case 'n':
343 cmd_flags.n = TRUE;
344 break;
345 case 'o':
346 cmd_flags.o = TRUE;
347 break;
348 case 'p':
349 cmd_flags.p = TRUE;
350 break;
351 case 'r':
352 cmd_flags.r = TRUE;
353 break;
354 case 'u':
355 if(cmd_flags.U == TRUE){
356 error("can't specifiy both -u and -U");
357 usage();
359 cmd_flags.u = TRUE;
360 break;
361 case 'U':
362 if(cmd_flags.u == TRUE){
363 error("can't specifiy both -U and -u");
364 usage();
366 cmd_flags.U = TRUE;
367 break;
368 case 'm':
369 cmd_flags.m = TRUE;
370 break;
371 case 'x':
372 cmd_flags.x = TRUE;
373 break;
374 case 'j':
375 cmd_flags.j = TRUE;
376 break;
377 case 's':
378 if(cmd_flags.s == TRUE){
379 error("more than one -s option specified");
380 usage();
382 cmd_flags.s = TRUE;
383 break;
384 case 'b':
385 if(cmd_flags.b == TRUE){
386 error("more than one -b option specified");
387 usage();
389 cmd_flags.b = TRUE;
390 break;
391 case 'i':
392 if(cmd_flags.i == TRUE){
393 error("more than one -i option specified");
394 usage();
396 cmd_flags.i = TRUE;
397 while(isdigit(argv[i][j+1])){
398 cmd_flags.index = cmd_flags.index * 10 +
399 (argv[i][j+1] - '0');
400 j++;
402 case 'l':
403 cmd_flags.l = TRUE;
404 break;
405 case 'f':
406 cmd_flags.f = TRUE;
407 break;
408 case 'v':
409 cmd_flags.v = TRUE;
410 break;
411 case 'A':
412 cmd_flags.A = TRUE;
413 break;
414 case 'P':
415 cmd_flags.P = TRUE;
416 break;
417 default:
418 error("invalid argument -%c", argv[i][j]);
419 usage();
422 if(cmd_flags.s == TRUE && cmd_flags.segname == NULL){
423 if(i + 2 == argc){
424 error("missing arguments to -s");
425 usage();
427 cmd_flags.segname = argv[i+1];
428 cmd_flags.sectname = argv[i+2];
429 i += 2;
431 if(cmd_flags.b == TRUE && cmd_flags.bincl_name == NULL){
432 if(i + 1 == argc){
433 error("missing arguments to -b");
434 usage();
436 cmd_flags.bincl_name = argv[i+1];
437 i += 1;
440 continue;
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);
452 if(errors == 0)
453 return(EXIT_SUCCESS);
454 else
455 return(EXIT_FAILURE);
459 * usage() prints the current usage message and exits indicating failure.
461 static
462 void
463 usage(
464 void)
466 fprintf(stderr, "Usage: %s [-agnopruUmxjlfAP[s segname sectname] [-] "
467 "[-t format] [[-arch <arch_flag>] ...] [file ...]\n", progname);
468 exit(EXIT_FAILURE);
472 * nm() is the routine that gets called by ofile_process() to process single
473 * object files.
475 static
476 void
478 struct ofile *ofile,
479 char *arch_name,
480 void *cookie)
482 uint32_t ncmds, mh_flags;
483 struct cmd_flags *cmd_flags;
484 struct process_flags process_flags;
485 uint32_t i, j, k;
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;
491 struct section *s;
492 struct section_64 *s64;
493 struct dylib_command *dl;
495 struct symbol *symbols;
496 uint32_t nsymbols;
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){
517 #ifdef LTO_SUPPORT
518 if(ofile->lto != NULL)
519 nm_lto(ofile, arch_name, cmd_flags);
520 #endif /* LTO_SUPPORT */
521 return;
523 st = NULL;
524 dyst = NULL;
525 lc = ofile->load_commands;
526 if(ofile->mh != NULL){
527 ncmds = ofile->mh->ncmds;
528 mh_flags = ofile->mh->flags;
530 else{
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");
561 return;
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;
570 else{
571 process_flags.sections64 = (struct section_64 **)
572 malloc(sizeof(struct section_64 *) *
573 process_flags.nsects);
574 process_flags.sections = NULL;
576 k = 0;
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);
641 j = 0;
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;
656 j++;
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,
665 &nsymbols);
667 /* set names in the symbols to be printed */
668 strings = ofile->object_addr + st->stroff;
669 strsize = st->strsize;
670 compare_lto = FALSE;
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";
678 else
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";
687 else
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;
701 nsymbols++;
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);
713 value_diffs = NULL;
714 if(cmd_flags->v == TRUE && cmd_flags->n == TRUE &&
715 cmd_flags->r == FALSE && cmd_flags->s == TRUE &&
716 nsymbols != 0){
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);
737 else
738 print_symbols(ofile, symbols, nsymbols, strings, st->strsize,
739 cmd_flags, &process_flags, arch_name, value_diffs);
741 free(symbols);
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;
754 #ifdef LTO_SUPPORT
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] = {
764 &lto_code_section,
765 &lto_data_section,
766 &lto_rodata_section
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] = {
772 &lto_code_section64,
773 &lto_data_section64,
774 &lto_rodata_section64
778 * nm_lto() is called by nm() to process an lto bitcode file.
780 static
781 void
782 nm_lto(
783 struct ofile *ofile,
784 char *arch_name,
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;
809 else{
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);
822 nsymbols = 0;
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 */
834 strings = NULL;
835 strsize = 0;
836 compare_lto = TRUE;
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);
847 else
848 print_symbols(ofile, symbols, nsymbols, NULL, 0,
849 cmd_flags, &process_flags, arch_name, NULL);
851 free(symbols);
853 #endif /* LTO_SUPPORT */
855 /* print header if needed */
856 static
857 void
858 print_header(
859 struct ofile *ofile,
860 char *arch_name,
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);
875 else
876 printf("\n%s", ofile->file_name);
877 if(arch_name != NULL)
878 printf(" (for architecture %s):\n", arch_name);
879 else
880 printf(":\n");
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.
889 static
890 struct symbol *
891 select_symbols(
892 struct ofile *ofile,
893 struct symtab_command *st,
894 struct dysymtab_command *dyst,
895 struct cmd_flags *cmd_flags,
896 struct process_flags *process_flags,
897 uint32_t *nsymbols)
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;
906 enum bool found;
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;
913 else{
914 all_symbols = NULL;
915 all_symbols64 = (struct nlist_64 *)(ofile->object_addr +st->symoff);
917 selected_symbols = allocate(sizeof(struct symbol) * st->nsyms);
918 *nsymbols = 0;
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());
923 else
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());
932 irefsym = m.irefsym;
933 nrefsym = m.nrefsym;
934 nextdefsym = m.nextdefsym;
935 iextdefsym = m.iextdefsym;
936 nlocalsym = m.nlocalsym;
937 ilocalsym = m.ilocalsym;
939 else{
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 +
951 dyst->extrefsymoff);
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);
965 else
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;
972 else
973 symbol.nl.n_type = N_UNDF;
974 symbol.nl.n_desc = (symbol.nl.n_desc &~ REFERENCE_TYPE) |
975 flags;
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);
984 else
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);
992 else
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){
999 found = FALSE;
1000 strings = ofile->object_addr + st->stroff;
1001 if(cmd_flags->i == TRUE)
1002 i = cmd_flags->index;
1003 else
1004 i = 0;
1005 for( ; i < st->nsyms; i++){
1006 if(ofile->mh != NULL)
1007 make_symbol_32(&symbol, all_symbols + i);
1008 else
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;
1016 found = TRUE;
1017 nest = 0;
1018 for(i = i + 1 ; i < st->nsyms; i++){
1019 if(ofile->mh != NULL)
1020 make_symbol_32(&symbol, all_symbols + i);
1021 else
1022 make_symbol_64(&symbol, all_symbols64 + i);
1023 if(symbol.nl.n_type == N_BINCL)
1024 nest++;
1025 else if(symbol.nl.n_type == N_EINCL){
1026 if(nest == 0){
1027 selected_symbols[(*nsymbols)++] = symbol;
1028 break;
1030 nest--;
1032 else if(nest == 0)
1033 selected_symbols[(*nsymbols)++] = symbol;
1036 if(found == TRUE)
1037 break;
1040 else{
1041 for(i = 0; i < st->nsyms; i++){
1042 if(ofile->mh != NULL)
1043 make_symbol_32(&symbol, all_symbols + i);
1044 else
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);
1053 else
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);
1063 static
1064 void
1065 make_symbol_32(
1066 struct symbol *symbol,
1067 struct nlist *nl)
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;
1076 static
1077 void
1078 make_symbol_64(
1079 struct symbol *symbol,
1080 struct nlist_64 *nl)
1082 symbol->nl = *nl;
1086 * select_symbol() returns TRUE or FALSE if the specified symbol is to be
1087 * printed based on the flags.
1089 static
1090 enum bool
1091 select_symbol(
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))
1100 return(TRUE);
1101 else
1102 return(FALSE);
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))
1108 return(FALSE);
1109 else
1110 return(TRUE);
1112 if(cmd_flags->g == TRUE && (symbol->nl.n_type & N_EXT) == 0)
1113 return(FALSE);
1114 if(cmd_flags->s == TRUE){
1115 if(((symbol->nl.n_type & N_TYPE) == N_SECT) &&
1116 (symbol->nl.n_sect == process_flags->nsect)){
1117 if(cmd_flags->l &&
1118 symbol->nl.n_value == process_flags->sect_addr){
1119 process_flags->sect_start_symbol = TRUE;
1122 else
1123 return(FALSE);
1125 if((symbol->nl.n_type & N_STAB) &&
1126 (cmd_flags->a == FALSE || cmd_flags->g == TRUE ||
1127 cmd_flags->u == TRUE))
1128 return(FALSE);
1129 return(TRUE);
1133 * print_mach_symbols() is called when the -m flag is specified and prints
1134 * symbols in the extended Mach-O style format.
1136 static
1137 void
1138 print_mach_symbols(
1139 struct ofile *ofile,
1140 struct symbol *symbols,
1141 uint32_t nsymbols,
1142 char *strings,
1143 uint32_t strsize,
1144 struct cmd_flags *cmd_flags,
1145 struct process_flags *process_flags,
1146 char *arch_name)
1148 uint32_t i, library_ordinal;
1149 char *ta_xfmt, *i_xfmt, *dashes, *spaces;
1150 uint32_t mh_flags;
1152 mh_flags = 0;
1153 if(ofile->mh != NULL ||
1154 (ofile->lto != NULL &&
1155 (ofile->lto_cputype & CPU_ARCH_ABI64) != CPU_ARCH_ABI64)){
1156 ta_xfmt = "%08llx";
1157 i_xfmt = "%08x";
1158 if(ofile->mh != NULL)
1159 mh_flags = ofile->mh->flags;
1160 spaces = " ";
1161 dashes = "--------";
1163 else{
1164 ta_xfmt = "%016llx";
1165 i_xfmt = "%016x";
1166 if(ofile->mh64 != NULL)
1167 mh_flags = ofile->mh64->flags;
1168 spaces = " ";
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);
1182 else
1183 printf(" (null)");
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)");
1189 else{
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");
1205 else{
1206 printf(" (indirect for ");
1207 printf(ta_xfmt, symbols[i].nl.n_value);
1208 printf(" %s)\n", symbols[i].indr_name);
1211 else
1212 printf("\n");
1213 continue;
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);
1229 else
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);
1237 continue;
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);
1252 else
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);
1260 else{
1261 if(ofile->lto)
1262 printf("%s", dashes);
1263 else
1264 printf(ta_xfmt, symbols[i].nl.n_value);
1267 switch(symbols[i].nl.n_type & N_TYPE){
1268 case N_UNDF:
1269 case N_PBUD:
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));
1277 else{
1278 if((symbols[i].nl.n_type & N_TYPE) == N_PBUD)
1279 printf(" (prebound ");
1280 else
1281 printf(" (");
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]) ");
1291 else
1292 printf("undefined) ");
1294 break;
1295 case N_ABS:
1296 printf(" (absolute) ");
1298 break;
1299 case N_INDR:
1300 printf(" (indirect) ");
1301 break;
1302 case N_SECT:
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) !=
1308 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);
1315 else{
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);
1323 else
1324 printf(" (?,?) ");
1325 break;
1326 default:
1327 printf(" (?) ");
1328 break;
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 ");
1337 else
1338 printf("private external ");
1340 else{
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 ");
1346 else
1347 printf("weak external ");
1349 else
1350 printf("external ");
1353 else{
1354 if(symbols[i].nl.n_type & N_PEXT)
1355 printf("non-external (was a private external) ");
1356 else
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)
1370 printf("[Thumb] ");
1372 if((symbols[i].nl.n_type & N_TYPE) == N_INDR)
1373 printf("%s (for %s)", symbols[i].name, symbols[i].indr_name);
1374 else
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)",
1390 library_ordinal);
1391 else
1392 printf(" (from %s)", process_flags->lib_names[
1393 library_ordinal-1]);
1396 printf("\n");
1401 * print_symbols() is called with the -m flag is not specified and prints
1402 * symbols in the standard BSD format.
1404 static
1405 void
1406 print_symbols(
1407 struct ofile *ofile,
1408 struct symbol *symbols,
1409 uint32_t nsymbols,
1410 char *strings,
1411 uint32_t strsize,
1412 struct cmd_flags *cmd_flags,
1413 struct process_flags *process_flags,
1414 char *arch_name,
1415 struct value_diff *value_diffs)
1417 uint32_t i;
1418 unsigned char c;
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)){
1424 ta_xfmt = "%08llx";
1425 i_xfmt = "%08x";
1426 spaces = " ";
1427 dashes = "--------";
1429 else{
1430 ta_xfmt = "%016llx";
1431 i_xfmt = "%016x";
1432 spaces = " ";
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);
1447 else
1448 printf(" (null)");
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)");
1454 else{
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");
1470 else{
1471 printf(" (indirect for ");
1472 printf(ta_xfmt, symbols[i].nl.n_value);
1473 printf(" %s)\n", symbols[i].indr_name);
1476 else
1477 printf("\n");
1478 continue;
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);
1493 else
1494 printf("%s: ", ofile->file_name);
1496 printf("%s ", symbols[i].name);
1498 /* type */
1499 c = symbols[i].nl.n_type;
1500 if(c & N_STAB)
1501 c = '-';
1502 else{
1503 switch(c & N_TYPE){
1504 case N_UNDF:
1505 c = 'u';
1506 if(symbols[i].nl.n_value != 0)
1507 c = 'c';
1508 break;
1509 case N_PBUD:
1510 c = 'u';
1511 break;
1512 case N_ABS:
1513 c = 'a';
1514 break;
1515 case N_SECT:
1516 if(symbols[i].nl.n_sect ==
1517 process_flags->text_nsect)
1518 c = 't';
1519 else if(symbols[i].nl.n_sect ==
1520 process_flags->data_nsect)
1521 c = 'd';
1522 else if(symbols[i].nl.n_sect ==
1523 process_flags->bss_nsect)
1524 c = 'b';
1525 else
1526 c = 's';
1527 break;
1528 case N_INDR:
1529 c = 'i';
1530 break;
1531 default:
1532 c = '?';
1533 break;
1536 if((symbols[i].nl.n_type & N_EXT) && c != '?')
1537 c = toupper(c);
1538 printf("%c ", c);
1539 printf(cmd_flags->format, symbols[i].nl.n_value);
1540 printf(" 0\n"); /* the 0 is the size for conformance */
1541 continue;
1543 c = symbols[i].nl.n_type;
1544 if(c & N_STAB){
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);
1557 else
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++){
1567 printf("%c", *p);
1568 if(*p == '('){
1569 p++;
1570 while(isdigit((unsigned char)*p))
1571 p++;
1572 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))
1578 p++;
1579 p--;
1582 printf("\n");
1584 else{
1585 printf("%s\n", symbols[i].name);
1587 continue;
1589 switch(c & N_TYPE){
1590 case N_UNDF:
1591 c = 'u';
1592 if(symbols[i].nl.n_value != 0)
1593 c = 'c';
1594 break;
1595 case N_PBUD:
1596 c = 'u';
1597 break;
1598 case N_ABS:
1599 c = 'a';
1600 break;
1601 case N_SECT:
1602 if(symbols[i].nl.n_sect == process_flags->text_nsect)
1603 c = 't';
1604 else if(symbols[i].nl.n_sect == process_flags->data_nsect)
1605 c = 'd';
1606 else if(symbols[i].nl.n_sect == process_flags->bss_nsect)
1607 c = 'b';
1608 else
1609 c = 's';
1610 break;
1611 case N_INDR:
1612 c = 'i';
1613 break;
1614 default:
1615 c = '?';
1616 break;
1618 if(cmd_flags->u == TRUE && c != 'u')
1619 continue;
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);
1632 else
1633 printf("%s: ", ofile->file_name);
1635 if((symbols[i].nl.n_type & N_EXT) && c != '?')
1636 c = toupper(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);
1640 else{
1641 if(cmd_flags->v && value_diffs != NULL){
1642 printf(ta_xfmt, value_diffs[i].size);
1643 printf(" ");
1645 if(ofile->lto)
1646 printf("%s", dashes);
1647 else
1648 printf(ta_xfmt, symbols[i].nl.n_value);
1650 printf(" %c ", c);
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);
1656 else
1657 printf("%s\n", symbols[i].name);
1661 struct stabnames {
1662 unsigned char n_type;
1663 char *name;
1665 static const struct stabnames stabnames[] = {
1666 { N_GSYM, "GSYM" },
1667 { N_FNAME, "FNAME" },
1668 { N_FUN, "FUN" },
1669 { N_STSYM, "STSYM" },
1670 { N_LCSYM, "LCSYM" },
1671 { N_BNSYM, "BNSYM" },
1672 { N_OPT, "OPT" },
1673 { N_RSYM, "RSYM" },
1674 { N_SLINE, "SLINE" },
1675 { N_ENSYM, "ENSYM" },
1676 { N_SSYM, "SSYM" },
1677 { N_SO, "SO" },
1678 { N_OSO, "OSO" },
1679 { N_LSYM, "LSYM" },
1680 { N_BINCL, "BINCL" },
1681 { N_SOL, "SOL" },
1682 { N_PARAMS,"PARAM" },
1683 { N_VERSION,"VERS" },
1684 { N_OLEVEL,"OLEV" },
1685 { N_PSYM, "PSYM" },
1686 { N_EINCL, "EINCL" },
1687 { N_ENTRY, "ENTRY" },
1688 { N_LBRAC, "LBRAC" },
1689 { N_EXCL, "EXCL" },
1690 { N_RBRAC, "RBRAC" },
1691 { N_BCOMM, "BCOMM" },
1692 { N_ECOMM, "ECOMM" },
1693 { N_ECOML, "ECOML" },
1694 { N_LENG, "LENG" },
1695 { N_PC, "PC" },
1696 { 0, 0 }
1700 * stab() returns the name of the specified stab n_type.
1702 static
1703 char *
1704 stab(
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)
1712 return(p->name);
1713 sprintf(prbuf, "%02x", (unsigned int)n_type);
1714 return(prbuf);
1718 * compare is the function used by qsort if any sorting of symbols is to be
1719 * done.
1721 static
1723 compare(
1724 struct symbol *p1,
1725 struct symbol *p2)
1727 int r;
1729 r = 0;
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
1737 * and sort by name
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)
1745 r = -1;
1746 else if((uint32_t)p2->nl.n_un.n_strx > strsize)
1747 r = 1;
1749 else
1750 r = strcmp(p1->nl.n_un.n_strx + strings,
1751 p2->nl.n_un.n_strx + strings);
1753 else
1754 r = strcmp(p1->name, p2->name);
1756 if(cmd_flags.r == TRUE)
1757 return(-r);
1758 else
1759 return(r);
1762 static
1764 value_diff_compare(
1765 struct value_diff *p1,
1766 struct value_diff *p2)
1768 if(p1->size < p2->size)
1769 return(-1);
1770 else if(p1->size > p2->size)
1771 return(1);
1772 /* if p1->size == p2->size */
1773 return(0);