• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Print information from ELF file in human-readable form.
2    Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
3    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
4 
5    This program is Open Source software; you can redistribute it and/or
6    modify it under the terms of the Open Software License version 1.0 as
7    published by the Open Source Initiative.
8 
9    You should have received a copy of the Open Software License along
10    with this program; if not, you may obtain a copy of the Open Software
11    License version 1.0 from http://www.opensource.org/licenses/osl.php or
12    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13    3001 King Ranch Road, Ukiah, CA 95482.   */
14 
15 #ifdef HAVE_CONFIG_H
16 # include <config.h>
17 #endif
18 
19 #include <ar.h>
20 #include <argp.h>
21 #include <assert.h>
22 #include <ctype.h>
23 #include <dwarf.h>
24 #include <errno.h>
25 #include <error.h>
26 #include <fcntl.h>
27 #include <gelf.h>
28 #include <inttypes.h>
29 #include <libdw.h>
30 #include <libebl.h>
31 #include <libintl.h>
32 #include <locale.h>
33 #include <mcheck.h>
34 #include <obstack.h>
35 #include <search.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdio_ext.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 #include <sys/param.h>
43 
44 #include <system.h>
45 
46 
47 /* Name and version of program.  */
48 static void print_version (FILE *stream, struct argp_state *state);
49 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
50 
51 
52 /* Values for the parameters which have no short form.  */
53 #define OPT_DEFINED	0x100
54 #define OPT_MARK_WEAK	0x101
55 
56 /* Definitions of arguments for argp functions.  */
57 static const struct argp_option options[] =
58 {
59   { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
60   { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 },
61   { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"),
62     0 },
63   { "dynamic", 'D', NULL, 0,
64     N_("Display dynamic symbols instead of normal symbols"), 0 },
65   { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 },
66   { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 },
67   { "print-armap", 's', NULL, 0,
68     N_("Include index for symbols from archive members"), 0 },
69 
70   { NULL, 0, NULL, 0, N_("Output format:"), 0 },
71   { "print-file-name", 'A', NULL, 0,
72     N_("Print name of the input file before every symbol"), 0 },
73   { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 },
74   { "format", 'f', "FORMAT", 0,
75     N_("Use the output format FORMAT.  FORMAT can be `bsd', `sysv' or `posix'.  The default is `sysv'"),
76     0 },
77   { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 },
78   { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 },
79   { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 },
80   { "mark-weak", OPT_MARK_WEAK, NULL, 0, N_("Mark weak symbols"), 0 },
81   { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 },
82 
83   { NULL, 0, NULL, 0, N_("Output options:"), 0 },
84   { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"),
85     0 },
86   { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 },
87   { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 },
88   { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
89   { NULL, 0, NULL, 0, NULL, 0 }
90 };
91 
92 /* Short description of program.  */
93 static const char doc[] = N_("List symbols from FILEs (a.out by default).");
94 
95 /* Strings for arguments in help texts.  */
96 static const char args_doc[] = N_("[FILE...]");
97 
98 /* Prototype for option handler.  */
99 static error_t parse_opt (int key, char *arg, struct argp_state *state);
100 
101 /* Function to print some extra text in the help message.  */
102 static char *more_help (int key, const char *text, void *input);
103 
104 /* Data structure to communicate with argp functions.  */
105 static struct argp argp =
106 {
107   options, parse_opt, args_doc, doc, NULL, more_help, NULL
108 };
109 
110 
111 /* Print symbols in file named FNAME.  */
112 static int process_file (const char *fname, bool more_than_one);
113 
114 /* Handle content of archive.  */
115 static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
116 		      const char *suffix);
117 
118 /* Handle ELF file.  */
119 static int handle_elf (Elf *elf, const char *prefix, const char *fname,
120 		       const char *suffix);
121 
122 
123 #define INTERNAL_ERROR(fname) \
124   error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"),      \
125 	 fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1))
126 
127 
128 /* Internal representation of symbols.  */
129 typedef struct GElf_SymX
130 {
131   GElf_Sym sym;
132   Elf32_Word xndx;
133   char *where;
134 } GElf_SymX;
135 
136 
137 /* User-selectable options.  */
138 
139 /* The selected output format.  */
140 static enum
141 {
142   format_sysv = 0,
143   format_bsd,
144   format_posix
145 } format;
146 
147 /* Print defined, undefined, or both?  */
148 static bool hide_undefined;
149 static bool hide_defined;
150 
151 /* Print local symbols also?  */
152 static bool hide_local;
153 
154 /* Nonzero if full filename should precede every symbol.  */
155 static bool print_file_name;
156 
157 /* If true print size of defined symbols in BSD format.  */
158 static bool print_size;
159 
160 /* If true print archive index.  */
161 static bool print_armap;
162 
163 /* If true reverse sorting.  */
164 static bool reverse_sort;
165 
166 /* Type of the section we are printing.  */
167 static GElf_Word symsec_type = SHT_SYMTAB;
168 
169 /* Sorting selection.  */
170 static enum
171 {
172   sort_name = 0,
173   sort_numeric,
174   sort_nosort
175 } sort;
176 
177 /* Radix for printed numbers.  */
178 static enum
179 {
180   radix_hex = 0,
181   radix_decimal,
182   radix_octal
183 } radix;
184 
185 /* If nonzero weak symbols are distinguished from global symbols by adding
186    a `*' after the identifying letter for the symbol class and type.  */
187 static bool mark_weak;
188 
189 
190 int
main(int argc,char * argv[])191 main (int argc, char *argv[])
192 {
193   int remaining;
194   int result = 0;
195 
196   /* Make memory leak detection possible.  */
197   mtrace ();
198 
199   /* We use no threads here which can interfere with handling a stream.  */
200   (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
201   (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
202   (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
203 
204   /* Set locale.  */
205   (void) setlocale (LC_ALL, "");
206 
207   /* Make sure the message catalog can be found.  */
208   (void) bindtextdomain (PACKAGE, LOCALEDIR);
209 
210   /* Initialize the message catalog.  */
211   (void) textdomain (PACKAGE);
212 
213   /* Parse and process arguments.  */
214   (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
215 
216   /* Tell the library which version we are expecting.  */
217   (void) elf_version (EV_CURRENT);
218 
219   if (remaining == argc)
220     /* The user didn't specify a name so we use a.out.  */
221     result = process_file ("a.out", false);
222   else
223     {
224       /* Process all the remaining files.  */
225       const bool more_than_one = remaining + 1 < argc;
226 
227       do
228 	result |= process_file (argv[remaining], more_than_one);
229       while (++remaining < argc);
230     }
231 
232   return result;
233 }
234 
235 
236 /* Print the version information.  */
237 static void
print_version(FILE * stream,struct argp_state * state)238 print_version (FILE *stream, /*@unused@*/ struct argp_state *state)
239 {
240   fprintf (stream, "nm (%s) %s\n", PACKAGE_NAME, VERSION);
241   fprintf (stream, gettext ("\
242 Copyright (C) %s Red Hat, Inc.\n\
243 This is free software; see the source for copying conditions.  There is NO\n\
244 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
245 "), "2004");
246   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
247 }
248 
249 
250 /* Handle program arguments.  */
251 static error_t
parse_opt(int key,char * arg,struct argp_state * state)252 parse_opt (int key, char *arg, /*@unused@*/ struct argp_state *state)
253 {
254   switch (key)
255     {
256     case 'a':
257       /* XXX */
258       break;
259 
260     case 'f':
261       if (strcmp (arg, "bsd") == 0)
262 	format = format_bsd;
263       else if (strcmp (arg, "posix") == 0)
264 	format = format_posix;
265       else
266 	/* Be bug compatible.  The BFD implementation also defaulted to
267 	   using the SysV format if nothing else matches.  */
268 	format = format_sysv;
269       break;
270 
271     case 'g':
272       hide_local = true;
273       break;
274 
275     case 'n':
276       sort = sort_numeric;
277       break;
278 
279     case 'p':
280       sort = sort_nosort;
281       break;
282 
283     case 't':
284       if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0)
285 	radix = radix_decimal;
286       else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0)
287 	radix = radix_octal;
288       else
289 	radix = radix_hex;
290       break;
291 
292     case 'u':
293       hide_undefined = false;
294       hide_defined = true;
295       break;
296 
297     case 'A':
298     case 'o':
299       print_file_name = true;
300       break;
301 
302     case 'B':
303       format = format_bsd;
304       break;
305 
306     case 'D':
307       symsec_type = SHT_DYNSYM;
308       break;
309 
310     case 'P':
311       format = format_posix;
312       break;
313 
314     case OPT_DEFINED:
315       hide_undefined = true;
316       hide_defined = false;
317       break;
318 
319     case OPT_MARK_WEAK:
320       mark_weak = true;
321       break;
322 
323     case 'S':
324       print_size = true;
325       break;
326 
327     case 's':
328       print_armap = true;
329       break;
330 
331     case 'r':
332       reverse_sort = true;
333       break;
334 
335     default:
336       return ARGP_ERR_UNKNOWN;
337     }
338   return 0;
339 }
340 
341 
342 static char *
more_help(int key,const char * text,void * input)343 more_help (int key, const char *text, /*@unused@*/ void *input)
344 {
345   char *buf;
346 
347   switch (key)
348     {
349     case ARGP_KEY_HELP_EXTRA:
350       /* We print some extra information.  */
351       if (asprintf (&buf, gettext ("Please report bugs to %s.\n"),
352 		    PACKAGE_BUGREPORT) < 0)
353 	buf = NULL;
354       return buf;
355 
356     default:
357       break;
358     }
359   return (char *) text;
360 }
361 
362 
363 /* Open the file and determine the type.  */
364 static int
process_file(const char * fname,bool more_than_one)365 process_file (const char *fname, bool more_than_one)
366 {
367   /* Open the file.  */
368   int fd = open (fname, O_RDONLY);
369   if (fd == -1)
370     {
371       error (0, errno, fname);
372       return 1;
373     }
374 
375   /* Now get the ELF descriptor.  */
376   Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
377   if (elf != NULL)
378     {
379       if (elf_kind (elf) == ELF_K_ELF)
380 	{
381 	  int result = handle_elf (elf, more_than_one ? "" : NULL,
382 				   fname, NULL);
383 
384 	  if (elf_end (elf) != 0)
385 	    INTERNAL_ERROR (fname);
386 
387 	  if (close (fd) != 0)
388 	    error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
389 
390 	  return result;
391 	}
392       else if (elf_kind (elf) == ELF_K_AR)
393 	{
394 	  int result = handle_ar (fd, elf, NULL, fname, NULL);
395 
396 	  if (elf_end (elf) != 0)
397 	    INTERNAL_ERROR (fname);
398 
399 	  if (close (fd) != 0)
400 	    error (EXIT_FAILURE, errno, gettext ("while close `%s'"), fname);
401 
402 	  return result;
403 	}
404 
405       /* We cannot handle this type.  Close the descriptor anyway.  */
406       if (elf_end (elf) != 0)
407 	INTERNAL_ERROR (fname);
408     }
409 
410   error (0, 0, gettext ("%s: File format not recognized"), fname);
411 
412   return 1;
413 }
414 
415 
416 static int
handle_ar(int fd,Elf * elf,const char * prefix,const char * fname,const char * suffix)417 handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
418 	   const char *suffix)
419 {
420   size_t fname_len = strlen (fname) + 1;
421   size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
422   char new_prefix[prefix_len + fname_len + 2];
423   size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
424   char new_suffix[suffix_len + 2];
425   Elf *subelf;
426   Elf_Cmd cmd = ELF_C_READ_MMAP;
427   int result = 0;
428 
429   char *cp = new_prefix;
430   if (prefix != NULL)
431     cp = stpcpy (cp, prefix);
432   cp = stpcpy (cp, fname);
433   stpcpy (cp, "[");
434 
435   cp = new_suffix;
436   if (suffix != NULL)
437     cp = stpcpy (cp, suffix);
438   stpcpy (cp, "]");
439 
440   /* First print the archive index if this is wanted.  */
441   if (print_armap)
442     {
443       Elf_Arsym *arsym = elf_getarsym (elf, NULL);
444 
445       if (arsym != NULL)
446 	{
447 	  Elf_Arhdr *arhdr = NULL;
448 	  size_t arhdr_off = 0;	/* Note: 0 is no valid offset.  */
449 
450 	  puts (gettext("\nArchive index:"));
451 
452 	  while (arsym->as_off != 0)
453 	    {
454 	      if (arhdr_off != arsym->as_off
455 		  && (elf_rand (elf, arsym->as_off) != arsym->as_off
456 		      || (subelf = elf_begin (fd, cmd, elf)) == NULL
457 		      || (arhdr = elf_getarhdr (subelf)) == NULL))
458 		{
459 		  error (0, 0, gettext ("invalid offset %zu for symbol %s"),
460 			 arsym->as_off, arsym->as_name);
461 		  continue;
462 		}
463 
464 	      printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name);
465 
466 	      ++arsym;
467 	    }
468 
469 	  if (elf_rand (elf, SARMAG) != SARMAG)
470 	    {
471 	      error (0, 0,
472 		     gettext ("cannot reset archive offset to beginning"));
473 	      return 1;
474 	    }
475 	}
476     }
477 
478   /* Process all the files contained in the archive.  */
479   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
480     {
481       /* The the header for this element.  */
482       Elf_Arhdr *arhdr = elf_getarhdr (subelf);
483 
484       /* Skip over the index entries.  */
485       if (strcmp (arhdr->ar_name, "/") != 0
486 	  && strcmp (arhdr->ar_name, "//") != 0)
487 	{
488 	  if (elf_kind (subelf) == ELF_K_ELF)
489 	    result |= handle_elf (subelf, new_prefix, arhdr->ar_name,
490 				  new_suffix);
491 	  else if (elf_kind (subelf) == ELF_K_AR)
492 	    result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
493 				 new_suffix);
494 	  else
495 	    {
496 	      error (0, 0, gettext ("%s%s%s: file format not recognized"),
497 		     new_prefix, arhdr->ar_name, new_suffix);
498 	      result = 1;
499 	    }
500 	}
501 
502       /* Get next archive element.  */
503       cmd = elf_next (subelf);
504       if (elf_end (subelf) != 0)
505 	INTERNAL_ERROR (fname);
506     }
507 
508   return result;
509 }
510 
511 
512 /* Mapping of radix and binary class to length.  */
513 static const int length_map[2][3] =
514 {
515   [ELFCLASS32 - 1] =
516   {
517     [radix_hex] = 8,
518     [radix_decimal] = 10,
519     [radix_octal] = 11
520   },
521   [ELFCLASS64 - 1] =
522   {
523     [radix_hex] = 16,
524     [radix_decimal] = 20,
525     [radix_octal] = 22
526   }
527 };
528 
529 
530 struct global_name
531 {
532   Dwarf_Global global;
533   const char *name;
534 };
535 
536 
537 static int
global_compare(const void * p1,const void * p2)538 global_compare (const void *p1, const void *p2)
539 {
540   const Dwarf_Global *g1 = (const Dwarf_Global *) p1;
541   const Dwarf_Global *g2 = (const Dwarf_Global *) p2;
542 
543   return strcmp (g1->name, g2->name);
544 }
545 
546 
547 static void *global_root;
548 
549 
550 static int
get_global(Dwarf * dbg,Dwarf_Global * global,void * arg)551 get_global (Dwarf *dbg, Dwarf_Global *global, void *arg)
552 {
553   tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global,
554 		   sizeof (Dwarf_Global)),
555 	   &global_root, global_compare);
556 
557   return DWARF_CB_OK;
558 }
559 
560 
561 struct local_name
562 {
563   const char *name;
564   const char *file;
565   Dwarf_Word lineno;
566   Dwarf_Addr lowpc;
567   Dwarf_Addr highpc;
568 };
569 
570 
571 static int
local_compare(const void * p1,const void * p2)572 local_compare (const void *p1, const void *p2)
573 {
574   struct local_name *g1 = (struct local_name *) p1;
575   struct local_name *g2 = (struct local_name *) p2;
576   int result;
577 
578   result = strcmp (g1->name, g2->name);
579   if (result == 0)
580     {
581       if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc)
582 	{
583 	  /* g2 is contained in g1.  Update the data.  */
584 	  g2->lowpc = g1->lowpc;
585 	  g2->highpc = g1->highpc;
586 	  result = 0;
587 	}
588       else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc)
589 	{
590 	  /* g1 is contained in g2.  Update the data.  */
591 	  g1->lowpc = g2->lowpc;
592 	  g1->highpc = g2->highpc;
593 	  result = 0;
594 	}
595       else
596 	result = g1->lowpc < g2->lowpc ? -1 : 1;
597     }
598 
599   return result;
600 }
601 
602 
603 static int
get_var_range(Dwarf_Die * die,Dwarf_Word * lowpc,Dwarf_Word * highpc)604 get_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc)
605 {
606   Dwarf_Attribute locattr_mem;
607   Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem);
608   if  (locattr == NULL)
609     return 1;
610 
611   Dwarf_Loc *loc;
612   size_t nloc;
613   if (dwarf_getloclist (locattr, &loc, &nloc) != 0)
614     return 1;
615 
616   /* Interpret the location expressions.  */
617   // XXX For now just the simple one:
618   if (nloc == 1 && loc[0].atom == DW_OP_addr)
619     {
620       *lowpc = *highpc = loc[0].number;
621       return 0;
622     }
623 
624   return 1;
625 }
626 
627 
628 
629 static void *local_root;
630 
631 
632 static void
get_local_names(Ebl * ebl,Dwarf * dbg)633 get_local_names (Ebl *ebl, Dwarf *dbg)
634 {
635   Dwarf_Off offset = 0;
636   Dwarf_Off old_offset;
637   size_t hsize;
638 
639   while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL,
640 		       NULL) == 0)
641     {
642       Dwarf_Die cudie_mem;
643       Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
644 
645       /* If we cannot get the CU DIE there is no need to go on with
646 	 this CU.  */
647       if (cudie == NULL)
648 	continue;
649       /* This better be a CU DIE.  */
650       if (dwarf_tag (cudie) != DW_TAG_compile_unit)
651 	continue;
652 
653       /* Get the line information.  */
654       Dwarf_Files *files;
655       size_t nfiles;
656       if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
657 	continue;
658 
659       Dwarf_Die die_mem;
660       Dwarf_Die *die = &die_mem;
661       if (dwarf_child (cudie, die) == 0)
662 	/* Iterate over all immediate children of the CU DIE.  */
663 	do
664 	  {
665 	    int tag = dwarf_tag (die);
666 	    if (tag != DW_TAG_subprogram && tag != DW_TAG_variable)
667 	      continue;
668 
669 	    /* We are interested in five attributes: name, decl_file,
670 	       decl_line, low_pc, and high_pc.  */
671 	    Dwarf_Attribute attr_mem;
672 	    Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem);
673 	    const char *name = dwarf_formstring (attr);
674 	    if (name == NULL)
675 	      continue;
676 
677 	    Dwarf_Word fileidx;
678 	    attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem);
679 	    if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles)
680 	      continue;
681 
682 	    Dwarf_Word lineno;
683 	    attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem);
684 	    if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0)
685 	      continue;
686 
687 	    Dwarf_Addr lowpc;
688 	    Dwarf_Addr highpc;
689 	    if (tag == DW_TAG_subprogram)
690 	      {
691 		if (dwarf_lowpc (die, &lowpc) != 0
692 		    || dwarf_highpc (die, &highpc) != 0)
693 		  continue;
694 	      }
695 	    else
696 	      {
697 		if (get_var_range (die, &lowpc, &highpc) != 0)
698 		  continue;
699 	      }
700 
701 	    /* We have all the information.  Create a record.  */
702 	    struct local_name *newp
703 	      = (struct local_name *) xmalloc (sizeof (*newp));
704 	    newp->name = name;
705 	    newp->file = dwarf_filesrc (files, fileidx, NULL, NULL);
706 	    newp->lineno = lineno;
707 	    newp->lowpc = lowpc;
708 	    newp->highpc = highpc;
709 
710 	    /* Since we cannot deallocate individual memory we do not test
711 	       for duplicates in the tree.  This should not happen anyway.  */
712 	    if (tsearch (newp, &local_root, local_compare) == NULL)
713 	      error (EXIT_FAILURE, errno,
714 		     gettext ("cannot create search tree"));
715 	  }
716 	while (dwarf_siblingof (die, die) == 0);
717     }
718 }
719 
720 
721 /* Show symbols in SysV format.  */
722 static void
show_symbols_sysv(Ebl * ebl,GElf_Word strndx,const char * prefix,const char * fname,const char * fullname,GElf_SymX * syms,size_t nsyms,int longest_name,int longest_where)723 show_symbols_sysv (Ebl *ebl, GElf_Word strndx,
724 		   const char *prefix, const char *fname, const char *fullname,
725 		   GElf_SymX *syms, size_t nsyms, int longest_name,
726 		   int longest_where)
727 {
728   size_t shnum;
729   if (elf_getshnum (ebl->elf, &shnum) < 0)
730     INTERNAL_ERROR (fullname);
731 
732   bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024;
733   const char **scnnames;
734   if (scnnames_malloced)
735     scnnames = (const char **) xmalloc (sizeof (const char *) * shnum);
736   else
737     scnnames = (const char **) alloca (sizeof (const char *) * shnum);
738   /* Get the section header string table index.  */
739   size_t shstrndx;
740   if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
741     error (EXIT_FAILURE, 0,
742 	   gettext ("cannot get section header string table index"));
743 
744   /* Cache the section names.  */
745   Elf_Scn *scn = NULL;
746   size_t cnt = 1;
747   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
748     {
749       GElf_Shdr shdr_mem;
750 
751       assert (elf_ndxscn (scn) == cnt++);
752 
753       scnnames[elf_ndxscn (scn)]
754 	= elf_strptr (ebl->elf, shstrndx,
755 		      gelf_getshdr (scn, &shdr_mem)->sh_name);
756     }
757 
758   int digits = length_map[gelf_getclass (ebl->elf) - 1][radix];
759 
760   /* We always print this prolog.  */
761   if (prefix == NULL || 1)
762     printf (gettext ("\n\nSymbols from %s:\n\n"), fullname);
763   else
764     printf (gettext ("\n\nSymbols from %s[%s]:\n\n"), prefix, fname);
765 
766   /* The header line.  */
767   printf (gettext ("%*s%-*s %-*s Class  Type     %-*s %*s Section\n\n"),
768 	  print_file_name ? (int) strlen (fullname) + 1: 0, "",
769 	  longest_name, sgettext ("sysv|Name"),
770 	  /* TRANS: the "sysv|" parts makes the string unique.  */
771 	  digits, sgettext ("sysv|Value"),
772 	  /* TRANS: the "sysv|" parts makes the string unique.  */
773 	  digits, sgettext ("sysv|Size"),
774 	  /* TRANS: the "sysv|" parts makes the string unique.  */
775 	  longest_where, sgettext ("sysv|Line"));
776 
777   /* Which format string to use (different radix for numbers).  */
778   const char *fmtstr;
779   if (radix == radix_hex)
780     fmtstr = "%-*s|%0*" PRIx64 "|%-6s|%-8s|%*" PRIx64 "|%*s|%s\n";
781   else if (radix == radix_decimal)
782     fmtstr = "%-*s|%*" PRId64 "|%-6s|%-8s|%*" PRId64 "|%*s|%s\n";
783   else
784     fmtstr = "%-*s|%0*" PRIo64 "|%-6s|%-8s|%*" PRIo64 "|%*s|%s\n";
785 
786   /* Iterate over all symbols.  */
787   for (cnt = 0; cnt < nsyms; ++cnt)
788     {
789       const char *symstr = elf_strptr (ebl->elf, strndx,
790 				       syms[cnt].sym.st_name);
791       char symbindbuf[50];
792       char symtypebuf[50];
793       char secnamebuf[1024];
794 
795       /* If we have to precede the line with the file name.  */
796       if (print_file_name)
797 	{
798 	  fputs_unlocked (fullname, stdout);
799 	  putchar_unlocked (':');
800 	}
801 
802       /* Print the actual string.  */
803       printf (fmtstr,
804 	      longest_name, symstr,
805 	      digits, syms[cnt].sym.st_value,
806 	      ebl_symbol_binding_name (ebl,
807 				       GELF_ST_BIND (syms[cnt].sym.st_info),
808 				       symbindbuf, sizeof (symbindbuf)),
809 	      ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info),
810 				    symtypebuf, sizeof (symtypebuf)),
811 	      digits, syms[cnt].sym.st_size, longest_where, syms[cnt].where,
812 	      ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx,
813 				secnamebuf, sizeof (secnamebuf), scnnames,
814 				shnum));
815     }
816 
817   if (scnnames_malloced)
818     free (scnnames);
819 }
820 
821 
822 static char
class_type_char(GElf_Sym * sym)823 class_type_char (GElf_Sym *sym)
824 {
825   int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL;
826 
827   /* XXX Add support for architecture specific types and classes.  */
828   if (sym->st_shndx == SHN_ABS)
829     return local_p ? 'a' : 'A';
830 
831   if (sym->st_shndx == SHN_UNDEF)
832     /* Undefined symbols must be global.  */
833     return 'U';
834 
835   char result = "NDTSFB          "[GELF_ST_TYPE (sym->st_info)];
836 
837   return local_p ? tolower (result) : result;
838 }
839 
840 
841 static void
show_symbols_bsd(Elf * elf,GElf_Ehdr * ehdr,GElf_Word strndx,const char * prefix,const char * fname,const char * fullname,GElf_SymX * syms,size_t nsyms)842 show_symbols_bsd (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx,
843 		  const char *prefix, const char *fname, const char *fullname,
844 		  GElf_SymX *syms, size_t nsyms)
845 {
846   int digits = length_map[gelf_getclass (elf) - 1][radix];
847 
848   if (prefix != NULL && ! print_file_name)
849     printf ("\n%s:\n", fname);
850 
851   static const char *const fmtstrs[] =
852     {
853       [radix_hex] = "%0*" PRIx64 " %c%s %s\n",
854       [radix_decimal] = "%*" PRId64 " %c%s %s\n",
855       [radix_octal] = "%0*" PRIo64 " %c%s %s\n"
856     };
857   static const char *const sfmtstrs[] =
858     {
859       [radix_hex] = "%2$0*1$" PRIx64 " %7$0*6$" PRIx64 " %3$c%4$s %5$s\n",
860       [radix_decimal] = "%2$*1$" PRId64 " %7$*6$" PRId64 " %3$c%4$s %5$s\n",
861       [radix_octal] = "%2$0*1$" PRIo64 " %7$0*6$" PRIo64 " %3$c%4$s %5$s\n"
862     };
863 
864   /* Iterate over all symbols.  */
865   for (size_t cnt = 0; cnt < nsyms; ++cnt)
866     {
867       const char *symstr = elf_strptr (elf, strndx, syms[cnt].sym.st_name);
868 
869       /* Printing entries with a zero-length name makes the output
870 	 not very well parseable.  Since these entries don't carry
871 	 much information we leave them out.  */
872       if (symstr[0] == '\0')
873 	continue;
874 
875       /* If we have to precede the line with the file name.  */
876       if (print_file_name)
877 	{
878 	  fputs_unlocked (fullname, stdout);
879 	  putchar_unlocked (':');
880 	}
881 
882       if (syms[cnt].sym.st_shndx == SHN_UNDEF)
883 	printf ("%*s U%s %s\n",
884 		digits, "",
885 		mark_weak
886 		? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK
887 		   ? "*" : " ")
888 		: "",
889 		elf_strptr (elf, strndx, syms[cnt].sym.st_name));
890       else
891 	printf (print_size ? sfmtstrs[radix] : fmtstrs[radix],
892 		digits, syms[cnt].sym.st_value,
893 		class_type_char (&syms[cnt].sym),
894 		mark_weak
895 		? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK
896 		   ? "*" : " ")
897 		: "",
898 		elf_strptr (elf, strndx, syms[cnt].sym.st_name),
899 		digits, (uint64_t) syms[cnt].sym.st_size);
900     }
901 }
902 
903 
904 static void
show_symbols_posix(Elf * elf,GElf_Ehdr * ehdr,GElf_Word strndx,const char * prefix,const char * fname,const char * fullname,GElf_SymX * syms,size_t nsyms)905 show_symbols_posix (Elf *elf, GElf_Ehdr *ehdr, GElf_Word strndx,
906 		    const char *prefix, const char *fname,
907 		    const char *fullname, GElf_SymX *syms, size_t nsyms)
908 {
909   if (prefix != NULL && ! print_file_name)
910     printf ("%s:\n", fullname);
911 
912   const char *fmtstr;
913   if (radix == radix_hex)
914     fmtstr = "%s %c%s %0*" PRIx64 " %0*" PRIx64 "\n";
915   else if (radix == radix_decimal)
916     fmtstr = "%s %c%s %*" PRId64 " %*" PRId64 "\n";
917   else
918     fmtstr = "%s %c%s %0*" PRIo64 " %0*" PRIo64 "\n";
919 
920   int digits = length_map[gelf_getclass (elf) - 1][radix];
921 
922   /* Iterate over all symbols.  */
923   for (size_t cnt = 0; cnt < nsyms; ++cnt)
924     {
925       const char *symstr = elf_strptr (elf, strndx, syms[cnt].sym.st_name);
926 
927       /* Printing entries with a zero-length name makes the output
928 	 not very well parseable.  Since these entries don't carry
929 	 much information we leave them out.  */
930       if (symstr[0] == '\0')
931 	continue;
932 
933       /* If we have to precede the line with the file name.  */
934       if (print_file_name)
935 	{
936 	  fputs_unlocked (fullname, stdout);
937 	  putchar_unlocked (':');
938 	  putchar_unlocked (' ');
939 	}
940 
941       printf (fmtstr,
942 	      symstr,
943 	      class_type_char (&syms[cnt].sym),
944 	      mark_weak
945 	      ? (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK ? "*" : " ")
946 	      : "",
947 	      digits, syms[cnt].sym.st_value,
948 	      digits, syms[cnt].sym.st_size);
949     }
950 }
951 
952 
953 /* Maximum size of memory we allocate on the stack.  */
954 #define MAX_STACK_ALLOC	65536
955 
956 static void
show_symbols(Ebl * ebl,GElf_Ehdr * ehdr,Elf_Scn * scn,Elf_Scn * xndxscn,GElf_Shdr * shdr,const char * prefix,const char * fname,const char * fullname)957 show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn,
958 	      GElf_Shdr *shdr, const char *prefix, const char *fname,
959 	      const char *fullname)
960 {
961   int sort_by_name (const void *p1, const void *p2)
962     {
963       GElf_SymX *s1 = (GElf_SymX *) p1;
964       GElf_SymX *s2 = (GElf_SymX *) p2;
965       int result;
966 
967       result = strcmp (elf_strptr (ebl->elf, shdr->sh_link, s1->sym.st_name),
968 		       elf_strptr (ebl->elf, shdr->sh_link, s2->sym.st_name));
969 
970       return reverse_sort ? -result : result;
971     }
972 
973   int sort_by_address (const void *p1, const void *p2)
974     {
975       GElf_SymX *s1 = (GElf_SymX *) p1;
976       GElf_SymX *s2 = (GElf_SymX *) p2;
977 
978       int result = (s1->sym.st_value < s2->sym.st_value
979 		    ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1));
980 
981       return reverse_sort ? -result : result;
982     }
983 
984   /* Get the section header string table index.  */
985   size_t shstrndx;
986   if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
987     error (EXIT_FAILURE, 0,
988 	   gettext ("cannot get section header string table index"));
989 
990   /* The section is that large.  */
991   size_t size = shdr->sh_size;
992   /* One entry is this large.  */
993   size_t entsize = shdr->sh_entsize;
994 
995   /* Consistency checks.  */
996   if (entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, ehdr->e_version))
997     error (0, 0,
998 	   gettext ("%s: entry size in section `%s' is not what we expect"),
999 	   fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1000   else if (size % entsize != 0)
1001     error (0, 0,
1002 	   gettext ("%s: size of section `%s' is not multiple of entry size"),
1003 	   fullname, elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
1004 
1005   /* Compute number of entries.  Handle buggy entsize values.  */
1006   size_t nentries = size / (entsize ?: 1);
1007 
1008 
1009 #define obstack_chunk_alloc xmalloc
1010 #define obstack_chunk_free free
1011   struct obstack whereob;
1012   obstack_init (&whereob);
1013 
1014   /* Get a DWARF debugging descriptor.  It's no problem if this isn't
1015      possible.  We just won't print any line number information.  */
1016   Dwarf *dbg = NULL;
1017   if (format == format_sysv)
1018     {
1019       dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL);
1020       if (dbg != NULL)
1021 	{
1022 	  (void) dwarf_getpubnames (dbg, get_global, NULL, 0);
1023 
1024 	  get_local_names (ebl, dbg);
1025 	}
1026     }
1027 
1028   /* Allocate the memory.
1029 
1030      XXX We can use a dirty trick here.  Since GElf_Sym == Elf64_Sym we
1031      can use the data memory instead of copying again if what we read
1032      is a 64 bit file.  */
1033   GElf_SymX *sym_mem;
1034   if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC)
1035     sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX));
1036   else
1037     sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX));
1038 
1039   /* Get the data of the section.  */
1040   Elf_Data *data = elf_getdata (scn, NULL);
1041   Elf_Data *xndxdata = elf_getdata (xndxscn, NULL);
1042   if (data == NULL || (xndxscn != NULL && xndxdata == NULL))
1043     INTERNAL_ERROR (fullname);
1044 
1045   /* Iterate over all symbols.  */
1046   int longest_name = 4;
1047   int longest_where = 4;
1048   size_t nentries_used = 0;
1049   for (size_t cnt = 0; cnt < nentries; ++cnt)
1050     {
1051       GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt,
1052 					&sym_mem[nentries_used].sym,
1053 					&sym_mem[nentries_used].xndx);
1054       if (sym == NULL)
1055 	INTERNAL_ERROR (fullname);
1056 
1057       /* Filter out administrative symbols without a name and those
1058 	 deselected by ther user with command line options.  */
1059       if ((hide_undefined && sym->st_shndx == SHN_UNDEF)
1060 	  || (hide_defined && sym->st_shndx != SHN_UNDEF)
1061 	  || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL))
1062 	continue;
1063 
1064       sym_mem[nentries_used].where = "";
1065       if (format == format_sysv)
1066 	{
1067 	  const char *symstr = elf_strptr (ebl->elf, shdr->sh_link,
1068 					   sym->st_name);
1069 
1070 	  longest_name = MAX ((size_t) longest_name, strlen (symstr));
1071 
1072 	  if (sym->st_shndx != SHN_UNDEF
1073 	      && GELF_ST_BIND (sym->st_info) != STB_LOCAL
1074 	      && global_root != NULL)
1075 	    {
1076 	      Dwarf_Global fake = { .name = symstr };
1077 	      Dwarf_Global **found = tfind (&fake, &global_root,
1078 					    global_compare);
1079 	      if (found != NULL)
1080 		{
1081 		  Dwarf_Die die_mem;
1082 		  Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset,
1083 						 &die_mem);
1084 
1085 		  Dwarf_Die cudie_mem;
1086 		  Dwarf_Die *cudie = NULL;
1087 
1088 		  Dwarf_Addr lowpc;
1089 		  Dwarf_Addr highpc;
1090 		  if (die != NULL
1091 		      && dwarf_lowpc (die, &lowpc) == 0
1092 		      && lowpc <= sym->st_value
1093 		      && dwarf_highpc (die, &highpc) == 0
1094 		      && highpc > sym->st_value)
1095 		    cudie = dwarf_offdie (dbg, (*found)->cu_offset,
1096 					  &cudie_mem);
1097 		  if (cudie != NULL)
1098 		    {
1099 		      Dwarf_Line *line = dwarf_getsrc_die (cudie,
1100 							   sym->st_value);
1101 		      if (line != NULL)
1102 			{
1103 			  /* We found the line.  */
1104 			  int lineno;
1105 			  (void) dwarf_lineno (line, &lineno);
1106 			  int n;
1107 			  n = obstack_printf (&whereob, "%s:%d%c",
1108 					      basename (dwarf_linesrc (line,
1109 								       NULL,
1110 								       NULL)),
1111 					      lineno, '\0');
1112 			  sym_mem[nentries_used].where
1113 			    = obstack_finish (&whereob);
1114 
1115 			  /* The return value of obstack_print included the
1116 			     NUL byte, so subtract one.  */
1117 			  if (--n > (int) longest_where)
1118 			    longest_where = (size_t) n;
1119 			}
1120 		    }
1121 		}
1122 	    }
1123 
1124 	  /* Try to find the symol among the local symbols.  */
1125 	  if (sym_mem[nentries_used].where[0] == '\0')
1126 	    {
1127 	      struct local_name fake =
1128 		{
1129 		  .name = symstr,
1130 		  .lowpc = sym->st_value,
1131 		  .highpc = sym->st_value,
1132 		};
1133 	      struct local_name **found = tfind (&fake, &local_root,
1134 						 local_compare);
1135 	      if (found != NULL)
1136 		{
1137 		  /* We found the line.  */
1138 		  int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c",
1139 					  basename ((*found)->file),
1140 					  (*found)->lineno,
1141 					  '\0');
1142 		  sym_mem[nentries_used].where = obstack_finish (&whereob);
1143 
1144 		  /* The return value of obstack_print included the
1145 		     NUL byte, so subtract one.  */
1146 		  if (--n > (int) longest_where)
1147 		    longest_where = (size_t) n;
1148 		}
1149 	    }
1150 	}
1151 
1152       /* We use this entry.  */
1153       ++nentries_used;
1154     }
1155   /* Now we know the exact number.  */
1156   nentries = nentries_used;
1157 
1158   /* Sort the entries according to the users wishes.  */
1159   if (sort == sort_name)
1160     qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name);
1161   else if (sort == sort_numeric)
1162     qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address);
1163 
1164   /* Finally print according to the users selection.  */
1165   switch (format)
1166     {
1167     case format_sysv:
1168       show_symbols_sysv (ebl, shdr->sh_link, prefix, fname,
1169 			 fullname, sym_mem, nentries, longest_name,
1170 			 longest_where);
1171       break;
1172 
1173     case format_bsd:
1174       show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname,
1175 			fullname, sym_mem, nentries);
1176       break;
1177 
1178     case format_posix:
1179     default:
1180       assert (format == format_posix);
1181       show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fname,
1182 			  fullname, sym_mem, nentries);
1183       break;
1184     }
1185 
1186   /* Free all memory.  */
1187   if (nentries * sizeof (GElf_Sym) >= MAX_STACK_ALLOC)
1188     free (sym_mem);
1189 
1190   obstack_free (&whereob, NULL);
1191 
1192   if (dbg != NULL)
1193     {
1194       tdestroy (global_root, free);
1195       global_root = NULL;
1196 
1197       tdestroy (local_root, free);
1198       local_root = NULL;
1199 
1200       (void) dwarf_end (dbg);
1201     }
1202 }
1203 
1204 
1205 static int
handle_elf(Elf * elf,const char * prefix,const char * fname,const char * suffix)1206 handle_elf (Elf *elf, const char *prefix, const char *fname,
1207 	    const char *suffix)
1208 {
1209   size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
1210   size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
1211   size_t fname_len = strlen (fname) + 1;
1212   char fullname[prefix_len + 1 + fname_len + suffix_len];
1213   char *cp = fullname;
1214   Elf_Scn *scn = NULL;
1215   int any = 0;
1216   int result = 0;
1217   GElf_Ehdr ehdr_mem;
1218   GElf_Ehdr *ehdr;
1219   Ebl *ebl;
1220 
1221   /* Get the backend for this object file type.  */
1222   ebl = ebl_openbackend (elf);
1223 
1224   /* We need the ELF header in a few places.  */
1225   ehdr = gelf_getehdr (elf, &ehdr_mem);
1226   if (ehdr == NULL)
1227     INTERNAL_ERROR (fullname);
1228 
1229   /* If we are asked to print the dynamic symbol table and this is
1230      executable or dynamic executable, fail.  */
1231   if (symsec_type == SHT_DYNSYM
1232       && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
1233     {
1234       /* XXX Add machine specific object file types.  */
1235       error (0, 0, gettext ("%s%s%s%s: Invalid operation"),
1236 	     prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : "");
1237       result = 1;
1238       goto out;
1239     }
1240 
1241   /* Create the full name of the file.  */
1242   if (prefix != NULL)
1243     cp = mempcpy (cp, prefix, prefix_len);
1244   cp = mempcpy (cp, fname, fname_len);
1245   if (suffix != NULL)
1246     memcpy (cp - 1, suffix, suffix_len + 1);
1247 
1248   /* Find the symbol table.
1249 
1250      XXX Can there be more than one?  Do we print all?  Currently we do.  */
1251   while ((scn = elf_nextscn (elf, scn)) != NULL)
1252     {
1253       GElf_Shdr shdr_mem;
1254       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1255 
1256       if (shdr == NULL)
1257 	INTERNAL_ERROR (fullname);
1258 
1259       if (shdr->sh_type == symsec_type)
1260 	{
1261 	  Elf_Scn *xndxscn = NULL;
1262 
1263 	  /* We have a symbol table.  First make sure we remember this.  */
1264 	  any = 1;
1265 
1266 	  /* Look for an extended section index table for this section.  */
1267 	  if (symsec_type == SHT_SYMTAB)
1268 	    {
1269 	      size_t scnndx = elf_ndxscn (scn);
1270 
1271 	      while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
1272 		{
1273 		  GElf_Shdr xndxshdr_mem;
1274 		  GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
1275 
1276 		  if (xndxshdr == NULL)
1277 		    INTERNAL_ERROR (fullname);
1278 
1279 		  if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX
1280 		      && xndxshdr->sh_link == scnndx)
1281 		    break;
1282 		}
1283 	    }
1284 
1285 	  show_symbols (ebl, ehdr, scn, xndxscn, shdr, prefix, fname,
1286 			fullname);
1287 	}
1288     }
1289 
1290   if (! any)
1291     {
1292       error (0, 0, gettext ("%s%s%s: no symbols"),
1293 	     prefix ?: "", prefix ? ":" : "", fname);
1294       result = 1;
1295     }
1296 
1297  out:
1298   /* Close the ELF backend library descriptor.  */
1299   ebl_closebackend (ebl);
1300 
1301   return result;
1302 }
1303