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