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