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. */
60 static void print_version (FILE *stream, struct argp_state *state);
61 void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
62
63 /* Bug report address. */
64 const 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. */
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-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. */
108 static const char doc[] = N_("List symbols from FILEs (a.out by default).");
109
110 /* Strings for arguments in help texts. */
111 static const char args_doc[] = N_("[FILE...]");
112
113 /* Prototype for option handler. */
114 static error_t parse_opt (int key, char *arg, struct argp_state *state);
115
116 /* Data structure to communicate with argp functions. */
117 static struct argp argp =
118 {
119 options, parse_opt, args_doc, doc, NULL, NULL, NULL
120 };
121
122
123 /* Print symbols in file named FNAME. */
124 static int process_file (const char *fname, bool more_than_one);
125
126 /* Handle content of archive. */
127 static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
128 const char *suffix);
129
130 /* Handle ELF file. */
131 static 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. */
141 typedef 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. */
152 static enum
153 {
154 format_sysv = 0,
155 format_bsd,
156 format_posix
157 } format;
158
159 /* Print defined, undefined, or both? */
160 static bool hide_undefined;
161 static bool hide_defined;
162
163 /* Print local symbols also? */
164 static bool hide_local;
165
166 /* Nonzero if full filename should precede every symbol. */
167 static bool print_file_name;
168
169 /* If true print size of defined symbols in BSD format. */
170 static bool print_size;
171
172 /* If true print archive index. */
173 static bool print_armap;
174
175 /* If true reverse sorting. */
176 static bool reverse_sort;
177
178 /* Type of the section we are printing. */
179 static GElf_Word symsec_type = SHT_SYMTAB;
180
181 /* Sorting selection. */
182 static enum
183 {
184 sort_name = 0,
185 sort_numeric,
186 sort_nosort
187 } sort;
188
189 /* Radix for printed numbers. */
190 static 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. */
199 static bool mark_weak;
200
201
202 int
main(int argc,char * argv[])203 main (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. */
249 static void
print_version(FILE * stream,struct argp_state * state)250 print_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 ("\
254 Copyright (C) %s Red Hat, Inc.\n\
255 This is free software; see the source for copying conditions. There is NO\n\
256 warranty; 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. */
263 static error_t
parse_opt(int key,char * arg,struct argp_state * state)264 parse_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. */
356 static int
process_file(const char * fname,bool more_than_one)357 process_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
408 static int
handle_ar(int fd,Elf * elf,const char * prefix,const char * fname,const char * suffix)409 handle_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. */
505 static 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
522 static int
global_compare(const void * p1,const void * p2)523 global_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
532 static void *global_root;
533
534
535 static int
get_global(Dwarf * dbg,Dwarf_Global * global,void * arg)536 get_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
547 struct 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
557 static int
local_compare(const void * p1,const void * p2)558 local_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
589 static int
get_var_range(Dwarf_Die * die,Dwarf_Word * lowpc,Dwarf_Word * highpc)590 get_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
615 static void *local_root;
616
617
618 static void
get_local_names(Dwarf * dbg)619 get_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. */
707 static const char *
sym_name(Elf * elf,GElf_Word strndx,GElf_Word st_name,char buf[],size_t n)708 sym_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. */
720 static void
show_symbols_sysv(Ebl * ebl,GElf_Word strndx,const char * prefix,const char * fname,const char * fullname,GElf_SymX * syms,size_t nsyms,int longest_name,int longest_where)721 show_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
828 static char
class_type_char(GElf_Sym * sym)829 class_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
847 static void
show_symbols_bsd(Elf * elf,GElf_Word strndx,const char * prefix,const char * fname,const char * fullname,GElf_SymX * syms,size_t nsyms)848 show_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
912 static void
show_symbols_posix(Elf * elf,GElf_Word strndx,const char * prefix,const char * fullname,GElf_SymX * syms,size_t nsyms)913 show_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
965 static int
sort_by_address(const void * p1,const void * p2)966 sort_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
977 static Elf_Data *sort_by_name_strtab;
978
979 static int
sort_by_name(const void * p1,const void * p2)980 sort_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
993 static void
show_symbols(Ebl * ebl,GElf_Ehdr * ehdr,Elf_Scn * scn,Elf_Scn * xndxscn,GElf_Shdr * shdr,const char * prefix,const char * fname,const char * fullname)994 show_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
1225 static int
handle_elf(Elf * elf,const char * prefix,const char * fname,const char * suffix)1226 handle_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