blob: 1a2970541cb0197567e154f49d837ed866e68ae1 [file] [log] [blame]
The Android Open Source Project441f72d2009-03-03 19:29:28 -08001/* 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}