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