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