blob: 8302a98c442e724ba3b204f1f4dddfc935881fa2 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Print symbol information from ELF file in human-readable form.
Mark Wielaard587c4b32015-04-14 11:59:36 +02002 Copyright (C) 2000-2008, 2009, 2011, 2012, 2014, 2015 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
Mark Wielaardde2ed972012-06-05 17:15:16 +02006 This file is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000010
Mark Wielaardde2ed972012-06-05 17:15:16 +020011 elfutils is distributed in the hope that it will be useful, but
Ulrich Drepper361df7d2006-04-04 21:38:57 +000012 WITHOUT ANY WARRANTY; without even the implied warranty of
Mark Wielaardde2ed972012-06-05 17:15:16 +020013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
Ulrich Drepper361df7d2006-04-04 21:38:57 +000015
Mark Wielaardde2ed972012-06-05 17:15:16 +020016 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000018
19#ifdef HAVE_CONFIG_H
20# include <config.h>
21#endif
22
23#include <ar.h>
24#include <argp.h>
25#include <assert.h>
26#include <ctype.h>
27#include <dwarf.h>
28#include <errno.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000029#include <fcntl.h>
30#include <gelf.h>
31#include <inttypes.h>
32#include <libdw.h>
33#include <libintl.h>
34#include <locale.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000035#include <obstack.h>
36#include <search.h>
37#include <stdbool.h>
38#include <stdio.h>
39#include <stdio_ext.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000043
Akihiko Odaki60b2bf12016-10-11 23:06:48 +090044#include <libeu.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000045#include <system.h>
Ulf Hermann29173842017-02-14 14:30:47 +010046#include <color.h>
Ulf Hermanne22cc802017-02-16 12:32:02 +010047#include <printversion.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000048#include "../libebl/libeblP.h"
Mark Wielaard70cd9072015-12-02 16:57:44 +010049#include "../libdwfl/libdwflP.h"
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000050
51
52/* Name and version of program. */
Ulrich Drepperfdc93e12009-01-17 11:47:10 -080053ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000054
55/* Bug report address. */
Ulrich Drepperfdc93e12009-01-17 11:47:10 -080056ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000057
58
59/* Values for the parameters which have no short form. */
Ulrich Drepper2356ba02011-10-03 07:23:07 -040060#define OPT_DEFINED 0x100
61#define OPT_MARK_SPECIAL 0x101
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000062
63/* Definitions of arguments for argp functions. */
64static const struct argp_option options[] =
65{
66 { NULL, 0, NULL, 0, N_("Output selection:"), 0 },
67 { "debug-syms", 'a', NULL, 0, N_("Display debugger-only symbols"), 0 },
68 { "defined-only", OPT_DEFINED, NULL, 0, N_("Display only defined symbols"),
69 0 },
70 { "dynamic", 'D', NULL, 0,
71 N_("Display dynamic symbols instead of normal symbols"), 0 },
72 { "extern-only", 'g', NULL, 0, N_("Display only external symbols"), 0 },
73 { "undefined-only", 'u', NULL, 0, N_("Display only undefined symbols"), 0 },
74 { "print-armap", 's', NULL, 0,
75 N_("Include index for symbols from archive members"), 0 },
76
77 { NULL, 0, NULL, 0, N_("Output format:"), 0 },
78 { "print-file-name", 'A', NULL, 0,
79 N_("Print name of the input file before every symbol"), 0 },
80 { NULL, 'o', NULL, OPTION_HIDDEN, "Same as -A", 0 },
81 { "format", 'f', "FORMAT", 0,
82 N_("Use the output format FORMAT. FORMAT can be `bsd', `sysv' or `posix'. The default is `sysv'"),
83 0 },
84 { NULL, 'B', NULL, 0, N_("Same as --format=bsd"), 0 },
85 { "portability", 'P', NULL, 0, N_("Same as --format=posix"), 0 },
86 { "radix", 't', "RADIX", 0, N_("Use RADIX for printing symbol values"), 0 },
Ulrich Drepper2356ba02011-10-03 07:23:07 -040087 { "mark-special", OPT_MARK_SPECIAL, NULL, 0, N_("Mark special symbols"), 0 },
88 { "mark-weak", OPT_MARK_SPECIAL, NULL, OPTION_HIDDEN, "", 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000089 { "print-size", 'S', NULL, 0, N_("Print size of defined symbols"), 0 },
90
91 { NULL, 0, NULL, 0, N_("Output options:"), 0 },
92 { "numeric-sort", 'n', NULL, 0, N_("Sort symbols numerically by address"),
93 0 },
94 { "no-sort", 'p', NULL, 0, N_("Do not sort the symbols"), 0 },
95 { "reverse-sort", 'r', NULL, 0, N_("Reverse the sense of the sort"), 0 },
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -040096#ifdef USE_DEMANGLE
97 { "demangle", 'C', NULL, 0,
98 N_("Decode low-level symbol names into source code names"), 0 },
99#endif
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000100 { NULL, 0, NULL, 0, N_("Miscellaneous:"), 0 },
101 { NULL, 0, NULL, 0, NULL, 0 }
102};
103
104/* Short description of program. */
105static const char doc[] = N_("List symbols from FILEs (a.out by default).");
106
107/* Strings for arguments in help texts. */
108static const char args_doc[] = N_("[FILE...]");
109
110/* Prototype for option handler. */
111static error_t parse_opt (int key, char *arg, struct argp_state *state);
112
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500113/* Parser children. */
114static struct argp_child argp_children[] =
115 {
116 { &color_argp, 0, N_("Output formatting"), 2 },
117 { NULL, 0, NULL, 0}
118 };
119
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000120/* Data structure to communicate with argp functions. */
121static struct argp argp =
122{
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500123 options, parse_opt, args_doc, doc, argp_children, NULL, NULL
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000124};
125
126
127/* Print symbols in file named FNAME. */
128static int process_file (const char *fname, bool more_than_one);
129
130/* Handle content of archive. */
131static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
132 const char *suffix);
133
134/* Handle ELF file. */
Mark Wielaard70cd9072015-12-02 16:57:44 +0100135static int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000136 const char *suffix);
137
138
139#define INTERNAL_ERROR(fname) \
Mark Wielaard587c4b32015-04-14 11:59:36 +0200140 error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"), \
141 fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000142
143
144/* Internal representation of symbols. */
145typedef struct GElf_SymX
146{
147 GElf_Sym sym;
148 Elf32_Word xndx;
149 char *where;
150} GElf_SymX;
151
152
153/* User-selectable options. */
154
155/* The selected output format. */
156static enum
157{
158 format_sysv = 0,
159 format_bsd,
160 format_posix
161} format;
162
163/* Print defined, undefined, or both? */
164static bool hide_undefined;
165static bool hide_defined;
166
167/* Print local symbols also? */
168static bool hide_local;
169
170/* Nonzero if full filename should precede every symbol. */
171static bool print_file_name;
172
173/* If true print size of defined symbols in BSD format. */
174static bool print_size;
175
176/* If true print archive index. */
177static bool print_armap;
178
179/* If true reverse sorting. */
180static bool reverse_sort;
181
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400182#ifdef USE_DEMANGLE
183/* If true demangle symbols. */
184static bool demangle;
185#endif
186
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000187/* Type of the section we are printing. */
188static GElf_Word symsec_type = SHT_SYMTAB;
189
190/* Sorting selection. */
191static enum
192{
193 sort_name = 0,
194 sort_numeric,
195 sort_nosort
196} sort;
197
198/* Radix for printed numbers. */
199static enum
200{
201 radix_hex = 0,
202 radix_decimal,
203 radix_octal
204} radix;
205
Ulrich Drepper2356ba02011-10-03 07:23:07 -0400206/* If nonzero mark special symbols:
207 - weak symbols are distinguished from global symbols by adding
208 a `*' after the identifying letter for the symbol class and type.
209 - TLS symbols are distinguished from normal symbols by adding
210 a '@' after the identifying letter for the symbol class and type. */
211static bool mark_special;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000212
213
214int
215main (int argc, char *argv[])
216{
217 int remaining;
218 int result = 0;
219
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000220 /* We use no threads here which can interfere with handling a stream. */
221 (void) __fsetlocking (stdin, FSETLOCKING_BYCALLER);
222 (void) __fsetlocking (stdout, FSETLOCKING_BYCALLER);
223 (void) __fsetlocking (stderr, FSETLOCKING_BYCALLER);
224
225 /* Set locale. */
226 (void) setlocale (LC_ALL, "");
227
228 /* Make sure the message catalog can be found. */
Ulrich Drepperb0243862007-06-06 00:09:36 +0000229 (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000230
231 /* Initialize the message catalog. */
Ulrich Drepperb0243862007-06-06 00:09:36 +0000232 (void) textdomain (PACKAGE_TARNAME);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000233
234 /* Parse and process arguments. */
235 (void) argp_parse (&argp, argc, argv, 0, &remaining, NULL);
236
237 /* Tell the library which version we are expecting. */
238 (void) elf_version (EV_CURRENT);
239
240 if (remaining == argc)
241 /* The user didn't specify a name so we use a.out. */
242 result = process_file ("a.out", false);
243 else
244 {
245 /* Process all the remaining files. */
246 const bool more_than_one = remaining + 1 < argc;
247
248 do
249 result |= process_file (argv[remaining], more_than_one);
250 while (++remaining < argc);
251 }
252
253 return result;
254}
255
256
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000257/* Handle program arguments. */
258static error_t
259parse_opt (int key, char *arg,
260 struct argp_state *state __attribute__ ((unused)))
261{
262 switch (key)
263 {
264 case 'a':
265 /* XXX */
266 break;
267
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400268#ifdef USE_DEMANGLE
269 case 'C':
270 demangle = true;
271 break;
272#endif
273
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000274 case 'f':
275 if (strcmp (arg, "bsd") == 0)
276 format = format_bsd;
277 else if (strcmp (arg, "posix") == 0)
278 format = format_posix;
279 else
280 /* Be bug compatible. The BFD implementation also defaulted to
281 using the SysV format if nothing else matches. */
282 format = format_sysv;
283 break;
284
285 case 'g':
286 hide_local = true;
287 break;
288
289 case 'n':
290 sort = sort_numeric;
291 break;
292
293 case 'p':
294 sort = sort_nosort;
295 break;
296
297 case 't':
298 if (strcmp (arg, "10") == 0 || strcmp (arg, "d") == 0)
299 radix = radix_decimal;
300 else if (strcmp (arg, "8") == 0 || strcmp (arg, "o") == 0)
301 radix = radix_octal;
302 else
303 radix = radix_hex;
304 break;
305
306 case 'u':
307 hide_undefined = false;
308 hide_defined = true;
309 break;
310
311 case 'A':
312 case 'o':
313 print_file_name = true;
314 break;
315
316 case 'B':
317 format = format_bsd;
318 break;
319
320 case 'D':
321 symsec_type = SHT_DYNSYM;
322 break;
323
324 case 'P':
325 format = format_posix;
326 break;
327
328 case OPT_DEFINED:
329 hide_undefined = true;
330 hide_defined = false;
331 break;
332
Ulrich Drepper2356ba02011-10-03 07:23:07 -0400333 case OPT_MARK_SPECIAL:
334 mark_special = true;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000335 break;
336
337 case 'S':
338 print_size = true;
339 break;
340
341 case 's':
342 print_armap = true;
343 break;
344
345 case 'r':
346 reverse_sort = true;
347 break;
348
349 default:
350 return ARGP_ERR_UNKNOWN;
351 }
352 return 0;
353}
354
355
356/* Open the file and determine the type. */
357static int
358process_file (const char *fname, bool more_than_one)
359{
360 /* Open the file. */
361 int fd = open (fname, O_RDONLY);
362 if (fd == -1)
363 {
364 error (0, errno, gettext ("cannot open '%s'"), fname);
365 return 1;
366 }
367
368 /* Now get the ELF descriptor. */
369 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
370 if (elf != NULL)
371 {
372 if (elf_kind (elf) == ELF_K_ELF)
373 {
Mark Wielaard70cd9072015-12-02 16:57:44 +0100374 int result = handle_elf (fd, elf, more_than_one ? "" : NULL,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000375 fname, NULL);
376
377 if (elf_end (elf) != 0)
378 INTERNAL_ERROR (fname);
379
380 if (close (fd) != 0)
Ulrich Drepperd112ef82005-09-03 21:31:27 +0000381 error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000382
383 return result;
384 }
385 else if (elf_kind (elf) == ELF_K_AR)
386 {
387 int result = handle_ar (fd, elf, NULL, fname, NULL);
388
389 if (elf_end (elf) != 0)
390 INTERNAL_ERROR (fname);
391
392 if (close (fd) != 0)
Ulrich Drepperd112ef82005-09-03 21:31:27 +0000393 error (EXIT_FAILURE, errno, gettext ("while closing '%s'"), fname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000394
395 return result;
396 }
397
398 /* We cannot handle this type. Close the descriptor anyway. */
399 if (elf_end (elf) != 0)
400 INTERNAL_ERROR (fname);
401 }
402
403 error (0, 0, gettext ("%s: File format not recognized"), fname);
404
405 return 1;
406}
407
408
409static int
410handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
411 const char *suffix)
412{
413 size_t fname_len = strlen (fname) + 1;
414 size_t prefix_len = prefix != NULL ? strlen (prefix) : 0;
415 char new_prefix[prefix_len + fname_len + 2];
416 size_t suffix_len = suffix != NULL ? strlen (suffix) : 0;
417 char new_suffix[suffix_len + 2];
418 Elf *subelf;
419 Elf_Cmd cmd = ELF_C_READ_MMAP;
420 int result = 0;
421
422 char *cp = new_prefix;
423 if (prefix != NULL)
424 cp = stpcpy (cp, prefix);
425 cp = stpcpy (cp, fname);
426 stpcpy (cp, "[");
427
428 cp = new_suffix;
429 if (suffix != NULL)
430 cp = stpcpy (cp, suffix);
431 stpcpy (cp, "]");
432
433 /* First print the archive index if this is wanted. */
434 if (print_armap)
435 {
436 Elf_Arsym *arsym = elf_getarsym (elf, NULL);
437
438 if (arsym != NULL)
439 {
440 Elf_Arhdr *arhdr = NULL;
441 size_t arhdr_off = 0; /* Note: 0 is no valid offset. */
442
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500443 fputs_unlocked (gettext("\nArchive index:\n"), stdout);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000444
445 while (arsym->as_off != 0)
446 {
447 if (arhdr_off != arsym->as_off
448 && (elf_rand (elf, arsym->as_off) != arsym->as_off
449 || (subelf = elf_begin (fd, cmd, elf)) == NULL
450 || (arhdr = elf_getarhdr (subelf)) == NULL))
451 {
452 error (0, 0, gettext ("invalid offset %zu for symbol %s"),
453 arsym->as_off, arsym->as_name);
Mark Wielaard0b799ad2014-12-26 16:12:52 +0100454 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000455 }
456
457 printf (gettext ("%s in %s\n"), arsym->as_name, arhdr->ar_name);
458
459 ++arsym;
460 }
461
462 if (elf_rand (elf, SARMAG) != SARMAG)
463 {
464 error (0, 0,
465 gettext ("cannot reset archive offset to beginning"));
466 return 1;
467 }
468 }
469 }
470
471 /* Process all the files contained in the archive. */
472 while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
473 {
474 /* The the header for this element. */
475 Elf_Arhdr *arhdr = elf_getarhdr (subelf);
476
477 /* Skip over the index entries. */
478 if (strcmp (arhdr->ar_name, "/") != 0
Mark Wielaard8fb260f2014-12-26 16:20:39 +0100479 && strcmp (arhdr->ar_name, "//") != 0
480 && strcmp (arhdr->ar_name, "/SYM64/") != 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000481 {
482 if (elf_kind (subelf) == ELF_K_ELF)
Mark Wielaard70cd9072015-12-02 16:57:44 +0100483 result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000484 new_suffix);
485 else if (elf_kind (subelf) == ELF_K_AR)
486 result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name,
487 new_suffix);
488 else
489 {
490 error (0, 0, gettext ("%s%s%s: file format not recognized"),
491 new_prefix, arhdr->ar_name, new_suffix);
492 result = 1;
493 }
494 }
495
496 /* Get next archive element. */
497 cmd = elf_next (subelf);
498 if (elf_end (subelf) != 0)
499 INTERNAL_ERROR (fname);
500 }
501
502 return result;
503}
504
505
506/* Mapping of radix and binary class to length. */
507static const int length_map[2][3] =
508{
509 [ELFCLASS32 - 1] =
510 {
511 [radix_hex] = 8,
512 [radix_decimal] = 10,
513 [radix_octal] = 11
514 },
515 [ELFCLASS64 - 1] =
516 {
517 [radix_hex] = 16,
518 [radix_decimal] = 20,
519 [radix_octal] = 22
520 }
521};
522
523
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000524static int
525global_compare (const void *p1, const void *p2)
526{
527 const Dwarf_Global *g1 = (const Dwarf_Global *) p1;
528 const Dwarf_Global *g2 = (const Dwarf_Global *) p2;
529
530 return strcmp (g1->name, g2->name);
531}
532
533
534static void *global_root;
535
536
537static int
538get_global (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
539 void *arg __attribute__ ((unused)))
540{
541 tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global,
542 sizeof (Dwarf_Global)),
543 &global_root, global_compare);
544
545 return DWARF_CB_OK;
546}
547
548
549struct local_name
550{
551 const char *name;
552 const char *file;
553 Dwarf_Word lineno;
554 Dwarf_Addr lowpc;
555 Dwarf_Addr highpc;
556};
557
558
559static int
560local_compare (const void *p1, const void *p2)
561{
562 struct local_name *g1 = (struct local_name *) p1;
563 struct local_name *g2 = (struct local_name *) p2;
564 int result;
565
566 result = strcmp (g1->name, g2->name);
567 if (result == 0)
568 {
569 if (g1->lowpc <= g2->lowpc && g1->highpc >= g2->highpc)
570 {
571 /* g2 is contained in g1. Update the data. */
572 g2->lowpc = g1->lowpc;
573 g2->highpc = g1->highpc;
574 result = 0;
575 }
576 else if (g2->lowpc <= g1->lowpc && g2->highpc >= g1->highpc)
577 {
578 /* g1 is contained in g2. Update the data. */
579 g1->lowpc = g2->lowpc;
580 g1->highpc = g2->highpc;
581 result = 0;
582 }
583 else
584 result = g1->lowpc < g2->lowpc ? -1 : 1;
585 }
586
587 return result;
588}
589
590
591static int
592get_var_range (Dwarf_Die *die, Dwarf_Word *lowpc, Dwarf_Word *highpc)
593{
594 Dwarf_Attribute locattr_mem;
595 Dwarf_Attribute *locattr = dwarf_attr (die, DW_AT_location, &locattr_mem);
596 if (locattr == NULL)
597 return 1;
598
Roland McGrath6724c902005-10-28 07:07:19 +0000599 Dwarf_Op *loc;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000600 size_t nloc;
Roland McGrath6724c902005-10-28 07:07:19 +0000601 if (dwarf_getlocation (locattr, &loc, &nloc) != 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000602 return 1;
603
604 /* Interpret the location expressions. */
605 // XXX For now just the simple one:
606 if (nloc == 1 && loc[0].atom == DW_OP_addr)
607 {
608 *lowpc = *highpc = loc[0].number;
609 return 0;
610 }
611
612 return 1;
613}
614
615
616
617static void *local_root;
618
619
620static void
621get_local_names (Dwarf *dbg)
622{
623 Dwarf_Off offset = 0;
624 Dwarf_Off old_offset;
625 size_t hsize;
626
627 while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL,
628 NULL) == 0)
629 {
630 Dwarf_Die cudie_mem;
631 Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
632
633 /* If we cannot get the CU DIE there is no need to go on with
634 this CU. */
635 if (cudie == NULL)
636 continue;
637 /* This better be a CU DIE. */
638 if (dwarf_tag (cudie) != DW_TAG_compile_unit)
639 continue;
640
641 /* Get the line information. */
642 Dwarf_Files *files;
643 size_t nfiles;
644 if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
645 continue;
646
647 Dwarf_Die die_mem;
648 Dwarf_Die *die = &die_mem;
649 if (dwarf_child (cudie, die) == 0)
650 /* Iterate over all immediate children of the CU DIE. */
651 do
652 {
653 int tag = dwarf_tag (die);
654 if (tag != DW_TAG_subprogram && tag != DW_TAG_variable)
655 continue;
656
657 /* We are interested in five attributes: name, decl_file,
658 decl_line, low_pc, and high_pc. */
659 Dwarf_Attribute attr_mem;
660 Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_name, &attr_mem);
661 const char *name = dwarf_formstring (attr);
662 if (name == NULL)
663 continue;
664
665 Dwarf_Word fileidx;
666 attr = dwarf_attr (die, DW_AT_decl_file, &attr_mem);
667 if (dwarf_formudata (attr, &fileidx) != 0 || fileidx >= nfiles)
668 continue;
669
670 Dwarf_Word lineno;
671 attr = dwarf_attr (die, DW_AT_decl_line, &attr_mem);
672 if (dwarf_formudata (attr, &lineno) != 0 || lineno == 0)
673 continue;
674
675 Dwarf_Addr lowpc;
676 Dwarf_Addr highpc;
677 if (tag == DW_TAG_subprogram)
678 {
679 if (dwarf_lowpc (die, &lowpc) != 0
680 || dwarf_highpc (die, &highpc) != 0)
681 continue;
682 }
683 else
684 {
685 if (get_var_range (die, &lowpc, &highpc) != 0)
686 continue;
687 }
688
689 /* We have all the information. Create a record. */
690 struct local_name *newp
691 = (struct local_name *) xmalloc (sizeof (*newp));
692 newp->name = name;
693 newp->file = dwarf_filesrc (files, fileidx, NULL, NULL);
694 newp->lineno = lineno;
695 newp->lowpc = lowpc;
696 newp->highpc = highpc;
697
Mark Wielaard3fbd8572015-12-02 16:44:42 +0100698 /* Check whether a similar local_name is already in the
699 cache. That should not happen. But if it does, we
700 don't want to leak memory. */
701 struct local_name **tres = tsearch (newp, &local_root,
702 local_compare);
703 if (tres == NULL)
704 error (EXIT_FAILURE, errno,
705 gettext ("cannot create search tree"));
706 else if (*tres != newp)
707 free (newp);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000708 }
709 while (dwarf_siblingof (die, die) == 0);
710 }
711}
712
Roland McGrath468fe4d2008-12-11 21:00:12 -0800713/* Do elf_strptr, but return a backup string and never NULL. */
714static const char *
715sym_name (Elf *elf, GElf_Word strndx, GElf_Word st_name, char buf[], size_t n)
716{
717 const char *symstr = elf_strptr (elf, strndx, st_name);
718 if (symstr == NULL)
719 {
720 snprintf (buf, n, "[invalid st_name %#" PRIx32 "]", st_name);
721 symstr = buf;
722 }
723 return symstr;
724}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000725
726/* Show symbols in SysV format. */
727static void
Marek Polacekc8920de2011-05-12 12:08:21 +0200728show_symbols_sysv (Ebl *ebl, GElf_Word strndx, const char *fullname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000729 GElf_SymX *syms, size_t nsyms, int longest_name,
730 int longest_where)
731{
732 size_t shnum;
Ulrich Drepperf1894932009-06-13 15:55:42 -0700733 if (elf_getshdrnum (ebl->elf, &shnum) < 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000734 INTERNAL_ERROR (fullname);
735
736 bool scnnames_malloced = shnum * sizeof (const char *) > 128 * 1024;
737 const char **scnnames;
738 if (scnnames_malloced)
739 scnnames = (const char **) xmalloc (sizeof (const char *) * shnum);
740 else
741 scnnames = (const char **) alloca (sizeof (const char *) * shnum);
742 /* Get the section header string table index. */
743 size_t shstrndx;
Ulrich Drepperf1894932009-06-13 15:55:42 -0700744 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000745 error (EXIT_FAILURE, 0,
746 gettext ("cannot get section header string table index"));
747
748 /* Cache the section names. */
749 Elf_Scn *scn = NULL;
750 size_t cnt = 1;
751 while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
752 {
753 GElf_Shdr shdr_mem;
Mark Wielaard207d8ec2019-04-28 17:51:06 +0200754 GElf_Shdr *shdr;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000755
Mark Wielaard03d76f42013-11-09 16:45:22 +0100756 assert (elf_ndxscn (scn) == cnt);
757 cnt++;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000758
Mark Wielaard207d8ec2019-04-28 17:51:06 +0200759 char *name = NULL;
760 shdr = gelf_getshdr (scn, &shdr_mem);
761 if (shdr != NULL)
762 name = elf_strptr (ebl->elf, shstrndx, shdr->sh_name);
Roland McGrath468fe4d2008-12-11 21:00:12 -0800763 if (unlikely (name == NULL))
Mark Wielaard207d8ec2019-04-28 17:51:06 +0200764 name = "[invalid section name]";
Roland McGrath468fe4d2008-12-11 21:00:12 -0800765 scnnames[elf_ndxscn (scn)] = name;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000766 }
767
768 int digits = length_map[gelf_getclass (ebl->elf) - 1][radix];
769
770 /* We always print this prolog. */
Marek Polacekc8920de2011-05-12 12:08:21 +0200771 printf (gettext ("\n\nSymbols from %s:\n\n"), fullname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000772
773 /* The header line. */
774 printf (gettext ("%*s%-*s %-*s Class Type %-*s %*s Section\n\n"),
775 print_file_name ? (int) strlen (fullname) + 1: 0, "",
776 longest_name, sgettext ("sysv|Name"),
777 /* TRANS: the "sysv|" parts makes the string unique. */
778 digits, sgettext ("sysv|Value"),
779 /* TRANS: the "sysv|" parts makes the string unique. */
780 digits, sgettext ("sysv|Size"),
781 /* TRANS: the "sysv|" parts makes the string unique. */
782 longest_where, sgettext ("sysv|Line"));
783
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400784#ifdef USE_DEMANGLE
785 size_t demangle_buffer_len = 0;
786 char *demangle_buffer = NULL;
787#endif
788
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000789 /* Iterate over all symbols. */
Mark Wielaard62e3c372020-01-16 23:33:52 +0100790 for (cnt = 0; cnt < nsyms; ++cnt)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000791 {
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400792 /* In this format SECTION entries are not printed. */
793 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_SECTION)
794 continue;
795
Roland McGrath468fe4d2008-12-11 21:00:12 -0800796 char symstrbuf[50];
797 const char *symstr = sym_name (ebl->elf, strndx, syms[cnt].sym.st_name,
798 symstrbuf, sizeof symstrbuf);
799
Mark Wielaard76ff94d2020-06-07 01:02:52 +0200800 /* Printing entries with a zero-length name makes the output
801 not very well parseable. Since these entries don't carry
802 much information we leave them out. */
803 if (symstr[0] == '\0')
804 continue;
805
806 /* We do not print the entries for files. */
807 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
808 continue;
809
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400810#ifdef USE_DEMANGLE
Jan Kratochvil7c6e7852014-01-15 21:16:57 +0100811 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
812 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400813 {
814 int status = -1;
815 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
816 &demangle_buffer_len, &status);
817
818 if (status == 0)
819 symstr = dmsymstr;
820 }
821#endif
822
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000823 char symbindbuf[50];
824 char symtypebuf[50];
825 char secnamebuf[1024];
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400826 char addressbuf[(64 + 2) / 3 + 1];
827 char sizebuf[(64 + 2) / 3 + 1];
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000828
829 /* If we have to precede the line with the file name. */
830 if (print_file_name)
831 {
832 fputs_unlocked (fullname, stdout);
833 putchar_unlocked (':');
834 }
835
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400836 /* Covert the address. */
837 if (syms[cnt].sym.st_shndx == SHN_UNDEF)
Mark Wielaard76ff94d2020-06-07 01:02:52 +0200838 {
839 sprintf (addressbuf, "%*c", digits, ' ');
840 sprintf (sizebuf, "%*c", digits, ' ');
841 }
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400842 else
843 {
Mark Wielaardf48eb6b2014-01-23 00:56:41 +0100844 snprintf (addressbuf, sizeof (addressbuf),
845 (radix == radix_hex ? "%0*" PRIx64
846 : (radix == radix_decimal ? "%0*" PRId64
847 : "%0*" PRIo64)),
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400848 digits, syms[cnt].sym.st_value);
Mark Wielaardf48eb6b2014-01-23 00:56:41 +0100849 snprintf (sizebuf, sizeof (sizebuf),
850 (radix == radix_hex ? "%0*" PRIx64
851 : (radix == radix_decimal ? "%0*" PRId64
852 : "%0*" PRIo64)),
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400853 digits, syms[cnt].sym.st_size);
854 }
855
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000856 /* Print the actual string. */
Mark Wielaard76ff94d2020-06-07 01:02:52 +0200857 const char *bind;
858 bind = ebl_symbol_binding_name (ebl,
859 GELF_ST_BIND (syms[cnt].sym.st_info),
860 symbindbuf, sizeof (symbindbuf));
861 if (bind != NULL && strncmp (bind, "GNU_", strlen ("GNU_")) == 0)
862 bind += strlen ("GNU_");
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400863 printf ("%-*s|%s|%-6s|%-8s|%s|%*s|%s\n",
Mark Wielaard76ff94d2020-06-07 01:02:52 +0200864 longest_name, symstr, addressbuf, bind,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000865 ebl_symbol_type_name (ebl, GELF_ST_TYPE (syms[cnt].sym.st_info),
866 symtypebuf, sizeof (symtypebuf)),
Ulrich Drepper66f4c372011-10-03 15:53:12 -0400867 sizebuf, longest_where, syms[cnt].where,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000868 ebl_section_name (ebl, syms[cnt].sym.st_shndx, syms[cnt].xndx,
869 secnamebuf, sizeof (secnamebuf), scnnames,
870 shnum));
871 }
872
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400873#ifdef USE_DEMANGLE
874 free (demangle_buffer);
875#endif
876
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000877 if (scnnames_malloced)
878 free (scnnames);
879}
880
881
882static char
Ulrich Drepper2356ba02011-10-03 07:23:07 -0400883class_type_char (Elf *elf, const GElf_Ehdr *ehdr, GElf_Sym *sym)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000884{
885 int local_p = GELF_ST_BIND (sym->st_info) == STB_LOCAL;
886
887 /* XXX Add support for architecture specific types and classes. */
888 if (sym->st_shndx == SHN_ABS)
889 return local_p ? 'a' : 'A';
890
891 if (sym->st_shndx == SHN_UNDEF)
892 /* Undefined symbols must be global. */
893 return 'U';
894
Ulrich Drepper2356ba02011-10-03 07:23:07 -0400895 char result = "NDTSFBD "[GELF_ST_TYPE (sym->st_info)];
896
897 if (result == 'D')
898 {
899 /* Special handling: unique data symbols. */
900 if (ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX
901 && GELF_ST_BIND (sym->st_info) == STB_GNU_UNIQUE)
902 result = 'u';
Mark Wielaard76ff94d2020-06-07 01:02:52 +0200903 else if (GELF_ST_BIND (sym->st_info) == STB_WEAK)
904 result = 'V';
905 else if (sym->st_shndx == SHN_COMMON)
906 result = 'C';
Ulrich Drepper2356ba02011-10-03 07:23:07 -0400907 else
908 {
909 GElf_Shdr shdr_mem;
910 GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, sym->st_shndx),
911 &shdr_mem);
912 if (shdr != NULL)
913 {
914 if ((shdr->sh_flags & SHF_WRITE) == 0)
915 result = 'R';
916 else if (shdr->sh_type == SHT_NOBITS)
917 result = 'B';
918 }
919 }
920 }
Mark Wielaard76ff94d2020-06-07 01:02:52 +0200921 else if (result == 'T')
922 {
923 if (GELF_ST_BIND (sym->st_info) == STB_WEAK)
924 result = 'W';
925 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000926
927 return local_p ? tolower (result) : result;
928}
929
930
931static void
Ulrich Drepper2356ba02011-10-03 07:23:07 -0400932show_symbols_bsd (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000933 const char *prefix, const char *fname, const char *fullname,
934 GElf_SymX *syms, size_t nsyms)
935{
936 int digits = length_map[gelf_getclass (elf) - 1][radix];
937
938 if (prefix != NULL && ! print_file_name)
939 printf ("\n%s:\n", fname);
940
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400941#ifdef USE_DEMANGLE
942 size_t demangle_buffer_len = 0;
943 char *demangle_buffer = NULL;
944#endif
945
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000946 /* Iterate over all symbols. */
947 for (size_t cnt = 0; cnt < nsyms; ++cnt)
948 {
Roland McGrath468fe4d2008-12-11 21:00:12 -0800949 char symstrbuf[50];
950 const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name,
951 symstrbuf, sizeof symstrbuf);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000952
953 /* Printing entries with a zero-length name makes the output
954 not very well parseable. Since these entries don't carry
955 much information we leave them out. */
956 if (symstr[0] == '\0')
957 continue;
958
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500959 /* We do not print the entries for files. */
960 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
961 continue;
962
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400963#ifdef USE_DEMANGLE
Jan Kratochvil7c6e7852014-01-15 21:16:57 +0100964 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
965 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -0400966 {
967 int status = -1;
968 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
969 &demangle_buffer_len, &status);
970
971 if (status == 0)
972 symstr = dmsymstr;
973 }
974#endif
975
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000976 /* If we have to precede the line with the file name. */
977 if (print_file_name)
978 {
979 fputs_unlocked (fullname, stdout);
980 putchar_unlocked (':');
981 }
982
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500983 bool is_tls = GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS;
984 bool is_weak = GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK;
985 const char *marker = (mark_special
986 ? (is_tls ? "@" : (is_weak ? "*" : " ")) : "");
987
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000988 if (syms[cnt].sym.st_shndx == SHN_UNDEF)
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -0500989 {
990 const char *color = "";
991 if (color_mode)
992 {
993 if (is_tls)
994 color = color_undef_tls;
995 else if (is_weak)
996 color = color_undef_weak;
997 else
998 color = color_undef;
999 }
1000
1001 printf ("%*s %sU%s %s", digits, "", color, marker, symstr);
1002 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001003 else
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001004 {
1005 const char *color = "";
1006 if (color_mode)
1007 {
1008 if (is_tls)
1009 color = color_tls;
1010 else if (is_weak)
1011 color = color_weak;
1012 else
1013 color = color_symbol;
1014 }
Mark Wielaardf48eb6b2014-01-23 00:56:41 +01001015 if (print_size && syms[cnt].sym.st_size != 0)
1016 {
1017#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %10$0*9$" PRIx64 " %7$s%3$c%4$s %5$s"
1018#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %10$*9$" PRId64 " %7$s%3$c%4$s %5$s"
1019#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %10$0*9$" PRIo64 " %7$s%3$c%4$s %5$s"
1020 printf ((radix == radix_hex ? HEXFMT
1021 : (radix == radix_decimal ? DECFMT : OCTFMT)),
1022 digits, syms[cnt].sym.st_value,
1023 class_type_char (elf, ehdr, &syms[cnt].sym), marker,
1024 symstr,
1025 color_mode ? color_address : "",
1026 color,
1027 color_mode ? color_off : "",
1028 digits, (uint64_t) syms[cnt].sym.st_size);
1029#undef HEXFMT
1030#undef DECFMT
1031#undef OCTFMT
1032 }
1033 else
1034 {
1035#define HEXFMT "%6$s%2$0*1$" PRIx64 "%8$s %7$s%3$c%4$s %5$s"
1036#define DECFMT "%6$s%2$*1$" PRId64 "%8$s %7$s%3$c%4$s %5$s"
1037#define OCTFMT "%6$s%2$0*1$" PRIo64 "%8$s %7$s%3$c%4$s %5$s"
1038 printf ((radix == radix_hex ? HEXFMT
1039 : (radix == radix_decimal ? DECFMT : OCTFMT)),
1040 digits, syms[cnt].sym.st_value,
1041 class_type_char (elf, ehdr, &syms[cnt].sym), marker,
1042 symstr,
1043 color_mode ? color_address : "",
1044 color,
1045 color_mode ? color_off : "");
1046#undef HEXFMT
1047#undef DECFMT
1048#undef OCTFMT
1049 }
Ulrich Drepperc6b3d0c2012-01-21 18:14:39 -05001050 }
1051
1052 if (color_mode)
1053 fputs_unlocked (color_off, stdout);
1054 putchar_unlocked ('\n');
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001055 }
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001056
1057#ifdef USE_DEMANGLE
1058 free (demangle_buffer);
1059#endif
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001060}
1061
1062
1063static void
Ulrich Drepper2356ba02011-10-03 07:23:07 -04001064show_symbols_posix (Elf *elf, const GElf_Ehdr *ehdr, GElf_Word strndx,
1065 const char *prefix, const char *fullname, GElf_SymX *syms,
1066 size_t nsyms)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001067{
1068 if (prefix != NULL && ! print_file_name)
1069 printf ("%s:\n", fullname);
1070
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001071 int digits = length_map[gelf_getclass (elf) - 1][radix];
1072
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001073#ifdef USE_DEMANGLE
1074 size_t demangle_buffer_len = 0;
1075 char *demangle_buffer = NULL;
1076#endif
1077
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001078 /* Iterate over all symbols. */
1079 for (size_t cnt = 0; cnt < nsyms; ++cnt)
1080 {
Roland McGrath468fe4d2008-12-11 21:00:12 -08001081 char symstrbuf[50];
1082 const char *symstr = sym_name (elf, strndx, syms[cnt].sym.st_name,
1083 symstrbuf, sizeof symstrbuf);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001084
1085 /* Printing entries with a zero-length name makes the output
1086 not very well parseable. Since these entries don't carry
1087 much information we leave them out. */
1088 if (symstr[0] == '\0')
1089 continue;
1090
Mark Wielaard76ff94d2020-06-07 01:02:52 +02001091 /* We do not print the entries for files. */
1092 if (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_FILE)
1093 continue;
1094
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001095#ifdef USE_DEMANGLE
Jan Kratochvil7c6e7852014-01-15 21:16:57 +01001096 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
1097 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001098 {
1099 int status = -1;
1100 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
1101 &demangle_buffer_len, &status);
1102
1103 if (status == 0)
1104 symstr = dmsymstr;
1105 }
1106#endif
1107
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001108 /* If we have to precede the line with the file name. */
1109 if (print_file_name)
1110 {
1111 fputs_unlocked (fullname, stdout);
1112 putchar_unlocked (':');
1113 putchar_unlocked (' ');
1114 }
1115
Mark Wielaard76ff94d2020-06-07 01:02:52 +02001116 printf ("%s %c%s", symstr,
Ulrich Drepper2356ba02011-10-03 07:23:07 -04001117 class_type_char (elf, ehdr, &syms[cnt].sym),
1118 mark_special
1119 ? (GELF_ST_TYPE (syms[cnt].sym.st_info) == STT_TLS
1120 ? "@"
1121 : (GELF_ST_BIND (syms[cnt].sym.st_info) == STB_WEAK
1122 ? "*" : " "))
Mark Wielaard76ff94d2020-06-07 01:02:52 +02001123 : "");
1124 if (syms[cnt].sym.st_shndx != SHN_UNDEF)
1125 printf ((radix == radix_hex
1126 ? " %0*" PRIx64 " %0*" PRIx64
1127 : (radix == radix_decimal
1128 ? " %*" PRId64 " %*" PRId64
1129 : " %0*" PRIo64 " %0*" PRIo64)),
1130 digits, syms[cnt].sym.st_value,
1131 digits, syms[cnt].sym.st_size);
1132 putchar ('\n');
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001133 }
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001134
1135#ifdef USE_DEMANGLE
1136 free (demangle_buffer);
1137#endif
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001138}
1139
1140
1141/* Maximum size of memory we allocate on the stack. */
1142#define MAX_STACK_ALLOC 65536
1143
Roland McGrathcb6d8652007-08-23 08:10:54 +00001144static int
1145sort_by_address (const void *p1, const void *p2)
1146{
1147 GElf_SymX *s1 = (GElf_SymX *) p1;
1148 GElf_SymX *s2 = (GElf_SymX *) p2;
1149
1150 int result = (s1->sym.st_value < s2->sym.st_value
1151 ? -1 : (s1->sym.st_value == s2->sym.st_value ? 0 : 1));
1152
1153 return reverse_sort ? -result : result;
1154}
1155
1156static Elf_Data *sort_by_name_strtab;
1157
1158static int
1159sort_by_name (const void *p1, const void *p2)
1160{
1161 GElf_SymX *s1 = (GElf_SymX *) p1;
1162 GElf_SymX *s2 = (GElf_SymX *) p2;
1163
1164 const char *n1 = sort_by_name_strtab->d_buf + s1->sym.st_name;
1165 const char *n2 = sort_by_name_strtab->d_buf + s2->sym.st_name;
1166
1167 int result = strcmp (n1, n2);
1168
1169 return reverse_sort ? -result : result;
1170}
1171
Mark Wielaard70cd9072015-12-02 16:57:44 +01001172/* Stub libdwfl callback, only the ELF handle already open is ever
1173 used. Only used for finding the alternate debug file if the Dwarf
1174 comes from the main file. We are not interested in separate
1175 debuginfo. */
1176static int
1177find_no_debuginfo (Dwfl_Module *mod,
1178 void **userdata,
1179 const char *modname,
1180 Dwarf_Addr base,
1181 const char *file_name,
1182 const char *debuglink_file,
1183 GElf_Word debuglink_crc,
1184 char **debuginfo_file_name)
1185{
1186 Dwarf_Addr dwbias;
1187 dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL);
1188
1189 /* We are only interested if the Dwarf has been setup on the main
1190 elf file but is only missing the alternate debug link. If dwbias
1191 hasn't even been setup, this is searching for separate debuginfo
1192 for the main elf. We don't care in that case. */
1193 if (dwbias == (Dwarf_Addr) -1)
1194 return -1;
1195
1196 return dwfl_standard_find_debuginfo (mod, userdata, modname, base,
1197 file_name, debuglink_file,
1198 debuglink_crc, debuginfo_file_name);
1199}
1200
1201/* Get the Dwarf for the module/file we want. */
1202struct getdbg
1203{
1204 const char *name;
1205 Dwarf **dbg;
1206};
1207
1208static int
1209getdbg_dwflmod (Dwfl_Module *dwflmod,
1210 void **userdata __attribute__ ((unused)),
1211 const char *name,
1212 Dwarf_Addr base __attribute__ ((unused)),
1213 void *arg)
1214{
1215 struct getdbg *get = (struct getdbg *) arg;
1216 if (get != NULL && get->name != NULL && strcmp (get->name, name) == 0)
1217 {
1218 Dwarf_Addr bias;
1219 *get->dbg = dwfl_module_getdwarf (dwflmod, &bias);
1220 return DWARF_CB_ABORT;
1221 }
1222
1223 return DWARF_CB_OK;
1224}
1225
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001226static void
Mark Wielaard70cd9072015-12-02 16:57:44 +01001227show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr,
1228 Elf_Scn *scn, Elf_Scn *xndxscn,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001229 GElf_Shdr *shdr, const char *prefix, const char *fname,
1230 const char *fullname)
1231{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001232 /* Get the section header string table index. */
1233 size_t shstrndx;
Ulrich Drepperf1894932009-06-13 15:55:42 -07001234 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001235 error (EXIT_FAILURE, 0,
1236 gettext ("cannot get section header string table index"));
1237
1238 /* The section is that large. */
1239 size_t size = shdr->sh_size;
1240 /* One entry is this large. */
1241 size_t entsize = shdr->sh_entsize;
1242
1243 /* Consistency checks. */
Mark Wielaard309e7122014-12-26 19:36:31 +01001244 if (entsize == 0
Mark Wielaarda2b964c2015-05-08 17:56:32 +02001245 || entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001246 error (0, 0,
Mark Wielaard309e7122014-12-26 19:36:31 +01001247 gettext ("%s: entry size in section %zd `%s' is not what we expect"),
1248 fullname, elf_ndxscn (scn),
1249 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001250 else if (size % entsize != 0)
1251 error (0, 0,
Mark Wielaard309e7122014-12-26 19:36:31 +01001252 gettext ("%s: size of section %zd `%s' is not multiple of entry size"),
1253 fullname, elf_ndxscn (scn),
1254 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001255
1256 /* Compute number of entries. Handle buggy entsize values. */
1257 size_t nentries = size / (entsize ?: 1);
1258
1259
1260#define obstack_chunk_alloc xmalloc
1261#define obstack_chunk_free free
1262 struct obstack whereob;
1263 obstack_init (&whereob);
1264
1265 /* Get a DWARF debugging descriptor. It's no problem if this isn't
1266 possible. We just won't print any line number information. */
1267 Dwarf *dbg = NULL;
Mark Wielaard70cd9072015-12-02 16:57:44 +01001268 Dwfl *dwfl = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001269 if (format == format_sysv)
1270 {
Mark Wielaard70cd9072015-12-02 16:57:44 +01001271 if (ehdr->e_type != ET_REL)
1272 dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL);
1273 else
1274 {
1275 /* Abuse libdwfl to do the relocations for us. This is just
1276 for the ET_REL file containing Dwarf, so no need for
1277 fancy lookups. */
1278
1279 /* Duplicate an fd for dwfl_report_offline to swallow. */
1280 int dwfl_fd = dup (fd);
1281 if (likely (dwfl_fd >= 0))
1282 {
1283 static const Dwfl_Callbacks callbacks =
1284 {
1285 .section_address = dwfl_offline_section_address,
1286 .find_debuginfo = find_no_debuginfo
1287 };
1288 dwfl = dwfl_begin (&callbacks);
1289 if (likely (dwfl != NULL))
1290 {
1291 /* Let 0 be the logical address of the file (or
1292 first in archive). */
1293 dwfl->offline_next_address = 0;
1294 if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd)
1295 == NULL)
1296 {
1297 /* Consumed on success, not on failure. */
1298 close (dwfl_fd);
1299 }
1300 else
1301 {
1302 dwfl_report_end (dwfl, NULL, NULL);
1303
1304 struct getdbg get = { .name = fname, .dbg = &dbg };
1305 dwfl_getmodules (dwfl, &getdbg_dwflmod, &get, 0);
1306 }
1307 }
1308 }
1309 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001310 if (dbg != NULL)
1311 {
1312 (void) dwarf_getpubnames (dbg, get_global, NULL, 0);
1313
1314 get_local_names (dbg);
1315 }
1316 }
1317
Mark Wielaardc08079a2015-06-27 22:07:01 +02001318 /* Get the data of the section. */
1319 Elf_Data *data = elf_getdata (scn, NULL);
1320 Elf_Data *xndxdata = elf_getdata (xndxscn, NULL);
1321 if (data == NULL || (xndxscn != NULL && xndxdata == NULL))
1322 INTERNAL_ERROR (fullname);
1323
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001324 /* Allocate the memory.
1325
1326 XXX We can use a dirty trick here. Since GElf_Sym == Elf64_Sym we
1327 can use the data memory instead of copying again if what we read
1328 is a 64 bit file. */
Mark Wielaard911f11a2016-03-21 16:01:02 +01001329 if (nentries > SIZE_MAX / sizeof (GElf_SymX))
1330 error (EXIT_FAILURE, 0,
1331 gettext ("%s: entries (%zd) in section %zd `%s' is too large"),
1332 fullname, nentries, elf_ndxscn (scn),
1333 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001334 GElf_SymX *sym_mem;
1335 if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC)
1336 sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX));
1337 else
1338 sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX));
1339
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001340 /* Iterate over all symbols. */
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001341#ifdef USE_DEMANGLE
1342 size_t demangle_buffer_len = 0;
1343 char *demangle_buffer = NULL;
1344#endif
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001345 int longest_name = 4;
1346 int longest_where = 4;
1347 size_t nentries_used = 0;
1348 for (size_t cnt = 0; cnt < nentries; ++cnt)
1349 {
1350 GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt,
1351 &sym_mem[nentries_used].sym,
1352 &sym_mem[nentries_used].xndx);
1353 if (sym == NULL)
1354 INTERNAL_ERROR (fullname);
1355
1356 /* Filter out administrative symbols without a name and those
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001357 deselected by the user with command line options. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001358 if ((hide_undefined && sym->st_shndx == SHN_UNDEF)
1359 || (hide_defined && sym->st_shndx != SHN_UNDEF)
1360 || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL))
1361 continue;
1362
1363 sym_mem[nentries_used].where = "";
1364 if (format == format_sysv)
1365 {
1366 const char *symstr = elf_strptr (ebl->elf, shdr->sh_link,
1367 sym->st_name);
Roland McGrath468fe4d2008-12-11 21:00:12 -08001368 if (symstr == NULL)
1369 continue;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001370
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001371#ifdef USE_DEMANGLE
Jan Kratochvil7c6e7852014-01-15 21:16:57 +01001372 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
1373 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001374 {
1375 int status = -1;
1376 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
1377 &demangle_buffer_len, &status);
1378
1379 if (status == 0)
1380 symstr = dmsymstr;
1381 }
1382#endif
1383
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001384 longest_name = MAX ((size_t) longest_name, strlen (symstr));
1385
1386 if (sym->st_shndx != SHN_UNDEF
1387 && GELF_ST_BIND (sym->st_info) != STB_LOCAL
1388 && global_root != NULL)
1389 {
1390 Dwarf_Global fake = { .name = symstr };
1391 Dwarf_Global **found = tfind (&fake, &global_root,
1392 global_compare);
1393 if (found != NULL)
1394 {
1395 Dwarf_Die die_mem;
1396 Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset,
1397 &die_mem);
1398
1399 Dwarf_Die cudie_mem;
1400 Dwarf_Die *cudie = NULL;
1401
1402 Dwarf_Addr lowpc;
1403 Dwarf_Addr highpc;
1404 if (die != NULL
1405 && dwarf_lowpc (die, &lowpc) == 0
1406 && lowpc <= sym->st_value
1407 && dwarf_highpc (die, &highpc) == 0
1408 && highpc > sym->st_value)
1409 cudie = dwarf_offdie (dbg, (*found)->cu_offset,
1410 &cudie_mem);
1411 if (cudie != NULL)
1412 {
1413 Dwarf_Line *line = dwarf_getsrc_die (cudie,
1414 sym->st_value);
1415 if (line != NULL)
1416 {
1417 /* We found the line. */
1418 int lineno;
1419 (void) dwarf_lineno (line, &lineno);
Mark Wielaarda3344c72015-05-06 12:45:49 +02001420 const char *file = dwarf_linesrc (line, NULL, NULL);
1421 file = (file != NULL) ? basename (file) : "???";
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001422 int n;
Mark Wielaarda3344c72015-05-06 12:45:49 +02001423 n = obstack_printf (&whereob, "%s:%d%c", file,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001424 lineno, '\0');
1425 sym_mem[nentries_used].where
1426 = obstack_finish (&whereob);
1427
1428 /* The return value of obstack_print included the
1429 NUL byte, so subtract one. */
1430 if (--n > (int) longest_where)
1431 longest_where = (size_t) n;
1432 }
1433 }
1434 }
1435 }
1436
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001437 /* Try to find the symbol among the local symbols. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001438 if (sym_mem[nentries_used].where[0] == '\0')
1439 {
1440 struct local_name fake =
1441 {
1442 .name = symstr,
1443 .lowpc = sym->st_value,
1444 .highpc = sym->st_value,
1445 };
1446 struct local_name **found = tfind (&fake, &local_root,
1447 local_compare);
1448 if (found != NULL)
1449 {
1450 /* We found the line. */
1451 int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c",
1452 basename ((*found)->file),
1453 (*found)->lineno,
1454 '\0');
1455 sym_mem[nentries_used].where = obstack_finish (&whereob);
1456
1457 /* The return value of obstack_print included the
1458 NUL byte, so subtract one. */
1459 if (--n > (int) longest_where)
1460 longest_where = (size_t) n;
1461 }
1462 }
1463 }
1464
1465 /* We use this entry. */
1466 ++nentries_used;
1467 }
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001468#ifdef USE_DEMANGLE
1469 free (demangle_buffer);
1470#endif
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001471 /* Now we know the exact number. */
Mark Wielaarddf332852019-08-29 17:46:52 +02001472 size_t nentries_orig = nentries;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001473 nentries = nentries_used;
1474
1475 /* Sort the entries according to the users wishes. */
1476 if (sort == sort_name)
Roland McGrathcb6d8652007-08-23 08:10:54 +00001477 {
1478 sort_by_name_strtab = elf_getdata (elf_getscn (ebl->elf, shdr->sh_link),
1479 NULL);
1480 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name);
1481 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001482 else if (sort == sort_numeric)
1483 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address);
1484
1485 /* Finally print according to the users selection. */
1486 switch (format)
1487 {
1488 case format_sysv:
Marek Polacekc8920de2011-05-12 12:08:21 +02001489 show_symbols_sysv (ebl, shdr->sh_link, fullname, sym_mem, nentries,
1490 longest_name, longest_where);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001491 break;
1492
1493 case format_bsd:
Ulrich Drepper2356ba02011-10-03 07:23:07 -04001494 show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname, fullname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001495 sym_mem, nentries);
1496 break;
1497
1498 case format_posix:
1499 default:
1500 assert (format == format_posix);
Ulrich Drepper2356ba02011-10-03 07:23:07 -04001501 show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fullname,
1502 sym_mem, nentries);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001503 break;
1504 }
1505
1506 /* Free all memory. */
Mark Wielaarddf332852019-08-29 17:46:52 +02001507 if (nentries_orig * sizeof (sym_mem[0]) >= MAX_STACK_ALLOC)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001508 free (sym_mem);
1509
1510 obstack_free (&whereob, NULL);
1511
1512 if (dbg != NULL)
1513 {
1514 tdestroy (global_root, free);
1515 global_root = NULL;
1516
1517 tdestroy (local_root, free);
1518 local_root = NULL;
1519
Mark Wielaard70cd9072015-12-02 16:57:44 +01001520 if (dwfl == NULL)
1521 (void) dwarf_end (dbg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001522 }
Mark Wielaard70cd9072015-12-02 16:57:44 +01001523 if (dwfl != NULL)
1524 dwfl_end (dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001525}
1526
1527
1528static int
Mark Wielaard70cd9072015-12-02 16:57:44 +01001529handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001530 const char *suffix)
1531{
1532 size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
1533 size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
1534 size_t fname_len = strlen (fname) + 1;
1535 char fullname[prefix_len + 1 + fname_len + suffix_len];
1536 char *cp = fullname;
1537 Elf_Scn *scn = NULL;
1538 int any = 0;
1539 int result = 0;
1540 GElf_Ehdr ehdr_mem;
1541 GElf_Ehdr *ehdr;
1542 Ebl *ebl;
1543
Mark Wielaard5d769dd2020-05-09 21:05:31 +02001544 /* Create the full name of the file. */
1545 if (prefix != NULL)
1546 cp = mempcpy (cp, prefix, prefix_len);
1547 cp = mempcpy (cp, fname, fname_len);
1548 if (suffix != NULL)
1549 memcpy (cp - 1, suffix, suffix_len + 1);
1550
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001551 /* Get the backend for this object file type. */
1552 ebl = ebl_openbackend (elf);
Mark Wielaard5d769dd2020-05-09 21:05:31 +02001553 if (ebl == NULL)
1554 INTERNAL_ERROR (fullname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001555
1556 /* We need the ELF header in a few places. */
1557 ehdr = gelf_getehdr (elf, &ehdr_mem);
1558 if (ehdr == NULL)
1559 INTERNAL_ERROR (fullname);
1560
1561 /* If we are asked to print the dynamic symbol table and this is
1562 executable or dynamic executable, fail. */
1563 if (symsec_type == SHT_DYNSYM
1564 && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
1565 {
1566 /* XXX Add machine specific object file types. */
1567 error (0, 0, gettext ("%s%s%s%s: Invalid operation"),
1568 prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : "");
1569 result = 1;
1570 goto out;
1571 }
1572
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001573 /* Find the symbol table.
1574
1575 XXX Can there be more than one? Do we print all? Currently we do. */
1576 while ((scn = elf_nextscn (elf, scn)) != NULL)
1577 {
1578 GElf_Shdr shdr_mem;
1579 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1580
1581 if (shdr == NULL)
1582 INTERNAL_ERROR (fullname);
1583
1584 if (shdr->sh_type == symsec_type)
1585 {
1586 Elf_Scn *xndxscn = NULL;
1587
1588 /* We have a symbol table. First make sure we remember this. */
1589 any = 1;
1590
1591 /* Look for an extended section index table for this section. */
1592 if (symsec_type == SHT_SYMTAB)
1593 {
1594 size_t scnndx = elf_ndxscn (scn);
1595
1596 while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
1597 {
1598 GElf_Shdr xndxshdr_mem;
1599 GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
1600
1601 if (xndxshdr == NULL)
1602 INTERNAL_ERROR (fullname);
1603
1604 if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX
1605 && xndxshdr->sh_link == scnndx)
1606 break;
1607 }
1608 }
1609
Mark Wielaard70cd9072015-12-02 16:57:44 +01001610 show_symbols (fd, ebl, ehdr, scn, xndxscn, shdr, prefix, fname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001611 fullname);
1612 }
1613 }
1614
1615 if (! any)
1616 {
1617 error (0, 0, gettext ("%s%s%s: no symbols"),
1618 prefix ?: "", prefix ? ":" : "", fname);
1619 result = 1;
1620 }
1621
1622 out:
1623 /* Close the ELF backend library descriptor. */
1624 ebl_closebackend (ebl);
1625
1626 return result;
1627}
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001628
1629
1630#include "debugpred.h"