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.  */
48static void print_version (FILE *stream, struct argp_state *state);
49void (*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.  */
57static 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.  */
93static const char doc[] = N_("List symbols from FILEs (a.out by default).");
94
95/* Strings for arguments in help texts.  */
96static const char args_doc[] = N_("[FILE...]");
97
98/* Prototype for option handler.  */
99static error_t parse_opt (int key, char *arg, struct argp_state *state);
100
101/* Function to print some extra text in the help message.  */
102static char *more_help (int key, const char *text, void *input);
103
104/* Data structure to communicate with argp functions.  */
105static 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.  */
112static int process_file (const char *fname, bool more_than_one);
113
114/* Handle content of archive.  */
115static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
116		      const char *suffix);
117
118/* Handle ELF file.  */
119static 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.  */
129typedef 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.  */
140static enum
141{
142  format_sysv = 0,
143  format_bsd,
144  format_posix
145} format;
146
147/* Print defined, undefined, or both?  */
148static bool hide_undefined;
149static bool hide_defined;
150
151/* Print local symbols also?  */
152static bool hide_local;
153
154/* Nonzero if full filename should precede every symbol.  */
155static bool print_file_name;
156
157/* If true print size of defined symbols in BSD format.  */
158static bool print_size;
159
160/* If true print archive index.  */
161static bool print_armap;
162
163/* If true reverse sorting.  */
164static bool reverse_sort;
165
166/* Type of the section we are printing.  */
167static GElf_Word symsec_type = SHT_SYMTAB;
168
169/* Sorting selection.  */
170static enum
171{
172  sort_name = 0,
173  sort_numeric,
174  sort_nosort
175} sort;
176
177/* Radix for printed numbers.  */
178static 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.  */
187static bool mark_weak;
188
189
190int
191main (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.  */
237static void
238print_version (FILE *stream, /*@unused@*/ struct argp_state *state)
239{
240  fprintf (stream, "nm (%s) %s\n", PACKAGE_NAME, VERSION);
241  fprintf (stream, gettext ("\
242Copyright (C) %s Red Hat, Inc.\n\
243This is free software; see the source for copying conditions.  There is NO\n\
244warranty; 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.  */
251static error_t
252parse_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
342static char *
343more_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.  */
364static int
365process_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
416static int
417handle_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.  */
513static 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
530struct global_name
531{
532  Dwarf_Global global;
533  const char *name;
534};
535
536
537static int
538global_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
547static void *global_root;
548
549
550static int
551get_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
561struct 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
571static int
572local_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
603static int
604get_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
629static void *local_root;
630
631
632static void
633get_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.  */
722static void
723show_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
822static char
823class_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
841static void
842show_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
904static void
905show_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
956static void
957show_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
1205static int
1206handle_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