blob: fb761ef3d8631176a678fd3d8c4dc86a6af762e3 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Print symbol information from ELF file in human-readable form.
Mark Wielaard815fe152020-06-07 16:13:13 +02002 Copyright (C) 2000-2008, 2009, 2011, 2012, 2014, 2015, 2020 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) \
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000140 error (EXIT_FAILURE, 0, _("%s: INTERNAL ERROR %d (%s): %s"), \
Mark Wielaard587c4b32015-04-14 11:59:36 +0200141 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 {
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000364 error (0, errno, _("cannot open '%s'"), fname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000365 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)
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000381 error (EXIT_FAILURE, errno, _("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)
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000393 error (EXIT_FAILURE, errno, _("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
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000403 error (0, 0, _("%s: File format not recognized"), fname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000404
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
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000443 fputs_unlocked (_("\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 {
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000452 error (0, 0, _("invalid offset %zu for symbol %s"),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000453 arsym->as_off, arsym->as_name);
Mark Wielaard0b799ad2014-12-26 16:12:52 +0100454 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000455 }
456
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000457 printf (_("%s in %s\n"), arsym->as_name, arhdr->ar_name);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000458
459 ++arsym;
460 }
461
462 if (elf_rand (elf, SARMAG) != SARMAG)
463 {
464 error (0, 0,
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000465 _("cannot reset archive offset to beginning"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000466 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 {
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000490 error (0, 0, _("%s%s%s: file format not recognized"),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000491 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,
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000705 _("cannot create search tree"));
Mark Wielaard3fbd8572015-12-02 16:44:42 +0100706 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,
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000746 _("cannot get section header string table index"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000747
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. */
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000771 printf (_("\n\nSymbols from %s:\n\n"), fullname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000772
773 /* The header line. */
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +0000774 printf (_("%*s%-*s %-*s Class Type %-*s %*s Section\n\n"),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000775 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
Mark Wielaard815fe152020-06-07 16:13:13 +02001156static Elf *sort_by_name_elf;
1157static size_t sort_by_name_ndx;
Roland McGrathcb6d8652007-08-23 08:10:54 +00001158
1159static int
1160sort_by_name (const void *p1, const void *p2)
1161{
1162 GElf_SymX *s1 = (GElf_SymX *) p1;
1163 GElf_SymX *s2 = (GElf_SymX *) p2;
1164
Mark Wielaard815fe152020-06-07 16:13:13 +02001165 const char *n1 = elf_strptr (sort_by_name_elf, sort_by_name_ndx,
1166 s1->sym.st_name) ?: "";
1167 const char *n2 = elf_strptr (sort_by_name_elf, sort_by_name_ndx,
1168 s2->sym.st_name) ?: "";
Roland McGrathcb6d8652007-08-23 08:10:54 +00001169
1170 int result = strcmp (n1, n2);
1171
1172 return reverse_sort ? -result : result;
1173}
1174
Mark Wielaard70cd9072015-12-02 16:57:44 +01001175/* Stub libdwfl callback, only the ELF handle already open is ever
1176 used. Only used for finding the alternate debug file if the Dwarf
1177 comes from the main file. We are not interested in separate
1178 debuginfo. */
1179static int
1180find_no_debuginfo (Dwfl_Module *mod,
1181 void **userdata,
1182 const char *modname,
1183 Dwarf_Addr base,
1184 const char *file_name,
1185 const char *debuglink_file,
1186 GElf_Word debuglink_crc,
1187 char **debuginfo_file_name)
1188{
1189 Dwarf_Addr dwbias;
1190 dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL);
1191
1192 /* We are only interested if the Dwarf has been setup on the main
1193 elf file but is only missing the alternate debug link. If dwbias
1194 hasn't even been setup, this is searching for separate debuginfo
1195 for the main elf. We don't care in that case. */
1196 if (dwbias == (Dwarf_Addr) -1)
1197 return -1;
1198
1199 return dwfl_standard_find_debuginfo (mod, userdata, modname, base,
1200 file_name, debuglink_file,
1201 debuglink_crc, debuginfo_file_name);
1202}
1203
1204/* Get the Dwarf for the module/file we want. */
1205struct getdbg
1206{
1207 const char *name;
1208 Dwarf **dbg;
1209};
1210
1211static int
1212getdbg_dwflmod (Dwfl_Module *dwflmod,
1213 void **userdata __attribute__ ((unused)),
1214 const char *name,
1215 Dwarf_Addr base __attribute__ ((unused)),
1216 void *arg)
1217{
1218 struct getdbg *get = (struct getdbg *) arg;
1219 if (get != NULL && get->name != NULL && strcmp (get->name, name) == 0)
1220 {
1221 Dwarf_Addr bias;
1222 *get->dbg = dwfl_module_getdwarf (dwflmod, &bias);
1223 return DWARF_CB_ABORT;
1224 }
1225
1226 return DWARF_CB_OK;
1227}
1228
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001229static void
Mark Wielaard70cd9072015-12-02 16:57:44 +01001230show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr,
1231 Elf_Scn *scn, Elf_Scn *xndxscn,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001232 GElf_Shdr *shdr, const char *prefix, const char *fname,
1233 const char *fullname)
1234{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001235 /* Get the section header string table index. */
1236 size_t shstrndx;
Ulrich Drepperf1894932009-06-13 15:55:42 -07001237 if (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001238 error (EXIT_FAILURE, 0,
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +00001239 _("cannot get section header string table index"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001240
1241 /* The section is that large. */
1242 size_t size = shdr->sh_size;
1243 /* One entry is this large. */
1244 size_t entsize = shdr->sh_entsize;
1245
1246 /* Consistency checks. */
Mark Wielaard309e7122014-12-26 19:36:31 +01001247 if (entsize == 0
Mark Wielaarda2b964c2015-05-08 17:56:32 +02001248 || entsize != gelf_fsize (ebl->elf, ELF_T_SYM, 1, EV_CURRENT))
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001249 error (0, 0,
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +00001250 _("%s: entry size in section %zd `%s' is not what we expect"),
Mark Wielaard309e7122014-12-26 19:36:31 +01001251 fullname, elf_ndxscn (scn),
1252 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001253 else if (size % entsize != 0)
1254 error (0, 0,
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +00001255 _("%s: size of section %zd `%s' is not multiple of entry size"),
Mark Wielaard309e7122014-12-26 19:36:31 +01001256 fullname, elf_ndxscn (scn),
1257 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001258
1259 /* Compute number of entries. Handle buggy entsize values. */
1260 size_t nentries = size / (entsize ?: 1);
1261
1262
1263#define obstack_chunk_alloc xmalloc
1264#define obstack_chunk_free free
1265 struct obstack whereob;
1266 obstack_init (&whereob);
1267
1268 /* Get a DWARF debugging descriptor. It's no problem if this isn't
1269 possible. We just won't print any line number information. */
1270 Dwarf *dbg = NULL;
Mark Wielaard70cd9072015-12-02 16:57:44 +01001271 Dwfl *dwfl = NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001272 if (format == format_sysv)
1273 {
Mark Wielaard70cd9072015-12-02 16:57:44 +01001274 if (ehdr->e_type != ET_REL)
1275 dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL);
1276 else
1277 {
1278 /* Abuse libdwfl to do the relocations for us. This is just
1279 for the ET_REL file containing Dwarf, so no need for
1280 fancy lookups. */
1281
1282 /* Duplicate an fd for dwfl_report_offline to swallow. */
1283 int dwfl_fd = dup (fd);
1284 if (likely (dwfl_fd >= 0))
1285 {
1286 static const Dwfl_Callbacks callbacks =
1287 {
1288 .section_address = dwfl_offline_section_address,
1289 .find_debuginfo = find_no_debuginfo
1290 };
1291 dwfl = dwfl_begin (&callbacks);
1292 if (likely (dwfl != NULL))
1293 {
1294 /* Let 0 be the logical address of the file (or
1295 first in archive). */
1296 dwfl->offline_next_address = 0;
1297 if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd)
1298 == NULL)
1299 {
1300 /* Consumed on success, not on failure. */
1301 close (dwfl_fd);
1302 }
1303 else
1304 {
1305 dwfl_report_end (dwfl, NULL, NULL);
1306
1307 struct getdbg get = { .name = fname, .dbg = &dbg };
1308 dwfl_getmodules (dwfl, &getdbg_dwflmod, &get, 0);
1309 }
1310 }
1311 }
1312 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001313 if (dbg != NULL)
1314 {
1315 (void) dwarf_getpubnames (dbg, get_global, NULL, 0);
1316
1317 get_local_names (dbg);
1318 }
1319 }
1320
Mark Wielaardc08079a2015-06-27 22:07:01 +02001321 /* Get the data of the section. */
1322 Elf_Data *data = elf_getdata (scn, NULL);
1323 Elf_Data *xndxdata = elf_getdata (xndxscn, NULL);
1324 if (data == NULL || (xndxscn != NULL && xndxdata == NULL))
1325 INTERNAL_ERROR (fullname);
1326
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001327 /* Allocate the memory.
1328
1329 XXX We can use a dirty trick here. Since GElf_Sym == Elf64_Sym we
1330 can use the data memory instead of copying again if what we read
1331 is a 64 bit file. */
Mark Wielaard911f11a2016-03-21 16:01:02 +01001332 if (nentries > SIZE_MAX / sizeof (GElf_SymX))
1333 error (EXIT_FAILURE, 0,
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +00001334 _("%s: entries (%zd) in section %zd `%s' is too large"),
Mark Wielaard911f11a2016-03-21 16:01:02 +01001335 fullname, nentries, elf_ndxscn (scn),
1336 elf_strptr (ebl->elf, shstrndx, shdr->sh_name));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001337 GElf_SymX *sym_mem;
1338 if (nentries * sizeof (GElf_SymX) < MAX_STACK_ALLOC)
1339 sym_mem = (GElf_SymX *) alloca (nentries * sizeof (GElf_SymX));
1340 else
1341 sym_mem = (GElf_SymX *) xmalloc (nentries * sizeof (GElf_SymX));
1342
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001343 /* Iterate over all symbols. */
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001344#ifdef USE_DEMANGLE
1345 size_t demangle_buffer_len = 0;
1346 char *demangle_buffer = NULL;
1347#endif
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001348 int longest_name = 4;
1349 int longest_where = 4;
1350 size_t nentries_used = 0;
1351 for (size_t cnt = 0; cnt < nentries; ++cnt)
1352 {
1353 GElf_Sym *sym = gelf_getsymshndx (data, xndxdata, cnt,
1354 &sym_mem[nentries_used].sym,
1355 &sym_mem[nentries_used].xndx);
1356 if (sym == NULL)
1357 INTERNAL_ERROR (fullname);
1358
1359 /* Filter out administrative symbols without a name and those
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001360 deselected by the user with command line options. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001361 if ((hide_undefined && sym->st_shndx == SHN_UNDEF)
1362 || (hide_defined && sym->st_shndx != SHN_UNDEF)
1363 || (hide_local && GELF_ST_BIND (sym->st_info) == STB_LOCAL))
1364 continue;
1365
1366 sym_mem[nentries_used].where = "";
1367 if (format == format_sysv)
1368 {
1369 const char *symstr = elf_strptr (ebl->elf, shdr->sh_link,
1370 sym->st_name);
Roland McGrath468fe4d2008-12-11 21:00:12 -08001371 if (symstr == NULL)
1372 continue;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001373
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001374#ifdef USE_DEMANGLE
Jan Kratochvil7c6e7852014-01-15 21:16:57 +01001375 /* Demangle if necessary. Require GNU v3 ABI by the "_Z" prefix. */
1376 if (demangle && symstr[0] == '_' && symstr[1] == 'Z')
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001377 {
1378 int status = -1;
1379 char *dmsymstr = __cxa_demangle (symstr, demangle_buffer,
1380 &demangle_buffer_len, &status);
1381
1382 if (status == 0)
1383 symstr = dmsymstr;
1384 }
1385#endif
1386
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001387 longest_name = MAX ((size_t) longest_name, strlen (symstr));
1388
1389 if (sym->st_shndx != SHN_UNDEF
1390 && GELF_ST_BIND (sym->st_info) != STB_LOCAL
1391 && global_root != NULL)
1392 {
1393 Dwarf_Global fake = { .name = symstr };
1394 Dwarf_Global **found = tfind (&fake, &global_root,
1395 global_compare);
1396 if (found != NULL)
1397 {
1398 Dwarf_Die die_mem;
1399 Dwarf_Die *die = dwarf_offdie (dbg, (*found)->die_offset,
1400 &die_mem);
1401
1402 Dwarf_Die cudie_mem;
1403 Dwarf_Die *cudie = NULL;
1404
1405 Dwarf_Addr lowpc;
1406 Dwarf_Addr highpc;
1407 if (die != NULL
1408 && dwarf_lowpc (die, &lowpc) == 0
1409 && lowpc <= sym->st_value
1410 && dwarf_highpc (die, &highpc) == 0
1411 && highpc > sym->st_value)
1412 cudie = dwarf_offdie (dbg, (*found)->cu_offset,
1413 &cudie_mem);
1414 if (cudie != NULL)
1415 {
1416 Dwarf_Line *line = dwarf_getsrc_die (cudie,
1417 sym->st_value);
1418 if (line != NULL)
1419 {
1420 /* We found the line. */
1421 int lineno;
1422 (void) dwarf_lineno (line, &lineno);
Mark Wielaarda3344c72015-05-06 12:45:49 +02001423 const char *file = dwarf_linesrc (line, NULL, NULL);
1424 file = (file != NULL) ? basename (file) : "???";
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001425 int n;
Mark Wielaarda3344c72015-05-06 12:45:49 +02001426 n = obstack_printf (&whereob, "%s:%d%c", file,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001427 lineno, '\0');
1428 sym_mem[nentries_used].where
1429 = obstack_finish (&whereob);
1430
1431 /* The return value of obstack_print included the
1432 NUL byte, so subtract one. */
1433 if (--n > (int) longest_where)
1434 longest_where = (size_t) n;
1435 }
1436 }
1437 }
1438 }
1439
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001440 /* Try to find the symbol among the local symbols. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001441 if (sym_mem[nentries_used].where[0] == '\0')
1442 {
1443 struct local_name fake =
1444 {
1445 .name = symstr,
1446 .lowpc = sym->st_value,
1447 .highpc = sym->st_value,
1448 };
1449 struct local_name **found = tfind (&fake, &local_root,
1450 local_compare);
1451 if (found != NULL)
1452 {
1453 /* We found the line. */
1454 int n = obstack_printf (&whereob, "%s:%" PRIu64 "%c",
1455 basename ((*found)->file),
1456 (*found)->lineno,
1457 '\0');
1458 sym_mem[nentries_used].where = obstack_finish (&whereob);
1459
1460 /* The return value of obstack_print included the
1461 NUL byte, so subtract one. */
1462 if (--n > (int) longest_where)
1463 longest_where = (size_t) n;
1464 }
1465 }
1466 }
1467
1468 /* We use this entry. */
1469 ++nentries_used;
1470 }
Ulrich Drepperb4a16cf2011-10-02 08:33:19 -04001471#ifdef USE_DEMANGLE
1472 free (demangle_buffer);
1473#endif
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001474 /* Now we know the exact number. */
Mark Wielaarddf332852019-08-29 17:46:52 +02001475 size_t nentries_orig = nentries;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001476 nentries = nentries_used;
1477
1478 /* Sort the entries according to the users wishes. */
1479 if (sort == sort_name)
Roland McGrathcb6d8652007-08-23 08:10:54 +00001480 {
Mark Wielaard815fe152020-06-07 16:13:13 +02001481 sort_by_name_elf = ebl->elf;
1482 sort_by_name_ndx = shdr->sh_link;
Roland McGrathcb6d8652007-08-23 08:10:54 +00001483 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_name);
1484 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001485 else if (sort == sort_numeric)
1486 qsort (sym_mem, nentries, sizeof (GElf_SymX), sort_by_address);
1487
1488 /* Finally print according to the users selection. */
1489 switch (format)
1490 {
1491 case format_sysv:
Marek Polacekc8920de2011-05-12 12:08:21 +02001492 show_symbols_sysv (ebl, shdr->sh_link, fullname, sym_mem, nentries,
1493 longest_name, longest_where);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001494 break;
1495
1496 case format_bsd:
Ulrich Drepper2356ba02011-10-03 07:23:07 -04001497 show_symbols_bsd (ebl->elf, ehdr, shdr->sh_link, prefix, fname, fullname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001498 sym_mem, nentries);
1499 break;
1500
1501 case format_posix:
1502 default:
1503 assert (format == format_posix);
Ulrich Drepper2356ba02011-10-03 07:23:07 -04001504 show_symbols_posix (ebl->elf, ehdr, shdr->sh_link, prefix, fullname,
1505 sym_mem, nentries);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001506 break;
1507 }
1508
1509 /* Free all memory. */
Mark Wielaarddf332852019-08-29 17:46:52 +02001510 if (nentries_orig * sizeof (sym_mem[0]) >= MAX_STACK_ALLOC)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001511 free (sym_mem);
1512
1513 obstack_free (&whereob, NULL);
1514
1515 if (dbg != NULL)
1516 {
1517 tdestroy (global_root, free);
1518 global_root = NULL;
1519
1520 tdestroy (local_root, free);
1521 local_root = NULL;
1522
Mark Wielaard70cd9072015-12-02 16:57:44 +01001523 if (dwfl == NULL)
1524 (void) dwarf_end (dbg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001525 }
Mark Wielaard70cd9072015-12-02 16:57:44 +01001526 if (dwfl != NULL)
1527 dwfl_end (dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001528}
1529
1530
1531static int
Mark Wielaard70cd9072015-12-02 16:57:44 +01001532handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001533 const char *suffix)
1534{
1535 size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
1536 size_t suffix_len = suffix == NULL ? 0 : strlen (suffix);
1537 size_t fname_len = strlen (fname) + 1;
1538 char fullname[prefix_len + 1 + fname_len + suffix_len];
1539 char *cp = fullname;
1540 Elf_Scn *scn = NULL;
1541 int any = 0;
1542 int result = 0;
1543 GElf_Ehdr ehdr_mem;
1544 GElf_Ehdr *ehdr;
1545 Ebl *ebl;
1546
Mark Wielaard5d769dd2020-05-09 21:05:31 +02001547 /* Create the full name of the file. */
1548 if (prefix != NULL)
1549 cp = mempcpy (cp, prefix, prefix_len);
1550 cp = mempcpy (cp, fname, fname_len);
1551 if (suffix != NULL)
1552 memcpy (cp - 1, suffix, suffix_len + 1);
1553
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001554 /* Get the backend for this object file type. */
1555 ebl = ebl_openbackend (elf);
Mark Wielaard5d769dd2020-05-09 21:05:31 +02001556 if (ebl == NULL)
1557 INTERNAL_ERROR (fullname);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001558
1559 /* We need the ELF header in a few places. */
1560 ehdr = gelf_getehdr (elf, &ehdr_mem);
1561 if (ehdr == NULL)
1562 INTERNAL_ERROR (fullname);
1563
1564 /* If we are asked to print the dynamic symbol table and this is
1565 executable or dynamic executable, fail. */
1566 if (symsec_type == SHT_DYNSYM
1567 && ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
1568 {
1569 /* XXX Add machine specific object file types. */
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +00001570 error (0, 0, _("%s%s%s%s: Invalid operation"),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001571 prefix ?: "", prefix ? "(" : "", fname, prefix ? ")" : "");
1572 result = 1;
1573 goto out;
1574 }
1575
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001576 /* Find the symbol table.
1577
1578 XXX Can there be more than one? Do we print all? Currently we do. */
1579 while ((scn = elf_nextscn (elf, scn)) != NULL)
1580 {
1581 GElf_Shdr shdr_mem;
1582 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
1583
1584 if (shdr == NULL)
1585 INTERNAL_ERROR (fullname);
1586
1587 if (shdr->sh_type == symsec_type)
1588 {
1589 Elf_Scn *xndxscn = NULL;
1590
1591 /* We have a symbol table. First make sure we remember this. */
1592 any = 1;
1593
1594 /* Look for an extended section index table for this section. */
1595 if (symsec_type == SHT_SYMTAB)
1596 {
1597 size_t scnndx = elf_ndxscn (scn);
1598
1599 while ((xndxscn = elf_nextscn (elf, xndxscn)) != NULL)
1600 {
1601 GElf_Shdr xndxshdr_mem;
1602 GElf_Shdr *xndxshdr = gelf_getshdr (xndxscn, &xndxshdr_mem);
1603
1604 if (xndxshdr == NULL)
1605 INTERNAL_ERROR (fullname);
1606
1607 if (xndxshdr->sh_type == SHT_SYMTAB_SHNDX
1608 && xndxshdr->sh_link == scnndx)
1609 break;
1610 }
1611 }
1612
Mark Wielaard70cd9072015-12-02 16:57:44 +01001613 show_symbols (fd, ebl, ehdr, scn, xndxscn, shdr, prefix, fname,
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001614 fullname);
1615 }
1616 }
1617
1618 if (! any)
1619 {
Dmitry V. Levin3ddd8f92020-12-16 08:00:00 +00001620 error (0, 0, _("%s%s%s: no symbols"),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001621 prefix ?: "", prefix ? ":" : "", fname);
1622 result = 1;
1623 }
1624
1625 out:
1626 /* Close the ELF backend library descriptor. */
1627 ebl_closebackend (ebl);
1628
1629 return result;
1630}
Ulrich Drepper3cbdd382008-01-02 17:44:39 +00001631
1632
1633#include "debugpred.h"